mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 09:44:13 +00:00
hv: Implement basic exception handling
Allows Python to handle hypervisor exceptions, and implements exception info display and basic debug commands. Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
b015dcf272
commit
4d64c33ca6
10 changed files with 269 additions and 5 deletions
2
Makefile
2
Makefile
|
@ -43,7 +43,7 @@ OBJECTS := \
|
|||
exception.o exception_asm.o \
|
||||
fb.o font.o font_retina.o \
|
||||
heapblock.o \
|
||||
hv.o hv_vm.o \
|
||||
hv.o hv_vm.o hv_exc.o hv_asm.o \
|
||||
iodev.o \
|
||||
kboot.o \
|
||||
main.o \
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import sys
|
||||
|
||||
from tgtypes import *
|
||||
from proxy import IODEV
|
||||
from proxy import IODEV, START, EXC, EXC_RET, ExcInfo
|
||||
from utils import *
|
||||
from sysreg import *
|
||||
from macho import MachO
|
||||
import shell
|
||||
|
||||
class HV:
|
||||
PTE_VALID = 1 << 0
|
||||
|
@ -34,12 +37,49 @@ class HV:
|
|||
def map_sw(self, ipa, pa, size):
|
||||
assert self.p.hv_map(ipa, pa | self.SPTE_MAP, size, 1) >= 0
|
||||
|
||||
def handle_exception(self, reason, code, info):
|
||||
self.ctx = ctx = ExcInfo.parse(self.iface.readmem(info, ExcInfo.sizeof()))
|
||||
|
||||
print(f"Guest exception: {code.name}")
|
||||
|
||||
self.u.print_exception(code, ctx)
|
||||
|
||||
locals = {
|
||||
"hv": self,
|
||||
"iface": self.iface,
|
||||
"p": self.p,
|
||||
"u": self.u,
|
||||
}
|
||||
|
||||
for attr in dir(self):
|
||||
locals[attr] = getattr(self, attr)
|
||||
|
||||
shell.run_shell(locals, "Entering debug shell", "Returning from exception")
|
||||
|
||||
self.iface.writemem(info, ExcInfo.build(self.ctx))
|
||||
self.p.exit(EXC_RET.HANDLED)
|
||||
|
||||
def skip(self):
|
||||
self.ctx.elr += 4
|
||||
raise shell.ExitConsole()
|
||||
|
||||
def cont(self):
|
||||
raise shell.ExitConsole()
|
||||
|
||||
def exit(self):
|
||||
sys.exit(0)
|
||||
|
||||
def init(self):
|
||||
self.iodev = self.p.iodev_whoami()
|
||||
|
||||
print("Initializing hypervisor over iodev %s" % self.iodev)
|
||||
self.p.hv_init()
|
||||
|
||||
self.iface.set_handler(START.EXCEPTION_LOWER, EXC.SYNC, self.handle_exception)
|
||||
self.iface.set_handler(START.EXCEPTION_LOWER, EXC.IRQ, self.handle_exception)
|
||||
self.iface.set_handler(START.EXCEPTION_LOWER, EXC.FIQ, self.handle_exception)
|
||||
self.iface.set_handler(START.EXCEPTION_LOWER, EXC.SERROR, self.handle_exception)
|
||||
|
||||
self.map_hw(0x2_00000000, 0x2_00000000, 0x5_00000000)
|
||||
self.map_hw(0x8_00000000, 0x8_00000000, 0x4_00000000)
|
||||
|
||||
|
@ -117,5 +157,7 @@ class HV:
|
|||
|
||||
print(f"Jumping to entrypoint at 0x{self.entry:x}")
|
||||
|
||||
self.p.reboot(self.entry, self.guest_base + self.bootargs_off, el1=True)
|
||||
self.iface.ttymode()
|
||||
self.iface.dev.timeout = None
|
||||
|
||||
# Does not return
|
||||
self.p.hv_start(self.entry, self.guest_base + self.bootargs_off)
|
||||
|
|
|
@ -470,6 +470,7 @@ class M1N1Proxy:
|
|||
|
||||
P_HV_INIT = 0xc00
|
||||
P_HV_MAP = 0xc01
|
||||
P_HV_START = 0xc02
|
||||
|
||||
def __init__(self, iface, debug=False):
|
||||
self.debug = debug
|
||||
|
@ -792,6 +793,9 @@ class M1N1Proxy:
|
|||
return self.request(self.P_HV_INIT)
|
||||
def hv_map(self, from_, to, size, incr):
|
||||
return self.request(self.P_HV_MAP, from_, to, size, incr)
|
||||
def hv_start(self, entry, *args):
|
||||
# does not return
|
||||
return self.request(self.P_HV_START, entry, *args)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import serial
|
||||
|
|
|
@ -129,6 +129,32 @@ class ProxyUtils(object):
|
|||
print(f"Pushing ADT ({adt_size} bytes)...")
|
||||
self.iface.writemem(adt_base, self.adt_data)
|
||||
|
||||
def print_exception(self, code, ctx):
|
||||
print(f" SPSR = {ctx.spsr}")
|
||||
print(f" ELR = 0x{ctx.elr:x}")
|
||||
print(f" ESR = {ctx.esr}")
|
||||
print(f" FAR = 0x{ctx.far:x}")
|
||||
|
||||
for i in range(0, 31, 4):
|
||||
j = min(30, i + 3)
|
||||
print(f" {f'x{i}-x{j}':>7} = {' '.join(f'{r:016x}' for r in ctx.regs[i:j + 1])}")
|
||||
|
||||
if ctx.esr.EC == ESR_EC.MSR:
|
||||
print()
|
||||
print(" == MSR fault decoding ==")
|
||||
iss = ESR_ISS_MSR(ctx.esr.ISS)
|
||||
enc = iss.Op0, iss.Op1, iss.CRn, iss.CRm, iss.Op2
|
||||
if enc in sysreg_rev:
|
||||
name = sysreg_rev[enc]
|
||||
else:
|
||||
name = f"s{iss.Op0}_{iss.Op1}_c{iss.CRn}_c{iss.CRm}_{iss.op2}"
|
||||
if iss.DIR == MSR_DIR.READ:
|
||||
print(f" Instruction: mrs x{iss.Rt}, {name}")
|
||||
else:
|
||||
print(f" Instruction: msr x{iss.Rt}, {name}")
|
||||
|
||||
print()
|
||||
|
||||
class LazyADT:
|
||||
def __init__(self, utils):
|
||||
self.__dict__["_utils"] = utils
|
||||
|
|
|
@ -22,6 +22,8 @@ extern volatile int exc_count;
|
|||
void exception_initialize(void);
|
||||
void exception_shutdown(void);
|
||||
|
||||
void print_regs(u64 *regs, int el12);
|
||||
|
||||
uint64_t el0_call(void *func, uint64_t a, uint64_t b, uint64_t c, uint64_t d);
|
||||
uint64_t el1_call(void *func, uint64_t a, uint64_t b, uint64_t c, uint64_t d);
|
||||
|
||||
|
|
14
src/hv.c
14
src/hv.c
|
@ -4,6 +4,10 @@
|
|||
#include "assert.h"
|
||||
#include "cpu_regs.h"
|
||||
|
||||
void hv_enter_guest(u64 x0, u64 x1, u64 x2, u64 x3, void *entry) __attribute__((noreturn));
|
||||
|
||||
extern char _hv_vectors_start[0];
|
||||
|
||||
void hv_init(void)
|
||||
{
|
||||
// Enable physical timer for EL1
|
||||
|
@ -20,8 +24,18 @@ void hv_init(void)
|
|||
HCR_AMO | // Trap SError exceptions
|
||||
HCR_VM); // Enable stage 2 translation
|
||||
|
||||
// No guest vectors initially
|
||||
msr(VBAR_EL12, 0);
|
||||
|
||||
sysop("dsb ishst");
|
||||
sysop("tlbi alle1is");
|
||||
sysop("dsb ish");
|
||||
sysop("isb");
|
||||
}
|
||||
|
||||
void hv_start(void *entry, u64 regs[4])
|
||||
{
|
||||
msr(VBAR_EL1, _hv_vectors_start);
|
||||
|
||||
hv_enter_guest(regs[0], regs[1], regs[2], regs[3], entry);
|
||||
}
|
||||
|
|
98
src/hv_asm.S
Normal file
98
src/hv_asm.S
Normal file
|
@ -0,0 +1,98 @@
|
|||
/* spDx-License-Identifier: MIT */
|
||||
|
||||
.align 11
|
||||
.globl _hv_vectors_start
|
||||
_hv_vectors_start:
|
||||
|
||||
mov x9, '0'
|
||||
b cpu_reset
|
||||
.align 7
|
||||
mov x9, '1'
|
||||
b exc_unk
|
||||
.align 7
|
||||
mov x9, '2'
|
||||
b exc_unk
|
||||
.align 7
|
||||
mov x9, '3'
|
||||
b exc_unk
|
||||
.align 7
|
||||
b _v_sp0_sync
|
||||
.align 7
|
||||
b _v_sp0_irq
|
||||
.align 7
|
||||
b _v_sp0_fiq
|
||||
.align 7
|
||||
b _v_sp0_serr
|
||||
.align 7
|
||||
b _v_hv_sync
|
||||
.align 7
|
||||
b _v_hv_irq
|
||||
.align 7
|
||||
b _v_hv_fiq
|
||||
.align 7
|
||||
b _v_hv_serr
|
||||
.align 7
|
||||
mov x9, 'p'
|
||||
b exc_unk
|
||||
.align 7
|
||||
mov x9, 'q'
|
||||
b exc_unk
|
||||
.align 7
|
||||
mov x9, 'r'
|
||||
b exc_unk
|
||||
.align 7
|
||||
mov x9, 's'
|
||||
b exc_unk
|
||||
.align 7
|
||||
|
||||
.globl _v_hv_sync
|
||||
.type _v_hv_sync, @function
|
||||
_v_hv_sync:
|
||||
str x30, [sp, #-16]!
|
||||
bl _exc_entry
|
||||
bl hv_exc_sync
|
||||
|
||||
b _exc_return
|
||||
|
||||
.globl _v_hv_irq
|
||||
.type _v_hv_irq, @function
|
||||
_v_hv_irq:
|
||||
str x30, [sp, #-16]!
|
||||
bl _exc_entry
|
||||
bl hv_exc_irq
|
||||
|
||||
b _exc_return
|
||||
|
||||
.globl _v_hv_fiq
|
||||
.type _v_hv_fiq, @function
|
||||
_v_hv_fiq:
|
||||
str x30, [sp, #-16]!
|
||||
bl _exc_entry
|
||||
bl hv_exc_fiq
|
||||
|
||||
b _exc_return
|
||||
|
||||
.globl _v_hv_serr
|
||||
.type _v_hv_serr, @function
|
||||
_v_hv_serr:
|
||||
str x30, [sp, #-16]!
|
||||
bl _exc_entry
|
||||
bl hv_exc_serr
|
||||
|
||||
b _exc_return
|
||||
|
||||
.globl hv_enter_guest
|
||||
.type hv_enter_guest, @function
|
||||
hv_enter_guest:
|
||||
mrs x5, daif
|
||||
msr daifclr, 3
|
||||
mov x6, #5
|
||||
orr x5, x5, x6 // EL1h
|
||||
msr spsr_el2, x5
|
||||
|
||||
msr elr_el2, x4
|
||||
msr spsel, #0
|
||||
mov x5, #0
|
||||
mov sp, x5
|
||||
|
||||
eret
|
74
src/hv_exc.c
Normal file
74
src/hv_exc.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "hv.h"
|
||||
#include "assert.h"
|
||||
#include "cpu_regs.h"
|
||||
#include "exception.h"
|
||||
#include "string.h"
|
||||
#include "uartproxy.h"
|
||||
|
||||
static void hv_exc_proxy(u64 *regs, uartproxy_exc_code_t type)
|
||||
{
|
||||
struct uartproxy_exc_info exc_info = {
|
||||
.spsr = mrs(SPSR_EL2),
|
||||
.elr = mrs(ELR_EL2),
|
||||
.esr = mrs(ESR_EL2),
|
||||
.far = mrs(FAR_EL2),
|
||||
.sp = {mrs(SP_EL0), mrs(SP_EL1), 0},
|
||||
.mpidr = mrs(MPIDR_EL1),
|
||||
};
|
||||
memcpy(exc_info.regs, regs, sizeof(exc_info.regs));
|
||||
|
||||
struct uartproxy_msg_start start = {
|
||||
.reason = START_EXCEPTION_LOWER,
|
||||
.code = type,
|
||||
.info = &exc_info,
|
||||
};
|
||||
|
||||
int ret = uartproxy_run(&start);
|
||||
|
||||
if (ret == EXC_RET_HANDLED) {
|
||||
memcpy(regs, exc_info.regs, sizeof(exc_info.regs));
|
||||
msr(SPSR_EL2, exc_info.spsr);
|
||||
msr(ELR_EL2, exc_info.elr);
|
||||
msr(SP_EL0, exc_info.sp[0]);
|
||||
msr(SP_EL1, exc_info.sp[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Guest exception not handled, rebooting.\n");
|
||||
print_regs(regs, 0);
|
||||
reboot();
|
||||
}
|
||||
|
||||
void hv_exc_sync(u64 *regs)
|
||||
{
|
||||
#if 0
|
||||
u64 esr = mrs(ESR_EL2);
|
||||
u32 ec = FIELD_GET(ESR_EC, esr);
|
||||
|
||||
switch (ec) {
|
||||
case ESR_EC_DABORT_LOWER:
|
||||
if (handle_dabort(regs))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
hv_exc_proxy(regs, EXC_SYNC);
|
||||
}
|
||||
|
||||
void hv_exc_irq(u64 *regs)
|
||||
{
|
||||
hv_exc_proxy(regs, EXC_IRQ);
|
||||
}
|
||||
|
||||
void hv_exc_fiq(u64 *regs)
|
||||
{
|
||||
hv_exc_proxy(regs, EXC_FIQ);
|
||||
}
|
||||
|
||||
void hv_exc_serr(u64 *regs)
|
||||
{
|
||||
hv_exc_proxy(regs, EXC_SERROR);
|
||||
}
|
|
@ -387,6 +387,9 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
|||
case P_HV_MAP:
|
||||
hv_map(request->args[0], request->args[1], request->args[2], request->args[3]);
|
||||
break;
|
||||
case P_HV_START:
|
||||
hv_start((void *)request->args[0], &request->args[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
reply->status = S_BADCMD;
|
||||
|
|
|
@ -105,7 +105,8 @@ typedef enum {
|
|||
P_DART_UNMAP,
|
||||
|
||||
P_HV_INIT = 0xc00,
|
||||
P_HV_MAP = 0xc01,
|
||||
P_HV_MAP,
|
||||
P_HV_START,
|
||||
|
||||
} ProxyOp;
|
||||
|
||||
|
|
Loading…
Reference in a new issue