Commit 055b24c3 authored by Jeffrey Lee's avatar Jeffrey Lee
Browse files

Tidy things up a bit

Detail:
  hdr/Options - Reduce the scope of SASTMhatbroken and InterruptDelay switches so that they're only enabled when we're building for ARMv4 targets
  s/ARM600, s/VMSAv6, s/ExtraSWIs, s/Exceptions - Move duplicate code out of s/ARM600 & s/VMSAv6 and into shared locations. OS_UpdateMEMC, the bulk of OS_MMUControl, and OS_SynchroniseCodeAreas are now located in s/ExtraSWIs. Meanwhile the data & prefetch abort veneers have been moved to the new file s/Exceptions. s/ARM600 and s/VMSAv6 are now almost purely to do with the different page table formats.
  s/GetAll - GET s/Exceptions
Admin:
  Tested on Raspberry Pi


Version 5.52. Tagged as 'Kernel-5_52'
parent f655fcf6
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.51"
Module_Version SETA 551
Module_MajorVersion SETS "5.52"
Module_Version SETA 552
Module_MinorVersion SETS ""
Module_Date SETS "30 Jun 2016"
Module_ApplicationDate SETS "30-Jun-16"
Module_ComponentName SETS "Kernel"
Module_ComponentPath SETS "castle/RiscOS/Sources/Kernel"
Module_FullVersion SETS "5.51"
Module_HelpVersion SETS "5.51 (30 Jun 2016)"
Module_FullVersion SETS "5.52"
Module_HelpVersion SETS "5.52 (30 Jun 2016)"
END
/* (5.51)
/* (5.52)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 5.51
#define Module_MajorVersion_CMHG 5.52
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 30 Jun 2016
#define Module_MajorVersion "5.51"
#define Module_Version 551
#define Module_MajorVersion "5.52"
#define Module_Version 552
#define Module_MinorVersion ""
#define Module_Date "30 Jun 2016"
......@@ -18,6 +18,6 @@
#define Module_ComponentName "Kernel"
#define Module_ComponentPath "castle/RiscOS/Sources/Kernel"
#define Module_FullVersion "5.51"
#define Module_HelpVersion "5.51 (30 Jun 2016)"
#define Module_LibraryVersionInfo "5:51"
#define Module_FullVersion "5.52"
#define Module_HelpVersion "5.52 (30 Jun 2016)"
#define Module_LibraryVersionInfo "5:52"
......@@ -77,12 +77,12 @@ LongCLISize * 1024 ; buffer size for long commands
GBLL XScaleMiniCache ; is the XScale mini data-cache used (at all)
GBLL XScaleJTAGDebug
SASTMhatbroken SETL {TRUE}
SASTMhatbroken SETL SupportARMv4 :LAND: NoARMv5
GBLL CacheCleanerHack ; Cache clean hack in ClearPhysRAM for platforms that use DCacheCleanAddress. Does not work with all CPUs!
GBLL InterruptDelay ; True if we might be running on a CPU with CPUFlag_InterruptDelay set (e.g. StrongARM)
CacheCleanerHack SETL {TRUE}
InterruptDelay SETL {TRUE}
InterruptDelay SETL SupportARMv4 :LAND: NoARMv5
ARM6support SETL (MEMM_Type = "ARM600") ; Needs updating for VMSAv6 compatability
XScaleMiniCache SETL {FALSE}
......
......@@ -274,61 +274,13 @@ PageShifts
= 12, 13, 0, 14 ; 1 2 3 4
= 0, 0, 0, 15 ; 5 6 7 8
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_UpdateMEMC: Read/write MEMC1 control register
SSETMEMC ROUT
AND r10, r0, r1
LDR r12, =ZeroPage
WritePSRc SVC_mode+I_bit+F_bit, r0
LDR r0, [r12, #MEMC_CR_SoftCopy] ; return old value
BIC r11, r0, r1
ORR r11, r11, R10
BIC r11, r11, #&FF000000
BIC r11, r11, #&00F00000
ORR r11, r11, #MEMCADR
STR r11, [r12, #MEMC_CR_SoftCopy]
; mjs Oct 2000 kernel/HAL split
;
; The kernel itself should now never call this SWI, but grudgingly has
; to maintain at least bit 10 of soft copy
;
; Here, we only mimic action of bit 10 to control video/cursor DMA (eg. for ADFS)
; The whole OS_UpdateMEMC thing would ideally be withdrawn as archaic, but
; unfortunately has not even been deprecated up to now
; for reference, the bits of the MEMC1 control register are:
;
; bits 0,1 => unused
; bits 2,3 => page size, irrelevant since always 4K
; bits 4,5 => low ROM access time (mostly irrelevant but set it up anyway)
; bits 6,7 => hi ROM access time (definitely irrelevant but set it up anyway)
; bits 8,9 => DRAM refresh control
; bit 10 => Video/cursor DMA enable
; bit 11 => Sound DMA enable
; bit 12 => OS mode
Push "r0,r1,r4, r14"
TST r11, #(1 :SHL: 10)
MOVEQ r0, #1 ; blank (video DMA disable)
MOVNE r0, #0 ; unblank (video DMA enable)
MOV r1, #0 ; no funny business with DPMS
ADD r4, r12, #VduDriverWorkSpace
LDR r4, [r4, #CurrentGraphicsVDriver]
MOV r4, r4, LSL #24
ORR r4, r4, #GraphicsV_SetBlank
BL CallGraphicsV
Pull "r0,r1,r4, r14"
WritePSRc SVC_mode+I_bit, r11
ExitSWIHandler
LTORG
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; SWI OS_MMUControl
; "ARM600"-specific OS_MMUControl code
;
; in: r0 = 0 (reason code 0, for modify control register)
; r1 = EOR mask
; r2 = AND mask
......@@ -337,47 +289,6 @@ SSETMEMC ROUT
;
; out: r1 = old value
; r2 = new value
;
; in: r0 bits 1 to 28 = 0, bit 0 = 1 (reason code 1, for flush request)
; r0 bit 31 set if cache(s) to be flushed
; r0 bit 30 set if TLB(s) to be flushed
; r0 bit 29 set if flush of entry only (else whole flush)
; r0 bit 28 set if write buffer to be flushed (implied by bit 31)
; r1 = entry specifier, if r0 bit 29 set
; (currently, flushing by entry is ignored, and just does full flush)
;
; in: r0 bits 0-7 = 2: reason code 2, read ARMop
; r0 bits 15-8 = ARMop index
;
; out: r0 = ARMop function ptr
;
MMUControlSWI Entry
BL MMUControlSub
PullEnv
ORRVS lr, lr, #V_bit
ExitSWIHandler
MMUControlSub
Push lr
AND lr,r0,#&FF
CMP lr, #MMUCReason_Unknown
ADDCC pc, pc, lr, LSL #2
B MMUControl_Unknown
B MMUControl_ModifyControl
B MMUControl_Flush
B MMUControl_GetARMop
MMUControl_Unknown
ADRL r0, ErrorBlock_HeapBadReason
[ International
BL TranslateError
|
SETV
]
Pull "pc"
MMUControl_ModifyControl ROUT
Push "r3,r4,r5"
CMP r1,#0
......@@ -446,234 +357,4 @@ MMUC_modcon_readonly
MOV r2, lr
Pull "r3,r4,r5,pc"
MMUControl_Flush
MOVS r10, r0
LDR r12, =ZeroPage
ARMop Cache_CleanInvalidateAll,MI,,r12
TST r10,#&40000000
ARMop TLB_InvalidateAll,NE,,r12
TST r10,#&10000000
ARMop DSB_ReadWrite,NE,,r12
ADDS r0,r10,#0
Pull "pc"
MMUControl_GetARMop
AND r0, r0, #&FF00
CMP r0, #(ARMopPtrTable_End-ARMopPtrTable):SHL:6
BHS MMUControl_Unknown
ADRL lr, ARMopPtrTable
LDR r0, [lr, r0, LSR #6]
LDR r0, [r0]
Pull "pc"
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Exception veneers
[ ChocolateAMB
; Instruction fetch abort pre-veneer, just to field possible lazy AMB aborts
;
PAbPreVeneer ROUT
Push "r0-r7, lr" ; wahey, we have an abort stack
SUB r0, lr_abort, #4 ; aborting address
MOV r2, #1
BL AMB_LazyFixUp ; can trash r0-r7, returns NE status if claimed and fixed up
Pull "r0-r7, lr", NE ; restore regs and
SUBNES pc, lr_abort, #4 ; restart aborting instruction if fixed up
LDR lr, [sp, #8*4] ; (not a lazy abort) restore lr
LDR r0, =ZeroPage+PAbHan ; we want to jump to PAb handler, in abort mode
LDR r0, [r0]
STR r0, [sp, #8*4]
Pull "r0-r7, pc"
]
; Preliminary layout of abort indirection nodes
^ 0
AI_Link # 4
AI_Low # 4
AI_High # 4
AI_WS # 4
AI_Addr # 4
EXPORT DAbPreVeneer
DAbPreVeneer ROUT
SUB r13_abort, r13_abort, #17*4 ; we use stacks, dontcherknow
STMIA r13_abort, {r0-r7} ; save unbanked registers anyway
STR lr_abort, [r13_abort, #15*4] ; save old PC, ie instruction address
[ ChocolateAMB
ARM_read_FAR r0 ; aborting address
MOV r2, #0
BL AMB_LazyFixUp ; can trash r0-r7, returns NE status if claimed and fixed up
LDR lr_abort, [r13_abort, #15*4] ; restore lr_abort
LDMIA r13_abort, {r0-r7} ; restore regs
ADDNE r13_abort, r13_abort, #17*4 ; if fixed up, restore r13_abort
SUBNES pc, lr_abort, #8 ; and restart aborting instruction
]
MRS r0, SPSR ; r0 = PSR when we aborted
MRS r1, CPSR ; r1 = CPSR
ADD r2, r13_abort, #8*4 ; r2 -> saved register bank for r8 onwards
LDR r4, =ZeroPage+Abort32_dumparea+3*4 ;use temp area (avoid overwriting main area for expected aborts)
ARM_read_FAR r3
STMIA r4, {r0,r3,lr_abort} ; dump 32-bit PSR, fault address, 32-bit PC
MOV r4, lr_abort ; move address of aborting instruction into an unbanked register
BIC r1, r1, #&1F ; knock out current mode bits
ANDS r3, r0, #&1F ; extract old mode bits (and test for USR26_mode (=0))
TEQNE r3, #USR32_mode ; if usr26 or usr32 then use ^ to store registers
[ SASTMhatbroken
STMEQIA r2!,{r8-r12}
STMEQIA r2 ,{r13,r14}^
SUBEQ r2, r2, #5*4
|
STMEQIA r2, {r8-r14}^
]
BEQ %FT05
ORR r3, r3, r1 ; and put in user's
MSR CPSR_c, r3 ; switch to user's mode
STMIA r2, {r8-r14} ; save the banked registers
MRS r5, SPSR ; get the SPSR for the aborter's mode
STR r5, [r2, #8*4] ; and store away in the spare slot on the end
; (this is needed for LDM with PC and ^)
ORR r1, r1, #ABT32_mode
MSR CPSR_c, r1 ; back to abort mode for the rest of this
05
Push "r0" ; save SPSR_abort
[ SASTMhatbroken
SUB sp, sp, #3*4
STMIA sp, {r13,r14}^ ; save USR bank in case STM ^, and also so we can corrupt them
NOP
STMDB sp!, {r8-r12}
|
SUB sp, sp, #8*4 ; make room for r8_usr to r14_usr and PC
STMIA sp, {r8-r15}^ ; save USR bank in case STM ^, and also so we can corrupt them
]
SUB r11, r2, #8*4 ; r11 -> register bank
STR r4, [sp, #7*4] ; store aborter's PC in user register bank
; Call normal exception handler
90
; copy temp area to real area (we believe this is an unexpected data abort now)
LDR r0, =ZeroPage+Abort32_dumparea
LDR r1, [r0,#3*4]
STR r1, [r0]
LDR r1, [r0,#4*4]
STR r1, [r0,#4]
LDR r1, [r0,#5*4]
STR r1, [r0,#2*4]
LDR r0, =ZeroPage ; we're going to call abort handler
[ ZeroPage = 0
STR r0, [r0, #CDASemaphore] ; so allow recovery if we were in CDA
|
MOV r2, #0
STR r2, [r0, #CDASemaphore] ; so allow recovery if we were in CDA
]
LDR r0, [r0, #DAbHan] ; get address of data abort handler
[ DebugAborts
DREG r0, "Handler address = "
]
ADD r2, r11, #8*4 ; point r2 at 2nd half of main register bank
LDMIA sp, {r8-r14}^ ; reload user bank registers
NOP ; don't access banked registers after LDM^
ADD sp, sp, #9*4 ; junk user bank stack frame + saved SPSR
MRS r1, CPSR
MRS r6, SPSR ; get original SPSR, with aborter's original mode
AND r7, r6, #&0F
TEQ r7, #USR26_mode ; also matches USR32
LDMEQIA r2, {r8-r14}^ ; if user mode then just use ^ to reload registers
NOP
BEQ %FT80
ORR r6, r6, #I32_bit ; use aborter's flags and mode but set I
BIC r6, r6, #T32_bit ; and don't set Thumb
MSR CPSR_c, r6 ; switch to aborter's mode
LDMIA r2, {r8-r14} ; reload banked registers
MSR CPSR_c, r1 ; switch back to ABT32
80
STR r0, [r13_abort, #16*4] ; save handler address at top of stack
LDR lr_abort, [r13_abort, #15*4] ; get abort address back in R14
LDMIA r13_abort, {r0-r7} ; reload r0-r7
ADD r13_abort, r13_abort, #16*4 ; we use stacks, dontcherknow
Pull pc
;
; ---------------- XOS_SynchroniseCodeAreas implementation ---------------
;
;this SWI effectively implements IMB and IMBrange (Instruction Memory Barrier)
;for newer ARMs
;entry:
; R0 = flags
; bit 0 set -> R1,R2 specify virtual address range to synchronise
; R1 = start address (word aligned, inclusive)
; R2 = end address (word aligned, inclusive)
; bit 0 clear synchronise entire virtual space
; bits 1..31 reserved
;
;exit:
; R0-R2 preserved
;
SyncCodeAreasSWI ROUT
Push "lr"
BL SyncCodeAreas
Pull "lr" ; no error return possible
B SLVK
SyncCodeAreas
TST R0,#1 ; range variant of SWI?
BEQ SyncCodeAreasFull
SyncCodeAreasRange
Push "r0-r2, lr"
MOV r0, r1
ADD r1, r2, #4 ;exclusive end address
LDR r2, =ZeroPage
LDRB lr, [r2, #Cache_Type]
CMP lr, #CT_ctype_WB_CR7_Lx ; DCache_LineLen lin or log?
LDRB lr, [r2, #DCache_LineLen]
MOVEQ r2, #4
MOVEQ lr, r2, LSL lr
LDREQ r2, =ZeroPage
SUB lr, lr, #1
ADD r1, r1, lr ;rounding up end address
MVN lr, lr
AND r0, r0, lr ;cache line aligned
AND r1, r1, lr ;cache line aligned
ARMop IMB_Range,,,r2
Pull "r0-r2, pc"
SyncCodeAreasFull
Push "r0, lr"
LDR r0, =ZeroPage
ARMop IMB_Full,,,r0
Pull "r0, pc"
LTORG
[ DebugAborts
InsertDebugRoutines
]
END
; Copyright 2016 Castle Technology Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > Exceptions
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Exception veneers
[ ChocolateAMB
; Instruction fetch abort pre-veneer, just to field possible lazy AMB aborts
;
PAbPreVeneer ROUT
Push "r0-r7, lr" ; wahey, we have an abort stack
SUB r0, lr_abort, #4 ; aborting address
MOV r2, #1
BL AMB_LazyFixUp ; can trash r0-r7, returns NE status if claimed and fixed up
[ MEMM_Type = "VMSAv6"
; DSB + ISB required to ensure effect of page table write is fully
; visible (after overwriting a faulting entry)
myDSB NE,r0
myISB NE,r0,,y
]
Pull "r0-r7, lr", NE ; restore regs and
SUBNES pc, lr_abort, #4 ; restart aborting instruction if fixed up
LDR lr, [sp, #8*4] ; (not a lazy abort) restore lr
LDR r0, =ZeroPage+PAbHan ; we want to jump to PAb handler, in abort mode
LDR r0, [r0]
STR r0, [sp, #8*4]
Pull "r0-r7, pc"
]
; Preliminary layout of abort indirection nodes
^ 0
AI_Link # 4
AI_Low # 4
AI_High # 4
AI_WS # 4
AI_Addr # 4
EXPORT DAbPreVeneer
DAbPreVeneer ROUT
SUB r13_abort, r13_abort, #17*4 ; we use stacks, dontcherknow
STMIA r13_abort, {r0-r7} ; save unbanked registers anyway
STR lr_abort, [r13_abort, #15*4] ; save old PC, ie instruction address
MyCLREX r0, r1 ; Exclusive monitor is in unpredictable state "after taking a data abort", clear it here
[ MEMM_Type = "VMSAv6"
; Fixup code for MVA-based cache/TLB ops, which can abort on ARMv7 if the specified MVA doesn't have a mapping.
; Must come before AMBControl, else things can go very wrong during OS_ChangeDynamicArea
; MVA cache ops have the form coproc=p15, CRn=c7, opc1=0, opc2=1
; MVA TLB ops have the form coproc=p15, CRn=c8, opc1=0, opc2=1
; Note that some non-MVA ops also follow the above rules - at the moment we make no attempt to filter those false-positives out
; This code is also written from the perspective of running on an ARMv7 CPU - behaviour under ARMv6 hasn't been checked!
; Also, as wrong as it seems, attempting to load the aborting instruction could trigger an abort (something wrong with the prefetch handler? or cache flushes not being done properly?)
; So this code must protect DFAR, DFSR, spsr_abort, and lr_abort from being clobbered
; We also need to be careful about how AMBControl will react to the abort:
; If DFAR and lr_abort both point to the same page, when we try loading the instruction (and it triggers an abort), AMBControl will map in the page
; So when control returns to us (and we determine that it wasn't an MVA op) AMBControl will be called again (for DFAR), see that the page is mapped in, and claim that it's a real abort instead of the lazy fixup that it really is
; (The workaround for that issue probably makes the DFAR, DFSR, spsr_abort, lr_abort saving irrelevant, but it's better to be safe than sorry)
CMP lr, #AplWorkMaxSize ; Assume that MVA ops won't come from application space (cheap workaround for above-mentioned AMBControl issue)
BLO %FT10
MRS r1, SPSR
TST r1, #T32_bit
BNE %FT10 ; We don't cope with Thumb ATM. Should really check for Jazelle too!
MOV r2, lr ; LR is already saved on the stack, but we can't load from it because any recursive abort won't have a clue what address we're trying to access.
; Protect DFAR, DFSR
ARM_read_FAR r3
ARM_read_FSR r4
LDR r0, [r2, #-8] ; Get aborting instruction
MSR SPSR_cxsf, r1 ; un-clobber SPSR, FAR, FSR
ARM_write_FAR r3
ARM_write_FSR r4
CMP r0, #&F0000000
BHS %FT10 ; Ignore cc=NV, which is MCR2 encoding
BIC r0, r0, #&F000000F ; Mask out the uninteresting bits
BIC r0, r0, #&0000F000
EOR r0, r0, #&0E000000 ; Desired value, minus CRn
EOR r0, r0, #&00000F30
CMP r0, #&00070000 ; CRn=c7?
CMPNE r0, #&00080000 ; CRn=c8?
BNE %FT10 ; It's not an MVA-based op
MOV lr_abort, r2 ; un-clobber LR (doesn't need un-clobbering if it wasn't an MVA op)
LDMIA r13_abort, {r0-r4} ; Restore the regs we intentionally clobbered
ADD r13_abort, r13_abort, #17*4
SUBS pc, lr_abort, #4 ; Resume execution at the next instruction
10
]
[ ChocolateAMB
ARM_read_FAR r0 ; aborting address
MOV r2, #0
BL AMB_LazyFixUp ; can trash r0-r7, returns NE status if claimed and fixed up
[ MEMM_Type = "VMSAv6"
; DSB + ISB required to ensure effect of page table write is fully
; visible (after overwriting a faulting entry)
myDSB NE,r0
myISB NE,r0,,y
]
LDR lr_abort, [r13_abort, #15*4] ; restore lr_abort
LDMIA r13_abort, {r0-r7} ; restore regs
ADDNE r13_abort, r13_abort, #17*4 ; if fixed up, restore r13_abort
SUBNES pc, lr_abort, #8 ; and restart aborting instruction
]
MRS r0, SPSR ; r0 = PSR when we aborted
MRS r1, CPSR ; r1 = CPSR
ADD r2, r13_abort, #8*4 ; r2 -> saved register bank for r8 onwards
LDR r4, =ZeroPage+Abort32_dumparea+3*4 ;use temp area (avoid overwriting main area for expected aborts)
ARM_read_FAR r3
STMIA r4, {r0,r3,lr_abort} ; dump 32-bit PSR, fault address, 32-bit PC
MOV r4, lr_abort ; move address of aborting instruction into an unbanked register
BIC r1, r1, #&1F ; knock out current mode bits
ANDS r3, r0, #&1F ; extract old mode bits (and test for USR26_mode (=0))
TEQNE r3, #USR32_mode ; if usr26 or usr32 then use ^ to store registers
[ SASTMhatbroken
STMEQIA r2!,{r8-r12}
STMEQIA r2 ,{r13,r14}^
SUBEQ r2, r2, #5*4
|
STMEQIA r2, {r8-r14}^
]
BEQ %FT05
ORR r3, r3, r1 ; and put in user's
MSR CPSR_c, r3 ; switch to user's mode
STMIA r2, {r8-r14} ; save the banked registers
MRS r5, SPSR ; get the SPSR for the aborter's mode
STR r5, [r2, #8*4] ; and store away in the spare slot on the end
; (this is needed for LDM with PC and ^)
ORR r1, r1, #ABT32_mode
MSR CPSR_c, r1 ; back to abort mode for the rest of this
05
Push "r0" ; save SPSR_abort
[ SASTMhatbroken
SUB sp, sp, #3*4
STMIA sp, {r13,r14}^ ; save USR bank in case STM ^, and also so we can corrupt them
NOP
STMDB sp!, {r8-r12}
|
SUB sp, sp, #8*4 ; make room for r8_usr to r14_usr and PC
STMIA sp, {r8-r15}^ ; save USR bank in case STM ^, and also so we can corrupt them
]
SUB r11, r2, #8*4 ; r11 -> register bank
STR r4, [sp, #7*4] ; store aborter's PC in user register bank
; Call normal exception handler
90
; copy temp area to real area (we believe this is an unexpected data abort now)
LDR r0, =ZeroPage+Abort32_dumparea
LDR r1, [r0,#3*4]
STR r1, [r0]
LDR r1, [r0,#4*4]
STR r1, [r0,#4]
LDR r1, [r0,#5*4]
STR r1, [r0,#2*4]
LDR r0, =ZeroPage ; we're going to call abort handler
[ ZeroPage = 0
STR r0, [r0, #CDASemaphore] ; so allow recovery if we were in CDA
|
MOV r2, #0
STR r2, [r0, #CDASemaphore] ; so allow recovery if we were in CDA
]
LDR r0, [r0, #DAbHan] ; get address of data abort handler
[ DebugAborts
DREG r0, "Handler address = "
]
ADD r2, r11, #8*4 ; point r2 at 2nd half of main register bank
LDMIA sp, {r8-r14}^ ; reload user bank registers
NOP ; don't access banked registers after LDM^
ADD sp, sp, #9*4 ; junk user bank stack frame + saved SPSR
MRS r1, CPSR
MRS r6, SPSR ; get original SPSR, with aborter's original mode
AND r7, r6, #&0F
TEQ r7, #USR26_mode ; also matches USR32
LDMEQIA r2, {r8-r14}^ ; if user mode then just use ^ to reload registers
NOP
BEQ %FT80
ORR r6, r6, #I32_bit ; use aborter's flags and mode but set I
BIC r6, r6, #T32_bit ; and don't set Thumb
MSR CPSR_c, r6 ; switch to aborter's mode
LDMIA r2, {r8-r14} ; reload banked registers
MSR CPSR_c, r1 ; switch back to ABT32