; 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 ; Instruction fetch abort pre-veneer ; PAbPreVeneer ROUT ; Produce a register dump containing everything important that could be ; corrupted by a recursive abort, or hard to access from child routines: ; R0-R14, SPSR, IFAR, IFSR, AIFSR ; = 19 words STR lr, [sp, #-20]! ; Save space for PSR, etc. ADD lr, sp, #20 Push "r0-r12,lr" ; R0-R13 ; Fill in SPSR & the available CP15 registers LDR r4, =ZeroPage+CPUFeatures+((CPUFeature_CP15_IFAR:SHR:5):SHL:2) LDR r4, [r4] MRS r0, SPSR LDR r8, [sp, #14*4] TST r4, #1:SHL:(CPUFeature_CP15_IFAR:AND:31) ARM_read_IFAR r9,NE SUBEQ r9, r8, #4 ; generate fake IFAR from LR (should be OK for everything except Jazelle) ASSERT CPUFeature_CP15_IFAR:SHR:5 = CPUFeature_CP15_IFSR:SHR:5 TST r4, #1:SHL:(CPUFeature_CP15_IFSR:AND:31) ARM_read_IFSR r10,NE ASSERT CPUFeature_CP15_IFAR:SHR:5 = CPUFeature_CP15_AIFSR:SHR:5 TST r4, #1:SHL:(CPUFeature_CP15_AIFSR:AND:31) ARM_read_AIFSR r11,NE STMDB lr, {r0,r9-r11} [ AMB_LazyMapIn MOV r0, r9 ; aborting address MOV r2, #1 BL AMB_LazyFixUp ; can trash r0-r7, returns NE status if claimed and fixed up BEQ %FT45 PageTableSync SUB r8, r8, #4 STR r8, [sp, #14*4] B %FT60 45 ] ; Try an AbortTrap memmap request ; extern _kernel_oserror *aborttrap_mem_access(void *buf,uint32_t addr,int len,int flags); IMPORT aborttrap_mem_access MOV r5, #0 ; Validate the SVC stack BL ValidateR13_svc BVS %FT48 ; Drop into SVC mode LDR r3, [sp, #15*4] SetMode SVC32_mode,r1 ; Preserve registers MRS r10, SPSR MOV r11, r14 ; Set up for the AbortTrap call MOV r1, r9 MOV r2, #1 ; Work out the necessary permissions TST r3, #&F LDRNE r3, =((AbortTrap_MemMap_PrivX+AbortTrap_MemMap_PrivR)<<4)+AbortTrap_Reason_MemMap LDREQ r3, =((AbortTrap_MemMap_UserX+AbortTrap_MemMap_UserR)<<4)+AbortTrap_Reason_MemMap ; Note that the buffer pointer (R0) is irrelevant for memmap requests BL aborttrap_mem_access ; Restore registers MOV r14, r11 MSR SPSR_cxsf, r10 ; Back to abort SetMode ABT32_mode, v1 CMP r0, #1 SUBLO r8, r8, #4 STRLO r8, [sp, #14*4] BLO %FT60 LDRNE r1, [r0] TSTNE r1, #&80000000 ; Serious error? MOVNE r5, r0 48 ; Pass on to PAbHan (i.e. OS_ChangeEnvironment), or raise an error [ AMB_LazyMapIn BL AMB_MakeFullyHonest ; PAbHan might not support recursive aborts ] ; Remember the details of this abort, for OS_ReadSysInfo 7 ADD r0, sp, #19*4 LDMDB r0, {r0-r4} ; LR, SPSR, IFAR, IFSR, AIFSR LDR r6, =ZeroPage+Abort32_dumparea ADD r7, r2, #4 STMIA r6, {r0-r1,r7} ; dump 32-bit PC, 32-bit PSR, IFAR+4 ; Is there an error to raise? MOVS r14, r5 BNE %FT70 ; Restore SPSR & CP15 registers LDR r5, =ZeroPage+CPUFeatures+((CPUFeature_CP15_IFAR:SHR:5):SHL:2) LDR r5, [r5] MSR SPSR_cxsf, r1 TST r5, #1:SHL:(CPUFeature_CP15_IFAR:AND:31) ARM_write_IFAR r2,NE ASSERT CPUFeature_CP15_IFAR:SHR:5 = CPUFeature_CP15_IFSR:SHR:5 TST r5, #1:SHL:(CPUFeature_CP15_IFSR:AND:31) ARM_write_IFSR r3,NE ASSERT CPUFeature_CP15_IFAR:SHR:5 = CPUFeature_CP15_AIFSR:SHR:5 TST r5, #1:SHL:(CPUFeature_CP15_AIFSR:AND:31) ARM_write_AIFSR r4,NE LDR lr, =ZeroPage+PAbHan LDR lr, [lr] STR lr, [sp, #15*4] LDMIA sp, {r0-r15} ; The recovered R13 should discard the everything else from the stack 60 LDR r4, [sp, #15*4] MSR SPSR_cxsf, r4 LDMIA sp, {r0-r13,r15}^ ; The recovered R13 should discard the everything else from the stack 70 ; Raise error (in R14) using the same mechanism that ABORTP uses for ; unhandled prefetch aborts - i.e. call through to DumpyTheRegisters. ; To do that, we must shuffle things around into a (part-filled) ; standard 17 word register dump. ADD r2, sp, #19*4 LDR r0, [sp, #14*4] ; Grab PC LDR r1, [sp, #15*4] ; Grab SPSR STMFD r2, {r0,r1} ; Store at top of stack LDMIA sp, {r0-r12} ; Load all the other regs ADD sp, sp, #19*4-17*4 ; Adjust SP to point at base of new dump STMIA sp, {r0-r7} ; Fill in R0-R7 ADD r0, sp, #8*4 ; R0 points to R8 LDR r1, [sp, #16*4] ; R1 is SPSR again MOV r4, #-1 ; R4 is magic value to stop error translation B DumpyTheRegisters DAbPreVeneer ROUT ; Produce a register dump containing everything important that could be ; corrupted by a recursive abort, or hard to access from child routines: ; R0-R14, SPSR, DFAR, DFSR, ADFSR ; = 19 words STR lr, [sp, #-20]! ; Save space for PSR, etc. ADD lr, sp, #20 Push "r0-r12,lr" ; R0-R13 ; Fill in SPSR & the available CP15 registers LDR r5, =ZeroPage+CPUFeatures+((CPUFeature_CP15_ADFSR:SHR:5):SHL:2) LDR r5, [r5] MRS r0, SPSR ARM_read_FAR r1 ; DFAR ARM_read_FSR r2 ; DFSR TST r5, #1:SHL:(CPUFeature_CP15_ADFSR:AND:31) ARM_read_ADFSR r3,NE STMDB lr, {r0-r3} MyCLREX r0, r1 ; Exclusive monitor is in unpredictable state "after taking a data abort", clear it here ; The next couple of bits want LR, SPSR & DFAR ADD r8, sp, #14*4 LDMIA r8, {r8-r10} ; LR, SPSR, DFAR [ 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! CMP r8, #AplWorkMaxSize ; Assume that MVA ops won't come from application space (extra safety to avoid recursive aborts breaking things) BLO %FT10 TST r9, #T32_bit BNE %FT10 ; We don't cope with Thumb ATM. Should really check for Jazelle too! LDR r0, [r8, #-8] ; Get aborting instruction 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 SUB r8, r8, #4 ; Resume execution at the next instruction STR r8, [sp, #14*4] B %FT70 10 ] [ AMB_LazyMapIn MOV r0, r10 ; DFAR MOV r2, #0 LDR r6, [sp, #17*4] ; DFSR BL AMB_LazyFixUp ; can trash r0-r7, returns NE status if claimed and fixed up BEQ %FT45 PageTableSync SUB r8, r8, #8 STR r8, [sp, #14*4] B %FT70 45 ] ; Try AbortTrap MOV r5, #0 BL ValidateR13_svc BVS %FT50 MOV r0, sp IMPORT aborttrap_dataabort_veneer BL aborttrap_dataabort_veneer CMP r0, #1 BLO %FT70 LDRNE r1, [r0] TSTNE r1, #&80000000 ; Serious error? MOVNE r5, r0 50 ADD r8, sp, #14*4 LDMIA r8, {r8-r10} ; LR, SPSR, DFAR ; Remember the details of this abort, for OS_ReadSysInfo 7 LDR r4, =ZeroPage+Abort32_dumparea STMIA r4, {r8-r10} ; dump 32-bit PC, 32-bit PSR, fault address MOV r2, #0 ; we're going to call abort handler STR r2, [r4, #CDASemaphore-Abort32_dumparea] ; so allow recovery if we were in CDA ; Pass on to DAbHan (i.e. OS_ChangeEnvironment), or raise an error [ AMB_LazyMapIn BL AMB_MakeFullyHonest ; DAbHan might not support recursive aborts ] ; Is there an error to raise? MOVS r14, r5 BNE %FT60 ; Restore SPSR & CP15 registers ADD r0, sp, #19*4 LDMDB r0, {r0-r3} LDR r5, =ZeroPage+CPUFeatures+((CPUFeature_CP15_DFAR_DFSR_writable:SHR:5):SHL:2) LDMIA r5, {r5,r6} MSR SPSR_cxsf, r0 TST r5, #1:SHL:(CPUFeature_CP15_DFAR_DFSR_writable:AND:31) ARM_write_FAR r1,NE ; DFAR ARM_write_FSR r2,NE ; DFSR ASSERT (CPUFeature_CP15_DFAR_DFSR_writable:SHR:5)+1 = CPUFeature_CP15_ADFSR:SHR:5 TST r6, #1:SHL:(CPUFeature_CP15_ADFSR:AND:31) ARM_write_ADFSR r3,NE LDR lr, =ZeroPage+DAbHan LDR lr, [lr] STR lr, [sp, #15*4] LDMIA sp, {r0-r15} ; The recovered R13 should discard the everything else from the stack 60 ; Raise error (in R14) using the same mechanism that ABORTD uses for ; unhandled data aborts - i.e. call through to DumpyTheRegisters. ; To do that, we must shuffle things around into a (part-filled) ; standard 17 word register dump. ADD r2, sp, #19*4 LDR r0, [sp, #14*4] ; Grab PC LDR r1, [sp, #15*4] ; Grab SPSR STMFD r2, {r0,r1} ; Store at top of stack LDMIA sp, {r0-r12} ; Load all the other regs ADD sp, sp, #19*4-17*4 ; Adjust SP to point at base of new dump STMIA sp, {r0-r7} ; Fill in R0-R7 ADD r0, sp, #8*4 ; R0 points to R8 LDR r1, [sp, #16*4] ; R1 is SPSR again MOV r4, #-1 ; R4 is magic value to stop error translation B DumpyTheRegisters 70 LDR r4, [sp, #15*4] MSR SPSR_cxsf, r4 LDMIA sp, {r0-r13,r15}^ ; The recovered R13 should discard the everything else from the stack ; In: ABT32 mode ; Out: R0-R3 corrupt ; VC if R13_svc is valid (at least up to next page boundary), VS if not ValidateR13_svc ROUT Entry SetMode SVC32_mode, r0 ; Check stack space against MB-aligned base addr MOV r0, r13, LSL #12 CMP r0, #4096<<12 BLO %FT90 ; Check SP alignment TST r13, #3 BNE %FT90 ; Check the page tables to make sure it's pointing to suitable memory SUB r0, r13, #1 SetMode ABT32_mode,r1 MOV r0, r0, LSR #Log2PageSize MOV r0, r0, LSL #Log2PageSize PTOp LoadAndDecodeL2Entry ; Decode the permissions CMP r2, #-1 LDRNE r1, =ZeroPage LDRNE r0, [r1, #MMU_PPLAccess] ANDNE r2, r2, #DynAreaFlags_APBits LDRNE r0, [r0, r2, LSL #2] MOVEQ r0, #0 ; Must have privileged read+write access AND r0, r0, #CMA_Partially_PrivR+CMA_Partially_PrivW CMP r0, #CMA_Partially_PrivR+CMA_Partially_PrivW SETV NE EXIT 90 SetMode ABT32_mode, r0 SETV EXIT END