📄 armtrap.s
字号:
;
; update TLS
ldr r0, =KData ; (r0) = ptr to KData page
ldr r2, [r0, #pCurThd] ; (r2) = pCurThread
ldr r0, [r2, #ThTlsNonSecure] ; (r0) = pCurThread->tlsNonSecure
str r0, [r2, #ThTlsPtr] ; pCurThread->tlsPtr = pCurThread->tlsNonSecure
ldr r2, =KData ; (r0) = ptr to KData page
str r0, [r2, #lpvTls] ; lpvTls = pCurThread->tlsNonSecure
;
; update SP
mov r0, sp ; (r0) = old sp (original r0 - r3 saved on stack)
sub sp, r1, #MAX_PSL_ARGS ; room for arguments on the new stack
; copy arguments
ldr r1, [r0]
ldr r2, [r0, #4]
str r1, [sp]
str r2, [sp, #4]
ldr r1, [r0, #8]
ldr r2, [r0, #12]
str r1, [sp, #8]
str r2, [sp, #12]
ldr r1, [r0, #16]
ldr r2, [r0, #20]
str r1, [sp, #16]
str r2, [sp, #20]
ldr r1, [r0, #24]
ldr r2, [r0, #28]
str r1, [sp, #24]
str r2, [sp, #28]
; save callee saved registers
; NOTE: we're relying on the fact that we only save 8 registers
; and will never trigger a DemmandCommit on the secure stack
; since the apiArgs and {r0-r3} were saved on the secure stack
; before and the area we need would have been committed.
sub r0, r0, #(CALLEE_SAVED_REGS - 16) ; already have room for {r0 - r3}
stmia r0, {r4-r11} ; save the caller registers
CBCommon
; common code for perform callback
; (r12) = function to call
; (r3) = mode to call into
ldr lr, =SYSCALL_RETURN ; return via a trap
cmp r3, #USER_MODE ; callback to user mode proc?
ldmfd sp!, {r0-r3} ; reload function arguments
beq RtnToUMode ; return to user mode if so
; calling callback in kmode
add lr, pc, #MD_CBRtn-(.+8)
IF Interworking :LOR: Thumbing
bx r12 ; invoke function in "kernel mode"
ELSE
mov pc, r12 ; invoke function in "kernel mode"
ENDIF
CBRtn
; return from CALLBACK
; r0 - r3 saved on stack
ldmfd sp!, {r0-r3} ; restore r0-r3
; fall thru to general callback return processing
MD_CBRtn
; (r0) = return value
ldr r3, =KData ; (r3) = ptr to KData page
ldr r2, [r3, #pCurThd] ; (r2) = pCurThread
ldr r1, [r2, #ThPcstkTop] ; (r1) = pCurThread->pcstkTop
ldr r1, [r1, #CstkPrevSP] ; (r1) = pCurThread->pcstkTop->dwPrevSP
tst r1, r1 ; need to switch stack?
beq CBRtnCommon ; go to common code if not
;
; stack switch is needed.
;
; restore callee saved registers
ldmia r1, {r4-r11}
; update TLS
ldr r12, [r2, #ThTlsSecure] ; (r12) = pCurThread->tlsSecure
str r12, [r2, #ThTlsPtr] ; pCurThread->tlsPtr = pCurThread->tlsSecure
str r12, [r3, #lpvTls] ; update global TLS
; update SP
add sp, r1, #CALLEE_SAVED_REGS
CBRtnCommon
;
; common code for callback return
;
sub sp, sp, #size_api_args ; make room for CallbackReturn arguments
str r0, [sp, #apiRa] ; save return value
add r0, sp, #svrrtnstr ; r0 = ptr to SVRRTNSTRUCT
CALL CallbackReturn ; call CallbackReturn
; (r0) = return address
mov r12, r0 ; (r12) = return address
ldr r0, [sp, #apiRa] ; (r0) = return value
add sp, sp, #size_api_args ; pop the temp stuffs
; continue at return address in kmode
IF Interworking :LOR: Thumbing
bx r12 ; return in "kernel mode"
ELSE
mov pc, r12 ; return in "kernel mode"
ENDIF
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:0x80 ; 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:0x80 ; 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:0x80 ; 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
;; V6 architectures introduce a new bit, and a new reason code.
;; This code will also work with all previous architectures, so should be
;; used for all builds (so an otherwise pre-V6 image will run properly on
;; a V6 system).
;; Two comments:
;; - bit 10 of the FSR is part of the reason code in V6, so the code would ideally
;; check that it is zero. BUT the value of bit 10 in older architectures is defined
;; as UNPREDICTABLE, so it is possible that some implementations will set this. We will
;; call LoadPageTable for 3 possible new reason codes: none of these are defined in the
;; V6 architecture specification (but could conceivably be used in implementation-specific
;; extensions). It is preferable to call LoadPageTable and then generate an abort on extra
;; (and very unlikely) reason codes, rather than not call LoadPageTable on old implementations
;; that spuriously set bit 10.
;; - Because the memory is paged in with 1st-level page table entries, any page translation aborts
;; will never cause memory to be mapped in, so only two reason codes actually need to be checked
;; below.
and r3, r1, #0xF ; type of data abort
cmp r3, #0x4 ; Instruction cache maintenance fault?
cmpne r3, #0x5 ; Section translation error?
cmpne r3, #0x7 ; Page translation error?
;; Reach here with EQ set if we should try to page in the FAR address
;; Reach here with NE set if we should just signal a fault.
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}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -