📄 int.s
字号:
;; MShowTec - www.mshowtec.com
;; msLinux int.s ver1.0
;; 20051221 lmjx create limiao@mshowtec.com
;;
;;
;; MSLINUX_INT_S
IMPORT mslinux_irq_handler
CODE32
AREA |C$$code|, CODE, READONLY
GET snds.s
EXPORT undef
IMPORT cpu_block_undef
undef
b cpu_block_undef
IMPORT mslinux_top_swi_stack
EXPORT swi
swi
ldr r2, =mslinux_top_swi_stack
ldr r2, [r2]
mov sp, r2 ;
stmfd sp!,{r0-r3, r12, lr}
mov r1, sp ;
mrs r3, spsr
ldr r0, [lr,#-4] ; get arm swi no.
bic r0, r0, #0xFF000000 ;
ldmfd sp!, {r0-r3, r12, pc}^
EXPORT prefetch
IMPORT cpu_block_prefatch
prefetch
b cpu_block_prefatch
EXPORT data
IMPORT cpu_block_data
data
b cpu_block_data
IMPORT timer_resched_cnt
IMPORT mslinux_irq_nesting
IMPORT mslinux_top_irq_stack
IMPORT errno_print
IMPORT schedule
EXPORT irq
irq
sub lr,lr,#4
stmfd sp!, {r0-r12, lr} ; Save all scratch registers
mrs r0, SPSR ; Save the task status register
stmfd sp!,{r0} ; necessary to allow nested interrupts
; Count number of region entrys (disable task switch for nested interrupts)
ldr r2,=mslinux_irq_nesting
ldrb r3,[r2]
add r3,r3,#1
strb r3,[r2]
tst r3,#0xff
mov r0,#1 ;1 for enter int nesting over
beq errno_print
; We must switch in systeme mode because the IRQ lr can be corrupted
; if a new IRQ is entered after a function call in the user
; interrupthandler
orr r1, r0,#(Mode_SYS | I_BIT)
msr CPSR_cf,r1
; Switch on irq stack
ldr r1,=mslinux_top_irq_stack ; Load top of irq stack address
ldr r1,[r1]
mov r3,sp ; save old stack pointer
ldr r0,=mslinux_irq_nesting
ldrb r2,[r0]
cmp r2, #1 ; if no irq nesting
moveq sp,r1 ; if no then load sp with top of irq stack
stmfd sp!,{r3,lr} ; Push system lr and old sp in new stack
bl mslinux_irq_handler ; call irq handler
; Pop registers and come back to tasks sp
ldmfd sp,{sp,lr} ; Restore lr and sp
; Return in IRQ mode
mov r1,#(Mode_IRQ | I_BIT)
msr CPSR_cf,r1
; Decrement region counter, if not equal to zero a task switch
; is not possible we must return from FIQ
ldr r2,=mslinux_irq_nesting ; Load counter adress
ldrb r3,[r2] ; load counter
cmp r3,#0 ; if nul -> error
mov r0,#2 ;2 for out int nesting over
beq errno_print
subs r3,r3,#1 ; decrement counter
strb r3,[r2] ; store counter
bne mslinux_return_irq ; if not nul interrupt return ( no switch possible)
ldr r2,=timer_resched_cnt ; Load timer_resched_cnt adress
ldr r3,[r2] ; load counter
cmp r3,#0 ; if nul -> do not resched
beq mslinux_return_irq ;int return
sub r3,r3,#1 ; decrement counter
str r3,[r2] ; store counter
; We now need to perform a task switch.
; We must call the switch function in systeme mode
ldmfd sp!,{r0,r1} ; Pop SPSR and r0 (scratch register) from the stack
ldr r2,[sp,#12*4] ; Load irq lr in the stack = task adress
; switch in systeme mode to create a fake system stack
; which contains {SPSR, r0, Task adress}
mov r3,#(Mode_SYS | I_BIT) ; switch in system mode
msr CPSR_cf,r3
stmfd sp!,{r0-r2} ; push {SPSR, r0 , Tasks adress} in system stack
; Switch in IRQ mode to empty the stack and pop all registers
mov r1,#(Mode_IRQ | I_BIT) ; Go to exception mode
msr CPSR_cf,r1
ldmfd sp!,{r1-r12, lr}; Empty the IRQ stack
; so we switch in system mode to call the task switch
mov r0,#(Mode_SYS | I_BIT) ; switch in system mode
msr CPSR_cf,r0
; Call task switch and save/restore task lr which was not saved
stmfd sp!,{lr} ; Save Systeme lr which was not saved
bl schedule ; call the task switch
ldmfd sp!,{lr} ; pop systeme mode lr
; Task was in ARM mode we restore the CPSR and return in task
ldmfd sp!,{r0} ; Pop the SPSR
msr CPSR_cf,r0 ; restore CPSR
ldmfd sp!,{r0,pc} ; Return in task
; Interrupt return if no task switching
mslinux_return_irq
ldmfd sp!,{r1} ; Transfert PSR in SPSR for interrupt return
msr SPSR_cf,r1
ldmfd sp!,{r0-r12, pc}^; Return from interrupt
EXPORT fiq
fiq
b fiq
AREA |C$$data|
int_swi_top_stack
% 4
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -