- call0 _spill_registers # destroys a3, a4, and SAR
-
- /* Advance PC, restore registers and SAR, and return from exception. */
-
- l32i a3, a2, PT_AREG5
- l32i a4, a2, PT_AREG4
- l32i a0, a2, PT_AREG0
- wsr a3, sar
- l32i a3, a2, PT_AREG3
-
- /* Restore clobbered registers. */
-
- l32i a7, a2, PT_AREG7
- l32i a11, a2, PT_AREG11
- l32i a15, a2, PT_AREG15
-
- movi a2, 0
- rfe
-
-ENDPROC(fast_syscall_spill_registers)
-
-/* Fixup handler.
- *
- * We get here if the spill routine causes an exception, e.g. tlb miss.
- * We basically restore WINDOWBASE and WINDOWSTART to the condition when
- * we entered the spill routine and jump to the user exception handler.
- *
- * a0: value of depc, original value in depc
- * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
- * a3: exctable, original value in excsave1
- */
-
-ENTRY(fast_syscall_spill_registers_fixup)
-
- rsr a2, windowbase # get current windowbase (a2 is saved)
- xsr a0, depc # restore depc and a0
- ssl a2 # set shift (32 - WB)
-
- /* We need to make sure the current registers (a0-a3) are preserved.
- * To do this, we simply set the bit for the current window frame
- * in WS, so that the exception handlers save them to the task stack.
- */
-
- xsr a3, excsave1 # get spill-mask
- slli a3, a3, 1 # shift left by one
-
- slli a2, a3, 32-WSBITS
- src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy......
- wsr a2, windowstart # set corrected windowstart
-
- srli a3, a3, 1
- rsr a2, excsave1
- l32i a2, a2, EXC_TABLE_DOUBLE_SAVE # restore a2
- xsr a2, excsave1
- s32i a3, a2, EXC_TABLE_DOUBLE_SAVE # save a3
- l32i a3, a2, EXC_TABLE_PARAM # original WB (in user task)
- xsr a2, excsave1
-
- /* Return to the original (user task) WINDOWBASE.
- * We leave the following frame behind:
- * a0, a1, a2 same
- * a3: trashed (saved in EXC_TABLE_DOUBLE_SAVE)
- * depc: depc (we have to return to that address)
- * excsave_1: exctable
- */
-
- wsr a3, windowbase
- rsync
-
- /* We are now in the original frame when we entered _spill_registers:
- * a0: return address
- * a1: used, stack pointer
- * a2: kernel stack pointer
- * a3: available
- * depc: exception address
- * excsave: exctable
- * Note: This frame might be the same as above.
- */
-
- /* Setup stack pointer. */
-
- addi a2, a2, -PT_USER_SIZE
- s32i a0, a2, PT_AREG0
-
- /* Make sure we return to this fixup handler. */
-
- movi a3, fast_syscall_spill_registers_fixup_return
- s32i a3, a2, PT_DEPC # setup depc
-
- /* Jump to the exception handler. */
-
- rsr a3, excsave1
- rsr a0, exccause
- addx4 a0, a0, a3 # find entry in table
- l32i a0, a0, EXC_TABLE_FAST_USER # load handler
- l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
- jx a0
-
-ENDPROC(fast_syscall_spill_registers_fixup)
-
-ENTRY(fast_syscall_spill_registers_fixup_return)
-
- /* When we return here, all registers have been restored (a2: DEPC) */
-
- wsr a2, depc # exception address
-
- /* Restore fixup handler. */
-
- rsr a2, excsave1
- s32i a3, a2, EXC_TABLE_DOUBLE_SAVE
- movi a3, fast_syscall_spill_registers_fixup
- s32i a3, a2, EXC_TABLE_FIXUP
- rsr a3, windowbase
- s32i a3, a2, EXC_TABLE_PARAM
- l32i a2, a2, EXC_TABLE_KSTK
-
- /* Load WB at the time the exception occurred. */
-
- rsr a3, sar # WB is still in SAR
- neg a3, a3
- wsr a3, windowbase
- rsync
-
- rsr a3, excsave1
- l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
-
- rfde
-
-ENDPROC(fast_syscall_spill_registers_fixup_return)
-
-/*
- * spill all registers.
- *
- * This is not a real function. The following conditions must be met:
- *
- * - must be called with call0.
- * - uses a3, a4 and SAR.
- * - the last 'valid' register of each frame are clobbered.
- * - the caller must have registered a fixup handler
- * (or be inside a critical section)
- * - PS_EXCM must be set (PS_WOE cleared?)
- */
-
-ENTRY(_spill_registers)
-