hv: Implement a periodic hypervisor ptimer and use vtimer for stepping

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2021-05-25 20:04:20 +09:00
parent 76c283deba
commit 2e014f58fa
4 changed files with 61 additions and 3 deletions

View file

@ -31,6 +31,7 @@ EvtMMIOTrace = Struct(
class HV_EVENT(IntEnum):
HOOK_VM = 1
VTIMER = 2
VMProxyHookData = Struct(
"flags" / RegAdapter(MMIOTraceFlags),
@ -92,7 +93,7 @@ class HV:
self.vbar_el1 = None
self.want_vbar = None
self.vectors = [None]
self.step = False
self._stepping = False
self.sym_offset = 0
self.symbols = []
self.sysreg = {}
@ -344,6 +345,9 @@ class HV:
code = HV_EVENT(code)
if code == HV_EVENT.HOOK_VM:
handled = self.handle_vm_hook(ctx)
elif code == HV_EVENT.VTIMER:
print("Step")
handled = True
except Exception as e:
print(f"Python exception while handling guest exception:")
traceback.print_exc()
@ -355,6 +359,9 @@ class HV:
self.u.print_exception(code, ctx)
if self._stepping or not handled:
self._stepping = False
locals = {
"hv": self,
"iface": self.iface,
@ -376,7 +383,7 @@ class HV:
if new_info != info_data:
self.iface.writemem(info, new_info)
if ret == EXC_RET.HANDLED and self.step:
if ret == EXC_RET.HANDLED and self._stepping:
ret = EXC_RET.STEP
self.p.exit(ret)
@ -387,6 +394,10 @@ class HV:
def cont(self):
raise shell.ExitConsole(EXC_RET.HANDLED)
def step(self):
self._stepping = True
raise shell.ExitConsole(EXC_RET.STEP)
def exit(self):
raise shell.ExitConsole(EXC_RET.EXIT_GUEST)
@ -490,7 +501,9 @@ class HV:
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.iface.set_handler(START.EXCEPTION, EXC.FIQ, 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)
self.map_hw(0x2_00000000, 0x2_00000000, 0x5_00000000)

View file

@ -5,10 +5,14 @@
#include "cpu_regs.h"
#include "utils.h"
#define HV_TICK_RATE 1000
void hv_enter_guest(u64 x0, u64 x1, u64 x2, u64 x3, void *entry);
extern char _hv_vectors_start[0];
u64 hv_tick_interval;
void hv_init(void)
{
// Enable physical timer for EL1
@ -28,6 +32,9 @@ void hv_init(void)
// No guest vectors initially
msr(VBAR_EL12, 0);
// Compute tick interval
hv_tick_interval = mrs(CNTFRQ_EL0) / HV_TICK_RATE;
sysop("dsb ishst");
sysop("tlbi alle1is");
sysop("dsb ish");
@ -38,7 +45,19 @@ void hv_start(void *entry, u64 regs[4])
{
msr(VBAR_EL1, _hv_vectors_start);
hv_arm_tick();
hv_enter_guest(regs[0], regs[1], regs[2], regs[3], entry);
printf("Exiting hypervisor.\n");
}
void hv_arm_tick(void)
{
msr(CNTP_TVAL_EL0, hv_tick_interval);
msr(CNTP_CTL_EL0, CNTx_CTL_ENABLE);
}
void hv_tick(void)
{
// printf("HV tick!\n");
}

View file

@ -29,6 +29,7 @@ struct hv_vm_proxy_hook_data {
typedef enum _hv_entry_type {
HV_HOOK_VM = 1,
HV_VTIMER,
} hv_entry_type;
/* VM */
@ -53,5 +54,7 @@ void hv_exc_proxy(u64 *regs, uartproxy_boot_reason_t reason, uartproxy_exc_code_
/* HV main */
void hv_init(void);
void hv_start(void *entry, u64 regs[4]);
void hv_arm_tick(void);
void hv_tick(void);
#endif

View file

@ -82,7 +82,30 @@ void hv_exc_irq(u64 *regs)
void hv_exc_fiq(u64 *regs)
{
hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_FIQ, NULL);
if (mrs(CNTP_CTL_EL0) == (CNTx_CTL_ISTATUS | CNTx_CTL_ENABLE)) {
msr(CNTP_CTL_EL0, CNTx_CTL_ISTATUS | CNTx_CTL_IMASK | CNTx_CTL_ENABLE);
hv_tick();
hv_arm_tick();
}
if (mrs(CNTV_CTL_EL0) == (CNTx_CTL_ISTATUS | CNTx_CTL_ENABLE)) {
msr(CNTV_CTL_EL0, CNTx_CTL_ISTATUS | CNTx_CTL_IMASK | CNTx_CTL_ENABLE);
hv_exc_proxy(regs, START_HV, HV_VTIMER, NULL);
}
u64 reg = mrs(SYS_IMP_APL_PMCR0);
if ((reg & (PMCR0_IMODE_MASK | PMCR0_IACT)) == (PMCR0_IMODE_FIQ | PMCR0_IACT)) {
printf("[FIQ] PMC IRQ, masking");
reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK);
hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_FIQ, NULL);
}
reg = mrs(SYS_IMP_APL_UPMCR0);
if ((reg & UPMCR0_IMODE_MASK) == UPMCR0_IMODE_FIQ && (mrs(SYS_IMP_APL_UPMSR) & UPMSR_IACT)) {
printf("[FIQ] UPMC IRQ, masking");
reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK);
hv_exc_proxy(regs, START_EXCEPTION_LOWER, EXC_FIQ, NULL);
}
}
void hv_exc_serr(u64 *regs)