hv: Support cleanly exiting the hypervisor from an exception

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2021-05-05 00:24:52 +09:00
parent d35fa5e0fc
commit a3440f2b48
6 changed files with 62 additions and 20 deletions

View file

@ -54,20 +54,23 @@ class HV:
for attr in dir(self): for attr in dir(self):
locals[attr] = getattr(self, attr) 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.iface.writemem(info, ExcInfo.build(self.ctx))
self.p.exit(EXC_RET.HANDLED) self.p.exit(ret)
def skip(self): def skip(self):
self.ctx.elr += 4 self.ctx.elr += 4
raise shell.ExitConsole() raise shell.ExitConsole(EXC_RET.HANDLED)
def cont(self): def cont(self):
raise shell.ExitConsole() raise shell.ExitConsole(EXC_RET.HANDLED)
def exit(self): def exit(self):
sys.exit(0) raise shell.ExitConsole(EXC_RET.EXIT_GUEST)
def init(self): def init(self):
self.adt = load_adt(self.u.get_adt()) self.adt = load_adt(self.u.get_adt())

View file

@ -90,6 +90,7 @@ class EXC(IntEnum):
class EXC_RET(IntEnum): class EXC_RET(IntEnum):
UNHANDLED = 1 UNHANDLED = 1
HANDLED = 2 HANDLED = 2
EXIT_GUEST = 3
ExcInfo = Struct( ExcInfo = Struct(
"spsr" / RegAdapter(SPSR), "spsr" / RegAdapter(SPSR),
@ -802,7 +803,6 @@ class M1N1Proxy:
def hv_map(self, from_, to, size, incr): def hv_map(self, from_, to, size, incr):
return self.request(self.P_HV_MAP, from_, to, size, incr) return self.request(self.P_HV_MAP, from_, to, size, incr)
def hv_start(self, entry, *args): def hv_start(self, entry, *args):
# does not return
return self.request(self.P_HV_START, entry, *args) return self.request(self.P_HV_START, entry, *args)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -4,7 +4,7 @@
#include "assert.h" #include "assert.h"
#include "cpu_regs.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]; extern char _hv_vectors_start[0];
@ -38,4 +38,6 @@ void hv_start(void *entry, u64 regs[4])
msr(VBAR_EL1, _hv_vectors_start); msr(VBAR_EL1, _hv_vectors_start);
hv_enter_guest(regs[0], regs[1], regs[2], regs[3], entry); hv_enter_guest(regs[0], regs[1], regs[2], regs[3], entry);
printf("Exiting hypervisor.\n");
} }

View file

@ -84,6 +84,17 @@ _v_hv_serr:
.globl hv_enter_guest .globl hv_enter_guest
.type hv_enter_guest, @function .type hv_enter_guest, @function
hv_enter_guest: 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 mrs x5, daif
msr daifclr, 3 msr daifclr, 3
mov x6, #5 mov x6, #5
@ -91,8 +102,24 @@ hv_enter_guest:
msr spsr_el2, x5 msr spsr_el2, x5
msr elr_el2, x4 msr elr_el2, x4
msr spsel, #0
mov x5, #0 mov x5, #0
mov sp, x5 msr sp_el0, x5
msr sp_el1, x5
eret 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

View file

@ -7,6 +7,8 @@
#include "string.h" #include "string.h"
#include "uartproxy.h" #include "uartproxy.h"
void hv_exit_guest(void) __attribute__((noreturn));
static void hv_exc_proxy(u64 *regs, uartproxy_exc_code_t type) static void hv_exc_proxy(u64 *regs, uartproxy_exc_code_t type)
{ {
struct uartproxy_exc_info exc_info = { 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); int ret = uartproxy_run(&start);
if (ret == EXC_RET_HANDLED) { switch (ret) {
case EXC_RET_HANDLED:
memcpy(regs, exc_info.regs, sizeof(exc_info.regs)); memcpy(regs, exc_info.regs, sizeof(exc_info.regs));
msr(SPSR_EL2, exc_info.spsr); msr(SPSR_EL2, exc_info.spsr);
msr(ELR_EL2, exc_info.elr); msr(ELR_EL2, exc_info.elr);
msr(SP_EL0, exc_info.sp[0]); msr(SP_EL0, exc_info.sp[0]);
msr(SP_EL1, exc_info.sp[1]); msr(SP_EL1, exc_info.sp[1]);
return; return;
} case EXC_EXIT_GUEST:
hv_exit_guest();
default:
printf("Guest exception not handled, rebooting.\n"); printf("Guest exception not handled, rebooting.\n");
print_regs(regs, 0); print_regs(regs, 0);
for (int i = 0; i < 300; i++) {
iodev_console_kick();
udelay(1000);
}
reboot(); reboot();
}
} }
void hv_exc_sync(u64 *regs) void hv_exc_sync(u64 *regs)

View file

@ -23,6 +23,7 @@ typedef enum _uartproxy_exc_code_t {
typedef enum _uartproxy_exc_ret_t { typedef enum _uartproxy_exc_ret_t {
EXC_RET_UNHANDLED = 1, EXC_RET_UNHANDLED = 1,
EXC_RET_HANDLED = 2, EXC_RET_HANDLED = 2,
EXC_EXIT_GUEST = 3,
} uartproxy_exc_ret_t; } uartproxy_exc_ret_t;
struct uartproxy_exc_info { struct uartproxy_exc_info {