mirror of https://github.com/l4ka/hazelnut.git
251 lines
7.8 KiB
Plaintext
251 lines
7.8 KiB
Plaintext
/********************************
|
|
* Prefetch_Abort Syscall Method *
|
|
********************************/
|
|
|
|
/***************************************
|
|
* Stack Frame *
|
|
****************************************
|
|
* IAbort * Syscall * Other *
|
|
****************************************
|
|
* SPSR * SPSR * ~ *<- Top TCB (start of kstack)
|
|
* a_lr -> pc * ~ * ~ *
|
|
* u_lr * u_lr -> pc * ~ *
|
|
* u_sp * u_sp * ~ *<- a_sp when in user mode
|
|
* r12 * #2 * o_lr -> pc *
|
|
* r11 * ~ * u-lr *
|
|
* ... * ... * u_sp *
|
|
* ... * ... * r12 *
|
|
* ... * ... * r11 *
|
|
* ... * ... * ... *
|
|
* ... * ... * r0 *
|
|
* r0 * ... * SPSR *
|
|
* #1 * ~ * #4 *
|
|
***************************************/
|
|
|
|
The immediate at the top of the stack specifies the stack layout.
|
|
|
|
/* Reset Entry Point 0x0
|
|
************************/
|
|
nop @ Not relavent since mmu disabled
|
|
...
|
|
|
|
/* Undefined Entry Point 0x4
|
|
****************************/
|
|
b undefined_entry @ Jump to Undefined Instruction entry
|
|
...
|
|
|
|
// stack user state
|
|
undefined_entry:
|
|
ldr sp, #current_thread_sp @ load current threads stack
|
|
str lr, [sp, #-4]! @ Stack ud_lr
|
|
stmdb sp, {r0 - 14}^ @ Stack user registers
|
|
msr spsr, lr @ Move SPSR to un_lr
|
|
str lr, [sp, #60]! @ Stack User CPSR
|
|
mov lr, #(ABORT_MODE | IRQ_MASK) @ Load now CPSR value
|
|
mrs cpsr, lr @ Change to abort mode
|
|
<undefined handler code>
|
|
|
|
// undefined_exit is an IPC exit since a exception IPC is generated or the
|
|
// thread is kill.
|
|
|
|
/* SWI Entry Point at 0x8
|
|
*************************/
|
|
b swi_entry @ Jump to SWI entry
|
|
...
|
|
|
|
// swi_entry is same as undefined since its an undefined instruction expecption
|
|
|
|
/* Prefetch Abort Entry Point 0xC
|
|
*********************************/
|
|
b prefetch_abort_entry @ Jump to prefetch abort entry
|
|
...
|
|
|
|
// dispatch
|
|
prefetch_abort_entry:
|
|
#ifdef EXCEPTION_VECTOR_RELOCATED
|
|
mvn lr, lr @ Value is negative of syscall #
|
|
#endif
|
|
stmia sp, {sp, lr}^ @ Stack User sp, lr (pc after syscall)
|
|
cmp lr, #SYSCALL_LIMIT @ Range Check
|
|
addlt pc, pc, lr, lsl #3 @ Jump to relavent point
|
|
prefetch_abort: @ a_lr >= SYSCALL_LIMIT
|
|
#ifdef EXCEPTION_VECTOR_RELOCATED
|
|
mvn lr, lr @ Not a syscall so restore a_lr
|
|
#endif
|
|
sub lr, lr, #4 @ Ajust a_lr for return pc value
|
|
str lr, [sp, #8] @ Stack a_lr
|
|
msr spsr, lr @ move SPSR to a_lr
|
|
str lr, [sp, #12] @ Stack user CPSR
|
|
strdb sp!, {r0-r12} @ Stack rest of user registers
|
|
... @ next 4/5 instructions of prefetch_abort
|
|
b prefetch_abort_rest
|
|
ipc_entry: @ a_lr = 0x4, ipc
|
|
<Syscall Entry Code> @ next 6 instructions of ipc_entry
|
|
b ipc_rest
|
|
nop @ dummy
|
|
|
|
// Syscall entry, ie ipc_entry
|
|
<Syscall Entry Label>
|
|
msr spsr, lr @ move SPSR to a_lr
|
|
str lr, [sp, #12] @ Stack SPSR
|
|
<Syscall code>
|
|
|
|
// Syscall exit (sp points to kstack of whatever thread we are returnning to)
|
|
// Arguments already in relavent regs */
|
|
<Syscall Exit Label>
|
|
ldr lr, [sp, #12] @ Unstack User CPSR to a_lr
|
|
msc lr, spsr @ Move User CPSR to SPSR
|
|
ldmia sp, {sp, pc}^ @ Restore User CPSR/sp, pc
|
|
|
|
// prefetch abort exit
|
|
prefetch_exit:
|
|
ldmia sp!, {r0-r12} @ Unstack rest registers
|
|
ldr lr, [sp, #12] @ Unstack User CPSR to a_lr
|
|
msc lr, spsr @ Move User CPSR to SPSR
|
|
ldmia sp, {sp, lr, pc}^ @ Restore User CPSR/sp/lr, pc
|
|
|
|
/* Data Abort Entry Point at 0xC
|
|
********************************/
|
|
b data_abort_entry @ Jump to data abort entry
|
|
...
|
|
|
|
data_abort_entry:
|
|
str lr, [sp, #-4]! @ Stack ud_lr
|
|
stmdb sp, {r0 - 14}^ @ Stack user registers
|
|
msr spsr, lr @ Move SPSR to un_lr
|
|
str lr, [sp, #60]! @ Stack User CPSR
|
|
<data_abort code>
|
|
|
|
// data_abort_exit is an IPC exit since a pager IPC is generated or the thread
|
|
// is kill.
|
|
|
|
/* Unused Entry Point at 0x14
|
|
*****************************/
|
|
nop @ Not relevent (reserved)
|
|
...
|
|
|
|
/* IRQ Entry Point at 0x18
|
|
**************************/
|
|
b irq_entry @ Jump to IRQ entry
|
|
|
|
// irq_entry same as undefined_entry since IRQ result in an IPC
|
|
// irq_exit is either IPC exit or a thread switch (possibly a debug int which
|
|
// is similar to a thread switch except the interrupted thread is restored
|
|
|
|
/* FIQ Entry Point at 0x1C
|
|
**************************/
|
|
fiq_entry:
|
|
|
|
// FIXUP, need to decide weather we interrupted user or kernel. if user its
|
|
// the same as irq. If kernel we have to a little magic.
|
|
|
|
// fiq_entry is the same as irq_entry but can start straight away without a
|
|
// branch
|
|
|
|
// Note: where we can assign IRQ or FIQ to a interrupt source kernel timer and
|
|
// debugging interrupts are FIQ so they can interrupt at any time and it
|
|
// seperates the handlers. Otherwise they have a common code base.
|
|
|
|
/********************************
|
|
* SWI + Register Syscall Method *
|
|
********************************/
|
|
|
|
/****************************
|
|
* Stack Frame *
|
|
*****************************
|
|
* Other * Syscall *
|
|
*****************************<- start of next TCB (start of kstack)
|
|
* p_lr -> pc * sv_lr -> pc *
|
|
* u_lr * u_lr *
|
|
* u_sp * u_sp *
|
|
* r12 * SPSR *
|
|
* r11 * ~ *
|
|
* ... * ~ *
|
|
* r0 * ... *
|
|
* SPSR * ~ *
|
|
****************************/
|
|
|
|
/* Reset Entry point 0x0
|
|
************************/
|
|
nop @ Not relavent since mmu disabled
|
|
...
|
|
|
|
/* Undefined Entry Point 0x4
|
|
****************************/
|
|
b undefined_entry @ Jump to Undefined Instruction entry
|
|
|
|
undefined_entry:
|
|
ldr sp, #current_thread_sp @ Load ud_sp
|
|
str lr, [sp, #-4]! @ Stack ud_lr (pc after exception)
|
|
stmdb sp, {r0 - r14}^ @ Stack registers
|
|
msr spsr, lr @ Move SPSR to ud_lr
|
|
str lr, [sp, #-64]! @ Stack SPSR
|
|
<undefined handler code>
|
|
|
|
// Undefined will exit in a ipc. So ipc_exit will be used
|
|
|
|
/* SWI Entry point 0x8
|
|
**********************/
|
|
b swi_entry @ Jump to SWI entry
|
|
...
|
|
|
|
/* dispatch */
|
|
swi_entry:
|
|
ldr sp, #current_thread_sp @ Load sv_sp
|
|
str lr, [sp, #-4]! @ Stack sv_lr (pc after syscall)
|
|
stmdb sp, {sp, lr}^ @ Stack u_sp, u_lr
|
|
msr spsr, lr @ Move SPSR to lr
|
|
str lr, [sp, #-12]! @ Stack SPSR
|
|
cmp r0, #SYSCALL_LIMIT @ Range Check
|
|
addlt pc, pc, r0, lsl #2 @ Jump to relavent Jump point
|
|
b invalid_swi @ Syscall # >= SYSCALL_LIMIT
|
|
ipc_entry: @ Syscall = 0, ipc
|
|
... @ First 6 ipc intructions
|
|
b ipc_rest @ Branch to rest of ipc code
|
|
nop @ Dummy to avoid cache stall on SA's
|
|
id_nearest: @ Syscall = 1, id_nearest
|
|
... @ ...
|
|
|
|
/* Syscall exit (sp points to kstack of whatever thread we are returnning to)
|
|
* Arguments already in relavent regs */
|
|
// If we switched threads
|
|
ldr lr, <new thread sp> @ load sp of new thread
|
|
str lr, #current_thread_sp @ store in kernel data
|
|
// If same thread we start here
|
|
ldr lr, [sp], #4 @ Unstrack SPSR to sv_lr
|
|
msc lr, spsr @ load SPSR
|
|
ldmia sp, {sp, lr, pc}^ @ Restore CPSR, sp, lr, pc
|
|
|
|
/* Prefetch Abort Entry point 0xC
|
|
*********************************/
|
|
b prefetch_abort_entry
|
|
...
|
|
|
|
// Same as undefined
|
|
|
|
/* Data Abort Entry Point at 0xC
|
|
********************************/
|
|
b data_abort_entry @ Jump to data abort entry
|
|
...
|
|
|
|
// Same as undefined
|
|
|
|
/* Unused Entry Point at 0x14
|
|
*****************************/
|
|
nop @ Not relevent (reserved)
|
|
...
|
|
|
|
/* IRQ Entry Point at 0x18
|
|
**************************/
|
|
b irq_entry @ Jump to IRQ entry
|
|
...
|
|
|
|
// Same as undefined
|
|
|
|
/* FIQ Entry Point at 0x1C
|
|
**************************/
|
|
fiq_entry:
|
|
|
|
// Same as undefined with the constraint of the prefetch syscall method
|
|
// fiq entry point.
|