📄 tlundef.s
字号:
;*
;* tlundef.s: Top-level undefined instruction handler.
;* supervisor stack version
;* Copyright (C) ARM Limited, 1998-2002. All rights reserved.
;*
;* This file contains the first layer of the undefined instruction handler
;* used for the VFP support code. It is responsible for:
;*
;* - Preserving the ARM processor state.
;* - Decoding the instruction sufficiently to determine whether it is a
;* coprocessor instruction, and if so, for what coprocessor.
;* - Calling a second layer handler for the correct coprocessor (or for
;* genuine undefined instructions) with the instruction and (a
;* sufficient amount of) the ARM processor state as parameters.
;* The prototype for this call is defined in the file "slundef.h".
;* - On return from the second layer, restoring the ARM processor state
;* (which may have been modified by emulation of the instruction) and
;* resuming execution of the original program at an address specified
;* by the second layer. (This allows the second layer to determine
;* whether the original instruction should be retried.)
;* CHANGES
;* 0. initial implementation
; Definitions of some important PSR bits:
Flags_mask EQU 0xF8000000
Java_bit EQU 0x01000000
Endian_bit EQU 0x200
Idisable_bit EQU 0x80
Fdisable_bit EQU 0x40
Thumb_bit EQU 0x20
Mode_mask EQU 0x1F
Mode_Usr32 EQU 0x10
Mode_Svc EQU 0x13
Mode_Undef EQU 0x1b
GBLL ARCH_V6_OR_LATER
if "6" <= {ARCHITECTURE} ; ok until architecture 10
ARCH_V6_OR_LATER SETL {TRUE}
else
ARCH_V6_OR_LATER SETL {FALSE}
endif
GBLL ARCH_HAS_THUMB2
if "6T2" <= {ARCHITECTURE} ; ok until architecture 10
ARCH_HAS_THUMB2 SETL {TRUE}
else
ARCH_HAS_THUMB2 SETL {FALSE}
endif
GBLL V6_ENDIAN_SWAP
if ARCH_V6_OR_LATER :LAND: {ENDIAN} = "big" :LAND: :LNOT: :DEF: ENDIAN_BE_32
V6_ENDIAN_SWAP SETL {TRUE}
else
V6_ENDIAN_SWAP SETL {FALSE}
endif
IMPORT Unknown_Thumb_Handler
IMPORT Unknown_Java_Handler
IMPORT Unknown_ARM_Handler
; Main entry point - should be branched to directly from the hardware
; undefined instruction vector.
AREA |TLUndef$$code|, CODE, READONLY
PRESERVE8
TLUndef_Handler
EXPORT TLUndef_Handler
; On entry the core is in Undef mode with IRQs disabled
; The return state is saved in R14_und and SPSR_und
; Save two registers on the Undef stack to make some workspace,
; and then switch to Supervisor Mode with IRQ enable restored.
STMDB R13!,{R0,R1}
MRS R0,CPSR
MRS R1,SPSR
ASSERT Mode_Svc = (Mode_Undef :AND: :NOT: 8)
BIC R0,R0,#(Idisable_bit :OR: 8)
AND R1,R1,#Idisable_bit
ORR R0,R0,R1
MSR CPSR_c,R0
; Start constructing the register dump by reserving space on the stack.
; Save the unbanked registers R2-R7.
; Reserve space also for R14_svc and SPSR_svc.
SUB R13,R13,#9*4 ; R8-R14,PC,CPSR
STMDB R13!,{R2-R7}
SUB R13,R13,#4*4 ; R14_svc,SPSR_svc,R0,R1
ADD R4,R13,#17*4 ; R4 -> PC,CPSR
BIC R13,R13,#7 ; Force 8-byte stack alignment
; Then switch back to Undef mode.
ORR R1,R0,#8
MSR CPSR_c,R1
; Pop the saved R0,R1 from the Undef stack, into unbanked R2,R3.
; Copy R14_und to unbanked R6, and SPSR_und to R7.
LDMIA R13!,{R2,R3} ; pop saved values of R0,R1
MOV R6,R14
MRS R7,SPSR
; Return to Supervisor Mode.
; Copy the saved values of R0,R1 to the register dump
MSR CPSR_c,R0
STR R2,[R4,#-15*4]
STR R3,[R4,#-14*4]
; At this point:
; R4 -> final 2 words of register dump (just above banked registers)
; R6 contains the original R14_undef value, and
; R7 contains the original SPSR_undef value
; R0 contains the current CPSR
; Now the banked registers. The strategy for this depends on whether
; we were called from a user mode: if so, we use a "user mode STM";
; otherwise, we must switch to a sanitised version of the mode we were
; called from (to be found in the SPSR), store the registers and switch
; back. "Sanitised" means that we must not unintentionally switch into
; Thumb state or Java state.
; Note: If called from Supervisor Mode this will save the current R13.
AND R5,R7,#Mode_mask
; At this point:
; R0 = the current CPSR
; R4 -> final 2 words of register dump (just above banked registers)
; R5 = the Mode_mask bits of SPSR_und
; R6 = R14_und value
; R7 = SPSR_und value
TEQ R5,#Mode_Usr32
STMEQDB R4,{R8-R14}^ ; User mode case
BEQ BankedSaveDone
BIC R2,R0,#Mode_mask ; Non-user mode case
ORR R2,R2,R5
MSR CPSR_c,R2
STMDB R4,{R8-R14}
MSR CPSR_c,R0
BankedSaveDone
; Finish the register dump construction by synthesising R15 and CPSR
; values (= address of undefined instruction plus 8 for ARM, 4 for Thumb,
; and SPSR_und)
; and storing them.
TST R7, #Thumb_bit
ADDEQ R1,R6,#4
ADDNE R1,R6,#2
STMIA R4,{R1,R7}
; Finally save the Supervisor Mode R14 and SPSR on the stack.
STR R14,[R4,#-17*4]
MRS R14,SPSR
STR R14,[R4,#-16*4]
; Prepare for a call to a handler function
SUB R1,R4,#15*4 ;R1 -> register dump
ADR R14,ReturnFromHandler ;Create return address
; Check for Java mode
; Not strictly necessary because the processor never signals
; Undef exceptions in Java state.
TST R7, #Java_bit
BNE Unknown_Java_Handler ; R14 -> ReturnFromHandler
; Check for Thumb mode
TST R7, #Thumb_bit
BNE ThumbStateBounce ; R14 -> ReturnFromHandler
KEEP
ArmStateBounce
; Now get the instruction that bounced. Security note: we don't have
; to be careful about whether the original program was in user mode:
; if the memory area concerned is inaccessible from user mode, any
; attempt to execute an instruction from it in user mode would cause a
; prefetch abort, not an undefined instruction exception.
LDR R0,[R6,#-4]
if V6_ENDIAN_SWAP
REV r0, r0
endif
; Is it a coprocessor instruction? To avoid the need to change this
; code in the future, this is checked carefully. (A check of instr[27]
; is sufficient in all hardware-generated cases, but some people like
; to "fake" undefined instruction trap entries when another exception
; handler cannot deal with an illegal instruction.)
; So we test for instruction bits 27:24 = 1100, 1101 or 1110, done
; as an optimised range check on (instruction << 4).
MOV R2,R0,LSL #4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -