From 75f206e65c5512974262fb4d7f87e4f2d765dcbf Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 25 May 2021 20:07:02 +0900 Subject: [PATCH] hv_exc, hv.py: Add support for interrupting guest with ^C Signed-off-by: Hector Martin --- proxyclient/hv.py | 33 ++++++++++++++++++++++++++++++--- src/hv.h | 1 + src/hv_exc.c | 11 +++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/proxyclient/hv.py b/proxyclient/hv.py index 380f66f9..b180e111 100644 --- a/proxyclient/hv.py +++ b/proxyclient/hv.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: MIT -import sys, traceback, struct, array, bisect, os +import sys, traceback, struct, array, bisect, os, signal from construct import * @@ -32,6 +32,7 @@ EvtMMIOTrace = Struct( class HV_EVENT(IntEnum): HOOK_VM = 1 VTIMER = 2 + USER_INTERRUPT = 3 VMProxyHookData = Struct( "flags" / RegAdapter(MMIOTraceFlags), @@ -98,6 +99,8 @@ class HV: self.symbols = [] self.sysreg = {} self.novm = False + self._in_handler = False + self._sigint_pending = False self.vm_hooks = [] def unmap(self, ipa, size): @@ -328,6 +331,8 @@ class HV: return self.handle_hvc(ctx) def handle_exception(self, reason, code, info): + self._in_handler = True + info_data = self.iface.readmem(info, ExcInfo.sizeof()) self.ctx = ctx = ExcInfo.parse(info_data) @@ -348,18 +353,23 @@ class HV: elif code == HV_EVENT.VTIMER: print("Step") handled = True + elif code == HV_EVENT.USER_INTERRUPT: + handled = True except Exception as e: print(f"Python exception while handling guest exception:") traceback.print_exc() if handled: ret = EXC_RET.HANDLED + if self._sigint_pending: + print("User interrupt") else: print(f"Guest exception: {reason.name}/{code.name}") - self.u.print_exception(code, ctx) - if self._stepping or not handled: + if self._sigint_pending or self._stepping or not handled: + + self._sigint_pending = False self._stepping = False locals = { @@ -374,7 +384,9 @@ class HV: if callable(a): locals[attr] = getattr(self, attr) + signal.signal(signal.SIGINT, signal.SIG_DFL) ret = shell.run_shell(locals, "Entering debug shell", "Returning from exception") + signal.signal(signal.SIGINT, self._handle_sigint) if ret is None: ret = EXC_RET.EXIT_GUEST @@ -387,6 +399,10 @@ class HV: ret = EXC_RET.STEP self.p.exit(ret) + self._in_handler = False + if self._sigint_pending: + self._handle_sigint() + def skip(self): self.ctx.elr += 4 raise shell.ExitConsole(EXC_RET.HANDLED) @@ -502,6 +518,7 @@ class HV: 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.iface.set_handler(START.EXCEPTION, EXC.FIQ, self.handle_exception) + self.iface.set_handler(START.HV, HV_EVENT.USER_INTERRUPT, self.handle_exception) self.iface.set_handler(START.HV, HV_EVENT.HOOK_VM, self.handle_exception) self.iface.set_handler(START.HV, HV_EVENT.VTIMER, self.handle_exception) self.iface.set_event_handler(EVENT.MMIOTRACE, self.handle_mmiotrace) @@ -690,6 +707,15 @@ class HV: self.iface.writemem(guest_base + self.bootargs_off, BootArgs.build(self.tba)) + def _handle_sigint(self, signal=None, stack=None): + self._sigint_pending = True + + if self._in_handler: + return + + # Kick the proxy to break out of the hypervisor + self.iface.dev.write(b"!") + def start(self): print(f"Disabling other iodevs...") for iodev in IODEV: @@ -709,6 +735,7 @@ class HV: print(f"Jumping to entrypoint at 0x{self.entry:x}") self.iface.dev.timeout = None + signal.signal(signal.SIGINT, self._handle_sigint) # Does not return self.p.hv_start(self.entry, self.guest_base + self.bootargs_off) diff --git a/src/hv.h b/src/hv.h index 93d80c04..5a68eae3 100644 --- a/src/hv.h +++ b/src/hv.h @@ -30,6 +30,7 @@ struct hv_vm_proxy_hook_data { typedef enum _hv_entry_type { HV_HOOK_VM = 1, HV_VTIMER, + HV_USER_INTERRUPT, } hv_entry_type; /* VM */ diff --git a/src/hv_exc.c b/src/hv_exc.c index 683a205f..e1ec7a96 100644 --- a/src/hv_exc.c +++ b/src/hv_exc.c @@ -57,6 +57,12 @@ void hv_exc_proxy(u64 *regs, uartproxy_boot_reason_t reason, uartproxy_exc_code_ } } +static void hv_exc_exit(u64 *regs) +{ + if (iodev_can_read(uartproxy_iodev)) + hv_exc_proxy(regs, START_HV, HV_USER_INTERRUPT, NULL); +} + void hv_exc_sync(u64 *regs) { bool handled = false; @@ -73,11 +79,14 @@ void hv_exc_sync(u64 *regs) msr(ELR_EL2, mrs(ELR_EL2) + 4); else hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_SYNC, NULL); + + hv_exc_exit(regs); } void hv_exc_irq(u64 *regs) { hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_IRQ, NULL); + hv_exc_exit(regs); } void hv_exc_fiq(u64 *regs) @@ -106,9 +115,11 @@ void hv_exc_fiq(u64 *regs) reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK); hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_FIQ, NULL); } + hv_exc_exit(regs); } void hv_exc_serr(u64 *regs) { hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_SERROR, NULL); + hv_exc_exit(regs); }