hv_exc, hv.py: Add support for interrupting guest with ^C

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2021-05-25 20:07:02 +09:00
parent 1ce8d8b706
commit 75f206e65c
3 changed files with 42 additions and 3 deletions

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import sys, traceback, struct, array, bisect, os import sys, traceback, struct, array, bisect, os, signal
from construct import * from construct import *
@ -32,6 +32,7 @@ EvtMMIOTrace = Struct(
class HV_EVENT(IntEnum): class HV_EVENT(IntEnum):
HOOK_VM = 1 HOOK_VM = 1
VTIMER = 2 VTIMER = 2
USER_INTERRUPT = 3
VMProxyHookData = Struct( VMProxyHookData = Struct(
"flags" / RegAdapter(MMIOTraceFlags), "flags" / RegAdapter(MMIOTraceFlags),
@ -98,6 +99,8 @@ class HV:
self.symbols = [] self.symbols = []
self.sysreg = {} self.sysreg = {}
self.novm = False self.novm = False
self._in_handler = False
self._sigint_pending = False
self.vm_hooks = [] self.vm_hooks = []
def unmap(self, ipa, size): def unmap(self, ipa, size):
@ -328,6 +331,8 @@ class HV:
return self.handle_hvc(ctx) return self.handle_hvc(ctx)
def handle_exception(self, reason, code, info): def handle_exception(self, reason, code, info):
self._in_handler = True
info_data = self.iface.readmem(info, ExcInfo.sizeof()) info_data = self.iface.readmem(info, ExcInfo.sizeof())
self.ctx = ctx = ExcInfo.parse(info_data) self.ctx = ctx = ExcInfo.parse(info_data)
@ -348,18 +353,23 @@ class HV:
elif code == HV_EVENT.VTIMER: elif code == HV_EVENT.VTIMER:
print("Step") print("Step")
handled = True handled = True
elif code == HV_EVENT.USER_INTERRUPT:
handled = True
except Exception as e: except Exception as e:
print(f"Python exception while handling guest exception:") print(f"Python exception while handling guest exception:")
traceback.print_exc() traceback.print_exc()
if handled: if handled:
ret = EXC_RET.HANDLED ret = EXC_RET.HANDLED
if self._sigint_pending:
print("User interrupt")
else: else:
print(f"Guest exception: {reason.name}/{code.name}") print(f"Guest exception: {reason.name}/{code.name}")
self.u.print_exception(code, ctx) 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 self._stepping = False
locals = { locals = {
@ -374,7 +384,9 @@ class HV:
if callable(a): if callable(a):
locals[attr] = getattr(self, attr) locals[attr] = getattr(self, attr)
signal.signal(signal.SIGINT, signal.SIG_DFL)
ret = shell.run_shell(locals, "Entering debug shell", "Returning from exception") ret = shell.run_shell(locals, "Entering debug shell", "Returning from exception")
signal.signal(signal.SIGINT, self._handle_sigint)
if ret is None: if ret is None:
ret = EXC_RET.EXIT_GUEST ret = EXC_RET.EXIT_GUEST
@ -387,6 +399,10 @@ class HV:
ret = EXC_RET.STEP ret = EXC_RET.STEP
self.p.exit(ret) self.p.exit(ret)
self._in_handler = False
if self._sigint_pending:
self._handle_sigint()
def skip(self): def skip(self):
self.ctx.elr += 4 self.ctx.elr += 4
raise shell.ExitConsole(EXC_RET.HANDLED) 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.FIQ, self.handle_exception)
self.iface.set_handler(START.EXCEPTION_LOWER, EXC.SERROR, 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.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.HOOK_VM, self.handle_exception)
self.iface.set_handler(START.HV, HV_EVENT.VTIMER, 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) 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)) 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): def start(self):
print(f"Disabling other iodevs...") print(f"Disabling other iodevs...")
for iodev in IODEV: for iodev in IODEV:
@ -709,6 +735,7 @@ class HV:
print(f"Jumping to entrypoint at 0x{self.entry:x}") print(f"Jumping to entrypoint at 0x{self.entry:x}")
self.iface.dev.timeout = None self.iface.dev.timeout = None
signal.signal(signal.SIGINT, self._handle_sigint)
# Does not return # Does not return
self.p.hv_start(self.entry, self.guest_base + self.bootargs_off) self.p.hv_start(self.entry, self.guest_base + self.bootargs_off)

View file

@ -30,6 +30,7 @@ struct hv_vm_proxy_hook_data {
typedef enum _hv_entry_type { typedef enum _hv_entry_type {
HV_HOOK_VM = 1, HV_HOOK_VM = 1,
HV_VTIMER, HV_VTIMER,
HV_USER_INTERRUPT,
} hv_entry_type; } hv_entry_type;
/* VM */ /* VM */

View file

@ -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) void hv_exc_sync(u64 *regs)
{ {
bool handled = false; bool handled = false;
@ -73,11 +79,14 @@ void hv_exc_sync(u64 *regs)
msr(ELR_EL2, mrs(ELR_EL2) + 4); msr(ELR_EL2, mrs(ELR_EL2) + 4);
else else
hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_SYNC, NULL); hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_SYNC, NULL);
hv_exc_exit(regs);
} }
void hv_exc_irq(u64 *regs) void hv_exc_irq(u64 *regs)
{ {
hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_IRQ, NULL); hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_IRQ, NULL);
hv_exc_exit(regs);
} }
void hv_exc_fiq(u64 *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); reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK);
hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_FIQ, NULL); hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_FIQ, NULL);
} }
hv_exc_exit(regs);
} }
void hv_exc_serr(u64 *regs) void hv_exc_serr(u64 *regs)
{ {
hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_SERROR, NULL); hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_SERROR, NULL);
hv_exc_exit(regs);
} }