📄 armtrap.s
字号:
movs pc, r12 ; switch to User Mode & jump to API function
; Direct system call return. Used for API calls made in kernel mode or to
; kernel mode functions.
DirectRet
stmfd sp!, {r0-r3} ; save return values
mov r0, #SYSTEM_MODE
stmfd sp!, {r0, r9} ; pass mode & extra info (unused)
mov r0, sp ; (r0) = ptr to mode & extra info
; System call return.
;
; (r0) = ptr to mode & static base
; (TOS) = mode
; (TOS+4) = static base
; (TOS+8) = saved r0-r3
SysRet
CALL ServerCallReturn
mov r12, r0 ; (r12) = return address
ldr r0, [sp] ; (r0) = target mode
add sp, sp, #8 ; retore stack (ignore extra field)
cmp r0, #USER_MODE ; return to user mode ??
ldmfd sp!, {r0-r3} ; reload return values
IF Interworking :LOR: Thumbing
bxne r12
ELSE
movne pc, r12 ; return in "kernel mode"
ENDIF
msr cpsr_c, #SVC_MODE:OR:0xC0 ; switch to SVC Mode w/IRQs disabled
tst r12, #0x01 ; returning to Thumb mode ??
msrne spsr_c, #USER_MODE | THUMB_STATE
msreq spsr_c, #USER_MODE ; set the Psr according to returning state
movs pc, r12 ; switch to User Mode and return
ENTRY_END PrefetchAbortEH
; Process a prefetch abort.
ProcessPrefAbort
add lr, lr, #0xF0000000 ; repair continuation address
stmfd sp!, {r0-r3, r12, lr}
IF {FALSE}
ldr r0, =LED_ALPHA
10 ldr r1, =0xC0DEAB00
str r1, [r0]
mov r1, #SPIN_DELAY
15 subs r1, r1, #1
bgt %B15
str lr, [r0]
mov r1, #SPIN_DELAY
17 subs r1, r1, #1
bgt %B17
ENDIF
mov r0, lr ; (r0) = faulting address
mfc15 r2, c13 ; (r2) = process base address
tst r0, #0xFE000000 ; slot 0 reference?
orreq r0, r0, r2 ; (r0) = process slot based address
CALL LoadPageTable ; (r0) = !0 if entry loaded
tst r0, r0
ldmnefd sp!, {r0-r3, r12, pc}^ ; restore regs & continue
ldmfd sp!, {r0-r3, r12}
ldr lr, =KData-4
stmdb lr, {r0-r3}
ldmfd sp!, {r0}
str r0, [lr] ; save resume address
mov r1, #ID_PREFETCH_ABORT ; (r1) = exception ID
;;b CommonHandler
LTORG
;-------------------------------------------------------------------------------
; Common fault handler code.
;
; The fault handlers all jump to this block of code to process an exception
; which cannot be handled in the fault handler or to reschedule.
;
; (r1) = exception ID
; original r0-r3 & lr saved at KData-0x14.
;-------------------------------------------------------------------------------
ALTERNATE_ENTRY CommonHandler
mrs r2, spsr
msr cpsr_c, #SVC_MODE:OR:0xC0 ; switch to Supervisor mode w/IRQs disabled
ldr r3, =KData ; (r3) = ptr to KData page
; Save the processor state into a thread structure. If the previous state was
; User or System and the kernel isn't busy, then save the state into the current
; thread. Otherwise, create a temporary thread structure on the kernel stack.
;
; (r1) = exception ID
; (r2) = SPSR
; (r3) = ptr to KData page
; Interrupted r0-r3, and Pc saved at (r3-0x14)
; In Supervisor Mode.
ALTERNATE_ENTRY SaveAndReschedule
IF {FALSE}
ldrb r0, [r3,#cNest] ; (r0) = kernel nest level
subs r0, r0, #1 ; in a bit deeper (0 if first entry)
strb r0, [r3,#cNest] ; save new nest level
ENDIF
and r0, r2, #0x1f ; (r0) = previous mode
cmp r0, #USER_MODE ; 'Z' set if from user mode
cmpne r0, #SYSTEM_MODE ; 'Z' set if from System mode
bne %F50 ; reentering kernel, save state on stack
ldr r0, [r3,#pCurThd] ; (r0) = ptr to current thread
add r0, r0, #TcxR4 ; (r0) = ptr to r4 save
stmia r0, {r4-r14}^ ; save User bank registers
10 ldmdb r3, {r3-r7} ; load saved r0-r3 & Pc
stmdb r0!, {r2-r6} ; save Psr, r0-r3
sub r0, r0, #THREAD_CONTEXT_OFFSET ; (r0) = ptr to Thread struct
str r7, [r0,#TcxPc] ; save Pc
mfc15 r2, c6 ; (r2) = fault address
mfc15 r3, c5 ; (r3) = fault status
; Process an exception or reschedule request.
FirstSchedule
20 msr cpsr_c, #SVC_MODE ; enable interrupts
CALL HandleException
ldr r2, [r0, #TcxPsr] ; (r2) = target status
and r1, r2, #0x1f ; (r1) = target mode
cmp r1, #USER_MODE
cmpne r1, #SYSTEM_MODE
bne %F30 ; not going back to user or system mode
add r0, r0, #TcxR3
ldmia r0, {r3-r14}^ ; reload user/system mode registers
ldr r1, =KData
msr cpsr_c, #SVC_MODE:OR:0xC0 ; disable all interrupts
ldrb r1, [r1, #bResched] ; (r1) = nest level + reschedule flag
cmp r1, #1
mov r1, #ID_RESCHEDULE
beq %B20 ; interrupted, reschedule again
msr spsr, r2
ldr lr, [r0, #TcxPc-TcxR3]
ldmdb r0, {r0-r2}
movs pc, lr ; return to user or system mode
; Return to a non-preemptible privileged mode.
;
; (r0) = ptr to THREAD structure
; (r2) = target mode
30
IF Interworking :LOR: Thumbing
tst r2, #THUMB_STATE ; returning to Thumb code ?
addne r1, r0, #THREAD_CONTEXT_OFFSET ; create pointer to context
bne ThumbDispatch ; and branch to thumb dispatch code
ENDIF
msr cpsr, r2 ; switch to target mode
add r0, r0, #TcxR0
ldmia r0, {r0-r15} ; reload all registers & return
; Save registers for fault from a non-preemptible state.
50 sub sp, sp, #TcxSizeof ; allocate space for temp. thread structure
cmp r0, #SVC_MODE
bne %F55 ; must mode switch to save state
add r0, sp, #TcxR4 ; (r0) = ptr to r4 save area
stmia r0, {r4-r14} ; save SVC state registers
add r4, sp, #TcxSizeof ; (r4) = old SVC stack pointer
str r4, [r0, #TcxSp-TcxR4] ; update stack pointer value
b %B10
55
IF Interworking :LOR: Thumbing
bic r0, r2, #THUMB_STATE ; Ensure Thumb bit is clear
msr cpsr, r0 ; and switch to mode exception came from
ELSE
msr cpsr, r2 ; switch to mode exception came from
ENDIF
add r0, sp, #TcxR4 ; (r0) = ptr to r4 save area
stmia r0, {r4-r14} ; save mode's register state
msr cpsr_c, #SVC_MODE:OR:0xC0 ; back to supervisor mode
b %B10 ; go save remaining state
LTORG
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
NESTED_ENTRY DataAbortHandler
sub lr, lr, #8 ; repair continuation address
stmfd sp!, {r0-r3, r12, lr}
PROLOG_END
sub r0, lr, #INTERLOCKED_START
cmp r0, #INTERLOCKED_END-INTERLOCKED_START
bllo CheckInterlockedRestart
mfc15 r0, c6 ; (r0) = FAR
mfc15 r1, c5 ; (r1) = FSR
IF {FALSE}
ldr r2, =LED_DISCRETE
str r1, [r2]
ldr r2, =LED_ALPHA
10 ldr r3, =0xDA2AAB00
str r3, [r2]
mov r3, #SPIN_DELAY
15 subs r3, r3, #1
bgt %B15
str lr, [r2]
mov r3, #SPIN_DELAY
17 subs r3, r3, #1
bgt %B17
str r0, [r2]
mov r3, #SPIN_DELAY
19 subs r3, r3, #1
bgt %B19
;;; b %B10
ENDIF
mfc15 r2, c13 ; (r2) = process base address
tst r0, #0xFE000000 ; slot 0 reference?
orreq r0, r0, r2 ; (r0) = process slot based address
and r1, r1, #0x0D ; type of data abort
cmp r1, #0x05 ; translation error?
movne r0, #0
CALLEQ LoadPageTable ; (r0) = !0 if entry loaded
tst r0, r0
ldmnefd sp!, {r0-r3, r12, pc}^ ; restore regs & continue
ldr lr, =KData-4
ldmfd sp!, {r0-r3, r12}
stmdb lr, {r0-r3}
ldmfd sp!, {r0}
str r0, [lr] ; save resume address
mov r1, #ID_DATA_ABORT ; (r1) = exception ID
b CommonHandler
ENTRY_END DataAbortHandler
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
NESTED_ENTRY IRQHandler
sub lr, lr, #4 ; fix return address
stmfd sp!, {r0-r3, r12, lr}
PROLOG_END
IF {FALSE}
ldr r0, =LED_ALPHA
10 ldr r1, =0x09090a0a
str r1, [r0]
mov r1, #SPIN_DELAY
15 subs r1, r1, #1
bgt %B15
str lr, [r0]
mov r1, #SPIN_DELAY
17 subs r1, r1, #1
bgt %B17
ENDIF
;
; Test interlocked API status.
;
sub r0, lr, #INTERLOCKED_START
cmp r0, #INTERLOCKED_END-INTERLOCKED_START
bllo CheckInterlockedRestart
IF CELOG
mov r0,#0x80000000 ; mark as ISR entry
stmfd sp!, {r0}
CALL CeLogInterrupt
ldmfd sp!, {r0}
;
; mark that we are going a level deeper
;
ldr r1, =KData
ldrsb r0, [r1,#cNest] ; (r0) = kernel nest level
add r0, r0, #1 ; in a bit deeper (0 if first entry)
strb r0, [r1,#cNest] ; save new nest level
ENDIF
;
; CAREFUL! The stack frame is being altered here. It's ok since
; the only routine relying on this was the Interlock Check. Note that
; we re-push LR onto the stack so that the incoming argument area to
; OEMInterruptHandler will be correct.
;
mrs r1, spsr ; (r1) = saved status reg
stmfd sp!, {r1} ; save SPSR onto the IRQ stack
mov r0,lr ; parameter to OEMInterruptHandler
msr cpsr_c, #SVC_MODE:OR:0x80 ; switch to supervisor mode w/IRQs disabled
stmfd sp!, {lr} ; save LR onto the SVC stack
stmfd sp!, {r0} ; save IRQ LR (in R0) onto the SVC stack (param)
;
; Now we call the OEM's interrupt handler code. It is up to them to
; enable interrupts if they so desire. We can't do it for them since
; there's only on interrupt and they haven't yet defined their nesting.
;
CALL OEMInterruptHandler
ldmfd sp!, {r1} ; dummy pop (parameter)
ldmfd sp!, {lr} ; restore SVC LR from the SVC stack
msr cpsr_c, #IRQ_MODE:OR:0x80 ; switch back to IRQ mode w/IRQs disabled
;
; Restore the saved program status register from the stack.
;
ldmfd sp!, {r1} ; restore IRQ SPSR from the IRQ stack
msr spsr, r1 ; (r1) = saved status reg
IF CELOG
;
; call CeLogInterrupt with cNest << 16 | SYSINTR
;
stmfd sp!, {r0}
ldr lr, =KData
ldrsb r1, [lr,#cNest] ; (r1) = cNest value (1, 2, etc)
sub r1, r1, #1 ; make one level less
orr r0, r0, r1, LSL #16 ; (r0) = cNest value << 16 + SYSINTR
strb r1, [lr,#cNest]
stmfd sp!, {r0}
CALL CeLogInterrupt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -