Commit 322fd3a6 authored by Jeffrey Lee's avatar Jeffrey Lee Committed by ROOL
Browse files

Fix AbortTrap's handling of LDA instruction for emulated AP1

When AP1 memory is being emulated (long descriptor page tables are in
use), the AbortTrap machinery is used to emulate usermode read access.
This provides coverage for all read instructions except those that
AbortTrap handles via MemMap requests - LDREX, LDA, LDAEX, LDF & LFM.

LDREX & LDAEX request both read & write access, so are fine (the MemMap
request will get passed through to the registered AbortTrap handlers).

LDF & LFM are irrelevant, since they only exist on ARM7500FE (on other
machines FPEmulator will translate them to regular LDR/LDM, which are
handled correctly)

LDA however, will generate a plain "memmap with usermode read" request.
When AbortTrap looks at the permissions of emulated AP1 it doesn't take
into account the fact that the usermode read permission is being
emulated, so it thinks that everything is fine and claims the memmap
was successful, causing the abort handler to retry the instruction
without making any changes, re...
parent e2e5a722
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 handling of AP1 emulation
REM Specifically, this checks that the LDA instruction triggers a MemMap request
REM Other aspects of AP1 emulation (i.e. emulation of ordinary load instructions) is at least partially validated by the other test programs (e.g. attest_ap)
ON ERROR ERROR EXT 0,REPORT$+" at "+STR$(ERL)
REM Check LDA is supported, and AP1 emulation is in use
SYS "OS_Memory",17,1 TO ,,permissions%
IF permissions%<>&3c THEN PRINT "AP1 not being emulated, skipping test" : END
SYS "OS_PlatformFeatures",34,12 TO flag%
IF flag%<>1 THEN PRINT "LDA not supported, skipping test" : END
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-R14}
.testinstr%
LDA R0,[R0]
; 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,da_size%,-1,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=1 TO 13
in_regs%!(A*4)=RND
NEXT A
in_regs%!0=(RND AND &FFC)+da_base%
REM It looks like callbacks are still active if we get stuck, so we could build a system to automatically break out after a timeout, but for now just let it get stuck
PRINT "!WARNING! Infinite abort loop here if LDA isn't handled correctly by AbortTrap"
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)=testinstr%+8
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%<>testinstr%+8 THEN PRINT "Wrong exception PC expected ";~(testinstr%+8);" 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% THEN PRINT "Wrong exception FAR expected ";~(!in_regs%);" actual ";~exc_far% : PROCend(1)
REM Check it was a MemMap request, with the correct parameters
IF !last_R1%<>&52 OR !last_R3%<>in_regs%!0 OR !last_R4%<>4 THEN PRINT "Wrong AbortTrap request" : PROCend
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
......@@ -9,12 +9,12 @@
GBLS Module_ApplicationDate
GBLS Module_HelpVersion
GBLS Module_ComponentName
Module_MajorVersion SETS "6.58"
Module_Version SETA 658
Module_MajorVersion SETS "6.59"
Module_Version SETA 659
Module_MinorVersion SETS ""
Module_Date SETS "28 Jul 2021"
Module_ApplicationDate SETS "28-Jul-21"
Module_Date SETS "07 Aug 2021"
Module_ApplicationDate SETS "07-Aug-21"
Module_ComponentName SETS "Kernel"
Module_FullVersion SETS "6.58"
Module_HelpVersion SETS "6.58 (28 Jul 2021)"
Module_FullVersion SETS "6.59"
Module_HelpVersion SETS "6.59 (07 Aug 2021)"
END
/* (6.58)
/* (6.59)
*
* This file is automatically maintained by srccommit, do not edit manually.
*
*/
#define Module_MajorVersion_CMHG 6.58
#define Module_MajorVersion_CMHG 6.59
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 28 Jul 2021
#define Module_Date_CMHG 07 Aug 2021
#define Module_MajorVersion "6.58"
#define Module_Version 658
#define Module_MajorVersion "6.59"
#define Module_Version 659
#define Module_MinorVersion ""
#define Module_Date "28 Jul 2021"
#define Module_Date "07 Aug 2021"
#define Module_ApplicationDate "28-Jul-21"
#define Module_ApplicationDate "07-Aug-21"
#define Module_ComponentName "Kernel"
#define Module_FullVersion "6.58"
#define Module_HelpVersion "6.58 (28 Jul 2021)"
#define Module_LibraryVersionInfo "6:58"
#define Module_FullVersion "6.59"
#define Module_HelpVersion "6.59 (07 Aug 2021)"
#define Module_LibraryVersionInfo "6:59"
......@@ -210,6 +210,7 @@ static inline _kernel_oserror *mem_access_internal(uint8_t *buf,uint32_t addr,in
/* Check for direct memory access */
bool have_permission;
_kernel_oserror *e;
int flags2 = flags;
#ifndef KERNEL
uint32_t access;
e = _swix(OS_Memory,_INR(0,2)|_OUT(1),OSMemReason_CheckMemoryAccess,addr,addr+chunk,&access);
......@@ -230,6 +231,17 @@ static inline _kernel_oserror *mem_access_internal(uint8_t *buf,uint32_t addr,in
{
uint32_t permissions = AP_To_Permissions(pageflags & 0xF);
have_permission = (permissions & mempermission_flags) == mempermission_flags;
/* Special handling for AP1 MemMap requests: If usermode read access is being requested, and AP1 is being emulated, and the page is already mapped as AP1, add in usermode execute access to the requested permissions.
This is necessary to stop us getting stuck in an infinite abort loop, due to the OS looking at the emulated permissions and thinking everything's fine, causing it to skip calling any AbortTrap handlers and try re-executing the instruction without making any changes.
By asking for execute permission, we should also ensure that any well-written AbortTrap handler will avoid mapping the memory as AP1 (e.g. anything that uses OS_Memory 18 won't select the emulated AP1) */
if (have_permission /* We think everything's fine */
&& ((pageflags & 0xF) == 1) /* But it's AP1 */
&& (permissions == (MemPermission_UserR+MemPermission_PrivX+MemPermission_PrivW+MemPermission_PrivR)) /* With AP1 emulation */
&& ((flags2 & (AbortTrap_Reason_Mask | AbortTrap_MemMap_UserR)) == (AbortTrap_Reason_MemMap | AbortTrap_MemMap_UserR))) /* And MemMap is asking for user read permission */
{
have_permission = false; /* Then we don't have the permissions */
flags2 |= AbortTrap_MemMap_UserX; /* And we should ask for execute permission (for this page) */
}
}
#endif
......@@ -252,7 +264,7 @@ static inline _kernel_oserror *mem_access_internal(uint8_t *buf,uint32_t addr,in
else
{
/* Check aborttrap */
e = mem_access_via_aborttrap(flags,buf,addr,chunk);
e = mem_access_via_aborttrap(flags2,buf,addr,chunk);
if (e)
return e;
}
......
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