From a3440f2b485d00e10fcb952181305ffe62783416 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 5 May 2021 00:24:52 +0900 Subject: [PATCH] hv: Support cleanly exiting the hypervisor from an exception Signed-off-by: Hector Martin --- proxyclient/hv.py | 13 ++++++++----- proxyclient/proxy.py | 2 +- src/hv.c | 4 +++- src/hv_asm.S | 31 +++++++++++++++++++++++++++++-- src/hv_exc.c | 31 ++++++++++++++++++++----------- src/uartproxy.h | 1 + 6 files changed, 62 insertions(+), 20 deletions(-) diff --git a/proxyclient/hv.py b/proxyclient/hv.py index b1a3ced4..67522dd2 100644 --- a/proxyclient/hv.py +++ b/proxyclient/hv.py @@ -54,20 +54,23 @@ class HV: for attr in dir(self): locals[attr] = getattr(self, attr) - shell.run_shell(locals, "Entering debug shell", "Returning from exception") + ret = shell.run_shell(locals, "Entering debug shell", "Returning from exception") + + if ret is None: + ret = EXC_RET.HANDLED self.iface.writemem(info, ExcInfo.build(self.ctx)) - self.p.exit(EXC_RET.HANDLED) + self.p.exit(ret) def skip(self): self.ctx.elr += 4 - raise shell.ExitConsole() + raise shell.ExitConsole(EXC_RET.HANDLED) def cont(self): - raise shell.ExitConsole() + raise shell.ExitConsole(EXC_RET.HANDLED) def exit(self): - sys.exit(0) + raise shell.ExitConsole(EXC_RET.EXIT_GUEST) def init(self): self.adt = load_adt(self.u.get_adt()) diff --git a/proxyclient/proxy.py b/proxyclient/proxy.py index 36fb0468..e0d2dc0f 100755 --- a/proxyclient/proxy.py +++ b/proxyclient/proxy.py @@ -90,6 +90,7 @@ class EXC(IntEnum): class EXC_RET(IntEnum): UNHANDLED = 1 HANDLED = 2 + EXIT_GUEST = 3 ExcInfo = Struct( "spsr" / RegAdapter(SPSR), @@ -802,7 +803,6 @@ class M1N1Proxy: 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__": diff --git a/src/hv.c b/src/hv.c index 6f4d13a7..9adff2fa 100644 --- a/src/hv.c +++ b/src/hv.c @@ -4,7 +4,7 @@ #include "assert.h" #include "cpu_regs.h" -void hv_enter_guest(u64 x0, u64 x1, u64 x2, u64 x3, void *entry) __attribute__((noreturn)); +void hv_enter_guest(u64 x0, u64 x1, u64 x2, u64 x3, void *entry); extern char _hv_vectors_start[0]; @@ -38,4 +38,6 @@ 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); + + printf("Exiting hypervisor.\n"); } diff --git a/src/hv_asm.S b/src/hv_asm.S index ccbea3d5..f92f7bbc 100644 --- a/src/hv_asm.S +++ b/src/hv_asm.S @@ -84,6 +84,17 @@ _v_hv_serr: .globl hv_enter_guest .type hv_enter_guest, @function hv_enter_guest: + stp x29, x30, [sp, #-16]! + stp x27, x28, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x19, x20, [sp, #-16]! + str x18, [sp, #-16]! + + mov x5, sp + msr tpidr_el2, x5 + mrs x5, daif msr daifclr, 3 mov x6, #5 @@ -91,8 +102,24 @@ hv_enter_guest: msr spsr_el2, x5 msr elr_el2, x4 - msr spsel, #0 mov x5, #0 - mov sp, x5 + msr sp_el0, x5 + msr sp_el1, x5 eret + +.globl hv_exit_guest +.type hv_exit_guest, @function +hv_exit_guest: + mrs x5, tpidr_el2 + mov sp, x5 + + ldr x18, [sp], #16 + ldp x19, x20, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x27, x28, [sp], #16 + ldp x29, x30, [sp], #16 + + ret diff --git a/src/hv_exc.c b/src/hv_exc.c index 9cc425e1..491fe878 100644 --- a/src/hv_exc.c +++ b/src/hv_exc.c @@ -7,6 +7,8 @@ #include "string.h" #include "uartproxy.h" +void hv_exit_guest(void) __attribute__((noreturn)); + static void hv_exc_proxy(u64 *regs, uartproxy_exc_code_t type) { struct uartproxy_exc_info exc_info = { @@ -27,18 +29,25 @@ static void hv_exc_proxy(u64 *regs, uartproxy_exc_code_t type) 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; + switch (ret) { + case 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; + case EXC_EXIT_GUEST: + hv_exit_guest(); + default: + printf("Guest exception not handled, rebooting.\n"); + print_regs(regs, 0); + for (int i = 0; i < 300; i++) { + iodev_console_kick(); + udelay(1000); + } + reboot(); } - - printf("Guest exception not handled, rebooting.\n"); - print_regs(regs, 0); - reboot(); } void hv_exc_sync(u64 *regs) diff --git a/src/uartproxy.h b/src/uartproxy.h index e46643a1..6887087a 100644 --- a/src/uartproxy.h +++ b/src/uartproxy.h @@ -23,6 +23,7 @@ typedef enum _uartproxy_exc_code_t { typedef enum _uartproxy_exc_ret_t { EXC_RET_UNHANDLED = 1, EXC_RET_HANDLED = 2, + EXC_EXIT_GUEST = 3, } uartproxy_exc_ret_t; struct uartproxy_exc_info {