Commit 84c73735 authored by Jeffrey Lee's avatar Jeffrey Lee Committed by ROOL
Browse files

AbortTrap prefetch abort support

Also make lazy task swapping aborts to use IFAR where possible, to
ensure any Thumb-2/Jazelle instructions which cross page boundaries are
handled correctly.
parent 5266c864
REM Copyright (c) 2021, RISC OS Open Ltd
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions are met:
REM * Redistributions of source code must retain the above copyright
REM notice, this list of conditions and the following disclaimer.
REM * Redistributions in binary form must reproduce the above copyright
REM notice, this list of conditions and the following disclaimer in the
REM documentation and/or other materials provided with the distribution.
REM * Neither the name of RISC OS Open Ltd nor the names of its contributors
REM may be used to endorse or promote products derived from this software
REM without specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
REM AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
REM IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
REM ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
REM LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
REM CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
REM SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
REM INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
REM CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
REM ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
REM POSSIBILITY OF SUCH DAMAGE.
REM Test AbortTrap serious error handling (prefetch aborts, via an abortable DA)
ON ERROR ERROR EXT 0,REPORT$+" at "+STR$(ERL)
da_size%=4096
SYS "OS_Module",6,,,1024 TO ,,rma%
FOR pass=0 TO 2 STEP 2
P%=rma%
[ OPT pass
.da_handler%
; R0 = DA handler reason, 5 = aborttrap
; R1 = flags
; R2 = buffer
; R3 = required address
; R4 = length
; R5 = current end of DA (nonsense for sparse DAs)
; R12 = param
STMFD R13!,{R0-R6,R14}
ADR R14,last_call%
MRS R6,CPSR
STMIA R14,{R0-R5,R6,R12}
CMP R0,#4 ; Normal DA resize op?
LDMLOFD R13!,{R0-R6,PC} ; Allow it
CMP R0,#5 ; Abort op?
BNE return_bad_reason
LDMFD R13!,{R0-R6,R14}
MSR CPSR_f,#(1<<28)
ADR R0,serious_error
MOV PC,LR
.return_bad_reason
LDMFD R13!,{R0-R6,R14}
MSR CPSR_f,#(1<<28)
ADR R0,bad_reason
MOV PC,LR
.bad_reason
EQUD 0
EQUS "Bad reason" : EQUB 0
ALIGN
.serious_error
EQUD &80000000
EQUS "Test serious error" : EQUB 0
ALIGN
.testcode%
STR R13,temp_r13%
STR R14,temp_r14%
ADR R0,in_regs%
LDMIA R0,{R0-R15}
; If we're still here, the abort didn't trigger
LDR R13,temp_r13%
LDR PC,temp_r14%
.temp_r13% EQUD 0
.temp_r14% EQUD 0
.last_call%
.last_R0% EQUD 0
.last_R1% EQUD 0
.last_R2% EQUD 0
.last_R3% EQUD 0
.last_R4% EQUD 0
.last_R5% EQUD 0
.last_PSR% EQUD 0
.last_R12% EQUD 0
.in_regs%
]
NEXT pass
seed%=-TIME
PRINT "seed: ";seed%
A%=RND(seed%)
wp%=RND
da_num%=0
ON ERROR PROCerror
PRINT "handler: ";~da_handler%
PRINT "wp: ";~wp%
PRINT "last_call: ";~last_call%
!last_R0%=0
!last_R1%=0
!last_R2%=0
!last_R3%=0
!last_R4%=0
!last_R5%=0
!last_PSR%=0
!last_R12%=0
REM Create an abortable DA
SYS "OS_DynamicArea",0,-1,0,-1,(1<<16),da_size%,da_handler%,wp%,"ATTest" TO ,da_num%,,da_base%
PRINT "da_base: ";~da_base%
REM Randomise input regs
FOR A=0 TO 13
in_regs%!(A*4)=RND
NEXT A
in_regs%!(15*4)=(RND AND &FFC)+da_base%
REM Do the test
CALL testcode%
REM We shouldn't be here!
PRINT "Failed"
PROCend(1)
DEF PROCerror
IF REPORT$="Test serious error" THEN
PROCcheckresult
ELSE
PRINT REPORT$;" at ";ERL : PROCend(1)
ENDIF
ENDPROC
DEF PROCcheckresult
REM Check registers match
in_regs%!(15*4)+=4
SYS "OS_ChangeEnvironment",13 TO ,exc_regs%
FOR A=0 TO 15
IF in_regs%!(A*4)<>exc_regs%!(A*4) THEN PRINT "Wrong reg R";A;" expected ";~(in_regs%!(A*4));" actual ";~(exc_regs%!(A*4)) : PROCend(1)
NEXT A
REM Check recorded fault info
SYS "OS_ReadSysInfo",7 TO ,exc_pc%,exc_psr%,exc_far%
IF exc_pc%<>in_regs%!(15*4) THEN PRINT "Wrong exception PC expected ";~(in_regs%!(15*4));" actual ";~exc_pc% : PROCend(1)
IF (exc_psr% AND &1F)<>&10 THEN PRINT "Wrong exception PSR ";~exc_psr% : PROCend(1)
IF exc_far%<>(in_regs%!(15*4)) THEN PRINT "Wrong exception FAR expected ";~(in_regs%!(15*4));" actual ";~exc_far% : PROCend(1)
PROCend(0)
ENDPROC
DEF PROCendtest
IF da_num%<>0 THEN PROClast : SYS "OS_DynamicArea",1,da_num% : da_num%=0
ENDPROC
DEF PROCend(E%)
PROCendtest
SYS "OS_Module",7,,rma%
IF E% THEN ERROR EXT 0,"Failed"
PRINT "Success"
END
ENDPROC
DEF PROClast
PRINT "last R0 ";~!last_R0%;" R1 ";~!last_R1%;" R2 ";~!last_R2%;" R3 ";~!last_R3%;" R4 ";~!last_R4%;" R5 ";~!last_R5%;" PSR ";~!last_PSR%;" R12 ";~!last_R12%
ENDPROC
REM Copyright (c) 2021, RISC OS Open Ltd
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions are met:
REM * Redistributions of source code must retain the above copyright
REM notice, this list of conditions and the following disclaimer.
REM * Redistributions in binary form must reproduce the above copyright
REM notice, this list of conditions and the following disclaimer in the
REM documentation and/or other materials provided with the distribution.
REM * Neither the name of RISC OS Open Ltd nor the names of its contributors
REM may be used to endorse or promote products derived from this software
REM without specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
REM AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
REM IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
REM ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
REM LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
REM CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
REM SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
REM INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
REM CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
REM ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
REM POSSIBILITY OF SUCH DAMAGE.
REM Test prefetch abort support for abortable DAs / AbortTrap
ON ERROR ERROR EXT 0,REPORT$+" at "+STR$(ERL)
da_size%=4096
SYS "OS_Module",6,,,1024 TO ,,rma%
FOR pass=0 TO 2 STEP 2
P%=rma%
[ OPT pass
.da_handler%
CMP R0,#4 ; Normal DA resize op?
MOVLO PC,LR ; Allow it
; R0 = DA handler reason, 5 = aborttrap
; R1 = flags
; R2 = buffer
; R3 = required address
; R4 = length
; R5 = current end of DA (nonsense for sparse DAs)
; R12 = param
STMFD R13!,{R0-R6,R14}
ADR R14,last_call%
MRS R6,CPSR
STMIA R14,{R0-R5,R6,R12}
CMP R0,#5 ; Abort op?
BNE return_bad_reason
AND R1,R1,#15
CMP R1,#2
BNE return_bad_reason ; only support memmap requests
; Satisfy the request by growing the DA
LDR R0,da_num_asm%
MOV R1,#4096
SWI "XOS_ChangeDynamicArea"
STRVS R0,[SP]
LDMVSFD R13!,{R0-R6,PC}
; Copy over some code to execute
ADR R0,da_code%
LDMIA R0,{R2,R3}
LDR R1,da_base_ptr%
STMIA R1,{R2,R3}
ADD R2,R1,#8
MOV R0,#1
SWI "XOS_SynchroniseCodeAreas"
LDMFD R13!,{R0-R6,PC}
.return_bad_reason
LDMFD R13!,{R0-R6,R14}
MSR CPSR_f,#(1<<28)
ADR R0,bad_reason
MOV PC,LR
.bad_reason
EQUD 0
EQUS "Bad reason" : EQUB 0
ALIGN
.da_code%
MOV R0,#123
MOV PC,LR
.read_sctlr%
SWI "OS_EnterOS"
MRC CP15,0,R0,C1,C0,0
SWI "OS_LeaveOS"
MOV PC,R14
.last_call%
.last_R0% EQUD 0
.last_R1% EQUD 0
.last_R2% EQUD 0
.last_R3% EQUD 0
.last_R4% EQUD 0
.last_R5% EQUD 0
.last_PSR% EQUD 0
.last_R12% EQUD 0
.da_base_ptr% EQUD 0
.da_num_asm% EQUD 0
]
NEXT pass
wp%=RND
da_num%=0
ON ERROR PRINT REPORT$;" at ";ERL : PROCend(1)
PRINT "handler: ";~da_handler%
PRINT "wp: ";~wp%
PRINT "last_call: ";~last_call%
REM Create an empty abortable DA
SYS "OS_DynamicArea",0,-1,0,-1,(1<<7)+(1<<16),da_size%,da_handler%,wp%,"ATTest" TO ,da_num%,,da_base%
!da_base_ptr%=da_base%
!da_num_asm%=da_num%
PRINT "da_base: ";~da_base%
REM Try executing code from the unmapped page
A%=-1
val%=USR da_base%
IF val%<>123 THEN PRINT "Failed" : PROCend(1)
PROCend(0)
DEF PROCendtest
IF da_num%<>0 THEN PROClast : SYS "OS_DynamicArea",1,da_num% : da_num%=0
ENDPROC
DEF PROCend(E%)
PROCendtest
SYS "OS_Module",7,,rma%
IF E% THEN ERROR EXT 0,"Failed"
PRINT "Success"
END
ENDPROC
DEF PROClast
PRINT "last R0 ";~!last_R0%;" R1 ";~!last_R1%;" R2 ";~!last_R2%;" R3 ";~!last_R3%;" R4 ";~!last_R4%;" R5 ";~!last_R5%;" PSR ";~!last_PSR%;" R12 ";~!last_R12%
ENDPROC
......@@ -21,28 +21,131 @@
; Instruction fetch abort pre-veneer
;
PAbPreVeneer ROUT
Push "r0-r7, lr" ; wahey, we have an abort stack
; 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
SUB r0, lr_abort, #4 ; aborting address
MOV r0, r9 ; aborting address
MOV r2, #1
BL AMB_LazyFixUp ; can trash r0-r7, returns NE status if claimed and fixed up
PageTableSyncNE
Pull "r0-r7, lr", NE ; restore regs and
SUBNES pc, lr_abort, #4 ; restart aborting instruction if 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
LDR lr, [sp, #8*4] ; (not a lazy abort) restore lr
]
; Remember the details of this abort, for OS_ReadSysInfo 7
LDR r4, =ZeroPage+Abort32_dumparea
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
STR lr, [r4] ; dump 32-bit PC
STR r1, [r4, #4] ; dump 32-bit PSR
STR lr, [r4, #2*4] ; fault address is PC (yes, PC, not PC-4)
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"
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
......
......@@ -1621,7 +1621,9 @@ GenErrorSWI * SLVK_SetV
; instruction directly. The expectation is that the handler will map in the
; indicated memory with (at minimum) the requested permissions. On success, the
; kernel will roll back the PC, the base register (if the base-updated abort
; model is in use), and re-execute the instruction.
; model is in use), and re-execute the instruction. Prefetch aborts will also
; result in reason code 2 being used (requesting the necessary read + execute
; permission), allowing for on-demand mapping of code regions.
;
; Note that the implementation doesn't attempt to deal with the StrongARM abort
; handling errata, so care must be taken when using handlers on afflicted CPUs.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment