Prevent double faults when either PC or SP is invalid
This commit is contained in:
parent
d5190cd788
commit
004f0652c9
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
void __attribute__((noreturn)) mcuReboot(void);
|
void __attribute__((noreturn)) mcuReboot(void);
|
||||||
void cleanInvalidateDCacheAndDMB(void);
|
void cleanInvalidateDCacheAndDMB(void);
|
||||||
|
bool cannotAccessVA(const void *address);
|
||||||
|
|
||||||
void FIQHandler(void);
|
void FIQHandler(void);
|
||||||
void undefinedInstructionHandler(void);
|
void undefinedInstructionHandler(void);
|
||||||
|
@ -116,3 +116,14 @@ cleanInvalidateDCacheAndDMB:
|
|||||||
mcr p15,0,r0,c7,c14,0 @ Clean and Invalidate Entire Data Cache
|
mcr p15,0,r0,c7,c14,0 @ Clean and Invalidate Entire Data Cache
|
||||||
mcr p15,0,r0,c7,c10,4 @ Drain Memory Barrier
|
mcr p15,0,r0,c7,c10,4 @ Drain Memory Barrier
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
|
.global cannotAccessVA
|
||||||
|
.type cannotAccessVA, %function
|
||||||
|
cannotAccessVA:
|
||||||
|
@ Thanks yellows8 for the hint
|
||||||
|
lsr r0, #12
|
||||||
|
lsl r0, #12
|
||||||
|
mcr p15,0,r0,c7,c8,0 @ VA to PA translation with privileged read permission check
|
||||||
|
mrc p15,0,r0,c7,c4,0 @ read PA register
|
||||||
|
and r0, #1 @ failure bit
|
||||||
|
bx lr
|
||||||
|
@ -63,10 +63,12 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[8 + i];
|
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[8 + i];
|
||||||
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[15 + i];
|
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[15 + i];
|
||||||
|
|
||||||
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xfff);
|
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xFFF);
|
||||||
|
|
||||||
//Dump code
|
//Dump code
|
||||||
vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
||||||
|
if(cannotAccessVA((u8 *)instr) || cannotAccessVA((u8 *)instr + dumpHeader.codeDumpSize))
|
||||||
|
dumpHeader.codeDumpSize = 0;
|
||||||
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
||||||
codeDump[i] = instr[i];
|
codeDump[i] = instr[i];
|
||||||
|
|
||||||
@ -81,13 +83,17 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
|
|
||||||
//Dump stack in place
|
//Dump stack in place
|
||||||
vu32 *sp = (vu32 *)registerDump[13];
|
vu32 *sp = (vu32 *)registerDump[13];
|
||||||
|
if(cannotAccessVA((u8 *)sp))
|
||||||
|
dumpHeader.stackDumpSize = 0;
|
||||||
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
||||||
*final++ = sp[i];
|
*final++ = sp[i];
|
||||||
|
|
||||||
|
|
||||||
vu8 *currentKProcess = *(vu8 **)0xFFFF9004;
|
vu8 *currentKProcess = (cannotAccessVA((u8 *)0xFFFF9004)) ? NULL : *(vu8 **)0xFFFF9004;
|
||||||
vu8 *currentKCodeSet = (currentKProcess != NULL) ? *(vu8 **)(currentKProcess + CODESET_OFFSET) : NULL;
|
vu8 *currentKCodeSet = (currentKProcess != NULL && ((u32)currentKProcess & 3) == 0 && !cannotAccessVA((u8 *)currentKProcess + CODESET_OFFSET))
|
||||||
if(currentKCodeSet != NULL)
|
? *(vu8 **)(currentKProcess + CODESET_OFFSET) : NULL;
|
||||||
|
|
||||||
|
if(currentKCodeSet != NULL && ((u32)currentKCodeSet & 3) == 0 && !cannotAccessVA((u8 *)currentKCodeSet))
|
||||||
{
|
{
|
||||||
vu32 *additionalData = final;
|
vu32 *additionalData = final;
|
||||||
dumpHeader.additionalDataSize = 16;
|
dumpHeader.additionalDataSize = 16;
|
||||||
@ -99,7 +105,7 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
additionalData[3] = *(vu32 *)(currentKCodeSet + 0x60);
|
additionalData[3] = *(vu32 *)(currentKCodeSet + 0x60);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dumpHeader.additionalDataSize = 16;
|
dumpHeader.additionalDataSize = 0;
|
||||||
|
|
||||||
//Copy header (actually optimized by the compiler)
|
//Copy header (actually optimized by the compiler)
|
||||||
final = (vu32 *)FINAL_BUFFER;
|
final = (vu32 *)FINAL_BUFFER;
|
||||||
|
@ -23,7 +23,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#define NULL 0
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
//Common data types
|
//Common data types
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
u32 readMPUConfig(u32 regionSettings[8]);
|
||||||
void FIQHandler(void);
|
void FIQHandler(void);
|
||||||
void undefinedInstructionHandler(void);
|
void undefinedInstructionHandler(void);
|
||||||
void dataAbortHandler(void);
|
void dataAbortHandler(void);
|
||||||
|
@ -62,3 +62,20 @@ GEN_HANDLER FIQHandler
|
|||||||
GEN_HANDLER undefinedInstructionHandler
|
GEN_HANDLER undefinedInstructionHandler
|
||||||
GEN_HANDLER prefetchAbortHandler
|
GEN_HANDLER prefetchAbortHandler
|
||||||
GEN_HANDLER dataAbortHandler
|
GEN_HANDLER dataAbortHandler
|
||||||
|
|
||||||
|
.global readMPUConfig
|
||||||
|
.type readMPUConfig, %function
|
||||||
|
readMPUConfig:
|
||||||
|
stmfd sp!, {r4-r8}
|
||||||
|
mrc p15,0,r1,c6,c0,0
|
||||||
|
mrc p15,0,r2,c6,c1,0
|
||||||
|
mrc p15,0,r3,c6,c2,0
|
||||||
|
mrc p15,0,r4,c6,c3,0
|
||||||
|
mrc p15,0,r5,c6,c4,0
|
||||||
|
mrc p15,0,r6,c6,c5,0
|
||||||
|
mrc p15,0,r7,c6,c6,0
|
||||||
|
mrc p15,0,r8,c6,c7,0
|
||||||
|
stmia r0, {r1-r8}
|
||||||
|
mrc p15,0,r0,c5,c0,2 @ read data access permission bits
|
||||||
|
ldmfd sp!, {r4-r8}
|
||||||
|
bx lr
|
||||||
|
@ -28,6 +28,29 @@
|
|||||||
#define REG_DUMP_SIZE (4*17)
|
#define REG_DUMP_SIZE (4*17)
|
||||||
#define CODE_DUMP_SIZE 48
|
#define CODE_DUMP_SIZE 48
|
||||||
|
|
||||||
|
bool cannotAccessAddress(const void *address)
|
||||||
|
{
|
||||||
|
u32 regionSettings[8];
|
||||||
|
u32 addr = (u32)address;
|
||||||
|
|
||||||
|
u32 dataAccessPermissions = readMPUConfig(regionSettings);
|
||||||
|
for(u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if((dataAccessPermissions & 0xF) == 0 || (regionSettings[i] & 1) == 0)
|
||||||
|
continue; //no access / region not enabled
|
||||||
|
|
||||||
|
u32 regionAddrBase = regionSettings[i] & ~0xFFF;
|
||||||
|
u32 regionSize = 1 << (((regionSettings[i] >> 1) & 0x1F) + 1);
|
||||||
|
|
||||||
|
if(addr >= regionAddrBase && addr < regionAddrBase + regionSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dataAccessPermissions >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type)
|
void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type)
|
||||||
{
|
{
|
||||||
ExceptionDumpHeader dumpHeader;
|
ExceptionDumpHeader dumpHeader;
|
||||||
@ -58,11 +81,13 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[2 + i];
|
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[2 + i];
|
||||||
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i];
|
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i];
|
||||||
|
|
||||||
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xfff);
|
dumpHeader.stackDumpSize = 0x1000 - (registerDump[13] & 0xFFF);
|
||||||
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize;
|
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize;
|
||||||
|
|
||||||
//Dump code
|
//Dump code
|
||||||
vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
vu8 *instr = (vu8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
||||||
|
if(cannotAccessAddress((u8 *)instr) || cannotAccessAddress((u8 *)instr + dumpHeader.codeDumpSize))
|
||||||
|
dumpHeader.codeDumpSize = 0;
|
||||||
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
for(u32 i = 0; i < dumpHeader.codeDumpSize; i++)
|
||||||
codeDump[i] = instr[i];
|
codeDump[i] = instr[i];
|
||||||
|
|
||||||
@ -79,6 +104,8 @@ void __attribute__((noreturn)) mainHandler(u32 regs[REG_DUMP_SIZE / 4], u32 type
|
|||||||
|
|
||||||
//Dump stack in place
|
//Dump stack in place
|
||||||
vu32 *sp = (vu32 *)registerDump[13];
|
vu32 *sp = (vu32 *)registerDump[13];
|
||||||
|
if(cannotAccessAddress((u8 *)sp))
|
||||||
|
dumpHeader.stackDumpSize = 0;
|
||||||
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
for(u32 i = 0; i < dumpHeader.stackDumpSize / 4; i++)
|
||||||
*final++ = sp[i];
|
*final++ = sp[i];
|
||||||
|
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
//Common data types
|
//Common data types
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
|
@ -114,7 +114,7 @@ if __name__ == "__main__":
|
|||||||
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
|
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
|
||||||
|
|
||||||
typeDetailsStr = ""
|
typeDetailsStr = ""
|
||||||
if exceptionType == 2 and (registers[16] & 0x20) == 0 and unpack_from("<I", codeDump[-4:])[0] == 0xe12fff7f:
|
if exceptionType == 2 and (registers[16] & 0x20) == 0 and codeDumpSize >= 4 and unpack_from("<I", codeDump[-4:])[0] == 0xe12fff7f:
|
||||||
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||||
elif processor != 9 and (registers[20] & 0x80000000) != 0:
|
elif processor != 9 and (registers[20] & 0x80000000) != 0:
|
||||||
typeDetailsStr = " (VFP exception)"
|
typeDetailsStr = " (VFP exception)"
|
||||||
|
Reference in New Issue
Block a user