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 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
|
/* entry.S - exception handler for emulating MIPS16 'entry' and 'exit'
pseudo-instructions. These instructions are generated by the compiler
when the -mentry switch is used. The instructions are not implemented
in the MIPS16 CPU; hence the exception handler that emulates them.
This module contains the following public functions:
* void __install_entry_handler(void);
This function installs the entry/exit exception handler. It should
be called before executing any MIPS16 functions that were compiled with
-mentry, typically before main() is called.
* void __remove_entry_handler(void);
This function removes the entry/exit exception handler. It should
be called when the program is exiting, or when it is known that no
more MIPS16 functions compiled with -mentry will be called.
*/
#ifdef __mips16
/* This file contains 32 bit assembly code. */
.set nomips16
#endif
#include "regs.S"
#define CAUSE_EXCMASK 0x3c /* mask for ExcCode in Cause Register */
#define EXC_RI 0x28 /* 101000 == 10 << 2 */
/* Set DEBUG to 1 to enable recording of the last 16 interrupt causes. */
#define DEBUG 0
#if DEBUG
.sdata
int_count:
.space 4 /* interrupt count modulo 16 */
int_cause:
.space 4*16 /* last 16 interrupt causes */
#endif
.text
.set noreorder /* Do NOT reorder instructions */
/* __entry_exit_handler - the reserved instruction exception handler
that emulates the entry and exit instruction. */
__entry_exit_handler:
.set noat /* Do NOT use at register */
#if DEBUG
/* Must avoid using 'la' pseudo-op because it uses gp register, which
may not have a good value in an exception handler. */
# la k0, int_count /* intcount = (intcount + 1) & 0xf */
lui k0 ,%hi(int_count)
addiu k0, k0 ,%lo(int_count)
lw k1, (k0)
addiu k1, k1, 1
andi k1, k1, 0x0f
sw k1, (k0)
# la k0, int_cause /* k1 = &int_cause[intcount] */
lui k0, %hi(int_cause)
addiu k0, k0, %lo(int_cause)
sll k1, k1, 2
add k1, k1, k0
#endif
mfc0 k0, C0_CAUSE /* Fetch cause */
#if DEBUG
sw k0, -4(k1) /* Save exception cause in buffer */
#endif
mfc0 k1, C0_EPC /* Check for Reserved Inst. without */
and k0, CAUSE_EXCMASK /* destroying any register */
subu k0, EXC_RI
bne k0, zero, check_others /* Sorry, go do something else */
and k0, k1, 1 /* Check for TR mode (pc.0 = 1) */
beq k0, zero, ri_in_32 /* Sorry, RI in 32-bit mode */
xor k1, 1
/* Since we now are going to emulate or die, we can use all the T-registers */
/* that MIPS16 does not use (at, t0-t8), and we don't have to save them. */
.set at /* Now it's ok to use at again */
#if 0
j leave
rfe
#endif
lhu t0, 0(k1) /* Fetch the offending instruction */
xor t8, k1, 1 /* Prepare t8 for exit */
and t1, t0, 0xf81f /* Check for entry/exit opcode */
bne t1, 0xe809, other_ri
deareg: and t1, t0, 0x0700 /* Isolate the three a-bits */
srl t1, 6 /* Adjust them so x4 is applied */
slt t2, t1, 17 /* See if this is the exit instruction */
beqz t2, doexit
la t2, savea
subu t2, t1
jr t2 /* Jump into the instruction table */
rfe /* We run the rest in user-mode */
/* This is the entry instruction! */
sw a3, 12(sp) /* 4: a0-a3 saved */
sw a2, 8(sp) /* 3: a0-a2 saved */
sw a1, 4(sp) /* 2: a0-a1 saved */
sw a0, 0(sp) /* 1: a0 saved */
savea: /* 0: No arg regs saved */
dera: and t1, t0, 0x0020 /* Isolate the save-ra bit */
move t7, sp /* Temporary SP */
beq t1, zero, desreg
subu sp, 32 /* Default SP adjustment */
sw ra, -4(t7)
subu t7, 4
desreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
beq t1, zero, leave
subu t1, 0x0040
beq t1, zero, leave /* Only one to save... */
sw s0, -4(t7) /* Do the first one */
sw s1, -8(t7) /* Do the last one */
leave: jr t8 /* Exit to unmodified EPC */
nop /* Urgh - the only nop!! */
doexf0: mtc1 v0,$f0 /* Copy float value */
b doex2
doexf1: mtc1 v1,$f0 /* Copy double value */
mtc1 v0,$f1
b doex2
doexit: slt t2, t1, 21
beq t2, zero, doexf0
slt t2, t1, 25
beq t2, zero, doexf1
doex2: and t1, t0, 0x0020 /* Isolate ra bit */
beq t1, zero, dxsreg /* t1 holds ra-bit */
addu t7, sp, 32 /* Temporary SP */
lw ra, -4(t7)
subu t7, 4
dxsreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */
beq t1, zero, leavex
subu t1, 0x0040
beq t1, zero, leavex /* Only one to save... */
lw s0, -4(t7) /* Do the first one */
lw s1, -8(t7) /* Do the last one */
leavex: jr ra /* Exit to ra */
addu sp, 32 /* Clean up stack pointer */
/* Come here for exceptions we can't handle. */
ri_in_32:
other_ri:
check_others: /* call the previous handler */
la k0,__previous
jr k0
nop
__exception_code:
.set noreorder
la k0, __entry_exit_handler
# lui k0, %hi(exception)
# addiu k0, k0, %lo(exception)
jr k0
nop
.set reorder
__exception_code_end:
.data
__previous:
.space (__exception_code_end - __exception_code)
.text
/* void __install_entry_handler(void)
Install our entry/exit reserved instruction exception handler.
*/
.ent __install_entry_handler
.globl __install_entry_handler
__install_entry_handler:
.set noreorder
mfc0 a0,C0_SR
nop
li a1,SR_BEV
and a1,a1,a0
beq a1,$0,baseaddr
lui a0,0x8000 /* delay slot */
lui a0,0xbfc0
addiu a0,a0,0x0100
baseaddr:
addiu a0,a0,0x080 /* a0 = base vector table address */
li a1,(__exception_code_end - __exception_code)
la a2,__exception_code
la a3,__previous
/* there must be a better way of doing this???? */
copyloop:
lw v0,0(a0)
sw v0,0(a3)
lw v0,0(a2)
sw v0,0(a0)
addiu a0,a0,4
addiu a2,a2,4
addiu a3,a3,4
subu a1,a1,4
bne a1,$0,copyloop
nop
j ra
nop
.set reorder
.end __install_entry_handler
/* void __remove_entry_handler(void);
Remove our entry/exit reserved instruction exception handler.
*/
.ent __remove_entry_handler
.globl __remove_entry_handler
__remove_entry_handler:
.set noreorder
mfc0 a0,C0_SR
nop
li a1,SR_BEV
and a1,a1,a0
beq a1,$0,res_baseaddr
lui a0,0x8000 /* delay slot */
lui a0,0xbfc0
addiu a0,a0,0x0200
res_baseaddr:
addiu a0,a0,0x0180 /* a0 = base vector table address */
li a1,(__exception_code_end - __exception_code)
la a3,__previous
/* there must be a better way of doing this???? */
res_copyloop:
lw v0,0(a3)
sw v0,0(a0)
addiu a0,a0,4
addiu a3,a3,4
subu a1,a1,4
bne a1,$0,res_copyloop
nop
j ra
nop
.set reorder
.end __remove_entry_handler
/* software_init_hook - install entry/exit handler and arrange to have it
removed at exit. This function is called by crt0.S. */
.text
.globl software_init_hook
.ent software_init_hook
software_init_hook:
.set noreorder
subu sp, sp, 8 /* allocate stack space */
sw ra, 4(sp) /* save return address */
jal __install_entry_handler /* install entry/exit handler */
nop
lui a0, %hi(__remove_entry_handler) /* arrange for exit to */
jal atexit /* de-install handler */
addiu a0, a0, %lo(__remove_entry_handler) /* delay slot */
lw ra, 4(sp) /* get return address */
j ra /* return */
addu sp, sp, 8 /* deallocate stack */
.set reorder
.end software_init_hook
|