Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * arch/v850/kernel/entry.S -- Low-level system-call handling, trap handlers, |
| 3 | * and context-switching |
| 4 | * |
| 5 | * Copyright (C) 2001,02,03 NEC Electronics Corporation |
| 6 | * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> |
| 7 | * |
| 8 | * This file is subject to the terms and conditions of the GNU General |
| 9 | * Public License. See the file COPYING in the main directory of this |
| 10 | * archive for more details. |
| 11 | * |
| 12 | * Written by Miles Bader <miles@gnu.org> |
| 13 | */ |
| 14 | |
| 15 | #include <linux/sys.h> |
| 16 | |
| 17 | #include <asm/entry.h> |
| 18 | #include <asm/current.h> |
| 19 | #include <asm/thread_info.h> |
| 20 | #include <asm/clinkage.h> |
| 21 | #include <asm/processor.h> |
| 22 | #include <asm/irq.h> |
| 23 | #include <asm/errno.h> |
| 24 | |
| 25 | #include <asm/asm-consts.h> |
| 26 | |
| 27 | |
| 28 | /* Make a slightly more convenient alias for C_SYMBOL_NAME. */ |
| 29 | #define CSYM C_SYMBOL_NAME |
| 30 | |
| 31 | |
| 32 | /* The offset of the struct pt_regs in a state-save-frame on the stack. */ |
| 33 | #define PTO STATE_SAVE_PT_OFFSET |
| 34 | |
| 35 | |
| 36 | /* Save argument registers to the state-save-frame pointed to by EP. */ |
| 37 | #define SAVE_ARG_REGS \ |
| 38 | sst.w r6, PTO+PT_GPR(6)[ep]; \ |
| 39 | sst.w r7, PTO+PT_GPR(7)[ep]; \ |
| 40 | sst.w r8, PTO+PT_GPR(8)[ep]; \ |
| 41 | sst.w r9, PTO+PT_GPR(9)[ep] |
| 42 | /* Restore argument registers from the state-save-frame pointed to by EP. */ |
| 43 | #define RESTORE_ARG_REGS \ |
| 44 | sld.w PTO+PT_GPR(6)[ep], r6; \ |
| 45 | sld.w PTO+PT_GPR(7)[ep], r7; \ |
| 46 | sld.w PTO+PT_GPR(8)[ep], r8; \ |
| 47 | sld.w PTO+PT_GPR(9)[ep], r9 |
| 48 | |
| 49 | /* Save value return registers to the state-save-frame pointed to by EP. */ |
| 50 | #define SAVE_RVAL_REGS \ |
| 51 | sst.w r10, PTO+PT_GPR(10)[ep]; \ |
| 52 | sst.w r11, PTO+PT_GPR(11)[ep] |
| 53 | /* Restore value return registers from the state-save-frame pointed to by EP. */ |
| 54 | #define RESTORE_RVAL_REGS \ |
| 55 | sld.w PTO+PT_GPR(10)[ep], r10; \ |
| 56 | sld.w PTO+PT_GPR(11)[ep], r11 |
| 57 | |
| 58 | |
| 59 | #define SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ |
| 60 | sst.w r1, PTO+PT_GPR(1)[ep]; \ |
| 61 | sst.w r5, PTO+PT_GPR(5)[ep] |
| 62 | #define SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL \ |
| 63 | sst.w r12, PTO+PT_GPR(12)[ep]; \ |
| 64 | sst.w r13, PTO+PT_GPR(13)[ep]; \ |
| 65 | sst.w r14, PTO+PT_GPR(14)[ep]; \ |
| 66 | sst.w r15, PTO+PT_GPR(15)[ep]; \ |
| 67 | sst.w r16, PTO+PT_GPR(16)[ep]; \ |
| 68 | sst.w r17, PTO+PT_GPR(17)[ep]; \ |
| 69 | sst.w r18, PTO+PT_GPR(18)[ep]; \ |
| 70 | sst.w r19, PTO+PT_GPR(19)[ep] |
| 71 | #define RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ |
| 72 | sld.w PTO+PT_GPR(1)[ep], r1; \ |
| 73 | sld.w PTO+PT_GPR(5)[ep], r5 |
| 74 | #define RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL \ |
| 75 | sld.w PTO+PT_GPR(12)[ep], r12; \ |
| 76 | sld.w PTO+PT_GPR(13)[ep], r13; \ |
| 77 | sld.w PTO+PT_GPR(14)[ep], r14; \ |
| 78 | sld.w PTO+PT_GPR(15)[ep], r15; \ |
| 79 | sld.w PTO+PT_GPR(16)[ep], r16; \ |
| 80 | sld.w PTO+PT_GPR(17)[ep], r17; \ |
| 81 | sld.w PTO+PT_GPR(18)[ep], r18; \ |
| 82 | sld.w PTO+PT_GPR(19)[ep], r19 |
| 83 | |
| 84 | /* Save `call clobbered' registers to the state-save-frame pointed to by EP. */ |
| 85 | #define SAVE_CALL_CLOBBERED_REGS \ |
| 86 | SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ |
| 87 | SAVE_ARG_REGS; \ |
| 88 | SAVE_RVAL_REGS; \ |
| 89 | SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL |
| 90 | /* Restore `call clobbered' registers from the state-save-frame pointed to |
| 91 | by EP. */ |
| 92 | #define RESTORE_CALL_CLOBBERED_REGS \ |
| 93 | RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ |
| 94 | RESTORE_ARG_REGS; \ |
| 95 | RESTORE_RVAL_REGS; \ |
| 96 | RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL |
| 97 | |
| 98 | /* Save `call clobbered' registers except for the return-value registers |
| 99 | to the state-save-frame pointed to by EP. */ |
| 100 | #define SAVE_CALL_CLOBBERED_REGS_NO_RVAL \ |
| 101 | SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ |
| 102 | SAVE_ARG_REGS; \ |
| 103 | SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL |
| 104 | /* Restore `call clobbered' registers except for the return-value registers |
| 105 | from the state-save-frame pointed to by EP. */ |
| 106 | #define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL \ |
| 107 | RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ |
| 108 | RESTORE_ARG_REGS; \ |
| 109 | RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL |
| 110 | |
| 111 | /* Save `call saved' registers to the state-save-frame pointed to by EP. */ |
| 112 | #define SAVE_CALL_SAVED_REGS \ |
| 113 | sst.w r2, PTO+PT_GPR(2)[ep]; \ |
| 114 | sst.w r20, PTO+PT_GPR(20)[ep]; \ |
| 115 | sst.w r21, PTO+PT_GPR(21)[ep]; \ |
| 116 | sst.w r22, PTO+PT_GPR(22)[ep]; \ |
| 117 | sst.w r23, PTO+PT_GPR(23)[ep]; \ |
| 118 | sst.w r24, PTO+PT_GPR(24)[ep]; \ |
| 119 | sst.w r25, PTO+PT_GPR(25)[ep]; \ |
| 120 | sst.w r26, PTO+PT_GPR(26)[ep]; \ |
| 121 | sst.w r27, PTO+PT_GPR(27)[ep]; \ |
| 122 | sst.w r28, PTO+PT_GPR(28)[ep]; \ |
| 123 | sst.w r29, PTO+PT_GPR(29)[ep] |
| 124 | /* Restore `call saved' registers from the state-save-frame pointed to by EP. */ |
| 125 | #define RESTORE_CALL_SAVED_REGS \ |
| 126 | sld.w PTO+PT_GPR(2)[ep], r2; \ |
| 127 | sld.w PTO+PT_GPR(20)[ep], r20; \ |
| 128 | sld.w PTO+PT_GPR(21)[ep], r21; \ |
| 129 | sld.w PTO+PT_GPR(22)[ep], r22; \ |
| 130 | sld.w PTO+PT_GPR(23)[ep], r23; \ |
| 131 | sld.w PTO+PT_GPR(24)[ep], r24; \ |
| 132 | sld.w PTO+PT_GPR(25)[ep], r25; \ |
| 133 | sld.w PTO+PT_GPR(26)[ep], r26; \ |
| 134 | sld.w PTO+PT_GPR(27)[ep], r27; \ |
| 135 | sld.w PTO+PT_GPR(28)[ep], r28; \ |
| 136 | sld.w PTO+PT_GPR(29)[ep], r29 |
| 137 | |
| 138 | |
| 139 | /* Save the PC stored in the special register SAVEREG to the state-save-frame |
| 140 | pointed to by EP. r19 is clobbered. */ |
| 141 | #define SAVE_PC(savereg) \ |
| 142 | stsr SR_ ## savereg, r19; \ |
| 143 | sst.w r19, PTO+PT_PC[ep] |
| 144 | /* Restore the PC from the state-save-frame pointed to by EP, to the special |
| 145 | register SAVEREG. LP is clobbered (it is used as a scratch register |
| 146 | because the POP_STATE macro restores it, and this macro is usually used |
| 147 | inside POP_STATE). */ |
| 148 | #define RESTORE_PC(savereg) \ |
| 149 | sld.w PTO+PT_PC[ep], lp; \ |
| 150 | ldsr lp, SR_ ## savereg |
| 151 | /* Save the PSW register stored in the special register SAVREG to the |
| 152 | state-save-frame pointed to by EP. r19 is clobbered. */ |
| 153 | #define SAVE_PSW(savereg) \ |
| 154 | stsr SR_ ## savereg, r19; \ |
| 155 | sst.w r19, PTO+PT_PSW[ep] |
| 156 | /* Restore the PSW register from the state-save-frame pointed to by EP, to |
| 157 | the special register SAVEREG. LP is clobbered (it is used as a scratch |
| 158 | register because the POP_STATE macro restores it, and this macro is |
| 159 | usually used inside POP_STATE). */ |
| 160 | #define RESTORE_PSW(savereg) \ |
| 161 | sld.w PTO+PT_PSW[ep], lp; \ |
| 162 | ldsr lp, SR_ ## savereg |
| 163 | |
| 164 | /* Save CTPC/CTPSW/CTBP registers to the state-save-frame pointed to by REG. |
| 165 | r19 is clobbered. */ |
| 166 | #define SAVE_CT_REGS \ |
| 167 | stsr SR_CTPC, r19; \ |
| 168 | sst.w r19, PTO+PT_CTPC[ep]; \ |
| 169 | stsr SR_CTPSW, r19; \ |
| 170 | sst.w r19, PTO+PT_CTPSW[ep]; \ |
| 171 | stsr SR_CTBP, r19; \ |
| 172 | sst.w r19, PTO+PT_CTBP[ep] |
| 173 | /* Restore CTPC/CTPSW/CTBP registers from the state-save-frame pointed to by EP. |
| 174 | LP is clobbered (it is used as a scratch register because the POP_STATE |
| 175 | macro restores it, and this macro is usually used inside POP_STATE). */ |
| 176 | #define RESTORE_CT_REGS \ |
| 177 | sld.w PTO+PT_CTPC[ep], lp; \ |
| 178 | ldsr lp, SR_CTPC; \ |
| 179 | sld.w PTO+PT_CTPSW[ep], lp; \ |
| 180 | ldsr lp, SR_CTPSW; \ |
| 181 | sld.w PTO+PT_CTBP[ep], lp; \ |
| 182 | ldsr lp, SR_CTBP |
| 183 | |
| 184 | |
| 185 | /* Push register state, except for the stack pointer, on the stack in the |
| 186 | form of a state-save-frame (plus some extra padding), in preparation for |
| 187 | a system call. This macro makes sure that the EP, GP, and LP |
| 188 | registers are saved, and TYPE identifies the set of extra registers to |
| 189 | be saved as well. Also copies (the new value of) SP to EP. */ |
| 190 | #define PUSH_STATE(type) \ |
| 191 | addi -STATE_SAVE_SIZE, sp, sp; /* Make room on the stack. */ \ |
| 192 | st.w ep, PTO+PT_GPR(GPR_EP)[sp]; \ |
| 193 | mov sp, ep; \ |
| 194 | sst.w gp, PTO+PT_GPR(GPR_GP)[ep]; \ |
| 195 | sst.w lp, PTO+PT_GPR(GPR_LP)[ep]; \ |
| 196 | type ## _STATE_SAVER |
| 197 | /* Pop a register state pushed by PUSH_STATE, except for the stack pointer, |
| 198 | from the the stack. */ |
| 199 | #define POP_STATE(type) \ |
| 200 | mov sp, ep; \ |
| 201 | type ## _STATE_RESTORER; \ |
| 202 | sld.w PTO+PT_GPR(GPR_GP)[ep], gp; \ |
| 203 | sld.w PTO+PT_GPR(GPR_LP)[ep], lp; \ |
| 204 | sld.w PTO+PT_GPR(GPR_EP)[ep], ep; \ |
| 205 | addi STATE_SAVE_SIZE, sp, sp /* Clean up our stack space. */ |
| 206 | |
| 207 | |
| 208 | /* Switch to the kernel stack if necessary, and push register state on the |
| 209 | stack in the form of a state-save-frame. Also load the current task |
| 210 | pointer if switching from user mode. The stack-pointer (r3) should have |
| 211 | already been saved to the memory location SP_SAVE_LOC (the reason for |
| 212 | this is that the interrupt vectors may be beyond a 22-bit signed offset |
| 213 | jump from the actual interrupt handler, and this allows them to save the |
| 214 | stack-pointer and use that register to do an indirect jump). This macro |
| 215 | makes sure that `special' registers, system registers, and the stack |
| 216 | pointer are saved; TYPE identifies the set of extra registers to be |
| 217 | saved as well. SYSCALL_NUM is the register in which the system-call |
| 218 | number this state is for is stored (r0 if this isn't a system call). |
| 219 | Interrupts should already be disabled when calling this. */ |
| 220 | #define SAVE_STATE(type, syscall_num, sp_save_loc) \ |
| 221 | tst1 0, KM; /* See if already in kernel mode. */ \ |
| 222 | bz 1f; \ |
| 223 | ld.w sp_save_loc, sp; /* ... yes, use saved SP. */ \ |
| 224 | br 2f; \ |
| 225 | 1: ld.w KSP, sp; /* ... no, switch to kernel stack. */ \ |
| 226 | 2: PUSH_STATE(type); \ |
| 227 | ld.b KM, r19; /* Remember old kernel-mode. */ \ |
| 228 | sst.w r19, PTO+PT_KERNEL_MODE[ep]; \ |
| 229 | ld.w sp_save_loc, r19; /* Remember old SP. */ \ |
| 230 | sst.w r19, PTO+PT_GPR(GPR_SP)[ep]; \ |
| 231 | mov 1, r19; /* Now definitely in kernel-mode. */ \ |
| 232 | st.b r19, KM; \ |
| 233 | GET_CURRENT_TASK(CURRENT_TASK); /* Fetch the current task pointer. */ \ |
| 234 | /* Save away the syscall number. */ \ |
| 235 | sst.w syscall_num, PTO+PT_CUR_SYSCALL[ep] |
| 236 | |
| 237 | |
| 238 | /* Save register state not normally saved by PUSH_STATE for TYPE, to the |
| 239 | state-save-frame on the stack; also copies SP to EP. r19 may be trashed. */ |
| 240 | #define SAVE_EXTRA_STATE(type) \ |
| 241 | mov sp, ep; \ |
| 242 | type ## _EXTRA_STATE_SAVER |
| 243 | /* Restore register state not normally restored by POP_STATE for TYPE, |
| 244 | from the state-save-frame on the stack; also copies SP to EP. |
| 245 | r19 may be trashed. */ |
| 246 | #define RESTORE_EXTRA_STATE(type) \ |
| 247 | mov sp, ep; \ |
| 248 | type ## _EXTRA_STATE_RESTORER |
| 249 | |
| 250 | /* Save any call-clobbered registers not normally saved by PUSH_STATE for |
| 251 | TYPE, to the state-save-frame on the stack. |
| 252 | EP may be trashed, but is not guaranteed to contain a copy of SP |
| 253 | (unlike after most SAVE_... macros). r19 may be trashed. */ |
| 254 | #define SAVE_EXTRA_STATE_FOR_SCHEDULE(type) \ |
| 255 | type ## _SCHEDULE_EXTRA_STATE_SAVER |
| 256 | /* Restore any call-clobbered registers not normally restored by |
| 257 | POP_STATE for TYPE, to the state-save-frame on the stack. |
| 258 | EP may be trashed, but is not guaranteed to contain a copy of SP |
| 259 | (unlike after most RESTORE_... macros). r19 may be trashed. */ |
| 260 | #define RESTORE_EXTRA_STATE_FOR_SCHEDULE(type) \ |
| 261 | type ## _SCHEDULE_EXTRA_STATE_RESTORER |
| 262 | |
| 263 | |
| 264 | /* These are extra_state_saver/restorer values for a user trap. Note |
| 265 | that we save the argument registers so that restarted syscalls will |
| 266 | function properly (otherwise it wouldn't be necessary), and we must |
| 267 | _not_ restore the return-value registers (so that traps can return a |
| 268 | value!), but call-clobbered registers are not saved at all, as the |
| 269 | caller of the syscall function should have saved them. */ |
| 270 | |
| 271 | #define TRAP_RET reti |
| 272 | /* Traps don't save call-clobbered registers (but do still save arg regs). |
| 273 | We preserve PSw to keep long-term state, namely interrupt status (for traps |
| 274 | from kernel-mode), and the single-step flag (for user traps). */ |
| 275 | #define TRAP_STATE_SAVER \ |
| 276 | SAVE_ARG_REGS; \ |
| 277 | SAVE_PC(EIPC); \ |
| 278 | SAVE_PSW(EIPSW) |
| 279 | /* When traps return, they just leave call-clobbered registers (except for arg |
| 280 | regs) with whatever value they have from the kernel. Traps don't preserve |
| 281 | the PSW, but we zero EIPSW to ensure it doesn't contain anything dangerous |
| 282 | (in particular, the single-step flag). */ |
| 283 | #define TRAP_STATE_RESTORER \ |
| 284 | RESTORE_ARG_REGS; \ |
| 285 | RESTORE_PC(EIPC); \ |
| 286 | RESTORE_PSW(EIPSW) |
| 287 | /* Save registers not normally saved by traps. We need to save r12, even |
| 288 | though it's nominally call-clobbered, because it's used when restarting |
| 289 | a system call (the signal-handling path uses SAVE_EXTRA_STATE, and |
| 290 | expects r12 to be restored when the trap returns). */ |
| 291 | #define TRAP_EXTRA_STATE_SAVER \ |
| 292 | SAVE_RVAL_REGS; \ |
| 293 | sst.w r12, PTO+PT_GPR(12)[ep]; \ |
| 294 | SAVE_CALL_SAVED_REGS; \ |
| 295 | SAVE_CT_REGS |
| 296 | #define TRAP_EXTRA_STATE_RESTORER \ |
| 297 | RESTORE_RVAL_REGS; \ |
| 298 | sld.w PTO+PT_GPR(12)[ep], r12; \ |
| 299 | RESTORE_CALL_SAVED_REGS; \ |
| 300 | RESTORE_CT_REGS |
| 301 | /* Save registers prior to calling scheduler (just before trap returns). |
| 302 | We have to save the return-value registers to preserve the trap's return |
| 303 | value. Note that ..._SCHEDULE_EXTRA_STATE_SAVER, unlike most ..._SAVER |
| 304 | macros, is required to setup EP itself if EP is needed (this is because |
| 305 | in many cases, the macro is empty). */ |
| 306 | #define TRAP_SCHEDULE_EXTRA_STATE_SAVER \ |
| 307 | mov sp, ep; \ |
| 308 | SAVE_RVAL_REGS |
| 309 | /* Note that ..._SCHEDULE_EXTRA_STATE_RESTORER, unlike most ..._RESTORER |
| 310 | macros, is required to setup EP itself if EP is needed (this is because |
| 311 | in many cases, the macro is empty). */ |
| 312 | #define TRAP_SCHEDULE_EXTRA_STATE_RESTORER \ |
| 313 | mov sp, ep; \ |
| 314 | RESTORE_RVAL_REGS |
| 315 | |
| 316 | /* Register saving/restoring for maskable interrupts. */ |
| 317 | #define IRQ_RET reti |
| 318 | #define IRQ_STATE_SAVER \ |
| 319 | SAVE_CALL_CLOBBERED_REGS; \ |
| 320 | SAVE_PC(EIPC); \ |
| 321 | SAVE_PSW(EIPSW) |
| 322 | #define IRQ_STATE_RESTORER \ |
| 323 | RESTORE_CALL_CLOBBERED_REGS; \ |
| 324 | RESTORE_PC(EIPC); \ |
| 325 | RESTORE_PSW(EIPSW) |
| 326 | #define IRQ_EXTRA_STATE_SAVER \ |
| 327 | SAVE_CALL_SAVED_REGS; \ |
| 328 | SAVE_CT_REGS |
| 329 | #define IRQ_EXTRA_STATE_RESTORER \ |
| 330 | RESTORE_CALL_SAVED_REGS; \ |
| 331 | RESTORE_CT_REGS |
| 332 | #define IRQ_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ |
| 333 | #define IRQ_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ |
| 334 | |
| 335 | /* Register saving/restoring for non-maskable interrupts. */ |
| 336 | #define NMI_RET reti |
| 337 | #define NMI_STATE_SAVER \ |
| 338 | SAVE_CALL_CLOBBERED_REGS; \ |
| 339 | SAVE_PC(FEPC); \ |
| 340 | SAVE_PSW(FEPSW); |
| 341 | #define NMI_STATE_RESTORER \ |
| 342 | RESTORE_CALL_CLOBBERED_REGS; \ |
| 343 | RESTORE_PC(FEPC); \ |
| 344 | RESTORE_PSW(FEPSW); |
| 345 | #define NMI_EXTRA_STATE_SAVER \ |
| 346 | SAVE_CALL_SAVED_REGS; \ |
| 347 | SAVE_CT_REGS |
| 348 | #define NMI_EXTRA_STATE_RESTORER \ |
| 349 | RESTORE_CALL_SAVED_REGS; \ |
| 350 | RESTORE_CT_REGS |
| 351 | #define NMI_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ |
| 352 | #define NMI_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ |
| 353 | |
| 354 | /* Register saving/restoring for debug traps. */ |
| 355 | #define DBTRAP_RET .long 0x014607E0 /* `dbret', but gas doesn't support it. */ |
| 356 | #define DBTRAP_STATE_SAVER \ |
| 357 | SAVE_CALL_CLOBBERED_REGS; \ |
| 358 | SAVE_PC(DBPC); \ |
| 359 | SAVE_PSW(DBPSW) |
| 360 | #define DBTRAP_STATE_RESTORER \ |
| 361 | RESTORE_CALL_CLOBBERED_REGS; \ |
| 362 | RESTORE_PC(DBPC); \ |
| 363 | RESTORE_PSW(DBPSW) |
| 364 | #define DBTRAP_EXTRA_STATE_SAVER \ |
| 365 | SAVE_CALL_SAVED_REGS; \ |
| 366 | SAVE_CT_REGS |
| 367 | #define DBTRAP_EXTRA_STATE_RESTORER \ |
| 368 | RESTORE_CALL_SAVED_REGS; \ |
| 369 | RESTORE_CT_REGS |
| 370 | #define DBTRAP_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ |
| 371 | #define DBTRAP_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ |
| 372 | |
| 373 | /* Register saving/restoring for a context switch. We don't need to save |
| 374 | too many registers, because context-switching looks like a function call |
| 375 | (via the function `switch_thread'), so callers will save any |
| 376 | call-clobbered registers themselves. We do need to save the CT regs, as |
| 377 | they're normally not saved during kernel entry (the kernel doesn't use |
| 378 | them). We save PSW so that interrupt-status state will correctly follow |
| 379 | each thread (mostly NMI vs. normal-IRQ/trap), though for the most part |
| 380 | it doesn't matter since threads are always in almost exactly the same |
| 381 | processor state during a context switch. The stack pointer and return |
| 382 | value are handled by switch_thread itself. */ |
| 383 | #define SWITCH_STATE_SAVER \ |
| 384 | SAVE_CALL_SAVED_REGS; \ |
| 385 | SAVE_PSW(PSW); \ |
| 386 | SAVE_CT_REGS |
| 387 | #define SWITCH_STATE_RESTORER \ |
| 388 | RESTORE_CALL_SAVED_REGS; \ |
| 389 | RESTORE_PSW(PSW); \ |
| 390 | RESTORE_CT_REGS |
| 391 | |
| 392 | |
| 393 | /* Restore register state from the state-save-frame on the stack, switch back |
| 394 | to the user stack if necessary, and return from the trap/interrupt. |
| 395 | EXTRA_STATE_RESTORER is a sequence of assembly language statements to |
| 396 | restore anything not restored by this macro. Only registers not saved by |
| 397 | the C compiler are restored (that is, R3(sp), R4(gp), R31(lp), and |
| 398 | anything restored by EXTRA_STATE_RESTORER). */ |
| 399 | #define RETURN(type) \ |
| 400 | ld.b PTO+PT_KERNEL_MODE[sp], r19; \ |
| 401 | di; /* Disable interrupts */ \ |
| 402 | cmp r19, r0; /* See if returning to kernel mode, */\ |
| 403 | bne 2f; /* ... if so, skip resched &c. */ \ |
| 404 | \ |
| 405 | /* We're returning to user mode, so check for various conditions that \ |
| 406 | trigger rescheduling. */ \ |
| 407 | GET_CURRENT_THREAD(r18); \ |
| 408 | ld.w TI_FLAGS[r18], r19; \ |
| 409 | andi _TIF_NEED_RESCHED, r19, r0; \ |
| 410 | bnz 3f; /* Call the scheduler. */ \ |
| 411 | 5: andi _TIF_SIGPENDING, r19, r18; \ |
| 412 | ld.w TASK_PTRACE[CURRENT_TASK], r19; /* ptrace flags */ \ |
| 413 | or r18, r19; /* see if either is non-zero */ \ |
| 414 | bnz 4f; /* if so, handle them */ \ |
| 415 | \ |
| 416 | /* Return to user state. */ \ |
| 417 | 1: st.b r0, KM; /* Now officially in user state. */ \ |
| 418 | \ |
| 419 | /* Final return. The stack-pointer fiddling is not needed when returning \ |
| 420 | to kernel-mode, but they don't hurt, and this way we can share the \ |
| 421 | (sometimes rather lengthy) POP_STATE macro. */ \ |
| 422 | 2: POP_STATE(type); \ |
| 423 | st.w sp, KSP; /* Save the kernel stack pointer. */ \ |
| 424 | ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp; /* Restore stack pointer. */ \ |
| 425 | type ## _RET; /* Return from the trap/interrupt. */ \ |
| 426 | \ |
| 427 | /* Call the scheduler before returning from a syscall/trap. */ \ |
| 428 | 3: SAVE_EXTRA_STATE_FOR_SCHEDULE(type); /* Prepare to call scheduler. */ \ |
| 429 | jarl call_scheduler, lp; /* Call scheduler */ \ |
| 430 | di; /* The scheduler enables interrupts */\ |
| 431 | RESTORE_EXTRA_STATE_FOR_SCHEDULE(type); \ |
| 432 | GET_CURRENT_THREAD(r18); \ |
| 433 | ld.w TI_FLAGS[r18], r19; \ |
| 434 | br 5b; /* Continue with return path. */ \ |
| 435 | \ |
| 436 | /* Handle a signal or ptraced process return. \ |
| 437 | r18 should be non-zero if there are pending signals. */ \ |
| 438 | 4: /* Not all registers are saved by the normal trap/interrupt entry \ |
| 439 | points (for instance, call-saved registers (because the normal \ |
| 440 | C-compiler calling sequence in the kernel makes sure they're \ |
| 441 | preserved), and call-clobbered registers in the case of \ |
| 442 | traps), but signal handlers may want to examine or change the \ |
| 443 | complete register state. Here we save anything not saved by \ |
| 444 | the normal entry sequence, so that it may be safely restored \ |
| 445 | (in a possibly modified form) after do_signal returns. */ \ |
| 446 | SAVE_EXTRA_STATE(type); /* Save state not saved by entry. */ \ |
| 447 | jarl handle_signal_or_ptrace_return, lp; \ |
| 448 | RESTORE_EXTRA_STATE(type); /* Restore extra regs. */ \ |
| 449 | br 1b |
| 450 | |
| 451 | |
| 452 | /* Jump to the appropriate function for the system call number in r12 |
| 453 | (r12 is not preserved), or return an error if r12 is not valid. The |
| 454 | LP register should point to the location where the called function |
| 455 | should return. [note that MAKE_SYS_CALL uses label 1] */ |
| 456 | #define MAKE_SYS_CALL \ |
| 457 | /* Figure out which function to use for this system call. */ \ |
| 458 | shl 2, r12; \ |
| 459 | /* See if the system call number is valid. */ \ |
| 460 | addi lo(CSYM(sys_call_table) - sys_call_table_end), r12, r0; \ |
| 461 | bnh 1f; \ |
| 462 | mov hilo(CSYM(sys_call_table)), r19; \ |
| 463 | add r19, r12; \ |
| 464 | ld.w 0[r12], r12; \ |
| 465 | /* Make the system call. */ \ |
| 466 | jmp [r12]; \ |
| 467 | /* The syscall number is invalid, return an error. */ \ |
| 468 | 1: addi -ENOSYS, r0, r10; \ |
| 469 | jmp [lp] |
| 470 | |
| 471 | |
| 472 | .text |
| 473 | |
| 474 | /* |
| 475 | * User trap. |
| 476 | * |
| 477 | * Trap 0 system calls are also handled here. |
| 478 | * |
| 479 | * The stack-pointer (r3) should have already been saved to the memory |
| 480 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be |
| 481 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and |
| 482 | * this allows them to save the stack-pointer and use that register to do an |
| 483 | * indirect jump). |
| 484 | * |
| 485 | * Syscall protocol: |
| 486 | * Syscall number in r12, args in r6-r9 |
| 487 | * Return value in r10 |
| 488 | */ |
| 489 | G_ENTRY(trap): |
| 490 | SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers. |
| 491 | stsr SR_ECR, r19 // Find out which trap it was. |
| 492 | ei // Enable interrupts. |
| 493 | mov hilo(ret_from_trap), lp // where the trap should return |
| 494 | |
| 495 | // The following two shifts (1) clear out extraneous NMI data in the |
| 496 | // upper 16-bits, (2) convert the 0x40 - 0x5f range of trap ECR |
| 497 | // numbers into the (0-31) << 2 range we want, (3) set the flags. |
| 498 | shl 27, r19 // chop off all high bits |
| 499 | shr 25, r19 // scale back down and then << 2 |
| 500 | bnz 2f // See if not trap 0. |
| 501 | |
| 502 | // Trap 0 is a `short' system call, skip general trap table. |
| 503 | MAKE_SYS_CALL // Jump to the syscall function. |
| 504 | |
| 505 | 2: // For other traps, use a table lookup. |
| 506 | mov hilo(CSYM(trap_table)), r18 |
| 507 | add r19, r18 |
| 508 | ld.w 0[r18], r18 |
| 509 | jmp [r18] // Jump to the trap handler. |
| 510 | END(trap) |
| 511 | |
| 512 | /* This is just like ret_from_trap, but first restores extra registers |
| 513 | saved by some wrappers. */ |
| 514 | L_ENTRY(restore_extra_regs_and_ret_from_trap): |
| 515 | RESTORE_EXTRA_STATE(TRAP) |
| 516 | // fall through |
| 517 | END(restore_extra_regs_and_ret_from_trap) |
| 518 | |
| 519 | /* Entry point used to return from a syscall/trap. */ |
| 520 | L_ENTRY(ret_from_trap): |
| 521 | RETURN(TRAP) |
| 522 | END(ret_from_trap) |
| 523 | |
| 524 | |
| 525 | /* This the initial entry point for a new child thread, with an appropriate |
| 526 | stack in place that makes it look the the child is in the middle of an |
| 527 | syscall. This function is actually `returned to' from switch_thread |
| 528 | (copy_thread makes ret_from_fork the return address in each new thread's |
| 529 | saved context). */ |
| 530 | C_ENTRY(ret_from_fork): |
| 531 | mov r10, r6 // switch_thread returns the prev task. |
| 532 | jarl CSYM(schedule_tail), lp // ...which is schedule_tail's arg |
| 533 | mov r0, r10 // Child's fork call should return 0. |
| 534 | br ret_from_trap // Do normal trap return. |
| 535 | C_END(ret_from_fork) |
| 536 | |
| 537 | |
| 538 | /* |
| 539 | * Trap 1: `long' system calls |
| 540 | * `Long' syscall protocol: |
| 541 | * Syscall number in r12, args in r6-r9, r13-r14 |
| 542 | * Return value in r10 |
| 543 | */ |
| 544 | L_ENTRY(syscall_long): |
| 545 | // Push extra arguments on the stack. Note that by default, the trap |
| 546 | // handler reserves enough stack space for 6 arguments, so we don't |
| 547 | // have to make any additional room. |
| 548 | st.w r13, 16[sp] // arg 5 |
| 549 | st.w r14, 20[sp] // arg 6 |
| 550 | |
| 551 | // Make sure r13 and r14 are preserved, in case we have to restart a |
| 552 | // system call because of a signal (ep has already been set by caller). |
| 553 | st.w r13, PTO+PT_GPR(13)[sp] |
| 554 | st.w r14, PTO+PT_GPR(13)[sp] |
| 555 | mov hilo(ret_from_long_syscall), lp |
| 556 | |
| 557 | MAKE_SYS_CALL // Jump to the syscall function. |
| 558 | END(syscall_long) |
| 559 | |
| 560 | /* Entry point used to return from a long syscall. Only needed to restore |
| 561 | r13/r14 if the general trap mechanism doesnt' do so. */ |
| 562 | L_ENTRY(ret_from_long_syscall): |
| 563 | ld.w PTO+PT_GPR(13)[sp], r13 // Restore the extra registers |
| 564 | ld.w PTO+PT_GPR(13)[sp], r14 |
| 565 | br ret_from_trap // The rest is the same as other traps |
| 566 | END(ret_from_long_syscall) |
| 567 | |
| 568 | |
| 569 | /* These syscalls need access to the struct pt_regs on the stack, so we |
| 570 | implement them in assembly (they're basically all wrappers anyway). */ |
| 571 | |
| 572 | L_ENTRY(sys_fork_wrapper): |
| 573 | #ifdef CONFIG_MMU |
| 574 | addi SIGCHLD, r0, r6 // Arg 0: flags |
| 575 | ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) |
| 576 | movea PTO, sp, r8 // Arg 2: parent context |
| 577 | mov r0, r9 // Arg 3/4/5: 0 |
| 578 | st.w r0, 16[sp] |
| 579 | st.w r0, 20[sp] |
| 580 | mov hilo(CSYM(do_fork)), r18 // Where the real work gets done |
| 581 | br save_extra_state_tramp // Save state and go there |
| 582 | #else |
| 583 | // fork almost works, enough to trick you into looking elsewhere :-( |
| 584 | addi -EINVAL, r0, r10 |
| 585 | jmp [lp] |
| 586 | #endif |
| 587 | END(sys_fork_wrapper) |
| 588 | |
| 589 | L_ENTRY(sys_vfork_wrapper): |
| 590 | addi CLONE_VFORK | CLONE_VM | SIGCHLD, r0, r6 // Arg 0: flags |
| 591 | ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) |
| 592 | movea PTO, sp, r8 // Arg 2: parent context |
| 593 | mov r0, r9 // Arg 3/4/5: 0 |
| 594 | st.w r0, 16[sp] |
| 595 | st.w r0, 20[sp] |
| 596 | mov hilo(CSYM(do_fork)), r18 // Where the real work gets done |
| 597 | br save_extra_state_tramp // Save state and go there |
| 598 | END(sys_vfork_wrapper) |
| 599 | |
| 600 | L_ENTRY(sys_clone_wrapper): |
| 601 | ld.w PTO+PT_GPR(GPR_SP)[sp], r19// parent's stack pointer |
| 602 | cmp r7, r0 // See if child SP arg (arg 1) is 0. |
| 603 | cmov z, r19, r7, r7 // ... and use the parent's if so. |
| 604 | movea PTO, sp, r8 // Arg 2: parent context |
| 605 | mov r0, r9 // Arg 3/4/5: 0 |
| 606 | st.w r0, 16[sp] |
| 607 | st.w r0, 20[sp] |
| 608 | mov hilo(CSYM(do_fork)), r18 // Where the real work gets done |
| 609 | br save_extra_state_tramp // Save state and go there |
| 610 | END(sys_clone_wrapper) |
| 611 | |
| 612 | |
| 613 | L_ENTRY(sys_execve_wrapper): |
| 614 | movea PTO, sp, r9 // add user context as 4th arg |
| 615 | jr CSYM(sys_execve) // Do real work (tail-call). |
| 616 | END(sys_execve_wrapper) |
| 617 | |
| 618 | |
| 619 | L_ENTRY(sys_sigsuspend_wrapper): |
| 620 | movea PTO, sp, r7 // add user context as 2nd arg |
| 621 | mov hilo(CSYM(sys_sigsuspend)), r18 // syscall function |
| 622 | jarl save_extra_state_tramp, lp // Save state and do it |
| 623 | br restore_extra_regs_and_ret_from_trap |
| 624 | END(sys_sigsuspend_wrapper) |
| 625 | L_ENTRY(sys_rt_sigsuspend_wrapper): |
| 626 | movea PTO, sp, r8 // add user context as 3rd arg |
| 627 | mov hilo(CSYM(sys_rt_sigsuspend)), r18 // syscall function |
| 628 | jarl save_extra_state_tramp, lp // Save state and do it |
| 629 | br restore_extra_regs_and_ret_from_trap |
| 630 | END(sys_rt_sigsuspend_wrapper) |
| 631 | |
| 632 | L_ENTRY(sys_sigreturn_wrapper): |
| 633 | movea PTO, sp, r6 // add user context as 1st arg |
| 634 | mov hilo(CSYM(sys_sigreturn)), r18 // syscall function |
| 635 | jarl save_extra_state_tramp, lp // Save state and do it |
| 636 | br restore_extra_regs_and_ret_from_trap |
| 637 | END(sys_sigreturn_wrapper) |
| 638 | L_ENTRY(sys_rt_sigreturn_wrapper): |
| 639 | movea PTO, sp, r6 // add user context as 1st arg |
| 640 | mov hilo(CSYM(sys_rt_sigreturn)), r18// syscall function |
| 641 | jarl save_extra_state_tramp, lp // Save state and do it |
| 642 | br restore_extra_regs_and_ret_from_trap |
| 643 | END(sys_rt_sigreturn_wrapper) |
| 644 | |
| 645 | |
| 646 | /* Save any state not saved by SAVE_STATE(TRAP), and jump to r18. |
| 647 | It's main purpose is to share the rather lengthy code sequence that |
| 648 | SAVE_STATE expands into among the above wrapper functions. */ |
| 649 | L_ENTRY(save_extra_state_tramp): |
| 650 | SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. |
| 651 | jmp [r18] // Do the work the caller wants |
| 652 | END(save_extra_state_tramp) |
| 653 | |
| 654 | |
| 655 | /* |
| 656 | * Hardware maskable interrupts. |
| 657 | * |
| 658 | * The stack-pointer (r3) should have already been saved to the memory |
| 659 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be |
| 660 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and |
| 661 | * this allows them to save the stack-pointer and use that register to do an |
| 662 | * indirect jump). |
| 663 | */ |
| 664 | G_ENTRY(irq): |
| 665 | SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers. |
| 666 | |
| 667 | stsr SR_ECR, r6 // Find out which interrupt it was. |
| 668 | movea PTO, sp, r7 // User regs are arg2 |
| 669 | |
| 670 | // All v850 implementations I know about encode their interrupts as |
| 671 | // multiples of 0x10, starting at 0x80 (after NMIs and software |
| 672 | // interrupts). Convert this number into a simple IRQ index for the |
| 673 | // rest of the kernel. We also clear the upper 16 bits, which hold |
| 674 | // NMI info, and don't appear to be cleared when a NMI returns. |
| 675 | shl 16, r6 // clear upper 16 bits |
| 676 | shr 20, r6 // shift back, and remove lower nibble |
| 677 | add -8, r6 // remove bias for irqs |
| 678 | |
| 679 | // Call the high-level interrupt handling code. |
| 680 | jarl CSYM(handle_irq), lp |
| 681 | |
| 682 | RETURN(IRQ) |
| 683 | END(irq) |
| 684 | |
| 685 | |
| 686 | /* |
| 687 | * Debug trap / illegal-instruction exception |
| 688 | * |
| 689 | * The stack-pointer (r3) should have already been saved to the memory |
| 690 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be |
| 691 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and |
| 692 | * this allows them to save the stack-pointer and use that register to do an |
| 693 | * indirect jump). |
| 694 | */ |
| 695 | G_ENTRY(dbtrap): |
| 696 | SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers. |
| 697 | |
| 698 | /* First see if we came from kernel mode; if so, the dbtrap |
| 699 | instruction has a special meaning, to set the DIR (`debug |
| 700 | information register') register. This is because the DIR register |
| 701 | can _only_ be manipulated/read while in `debug mode,' and debug |
| 702 | mode is only active while we're inside the dbtrap handler. The |
| 703 | exact functionality is: { DIR = (DIR | r6) & ~r7; return DIR; }. */ |
| 704 | ld.b PTO+PT_KERNEL_MODE[sp], r19 |
| 705 | cmp r19, r0 |
| 706 | bz 1f |
| 707 | |
| 708 | stsr SR_DIR, r10 |
| 709 | or r6, r10 |
| 710 | not r7, r7 |
| 711 | and r7, r10 |
| 712 | ldsr r10, SR_DIR |
| 713 | stsr SR_DIR, r10 // Confirm the value we set |
| 714 | st.w r10, PTO+PT_GPR(10)[sp] // return it |
| 715 | br 3f |
| 716 | |
| 717 | 1: ei // Enable interrupts. |
| 718 | |
| 719 | /* The default signal type we raise. */ |
| 720 | mov SIGTRAP, r6 |
| 721 | |
| 722 | /* See if it's a single-step trap. */ |
| 723 | stsr SR_DBPSW, r19 |
| 724 | andi 0x0800, r19, r19 |
| 725 | bnz 2f |
| 726 | |
| 727 | /* Look to see if the preceding instruction was is a dbtrap or not, |
| 728 | to decide which signal we should use. */ |
| 729 | stsr SR_DBPC, r19 // PC following trapping insn |
| 730 | ld.hu -2[r19], r19 |
| 731 | ori 0xf840, r0, r20 // DBTRAP insn |
| 732 | cmp r19, r20 // Was this trap caused by DBTRAP? |
| 733 | cmov ne, SIGILL, r6, r6 // Choose signal appropriately |
| 734 | |
| 735 | /* Raise the desired signal. */ |
| 736 | 2: mov CURRENT_TASK, r7 // Arg 1: task |
| 737 | jarl CSYM(send_sig), lp // tail call |
| 738 | |
| 739 | 3: RETURN(DBTRAP) |
| 740 | END(dbtrap) |
| 741 | |
| 742 | |
| 743 | /* |
| 744 | * Hardware non-maskable interrupts. |
| 745 | * |
| 746 | * The stack-pointer (r3) should have already been saved to the memory |
| 747 | * location ENTRY_SP (the reason for this is that the interrupt vectors may be |
| 748 | * beyond a 22-bit signed offset jump from the actual interrupt handler, and |
| 749 | * this allows them to save the stack-pointer and use that register to do an |
| 750 | * indirect jump). |
| 751 | */ |
| 752 | G_ENTRY(nmi): |
| 753 | SAVE_STATE (NMI, r0, NMI_ENTRY_SP); /* Save registers. */ |
| 754 | |
| 755 | stsr SR_ECR, r6; /* Find out which nmi it was. */ |
| 756 | shr 20, r6; /* Extract NMI code in bits 20-24. */ |
| 757 | movea PTO, sp, r7; /* User regs are arg2. */ |
| 758 | |
| 759 | /* Non-maskable interrupts always lie right after maskable interrupts. |
| 760 | Call the generic IRQ handler, with two arguments, the IRQ number, |
| 761 | and a pointer to the user registers, to handle the specifics. |
| 762 | (we subtract one because the first NMI has code 1). */ |
| 763 | addi FIRST_NMI - 1, r6, r6 |
| 764 | jarl CSYM(handle_irq), lp |
| 765 | |
| 766 | RETURN(NMI) |
| 767 | END(nmi) |
| 768 | |
| 769 | |
| 770 | /* |
| 771 | * Trap with no handler |
| 772 | */ |
| 773 | L_ENTRY(bad_trap_wrapper): |
| 774 | mov r19, r6 // Arg 0: trap number |
| 775 | movea PTO, sp, r7 // Arg 1: user regs |
| 776 | jr CSYM(bad_trap) // tail call handler |
| 777 | END(bad_trap_wrapper) |
| 778 | |
| 779 | |
| 780 | /* |
| 781 | * Invoke the scheduler, called from the trap/irq kernel exit path. |
| 782 | * |
| 783 | * This basically just calls `schedule', but also arranges for extra |
| 784 | * registers to be saved for ptrace'd processes, so ptrace can modify them. |
| 785 | */ |
| 786 | L_ENTRY(call_scheduler): |
| 787 | ld.w TASK_PTRACE[CURRENT_TASK], r19 // See if task is ptrace'd |
| 788 | cmp r19, r0 |
| 789 | bnz 1f // ... yes, do special stuff |
| 790 | jr CSYM(schedule) // ... no, just tail-call scheduler |
| 791 | |
| 792 | // Save extra regs for ptrace'd task. We want to save anything |
| 793 | // that would otherwise only be `implicitly' saved by the normal |
| 794 | // compiler calling-convention. |
| 795 | 1: mov sp, ep // Setup EP for SAVE_CALL_SAVED_REGS |
| 796 | SAVE_CALL_SAVED_REGS // Save call-saved registers to stack |
| 797 | mov lp, r20 // Save LP in a callee-saved register |
| 798 | |
| 799 | jarl CSYM(schedule), lp // Call scheduler |
| 800 | |
| 801 | mov r20, lp |
| 802 | mov sp, ep // We can't rely on EP after return |
| 803 | RESTORE_CALL_SAVED_REGS // Restore (possibly modified) regs |
| 804 | jmp [lp] // Return to the return path |
| 805 | END(call_scheduler) |
| 806 | |
| 807 | |
| 808 | /* |
| 809 | * This is an out-of-line handler for two special cases during the kernel |
| 810 | * trap/irq exit sequence: |
| 811 | * |
| 812 | * (1) If r18 is non-zero then a signal needs to be handled, which is |
| 813 | * done, and then the caller returned to. |
| 814 | * |
| 815 | * (2) If r18 is non-zero then we're returning to a ptraced process, which |
| 816 | * has several special cases -- single-stepping and trap tracing, both |
| 817 | * of which require using the `dbret' instruction to exit the kernel |
| 818 | * instead of the normal `reti' (this is because the CPU not correctly |
| 819 | * single-step after a reti). In this case, of course, this handler |
| 820 | * never returns to the caller. |
| 821 | * |
| 822 | * In either case, all registers should have been saved to the current |
| 823 | * state-save-frame on the stack, except for callee-saved registers. |
| 824 | * |
| 825 | * [These two different cases are combined merely to avoid bloating the |
| 826 | * macro-inlined code, not because they really make much sense together!] |
| 827 | */ |
| 828 | L_ENTRY(handle_signal_or_ptrace_return): |
| 829 | cmp r18, r0 // See if handling a signal |
| 830 | bz 1f // ... nope, go do ptrace return |
| 831 | |
| 832 | // Handle a signal |
| 833 | mov lp, r20 // Save link-pointer |
| 834 | mov r10, r21 // Save return-values (for trap) |
| 835 | mov r11, r22 |
| 836 | |
| 837 | movea PTO, sp, r6 // Arg 1: struct pt_regs *regs |
| 838 | mov r0, r7 // Arg 2: sigset_t *oldset |
| 839 | jarl CSYM(do_signal), lp // Handle the signal |
| 840 | di // sig handling enables interrupts |
| 841 | |
| 842 | mov r20, lp // Restore link-pointer |
| 843 | mov r21, r10 // Restore return-values (for trap) |
| 844 | mov r22, r11 |
| 845 | ld.w TASK_PTRACE[CURRENT_TASK], r19 // check ptrace flags too |
| 846 | cmp r19, r0 |
| 847 | bnz 1f // ... some set, so look more |
| 848 | 2: jmp [lp] // ... none set, so return normally |
| 849 | |
| 850 | // ptrace return |
| 851 | 1: ld.w PTO+PT_PSW[sp], r19 // Look at user-processes's flags |
| 852 | andi 0x0800, r19, r19 // See if single-step flag is set |
| 853 | bz 2b // ... nope, return normally |
| 854 | |
| 855 | // Return as if from a dbtrap insn |
| 856 | st.b r0, KM // Now officially in user state. |
| 857 | POP_STATE(DBTRAP) // Restore regs |
| 858 | st.w sp, KSP // Save the kernel stack pointer. |
| 859 | ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp // Restore user stack pointer. |
| 860 | DBTRAP_RET // Return from the trap/interrupt. |
| 861 | END(handle_signal_or_ptrace_return) |
| 862 | |
| 863 | |
| 864 | /* |
| 865 | * This is where we switch between two threads. The arguments are: |
| 866 | * r6 -- pointer to the struct thread for the `current' process |
| 867 | * r7 -- pointer to the struct thread for the `new' process. |
| 868 | * when this function returns, it will return to the new thread. |
| 869 | */ |
| 870 | C_ENTRY(switch_thread): |
| 871 | // Return the previous task (r10 is not clobbered by restore below) |
| 872 | mov CURRENT_TASK, r10 |
| 873 | // First, push the current processor state on the stack |
| 874 | PUSH_STATE(SWITCH) |
| 875 | // Now save the location of the kernel stack pointer for this thread; |
| 876 | // since we've pushed all other state on the stack, this is enough to |
| 877 | // restore it all later. |
| 878 | st.w sp, THREAD_KSP[r6] |
| 879 | // Now restore the stack pointer from the new process |
| 880 | ld.w THREAD_KSP[r7], sp |
| 881 | // ... and restore all state from that |
| 882 | POP_STATE(SWITCH) |
| 883 | // Update the current task pointer |
| 884 | GET_CURRENT_TASK(CURRENT_TASK) |
| 885 | // Now return into the new thread |
| 886 | jmp [lp] |
| 887 | C_END(switch_thread) |
| 888 | |
| 889 | |
| 890 | .data |
| 891 | |
| 892 | .align 4 |
| 893 | C_DATA(trap_table): |
| 894 | .long bad_trap_wrapper // trap 0, doesn't use trap table. |
| 895 | .long syscall_long // trap 1, `long' syscall. |
| 896 | .long bad_trap_wrapper |
| 897 | .long bad_trap_wrapper |
| 898 | .long bad_trap_wrapper |
| 899 | .long bad_trap_wrapper |
| 900 | .long bad_trap_wrapper |
| 901 | .long bad_trap_wrapper |
| 902 | .long bad_trap_wrapper |
| 903 | .long bad_trap_wrapper |
| 904 | .long bad_trap_wrapper |
| 905 | .long bad_trap_wrapper |
| 906 | .long bad_trap_wrapper |
| 907 | .long bad_trap_wrapper |
| 908 | .long bad_trap_wrapper |
| 909 | .long bad_trap_wrapper |
| 910 | C_END(trap_table) |
| 911 | |
| 912 | |
| 913 | .section .rodata |
| 914 | |
| 915 | .align 4 |
| 916 | C_DATA(sys_call_table): |
| 917 | .long CSYM(sys_restart_syscall) // 0 |
| 918 | .long CSYM(sys_exit) |
| 919 | .long sys_fork_wrapper |
| 920 | .long CSYM(sys_read) |
| 921 | .long CSYM(sys_write) |
| 922 | .long CSYM(sys_open) // 5 |
| 923 | .long CSYM(sys_close) |
| 924 | .long CSYM(sys_waitpid) |
| 925 | .long CSYM(sys_creat) |
| 926 | .long CSYM(sys_link) |
| 927 | .long CSYM(sys_unlink) // 10 |
| 928 | .long sys_execve_wrapper |
| 929 | .long CSYM(sys_chdir) |
| 930 | .long CSYM(sys_time) |
| 931 | .long CSYM(sys_mknod) |
| 932 | .long CSYM(sys_chmod) // 15 |
| 933 | .long CSYM(sys_chown) |
| 934 | .long CSYM(sys_ni_syscall) // was: break |
| 935 | .long CSYM(sys_ni_syscall) // was: oldstat (aka stat) |
| 936 | .long CSYM(sys_lseek) |
| 937 | .long CSYM(sys_getpid) // 20 |
| 938 | .long CSYM(sys_mount) |
| 939 | .long CSYM(sys_oldumount) |
| 940 | .long CSYM(sys_setuid) |
| 941 | .long CSYM(sys_getuid) |
| 942 | .long CSYM(sys_stime) // 25 |
| 943 | .long CSYM(sys_ptrace) |
| 944 | .long CSYM(sys_alarm) |
| 945 | .long CSYM(sys_ni_syscall) // was: oldfstat (aka fstat) |
| 946 | .long CSYM(sys_pause) |
| 947 | .long CSYM(sys_utime) // 30 |
| 948 | .long CSYM(sys_ni_syscall) // was: stty |
| 949 | .long CSYM(sys_ni_syscall) // was: gtty |
| 950 | .long CSYM(sys_access) |
| 951 | .long CSYM(sys_nice) |
| 952 | .long CSYM(sys_ni_syscall) // 35, was: ftime |
| 953 | .long CSYM(sys_sync) |
| 954 | .long CSYM(sys_kill) |
| 955 | .long CSYM(sys_rename) |
| 956 | .long CSYM(sys_mkdir) |
| 957 | .long CSYM(sys_rmdir) // 40 |
| 958 | .long CSYM(sys_dup) |
| 959 | .long CSYM(sys_pipe) |
| 960 | .long CSYM(sys_times) |
| 961 | .long CSYM(sys_ni_syscall) // was: prof |
| 962 | .long CSYM(sys_brk) // 45 |
| 963 | .long CSYM(sys_setgid) |
| 964 | .long CSYM(sys_getgid) |
| 965 | .long CSYM(sys_signal) |
| 966 | .long CSYM(sys_geteuid) |
| 967 | .long CSYM(sys_getegid) // 50 |
| 968 | .long CSYM(sys_acct) |
| 969 | .long CSYM(sys_umount) // recycled never used phys() |
| 970 | .long CSYM(sys_ni_syscall) // was: lock |
| 971 | .long CSYM(sys_ioctl) |
| 972 | .long CSYM(sys_fcntl) // 55 |
| 973 | .long CSYM(sys_ni_syscall) // was: mpx |
| 974 | .long CSYM(sys_setpgid) |
| 975 | .long CSYM(sys_ni_syscall) // was: ulimit |
| 976 | .long CSYM(sys_ni_syscall) |
| 977 | .long CSYM(sys_umask) // 60 |
| 978 | .long CSYM(sys_chroot) |
| 979 | .long CSYM(sys_ustat) |
| 980 | .long CSYM(sys_dup2) |
| 981 | .long CSYM(sys_getppid) |
| 982 | .long CSYM(sys_getpgrp) // 65 |
| 983 | .long CSYM(sys_setsid) |
| 984 | .long CSYM(sys_sigaction) |
| 985 | .long CSYM(sys_sgetmask) |
| 986 | .long CSYM(sys_ssetmask) |
| 987 | .long CSYM(sys_setreuid) // 70 |
| 988 | .long CSYM(sys_setregid) |
| 989 | .long sys_sigsuspend_wrapper |
| 990 | .long CSYM(sys_sigpending) |
| 991 | .long CSYM(sys_sethostname) |
| 992 | .long CSYM(sys_setrlimit) // 75 |
| 993 | .long CSYM(sys_getrlimit) |
| 994 | .long CSYM(sys_getrusage) |
| 995 | .long CSYM(sys_gettimeofday) |
| 996 | .long CSYM(sys_settimeofday) |
| 997 | .long CSYM(sys_getgroups) // 80 |
| 998 | .long CSYM(sys_setgroups) |
| 999 | .long CSYM(sys_select) |
| 1000 | .long CSYM(sys_symlink) |
| 1001 | .long CSYM(sys_ni_syscall) // was: oldlstat (aka lstat) |
| 1002 | .long CSYM(sys_readlink) // 85 |
| 1003 | .long CSYM(sys_uselib) |
| 1004 | .long CSYM(sys_swapon) |
| 1005 | .long CSYM(sys_reboot) |
| 1006 | .long CSYM(old_readdir) |
| 1007 | .long CSYM(sys_mmap) // 90 |
| 1008 | .long CSYM(sys_munmap) |
| 1009 | .long CSYM(sys_truncate) |
| 1010 | .long CSYM(sys_ftruncate) |
| 1011 | .long CSYM(sys_fchmod) |
| 1012 | .long CSYM(sys_fchown) // 95 |
| 1013 | .long CSYM(sys_getpriority) |
| 1014 | .long CSYM(sys_setpriority) |
| 1015 | .long CSYM(sys_ni_syscall) // was: profil |
| 1016 | .long CSYM(sys_statfs) |
| 1017 | .long CSYM(sys_fstatfs) // 100 |
| 1018 | .long CSYM(sys_ni_syscall) // i386: ioperm |
| 1019 | .long CSYM(sys_socketcall) |
| 1020 | .long CSYM(sys_syslog) |
| 1021 | .long CSYM(sys_setitimer) |
| 1022 | .long CSYM(sys_getitimer) // 105 |
| 1023 | .long CSYM(sys_newstat) |
| 1024 | .long CSYM(sys_newlstat) |
| 1025 | .long CSYM(sys_newfstat) |
| 1026 | .long CSYM(sys_ni_syscall) // was: olduname (aka uname) |
| 1027 | .long CSYM(sys_ni_syscall) // 110, i386: iopl |
| 1028 | .long CSYM(sys_vhangup) |
| 1029 | .long CSYM(sys_ni_syscall) // was: idle |
| 1030 | .long CSYM(sys_ni_syscall) // i386: vm86old |
| 1031 | .long CSYM(sys_wait4) |
| 1032 | .long CSYM(sys_swapoff) // 115 |
| 1033 | .long CSYM(sys_sysinfo) |
| 1034 | .long CSYM(sys_ipc) |
| 1035 | .long CSYM(sys_fsync) |
| 1036 | .long sys_sigreturn_wrapper |
| 1037 | .long sys_clone_wrapper // 120 |
| 1038 | .long CSYM(sys_setdomainname) |
| 1039 | .long CSYM(sys_newuname) |
| 1040 | .long CSYM(sys_ni_syscall) // i386: modify_ldt, m68k: cacheflush |
| 1041 | .long CSYM(sys_adjtimex) |
| 1042 | .long CSYM(sys_ni_syscall) // 125 - sys_mprotect |
| 1043 | .long CSYM(sys_sigprocmask) |
| 1044 | .long CSYM(sys_ni_syscall) // sys_create_module |
| 1045 | .long CSYM(sys_init_module) |
| 1046 | .long CSYM(sys_delete_module) |
| 1047 | .long CSYM(sys_ni_syscall) // 130 - sys_get_kernel_syms |
| 1048 | .long CSYM(sys_quotactl) |
| 1049 | .long CSYM(sys_getpgid) |
| 1050 | .long CSYM(sys_fchdir) |
| 1051 | .long CSYM(sys_bdflush) |
| 1052 | .long CSYM(sys_sysfs) // 135 |
| 1053 | .long CSYM(sys_personality) |
| 1054 | .long CSYM(sys_ni_syscall) // for afs_syscall |
| 1055 | .long CSYM(sys_setfsuid) |
| 1056 | .long CSYM(sys_setfsgid) |
| 1057 | .long CSYM(sys_llseek) // 140 |
| 1058 | .long CSYM(sys_getdents) |
| 1059 | .long CSYM(sys_select) // for backward compat; remove someday |
| 1060 | .long CSYM(sys_flock) |
| 1061 | .long CSYM(sys_ni_syscall) // sys_msync |
| 1062 | .long CSYM(sys_readv) // 145 |
| 1063 | .long CSYM(sys_writev) |
| 1064 | .long CSYM(sys_getsid) |
| 1065 | .long CSYM(sys_fdatasync) |
| 1066 | .long CSYM(sys_sysctl) |
| 1067 | .long CSYM(sys_ni_syscall) // 150 - sys_mlock |
| 1068 | .long CSYM(sys_ni_syscall) // sys_munlock |
| 1069 | .long CSYM(sys_ni_syscall) // sys_mlockall |
| 1070 | .long CSYM(sys_ni_syscall) // sys_munlockall |
| 1071 | .long CSYM(sys_sched_setparam) |
| 1072 | .long CSYM(sys_sched_getparam) // 155 |
| 1073 | .long CSYM(sys_sched_setscheduler) |
| 1074 | .long CSYM(sys_sched_getscheduler) |
| 1075 | .long CSYM(sys_sched_yield) |
| 1076 | .long CSYM(sys_sched_get_priority_max) |
| 1077 | .long CSYM(sys_sched_get_priority_min) // 160 |
| 1078 | .long CSYM(sys_sched_rr_get_interval) |
| 1079 | .long CSYM(sys_nanosleep) |
| 1080 | .long CSYM(sys_ni_syscall) // sys_mremap |
| 1081 | .long CSYM(sys_setresuid) |
| 1082 | .long CSYM(sys_getresuid) // 165 |
| 1083 | .long CSYM(sys_ni_syscall) // for vm86 |
| 1084 | .long CSYM(sys_ni_syscall) // sys_query_module |
| 1085 | .long CSYM(sys_poll) |
| 1086 | .long CSYM(sys_nfsservctl) |
| 1087 | .long CSYM(sys_setresgid) // 170 |
| 1088 | .long CSYM(sys_getresgid) |
| 1089 | .long CSYM(sys_prctl) |
| 1090 | .long sys_rt_sigreturn_wrapper |
| 1091 | .long CSYM(sys_rt_sigaction) |
| 1092 | .long CSYM(sys_rt_sigprocmask) // 175 |
| 1093 | .long CSYM(sys_rt_sigpending) |
| 1094 | .long CSYM(sys_rt_sigtimedwait) |
| 1095 | .long CSYM(sys_rt_sigqueueinfo) |
| 1096 | .long sys_rt_sigsuspend_wrapper |
| 1097 | .long CSYM(sys_pread64) // 180 |
| 1098 | .long CSYM(sys_pwrite64) |
| 1099 | .long CSYM(sys_lchown) |
| 1100 | .long CSYM(sys_getcwd) |
| 1101 | .long CSYM(sys_capget) |
| 1102 | .long CSYM(sys_capset) // 185 |
| 1103 | .long CSYM(sys_sigaltstack) |
| 1104 | .long CSYM(sys_sendfile) |
| 1105 | .long CSYM(sys_ni_syscall) // streams1 |
| 1106 | .long CSYM(sys_ni_syscall) // streams2 |
| 1107 | .long sys_vfork_wrapper // 190 |
| 1108 | .long CSYM(sys_ni_syscall) |
| 1109 | .long CSYM(sys_mmap2) |
| 1110 | .long CSYM(sys_truncate64) |
| 1111 | .long CSYM(sys_ftruncate64) |
| 1112 | .long CSYM(sys_stat64) // 195 |
| 1113 | .long CSYM(sys_lstat64) |
| 1114 | .long CSYM(sys_fstat64) |
| 1115 | .long CSYM(sys_fcntl64) |
| 1116 | .long CSYM(sys_getdents64) |
| 1117 | .long CSYM(sys_pivot_root) // 200 |
| 1118 | .long CSYM(sys_gettid) |
| 1119 | .long CSYM(sys_tkill) |
| 1120 | sys_call_table_end: |
| 1121 | C_END(sys_call_table) |