📄 armtrap.s
字号:
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 NKPROF
mov r0,#0x80000000 ; mark as ISR entry
stmfd sp!, {r0, lr}
CALL CeLogInterrupt
ldmfd sp!, {r0, lr}
;
; 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
; (r0) = SYSINTR returned
; call the ISR hook (pfnOEMIntrOccurs is set to a faked function if not changed by OEM)
ldr r1, =pfnOEMIntrOccurs
ldr r1, [r1] ; (r1) = pfnOEMIntrOccurs
mov lr, pc ; (lr) = return address
IF Interworking :LOR: Thumbing
bx r1 ; call the pfnOEMIntrOccurs
ELSE
mov pc, r1 ; call the pfnOEMIntrOccurs
ENDIF
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 NKPROF
;
; 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
ldmfd sp!, {r0}
ldmfd sp!, {r0}
ENDIF
ldr lr, =KData ; (lr) = ptr to KDataStruct
cmp r0, #SYSINTR_RESCHED
beq %F10
sub r0, r0, #SYSINTR_DEVICES
cmp r0, #SYSINTR_MAX_DEVICES
;
; If not a device request (and not SYSINTR_RESCHED)
;
ldrhsb r0, [lr, #bResched] ; (r0) = reschedule flag
bhs %F20 ; not a device request
cmp r0, #32 ; (r0 >= 32)?
subge r0, r0, #32 ; r0 -= 32 if true
ldrlt r2, [lr, #PendEvents1] ; (r2) = pending interrupt event mask (lower 32)
ldrge r2, [lr, #PendEvents2] ; (r2) = pending interrupt event mask (upper 32)
mov r1, #1
orr r2, r2, r1, LSL r0 ; (r2) = new pending mask
strlt r2, [lr, #PendEvents1] ; save it
strge r2, [lr, #PendEvents2] ; save it
;
; mark reschedule needed
;
10 ldrb r0, [lr, #bResched] ; (r0) = reschedule flag
orr r0, r0, #1 ; set "reschedule needed bit"
strb r0, [lr, #bResched] ; update flag
20 mrs r1, spsr ; (r1) = saved status register value
and r1, r1, #0x1F ; (r1) = interrupted mode
cmp r1, #USER_MODE ; previously in user mode?
cmpne r1, #SYSTEM_MODE ; if not, was it system mode?
cmpeq r0, #1 ; user or system: is resched == 1
ldmnefd sp!, {r0-r3, r12, pc}^ ; can't reschedule right now so return
sub lr, lr, #4
ldmfd sp!, {r0-r3, r12}
stmdb lr, {r0-r3}
ldmfd sp!, {r0}
str r0, [lr] ; save resume address
mov r1, #ID_RESCHEDULE ; (r1) = exception ID
b CommonHandler
ENTRY_END IRQHandler
;;;NESTED_ENTRY FIQResched
;-------------------------------------------------------------------------------
; CheckInterlockedRestart - check for restarting an InterlockedXXX API call
;
; This routine is called by the Data Abort and IRQ handlers when the PC of
; the aborted or interrupted instruction is inside the interlocked api region
; contained at the tail of the kernel data page. If the PC points to a MOV
; instruction then the operation has completed so no restart is needed.
; Otherwise, a backwards scan is made to look for a "ldr r12, [r0]" instruction
; which is the beginning of all of the interlocked api routines.
;
; Entry (r0) = interrupted PC - INTERLOCKED_START
; (sp) = ptr to saved registers ({r0-r3, r12, lr}
; Exit LR value in register frame updated if necessary
; Uses r0, r1, r2
;-------------------------------------------------------------------------------
LEAF_ENTRY CheckInterlockedRestart
IF {FALSE}
ldr r1, =LED_ALPHA
ldr r2, =0xCEFF00AA
str r2, [r1]
ENDIF
add r0, r0, #INTERLOCKED_START ; (r0) = interrupted PC
ldr r1, [r0] ; (r1) = interrupted instruction
ldr r2, =0xE1A0 ; (r2) = "mov rx, ry" opcode
cmp r2, r1, LSR #16 ; is it a MOV instruction?
IF Interworking :LOR: Thumbing
ldrne r2, =0xE12FFF1 ; or is it a BX instruction ?
cmpne r2, r1, LSR #4
ENDIF
moveq pc, lr ; Y: return to caller
ldr r2, =0xE590C000 ; (r2) = "ldr r12, [r0]" instruction
cmp r1, r2 ; at start of routine?
moveq pc, lr ; Y: return to caller
10 ldr r1, [r0, #-4]! ; (r1) = previous instruction
cmp r1, r2 ; found start of routine?
bne %B10 ; N: keep backing up
str r0, [sp, #FrameLR] ; update return address in stack frame
IF {FALSE}
ldr r1, =LED_ALPHA
ldr r2, =0xCEBACBAC
str r2, [r1]
ENDIF
mov pc, lr ; return
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
LEAF_ENTRY ZeroPage
; void ZeroPage(void *vpPage)
;
; Entry (r0) = (vpPage) = ptr to address of page to zero
; Return none
; Uses r0-r3, r12
mov r1, #0
mov r2, #0
mov r3, #0
mov r12, #0
10 stmia r0!, {r1-r3, r12} ; clear 16 bytes (64 bytes per loop)
stmia r0!, {r1-r3, r12}
stmia r0!, {r1-r3, r12}
stmia r0!, {r1-r3, r12}
tst r0, #0xFF0
bne %B10
RETURN ; return to caller
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
LEAF_ENTRY GetHighPos
add r1, pc, #PosTable-(.+8)
mov r2, #-1
and r3, r0, #0xff
ldrb r3, [r1, +r3]
teq r3, #0
bne done
mov r0, r0, lsr #8
add r2, r2, #8
and r3, r0, #0xff
ldrb r3, [r1, +r3]
teq r3, #0
bne done
mov r0, r0, lsr #8
add r2, r2, #8
and r3, r0, #0xff
ldrb r3, [r1, +r3]
teq r3, #0
bne done
mov r0, r0, lsr #8
add r2, r2, #8
and r3, r0, #0xff
ldrb r3, [r1, +r3]
teq r3, #0
bne done
add r3, r3, #9
done
add r0, r3, r2
RETURN ; return to caller
PosTable
DCB 0,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
DCB 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
DCB 7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
DCB 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
DCB 8,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
DCB 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
DCB 7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
DCB 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
;-------------------------------------------------------------------------------
; INTERRUPTS_ON - enable interrupts
;-------------------------------------------------------------------------------
LEAF_ENTRY INTERRUPTS_ON
mrs r0, cpsr ; (r0) = current status
bic r1, r0, #0x80 ; clear interrupt disable bit
msr cpsr, r1 ; update status register
RETURN ; return to caller
;-------------------------------------------------------------------------------
; INTERRUPTS_OFF - disable interrupts
;-------------------------------------------------------------------------------
LEAF_ENTRY INTERRUPTS_OFF
mrs r0, cpsr ; (r0) = current status
orr r1, r0, #0x80 ; set interrupt disable bit
msr cpsr, r1 ; update status register
RETURN ; return to caller
;-------------------------------------------------------------------------------
; INTERRUPTS_ENABLE - enable/disable interrupts based on arguemnt and return current status
;-------------------------------------------------------------------------------
LEAF_ENTRY INTERRUPTS_ENABLE
mrs r1, cpsr ; (r1) = current status
cmp r0, #0 ; eanble or disable?
orreq r2, r1, #0x80 ; disable - set interrupt disable bit
bicne r2, r1, #0x80 ; enable - clear interrupt disable bit
msr cpsr, r2 ; update status register
ands r1, r1, #0x80 ; was interrupt enabled?
moveq r0, #1 ; yes, return 1
movne r0, #0 ; no, return 0
RETURN ; return to caller
;----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -