[444] | 1 | /* entry.S - exception handler for emulating MIPS16 'entry' and 'exit' |
---|
| 2 | pseudo-instructions. These instructions are generated by the compiler |
---|
| 3 | when the -mentry switch is used. The instructions are not implemented |
---|
| 4 | in the MIPS16 CPU; hence the exception handler that emulates them. |
---|
| 5 | |
---|
| 6 | This module contains the following public functions: |
---|
| 7 | |
---|
| 8 | * void __install_entry_handler(void); |
---|
| 9 | |
---|
| 10 | This function installs the entry/exit exception handler. It should |
---|
| 11 | be called before executing any MIPS16 functions that were compiled with |
---|
| 12 | -mentry, typically before main() is called. |
---|
| 13 | |
---|
| 14 | * void __remove_entry_handler(void); |
---|
| 15 | |
---|
| 16 | This function removes the entry/exit exception handler. It should |
---|
| 17 | be called when the program is exiting, or when it is known that no |
---|
| 18 | more MIPS16 functions compiled with -mentry will be called. |
---|
| 19 | */ |
---|
| 20 | |
---|
| 21 | #ifdef __mips16 |
---|
| 22 | /* This file contains 32 bit assembly code. */ |
---|
| 23 | .set nomips16 |
---|
| 24 | #endif |
---|
| 25 | |
---|
| 26 | #include "regs.S" |
---|
| 27 | |
---|
| 28 | #define CAUSE_EXCMASK 0x3c /* mask for ExcCode in Cause Register */ |
---|
| 29 | #define EXC_RI 0x28 /* 101000 == 10 << 2 */ |
---|
| 30 | |
---|
| 31 | /* Set DEBUG to 1 to enable recording of the last 16 interrupt causes. */ |
---|
| 32 | |
---|
| 33 | #define DEBUG 0 |
---|
| 34 | |
---|
| 35 | #if DEBUG |
---|
| 36 | |
---|
| 37 | .sdata |
---|
| 38 | int_count: |
---|
| 39 | .space 4 /* interrupt count modulo 16 */ |
---|
| 40 | int_cause: |
---|
| 41 | .space 4*16 /* last 16 interrupt causes */ |
---|
| 42 | #endif |
---|
| 43 | |
---|
| 44 | .text |
---|
| 45 | |
---|
| 46 | .set noreorder /* Do NOT reorder instructions */ |
---|
| 47 | |
---|
| 48 | |
---|
| 49 | /* __entry_exit_handler - the reserved instruction exception handler |
---|
| 50 | that emulates the entry and exit instruction. */ |
---|
| 51 | |
---|
| 52 | __entry_exit_handler: |
---|
| 53 | .set noat /* Do NOT use at register */ |
---|
| 54 | #if DEBUG |
---|
| 55 | /* Must avoid using 'la' pseudo-op because it uses gp register, which |
---|
| 56 | may not have a good value in an exception handler. */ |
---|
| 57 | |
---|
| 58 | # la k0, int_count /* intcount = (intcount + 1) & 0xf */ |
---|
| 59 | lui k0 ,%hi(int_count) |
---|
| 60 | addiu k0, k0 ,%lo(int_count) |
---|
| 61 | lw k1, (k0) |
---|
| 62 | addiu k1, k1, 1 |
---|
| 63 | andi k1, k1, 0x0f |
---|
| 64 | sw k1, (k0) |
---|
| 65 | # la k0, int_cause /* k1 = &int_cause[intcount] */ |
---|
| 66 | lui k0, %hi(int_cause) |
---|
| 67 | addiu k0, k0, %lo(int_cause) |
---|
| 68 | sll k1, k1, 2 |
---|
| 69 | add k1, k1, k0 |
---|
| 70 | #endif |
---|
| 71 | mfc0 k0, C0_CAUSE /* Fetch cause */ |
---|
| 72 | #if DEBUG |
---|
| 73 | sw k0, -4(k1) /* Save exception cause in buffer */ |
---|
| 74 | #endif |
---|
| 75 | mfc0 k1, C0_EPC /* Check for Reserved Inst. without */ |
---|
| 76 | and k0, CAUSE_EXCMASK /* destroying any register */ |
---|
| 77 | subu k0, EXC_RI |
---|
| 78 | bne k0, zero, check_others /* Sorry, go do something else */ |
---|
| 79 | |
---|
| 80 | and k0, k1, 1 /* Check for TR mode (pc.0 = 1) */ |
---|
| 81 | beq k0, zero, ri_in_32 /* Sorry, RI in 32-bit mode */ |
---|
| 82 | xor k1, 1 |
---|
| 83 | |
---|
| 84 | /* Since we now are going to emulate or die, we can use all the T-registers */ |
---|
| 85 | /* that MIPS16 does not use (at, t0-t8), and we don't have to save them. */ |
---|
| 86 | |
---|
| 87 | .set at /* Now it's ok to use at again */ |
---|
| 88 | |
---|
| 89 | #if 0 |
---|
| 90 | j leave |
---|
| 91 | rfe |
---|
| 92 | #endif |
---|
| 93 | |
---|
| 94 | lhu t0, 0(k1) /* Fetch the offending instruction */ |
---|
| 95 | xor t8, k1, 1 /* Prepare t8 for exit */ |
---|
| 96 | and t1, t0, 0xf81f /* Check for entry/exit opcode */ |
---|
| 97 | bne t1, 0xe809, other_ri |
---|
| 98 | |
---|
| 99 | deareg: and t1, t0, 0x0700 /* Isolate the three a-bits */ |
---|
| 100 | srl t1, 6 /* Adjust them so x4 is applied */ |
---|
| 101 | slt t2, t1, 17 /* See if this is the exit instruction */ |
---|
| 102 | beqz t2, doexit |
---|
| 103 | la t2, savea |
---|
| 104 | subu t2, t1 |
---|
| 105 | jr t2 /* Jump into the instruction table */ |
---|
| 106 | rfe /* We run the rest in user-mode */ |
---|
| 107 | |
---|
| 108 | /* This is the entry instruction! */ |
---|
| 109 | sw a3, 12(sp) /* 4: a0-a3 saved */ |
---|
| 110 | sw a2, 8(sp) /* 3: a0-a2 saved */ |
---|
| 111 | sw a1, 4(sp) /* 2: a0-a1 saved */ |
---|
| 112 | sw a0, 0(sp) /* 1: a0 saved */ |
---|
| 113 | savea: /* 0: No arg regs saved */ |
---|
| 114 | |
---|
| 115 | dera: and t1, t0, 0x0020 /* Isolate the save-ra bit */ |
---|
| 116 | move t7, sp /* Temporary SP */ |
---|
| 117 | beq t1, zero, desreg |
---|
| 118 | subu sp, 32 /* Default SP adjustment */ |
---|
| 119 | sw ra, -4(t7) |
---|
| 120 | subu t7, 4 |
---|
| 121 | |
---|
| 122 | desreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */ |
---|
| 123 | beq t1, zero, leave |
---|
| 124 | subu t1, 0x0040 |
---|
| 125 | beq t1, zero, leave /* Only one to save... */ |
---|
| 126 | sw s0, -4(t7) /* Do the first one */ |
---|
| 127 | sw s1, -8(t7) /* Do the last one */ |
---|
| 128 | |
---|
| 129 | leave: jr t8 /* Exit to unmodified EPC */ |
---|
| 130 | nop /* Urgh - the only nop!! */ |
---|
| 131 | |
---|
| 132 | doexf0: mtc1 v0,$f0 /* Copy float value */ |
---|
| 133 | b doex2 |
---|
| 134 | |
---|
| 135 | doexf1: mtc1 v1,$f0 /* Copy double value */ |
---|
| 136 | mtc1 v0,$f1 |
---|
| 137 | b doex2 |
---|
| 138 | |
---|
| 139 | doexit: slt t2, t1, 21 |
---|
| 140 | beq t2, zero, doexf0 |
---|
| 141 | slt t2, t1, 25 |
---|
| 142 | beq t2, zero, doexf1 |
---|
| 143 | |
---|
| 144 | doex2: and t1, t0, 0x0020 /* Isolate ra bit */ |
---|
| 145 | beq t1, zero, dxsreg /* t1 holds ra-bit */ |
---|
| 146 | addu t7, sp, 32 /* Temporary SP */ |
---|
| 147 | lw ra, -4(t7) |
---|
| 148 | subu t7, 4 |
---|
| 149 | |
---|
| 150 | dxsreg: and t1, t0, 0x00c0 /* Isolate the two s-bits */ |
---|
| 151 | beq t1, zero, leavex |
---|
| 152 | subu t1, 0x0040 |
---|
| 153 | beq t1, zero, leavex /* Only one to save... */ |
---|
| 154 | lw s0, -4(t7) /* Do the first one */ |
---|
| 155 | lw s1, -8(t7) /* Do the last one */ |
---|
| 156 | |
---|
| 157 | leavex: jr ra /* Exit to ra */ |
---|
| 158 | addu sp, 32 /* Clean up stack pointer */ |
---|
| 159 | |
---|
| 160 | /* Come here for exceptions we can't handle. */ |
---|
| 161 | |
---|
| 162 | ri_in_32: |
---|
| 163 | other_ri: |
---|
| 164 | check_others: /* call the previous handler */ |
---|
| 165 | la k0,__previous |
---|
| 166 | jr k0 |
---|
| 167 | nop |
---|
| 168 | |
---|
| 169 | __exception_code: |
---|
| 170 | .set noreorder |
---|
| 171 | la k0, __entry_exit_handler |
---|
| 172 | # lui k0, %hi(exception) |
---|
| 173 | # addiu k0, k0, %lo(exception) |
---|
| 174 | jr k0 |
---|
| 175 | nop |
---|
| 176 | .set reorder |
---|
| 177 | __exception_code_end: |
---|
| 178 | |
---|
| 179 | .data |
---|
| 180 | __previous: |
---|
| 181 | .space (__exception_code_end - __exception_code) |
---|
| 182 | .text |
---|
| 183 | |
---|
| 184 | |
---|
| 185 | /* void __install_entry_handler(void) |
---|
| 186 | |
---|
| 187 | Install our entry/exit reserved instruction exception handler. |
---|
| 188 | */ |
---|
| 189 | .ent __install_entry_handler |
---|
| 190 | .globl __install_entry_handler |
---|
| 191 | __install_entry_handler: |
---|
| 192 | .set noreorder |
---|
| 193 | mfc0 a0,C0_SR |
---|
| 194 | nop |
---|
| 195 | li a1,SR_BEV |
---|
| 196 | and a1,a1,a0 |
---|
| 197 | beq a1,$0,baseaddr |
---|
| 198 | lui a0,0x8000 /* delay slot */ |
---|
| 199 | lui a0,0xbfc0 |
---|
| 200 | addiu a0,a0,0x0100 |
---|
| 201 | baseaddr: |
---|
| 202 | addiu a0,a0,0x080 /* a0 = base vector table address */ |
---|
| 203 | li a1,(__exception_code_end - __exception_code) |
---|
| 204 | la a2,__exception_code |
---|
| 205 | la a3,__previous |
---|
| 206 | /* there must be a better way of doing this???? */ |
---|
| 207 | copyloop: |
---|
| 208 | lw v0,0(a0) |
---|
| 209 | sw v0,0(a3) |
---|
| 210 | lw v0,0(a2) |
---|
| 211 | sw v0,0(a0) |
---|
| 212 | addiu a0,a0,4 |
---|
| 213 | addiu a2,a2,4 |
---|
| 214 | addiu a3,a3,4 |
---|
| 215 | subu a1,a1,4 |
---|
| 216 | bne a1,$0,copyloop |
---|
| 217 | nop |
---|
| 218 | j ra |
---|
| 219 | nop |
---|
| 220 | .set reorder |
---|
| 221 | .end __install_entry_handler |
---|
| 222 | |
---|
| 223 | |
---|
| 224 | /* void __remove_entry_handler(void); |
---|
| 225 | |
---|
| 226 | Remove our entry/exit reserved instruction exception handler. |
---|
| 227 | */ |
---|
| 228 | |
---|
| 229 | .ent __remove_entry_handler |
---|
| 230 | .globl __remove_entry_handler |
---|
| 231 | __remove_entry_handler: |
---|
| 232 | .set noreorder |
---|
| 233 | |
---|
| 234 | mfc0 a0,C0_SR |
---|
| 235 | nop |
---|
| 236 | li a1,SR_BEV |
---|
| 237 | and a1,a1,a0 |
---|
| 238 | beq a1,$0,res_baseaddr |
---|
| 239 | lui a0,0x8000 /* delay slot */ |
---|
| 240 | lui a0,0xbfc0 |
---|
| 241 | addiu a0,a0,0x0200 |
---|
| 242 | res_baseaddr: |
---|
| 243 | addiu a0,a0,0x0180 /* a0 = base vector table address */ |
---|
| 244 | li a1,(__exception_code_end - __exception_code) |
---|
| 245 | la a3,__previous |
---|
| 246 | |
---|
| 247 | /* there must be a better way of doing this???? */ |
---|
| 248 | res_copyloop: |
---|
| 249 | lw v0,0(a3) |
---|
| 250 | sw v0,0(a0) |
---|
| 251 | addiu a0,a0,4 |
---|
| 252 | addiu a3,a3,4 |
---|
| 253 | subu a1,a1,4 |
---|
| 254 | bne a1,$0,res_copyloop |
---|
| 255 | nop |
---|
| 256 | j ra |
---|
| 257 | nop |
---|
| 258 | .set reorder |
---|
| 259 | .end __remove_entry_handler |
---|
| 260 | |
---|
| 261 | |
---|
| 262 | /* software_init_hook - install entry/exit handler and arrange to have it |
---|
| 263 | removed at exit. This function is called by crt0.S. */ |
---|
| 264 | |
---|
| 265 | .text |
---|
| 266 | .globl software_init_hook |
---|
| 267 | .ent software_init_hook |
---|
| 268 | software_init_hook: |
---|
| 269 | .set noreorder |
---|
| 270 | subu sp, sp, 8 /* allocate stack space */ |
---|
| 271 | sw ra, 4(sp) /* save return address */ |
---|
| 272 | jal __install_entry_handler /* install entry/exit handler */ |
---|
| 273 | nop |
---|
| 274 | lui a0, %hi(__remove_entry_handler) /* arrange for exit to */ |
---|
| 275 | jal atexit /* de-install handler */ |
---|
| 276 | addiu a0, a0, %lo(__remove_entry_handler) /* delay slot */ |
---|
| 277 | lw ra, 4(sp) /* get return address */ |
---|
| 278 | j ra /* return */ |
---|
| 279 | addu sp, sp, 8 /* deallocate stack */ |
---|
| 280 | .set reorder |
---|
| 281 | .end software_init_hook |
---|