📄 armtrap.s
字号:
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
ldr r2, [lr, #PendEvents] ; (r2) = pending interrupt event mask
mov r1, #1
orr r2, r2, r1, LSL r0 ; (r2) = new pending mask
str r2, [lr, #PendEvents] ; 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/_OFF - enable or disable interrupts
;-------------------------------------------------------------------------------
LEAF_ENTRY INTERRUPTS_ON
mrs r0, cpsr ; (r0) = current status
bic r1, r0, #0xC0 ; clear interrupt disable bit
msr cpsr, r1 ; update status register
RETURN ; return to caller
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
LEAF_ENTRY INTERRUPTS_OFF
mrs r0, cpsr ; (r0) = current status
orr r1, r0, #0xC0 ; set interrupt disable bit
msr cpsr, r1 ; update status register
RETURN ; return to caller
;-------------------------------------------------------------------------------
; SetCPUASID - setup processor specific address space information
;
; SetCPUASID will update the virtual memory tables so that new current process
; is mapped into slot 0 and set the h/w address space ID register for the new
; process.
;
; Entry (r0) = ptr to THREAD structure
; Return nothing
; Uses r0-r3, r12
;-------------------------------------------------------------------------------
LEAF_ENTRY SetCPUASID
IF CELOG
ldr r1, [r0, #ThProc] ; (r1) = ptr to new process
ldr r2, [r1, #PrcHandle] ; (r2) = handle of new process
ldr r3, =KData ; (r3) = ptr to KDataStruct
ldr r1, [r3, #hCurProc] ; (r1) = hCurProc
cmp r1, r2 ; if new process == old process
beq %F31 ; then skip CeLog call
stmfd sp!, {r0-r3, r12, lr} ; save regs
mov r0, r2 ; (r0) = handle of new process
CALL CELOG_ThreadMigrateARM
ldmfd sp!, {r0-r3, r12, lr} ; restore regs
31
ENDIF
ldr r1, [r0, #ThProc] ; (r1) = ptr to thread's current process
ldr r12, =KData ; (r12) = ptr to KDataStruct
ldr r2, [r1, #PrcHandle] ; (r2) = current proc's handle
ldr r3, [r1, #PrcVMBase] ; (r3) = current proc's slot base address
str r1, [r12, #pCurPrc] ; set pCurProc
str r2, [r12, #hCurProc] ; set hCurProc
add r12, r12, #aSections ; (r12) = ptr to SectionTable
ldr r2, [r12, r3, LSR #VA_SECTION-2] ; (r2) = process's memory section
mtc15 r3, c13 ; set process base address register
str r2, [r12] ; copy to slot 0 for VirtualAlloc & friends
; Set DOMAIN Access.
RETURN ; return to caller
IF CELOG
LTORG
ENDIF
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
NESTED_ENTRY KCall
PROLOG_END
; KCall - call kernel function
;
; KCall invokes a kernel function in a non-preemtable state by switching
; to SVC mode. This switches to the kernel stack and inhibits rescheduling.
;
; Entry (r0) = ptr to function to call
; (r1) = first function arg
; (r2) = second fucntion arg
; (r3) = third function arg
; Exit (r0) = function return value
; Uses r0-r3, r12
mrs r12, cpsr ; (r12) = current status
and r12, r12, #0x1F ; (r12) = current mode
cmp r12, #SYSTEM_MODE
mov r12, r0 ; (r12) = address of function to call
mov r0, r1 ; \ ;
mov r1, r2 ; | ripple args down
mov r2, r3 ; /
IF Thumbing
bxne r12 ; already non-preemptible, invoke routine directly
ELSE
movne pc, r12 ; already non-preemptible, invoke routine directly
ENDIF
msr cpsr_c, #SVC_MODE
mov lr, pc ; (lr_svc) = PC+8
IF Thumbing
bx r12 ; invoke routine in non-preemptible state
ELSE
mov pc, r12 ; invoke routine in non-preemptible state
ENDIF
msr cpsr_c, #SYSTEM_MODE ; back to preemtible state
ldr r3, =KData ; (r3) = ptr to KDataStruct
ldrb r12, [r3, #bResched] ; (r12) = reschedule flag
cmp r12, #1
beq %F1
ldrb r12, [r3, #dwKCRes]
cmp r12, #1
RETURN_NE ; no reschedule needed so return
1 mov r12, lr
mrs r2, cpsr
IF Thumbing
tst r12, #0x01 ; return to thumb mode ?
orrne r2, r2, #THUMB_STATE ; then update the Psr
ENDIF
msr cpsr_c, #SVC_MODE:OR:0xC0
stmdb r3, {r0-r3, r12}
mov r1, #ID_RESCHEDULE
b SaveAndReschedule
ENTRY_END KCall
;-------------------------------------------------------------------------------
; InSysCall - check if in non-preemptible state
;
; InSysCall is called to test if code is being called in a preemptible state
; or not. Only user mode or system mode code is preemptible. Since this code
; cannot be called in user mode, we just check for system mode.
;
; Entry none
; Return (r0) = 0 if preemtible, !=0 not preemptible
;-------------------------------------------------------------------------------
LEAF_ENTRY InSysCall
mrs r0, cpsr ; (r0) = current status
and r0, r0, #0x1F ; (r0) = current mode
eor r0, r0, #SYSTEM_MODE ; (r0) = 0 iff in system mode
RETURN ; return to caller
;-------------------------------------------------------------------------------
; CaptureContext is invoked in kernel context on the user thread's stack to
; build a context structure to be used for exception unwinding.
;
; Note: The Psr & Pc values will be updated by ExceptionDispatch from information
; in the excinfo struct pointed at by the THREAD.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -