thermosphere: add shadow page table hooks

note: HCR.TVM not supported by qemu yet
This commit is contained in:
TuxSH 2019-08-01 02:58:16 +02:00
parent 045f556f80
commit e6c5eb3928
5 changed files with 82 additions and 5 deletions

View file

@ -18,4 +18,15 @@
#include "../../types.h" #include "../../types.h"
static inline u64 transformKernelAddress(u64 pa)
{
switch (pa) {
// GICv2 CPU -> vCPU interface
case 0x08010000:
return 0x08040000;
default:
return pa;
}
}
uintptr_t configureMemoryMap(u32 *addrSpaceSize); uintptr_t configureMemoryMap(u32 *addrSpaceSize);

View file

@ -18,4 +18,15 @@
#include "../../types.h" #include "../../types.h"
static inline u64 transformKernelAddress(u64 pa)
{
switch (pa) {
// GICv2 CPU -> vCPU interface
case 0x50042000:
return 0x50046000;
default:
return pa;
}
}
uintptr_t configureMemoryMap(u32 *addrSpaceSize); uintptr_t configureMemoryMap(u32 *addrSpaceSize);

View file

@ -16,6 +16,8 @@
#include "shadow_page_tables.h" #include "shadow_page_tables.h"
#include "platform/memory_map_mmu_cfg.h"
#include "debug_log.h"
#ifdef A32_SUPPORTED #ifdef A32_SUPPORTED
static void replacePageTableShortL2(u32 *ttbl) static void replacePageTableShortL2(u32 *ttbl)
@ -91,9 +93,11 @@ static void replacePageTableLongImpl(u64 *ttbl, u32 level, u32 nbits)
replacePageTableLongImpl((u64 *)addr, level + 1, 9); replacePageTableLongImpl((u64 *)addr, level + 1, 9);
} else { } else {
u64 pa = ttbl[i] & MASK2L(47, 12); u64 pa = ttbl[i] & MASK2L(47, 12);
// FIXME u64 newPa = transformKernelAddress(pa);
if (pa == 0x50042000ull) { if (pa != newPa) {
ttbl[i] = (ttbl[i] & ~MASK2L(47, 12)) | 0x50046000ull; // Note: unreachable on QEMU yet
DEBUG("EL1 in-place page-table entry swap: 0x%08llx => 0x%08llx\n", pa, newPa);
ttbl[i] = (ttbl[i] & ~MASK2L(47, 12)) | newPa;
} }
} }
@ -101,6 +105,7 @@ static void replacePageTableLongImpl(u64 *ttbl, u32 level, u32 nbits)
} }
default: default:
__builtin_unreachable();
break; break;
} }
} }
@ -126,3 +131,8 @@ void replacePageTableLong(u64 *ttbl, u32 txsz)
replacePageTableLongImpl(ttbl, 3, startBit - 11); replacePageTableLongImpl(ttbl, 3, startBit - 11);
} }
} }
void replaceKernelPageTables(void)
{
}

View file

@ -18,6 +18,8 @@
#include "synchronization.h" #include "synchronization.h"
#include "sysreg.h" #include "sysreg.h"
#include "arm.h" #include "arm.h"
#include "debug_log.h"
#include "shadow_page_tables.h"
static void doSystemRegisterRwImpl(u64 *val, u32 iss) static void doSystemRegisterRwImpl(u64 *val, u32 iss)
{ {
@ -86,6 +88,49 @@ void doSystemRegisterWrite(ExceptionStackFrame *frame, u32 iss, u32 reg1, u32 re
val = frame->x[reg1]; val = frame->x[reg1];
} }
} }
// Hooks go here:
switch (iss) {
case ENCODE_SYSREG_ISS(SCTLR_EL1): {
DEBUG("Hooked sysreg write: SCTLR_EL1 = %0x016llx\n", val);
// Possible MMU (re)-enablement
if (val & 1) {
u64 tcr = GET_SYSREG(tcr_el1);
if (((tcr >> 14) & 3) == 0) {
// 4KB granule
replacePageTableLong((u64 *)(GET_SYSREG(ttbr0_el1) & MASK2L(47, 1)), (u32)(tcr & 0x3F));
replacePageTableLong((u64 *)(GET_SYSREG(ttbr1_el1) & MASK2L(47, 1)), (u32)((tcr >> 16) & 0x3F));
}
}
break;
}
case ENCODE_SYSREG_ISS(TTBR1_EL1): {
DEBUG("Hooked sysreg write: TTBR1_EL1 = %0x016llx\n", val);
u64 tcr = GET_SYSREG(tcr_el1);
// MMU enabled & 4KB granule
if ((GET_SYSREG(sctlr_el1) & 1) && ((tcr >> 14) & 3) == 0) {
// Note: lack of ttbr0 intentional here
replacePageTableLong((u64 *)(val & MASK2L(47, 1)), (u32)((tcr >> 16) & 0x3F));
}
break;
}
case ENCODE_SYSREG_ISS(TCR_EL1): {
DEBUG("Hooked sysreg write: TCR_EL1 = %0x016llx\n", val);
u64 tcr = val;
// MMU enabled & 4KB granule
if ((GET_SYSREG(sctlr_el1) & 1) && ((tcr >> 14) & 3) == 0) {
// Note: lack of ttbr0 intentional here
replacePageTableLong((u64 *)(GET_SYSREG(ttbr1_el1) & MASK2L(47, 1)), (u32)((tcr >> 16) & 0x3F));
}
break;
}
// Note: TTBR0_EL1 deliberately not hooked
default:
break;
}
doSystemRegisterRwImpl(&val, iss); doSystemRegisterRwImpl(&val, iss);
skipFaultingInstruction(frame, 4); skipFaultingInstruction(frame, 4);
} }

View file

@ -36,8 +36,8 @@ void enableTraps(void)
u64 hcr = GET_SYSREG(hcr_el2); u64 hcr = GET_SYSREG(hcr_el2);
// Trap *writes* to memory control registers // Trap *writes* to memory control registers
//hcr |= HCR_TVM; // Note: QEMU doesn't support this bit as of August 2019...
// actually don't hcr |= HCR_TVM;
// Trap SMC instructions // Trap SMC instructions
hcr |= HCR_TSC; hcr |= HCR_TSC;