1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
/* $Id: r4k_genex.S,v 1.3 1999/11/23 17:12:49 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1994 - 1999 by Ralf Baechle
* Copyright (C) 1999 Silicon Graphics
*
* Low level exception handling
*/
#define __ASSEMBLY__
#include <linux/init.h>
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/fpregdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/r4kcacheops.h>
.macro __build_clear_none
.endm
.macro __build_clear_sti
STI
.endm
.macro __build_clear_cli
CLI
.endm
.macro __build_clear_fpe
cfc1 a1, fcr31
li a2, ~(0x3f << 13)
and a2, a1
ctc1 a2, fcr31
STI
.endm
.macro __build_clear_ade
dmfc0 t0, CP0_BADVADDR
sd t0, PT_BVADDR(sp)
KMODE
.endm
.macro __BUILD_silent exception
.endm
/* Gas tries to parse the PRINT argument as a string containing
string escapes and emits bogus warnings if it believes to
recognize an unknown escape code. So make the arguments
start with an n and gas will believe \n is ok ... */
.macro __BUILD_verbose nexception
ld a1, PT_EPC(sp)
PRINT("Got \nexception at %016lx\012")
.endm
.macro __BUILD_count exception
.set reorder
ld t0,exception_count_\exception
daddiu t0, 1
sd t0,exception_count_\exception
.set noreorder
.comm exception_count\exception, 8, 8
.endm
.macro BUILD_HANDLER exception handler clear verbose
.align 5
NESTED(handle_\exception, PT_SIZE, sp)
.set noat
SAVE_ALL
__BUILD_clear_\clear
.set at
__BUILD_\verbose \exception
move a0, sp
jal do_\handler
j ret_from_sys_call
nop
END(handle_\exception)
.endm
BUILD_HANDLER adel ade ade silent /* #4 */
BUILD_HANDLER ades ade ade silent /* #5 */
BUILD_HANDLER ibe ibe cli silent /* #6 */
BUILD_HANDLER dbe dbe cli silent /* #7 */
BUILD_HANDLER bp bp sti silent /* #9 */
BUILD_HANDLER ri ri sti silent /* #10 */
BUILD_HANDLER cpu cpu sti silent /* #11 */
BUILD_HANDLER ov ov sti silent /* #12 */
BUILD_HANDLER tr tr sti silent /* #13 */
BUILD_HANDLER fpe fpe fpe silent /* #15 */
BUILD_HANDLER watch watch sti verbose /* #23 */
BUILD_HANDLER reserved reserved sti verbose /* others */
__INIT
/* General exception handler for CPUs with virtual coherency exception.
*
* Be careful when changing this, it has to be at most 128 bytes to fit
* into space reserved for the exception handler.
*/
NESTED(except_vec3_r4000, 0, sp)
.set noat
mfc0 k1, CP0_CAUSE
andi k1, k1, 0x7c
li k0, 31<<2
beq k1, k0, handle_vced
li k0, 14<<2
beq k1, k0, handle_vcei
dsll k1, k1, 1
ld k0, exception_handlers(k1)
jr k0
/*
* Big shit, we now may have two dirty primary cache lines for the same
* physical address. We can savely invalidate the line pointed to by
* c0_badvaddr because after return from this exception handler the load /
* store will be re-executed.
*/
handle_vced:
mfc0 k0, CP0_BADVADDR
li k1, -4 # Is this ...
and k0, k1 # ... really needed?
mtc0 zero, CP0_TAGLO
cache Index_Store_Tag_D,(k0)
cache Hit_Writeback_Inv_SD,(k0)
lui k0, %hi(vced_count)
lw k1, %lo(vced_count)(k0)
addiu k1, 1
sw k1, %lo(vced_count)(k0)
eret
handle_vcei:
mfc0 k0, CP0_BADVADDR
cache Hit_Writeback_Inv_SD,(k0) # also cleans pi
lui k0, %hi(vcei_count)
lw k1, %lo(vcei_count)(k0)
addiu k1, 1
sw k1, %lo(vcei_count)(k0)
eret
END(except_vec3_r4000)
.set at
/* General exception vector for all other CPUs. */
NESTED(except_vec3_generic, 0, sp)
.set noat
mfc0 k1, CP0_CAUSE
andi k1, k1, 0x7c
dsll k1, k1, 1
ld k0, exception_handlers(k1)
jr k0
nop
END(except_vec3_generic)
.set at
/*
* Special interrupt vector for embedded MIPS. This is a dedicated interrupt
* vector which reduces interrupt processing overhead. The jump instruction
* will be inserted here at initialization time. This handler may only be 8
* bytes in size!
*/
NESTED(except_vec4, 0, sp)
1: j 1b /* Dummy, will be replaced */
nop
END(except_vec4)
__FINIT
|