📄 interrup.s
字号:
;*************************************************************************
;
;
; IMPORTANT - USE OF THIS SOFTWARE IS SUBJECT TO LICENSE RESTRICTIONS
; CAREFULLY READ THE LICENSE AGREEMENT BEFORE USING THE SOFTWARE
;
;
;*************************************************************************
; ORIGIN UK 35-0450.05-400
;******************************************************************
;
; ARM VRTRmc
;
;******************************************************************
;
; Description
; ===========
;
; INTERRUP.S - Interrupt Handler
;
;
; Revision History
; ================
;
; Version Date Author Reason for Change
; 1.0 14/03/96 Samsung & P.Cumming Initial Version
; Derived from Samsung
; 1.1 18/04/96 P.Cumming ui_enter/exit & interrupt
; en/disable separate segments
; 1.2 10/05/96 P.Cumming VMC_PROBE_INTERRUPT added
; 1.3 30/07/96 P.Cumming int enable/disable removed
; 1.4 11/09/96 P.Cumming ui_enter check IRQ/FIQ race
;*******************************************************************
;****************************************************************************
; ARM Constants
;****************************************************************************
ResetV EQU 0
UndefInstrV EQU 4
SWIV EQU 8
PrefAbortV EQU &c
DataAbortV EQU &10
AddrExceptV EQU &14
IRQV EQU &18
FIQV EQU &1c
ErrorV EQU &20
LastV EQU &24
UserMode EQU &10
FIQMode EQU &11
IRQMode EQU &12
SVCMode EQU &13
AbortMode EQU &17
UndefMode EQU &1b
MaskMode EQU &1f
PSR_32Bit EQU &10
ModeMask EQU &0000001f
SubModeMask EQU &0000000f
NoInt EQU &000000c0
NoIRQInt EQU &00000080
NoFIQInt EQU &00000040
ThumbMode EQU &00000020
IFConfig EQU &000000d0
CCMask EQU &f0000000
;****************************************************************************
; External Symbols Declaration
;****************************************************************************
IMPORT vmc_intr_count
IMPORT vmc_timer_ticks
IMPORT vmc_ticker
IMPORT vmc_sched_needed
IMPORT vmc_tresched
IMPORT vmc_keep_FIQ_enabled
IF :DEF:VMC_PROBE_INTERRUPT
IMPORT vmc_intr_disable_start
IMPORT vmc_intr_disable_stop
ENDIF
EXPORT |ui_enter|
EXPORT |ui_exit|
AREA |C$$code$$interrupt|, CODE, READONLY, INTERWORK
IF Thumb = {TRUE}
CODE32
ENDIF
c_intr_count DCD vmc_intr_count
c_timer_ticks DCD vmc_timer_ticks
c_sched_needed DCD vmc_sched_needed
c_keep_FIQ_enabled DCD vmc_keep_FIQ_enabled
;****************************************************************************
; ui_enter : Interrupt Enter Routine
;****************************************************************************
;
; extern void ui_enter(void);
;
|ui_enter|
;
; ui_enter stack frame
;
; +---------------+
; | v1 - v4 | <---- sp
; +---------------+
; | lr |
; +---------------+
; | spsr | <---- ui_enter start part sp
; +---------------+
; | r0 - r3 |
; +---------------+
; | ip |
; +---------------+
; | lr |
; +---------------+
;
stmfd sp!,{v1-v4,lr} ;save local variable & return address
ldr v1,c_keep_FIQ_enabled ;load address of vmc_keep_FIQ_enabled
ldrb v2,[v1] ;get vmc_keep_FIQ_enables
cmp v2,#0 ;check if we keep FIQ enabled
; interrupt disable --> IRQ & FIQ
mrs v1,cpsr ;get CPSR
orreq v2,v1,#NoInt ;IRQ & FIQ interrupt disable bit set
orrne v2,v1,#NoIRQInt ;IRQ disable bit set
msr cpsr,v2 ;interrupt disable
; interrupt count inc & first interrupt check
ldr v4,c_intr_count ;initial value = 0
ldrb v3,[v4] ;get interrupt count
add v3,v3,#1 ;increment interrupt count
strb v3,[v4] ;save interrupt count
; if not first interrupt, restore status & return
cmp v3,#1 ;first interrupt ?
beq check_race
msr cpsr,v1 ;restore saved CPSR
ldmfd sp!,{v1-v4,pc} ;return ui_enter
check_race
; check race condition
mrs v4,spsr ;get interrupted task's status
and lr,v4,#ModeMask
cmp lr,#SVCMode
beq first_interrupt
msr cpsr,v1
ldmfd sp!,{v1-v4,pc} ;return ui_enter
first_interrupt
; first interrupt --> make task's interrupt stack frame
ldr v3,[sp,#(11*4)] ;get interrupted task's return address
bic v2,v2,#ModeMask
orr v2,v2,lr
msr cpsr,v2 ;change before interrupt mode
; make task's interrupt stack frame
;
; +---------------+
; | cpsr |
; +---------------+
; | r0 - r3 |
; +---------------+
; | ip |
; +---------------+
; | lr |
; +---------------+
; | pc |
; +---------------+
;
stmfd sp!,{v3} ;save interrupted task's return address
stmfd sp!,{r0-r3,ip,lr} ;save scratch register to task's stack
stmfd sp!,{v4} ;save interrupted task's status
; return to ui_enter start mode
msr cpsr,v1 ;return to interrupt mode
ldmfd sp!,{v1-v4,pc} ;return ui_enter
IF Thumb = {TRUE}
CODE16
;****************************************************************************
; ui_exit : Interrupt Exit Routine
;****************************************************************************
;
; extern void ui_exit(void);
;
|ui_exit|
ldr r2,=ui_exit_32
bx r2
;
; ui_exit stack frame
;
; +---------------+
; | spsr | <---- Interrupted task processor status
; +---------------+
; | r0 - r3 |
; +---------------+
; | ip |
; +---------------+
; | lr | <---- Interrupted task program count
; +---------------+
;
CODE32
ALIGN
ui_exit_32
ELSE
|ui_exit|
ENDIF
;
ldr r0,c_keep_FIQ_enabled ;load address of vmc_keep_FIQ_enabled
ldrb r1,[r0] ;get vmc_keep_FIQ_enables
cmp r1,#0 ;check if we keep FIQ enabled
; interrupt disable --> IRQ & FIQ
mrs r2,cpsr ;get CPSR
orreq lr,r2,#NoInt ;IRQ & FIQ interrupt disable bit set
orrne lr,r2,#NoIRQInt ;IRQ disable bit set
msr cpsr,lr ;interrupt disable
; interrupt count decrement & final interrupt exit check
ldr r1,c_intr_count ;initial value = 0
ldrb r3,[r1] ;get interrupt count
subs r3,r3,#1 ;check final interrupt exit
strb r3,[r1] ;save interrupt count
; if not the outermost interrupt exit, return
ldmfd sp!,{lr} ;get SPSR
and r0,lr,#ModeMask ;
teqeq r0,#SVCMode ;if outermost, check race condition
msrne spsr,lr ;if not the outermost interrupt,
ldmnefd sp!,{r0-r3,ip,pc}^ ;then return to interrupted mode
;
continue_interrupt
stmfd sp!,{v1,v2,lr} ;save SPSR & v1-v2
ldr v1,c_timer_ticks
ldr r0,[v1] ;get vmc_timer_ticks -> vmc_ticker arg.
cmp r0,#0 ;timer tick interrupt issue ?
beq timer_check_done ;if vmc_timer_ticks = 0, done
mov v2,r2 ;copy CPSR before interrupt disabling
add r3,r3,#1 ;vmc_intr_count++
strb r3,[r1] ;
mov r1,#0 ;clear vmc_timer_ticks
str r1,[v1] ;
handle_timeout
; interrupt enable ?
msr cpsr,v2 ;interrupt enable
bl vmc_ticker ;void vmc_ticker(int ticks)
; interrupt disable ?
ldr r0,c_keep_FIQ_enabled ;load address of vmc_keep_FIQ_enabled
ldrb r1,[r0] ;get vmc_keep_FIQ_enables
cmp r1,#0 ;check if we keep FIQ enabled
orreq lr,v2,#NoInt ;IRQ & FIQ interrupt disable bit set
orrne lr,v2,#NoIRQInt ;IRQ disable bit set
msr cpsr,lr ;interrupt disable
; check timer ticks
mov r1,#0 ;
swp r0,r1,[v1] ;get & clear vmc_timer_ticks
cmp r0,#0 ;timer tick interrupt issue ?
bne handle_timeout
ldr r1,c_intr_count ;initial value = 0
ldrb r3,[r1] ;get interrupt count
sub r3,r3,#1 ;check final interrupt exit
strb r3,[r1] ;save interrupt count
timer_check_done
ldr v1,c_keep_FIQ_enabled ;load address of vmc_keep_FIQ_enabled
ldrb v2,[v1] ;get vmc_keep_FIQ_enables
cmp v2,#0 ;check if we keep FIQ enabled
ldmfd sp!,{v1,v2,lr} ;get SPSR & v1-v2
orreq lr,lr,#NoInt ;FIQ & IRQ interrupt disable
orrne lr,lr,#NoIRQInt ;IRQ disable bit set
IF Thumb = {TRUE}
bic lr,lr,#ThumbMode ;disable thumb mode if enabled
ENDIF
msr spsr,lr ;
ldmfd sp!,{r0-r3,ip,lr}
subs pc,pc,#0 ;change to task mode &
nop ;interrupt disable
nop
; Changed to task mode
ldr r2,c_sched_needed ;get rescheduling flag
ldrb r0,[r2] ;
cmp r0,#0 ;check rescheduling task
blne vmc_tresched ;call rescheduling procedure
; return to the interrupted task - interrupted task stack frame
;
; +---------------+
; | cpsr |
; +---------------+
; | r0 - r3 |
; +---------------+
; | ip |
; +---------------+
; | lr |
; +---------------+
; | pc |
; +---------------+
;
ldmfd sp!,{lr} ;recover the CPSR when the task was
; return to interrupted task will return if ARM or Thumb
msr spsr, lr
ldmfd sp!, {r0-r3,ip,lr,pc}^
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -