2021-05-01 10:05:21 +00:00
|
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
|
|
|
|
#include "hv.h"
|
|
|
|
#include "assert.h"
|
|
|
|
#include "cpu_regs.h"
|
2021-05-25 11:05:10 +00:00
|
|
|
#include "gxf.h"
|
2021-05-27 15:03:11 +00:00
|
|
|
#include "pcie.h"
|
2021-05-27 12:16:17 +00:00
|
|
|
#include "smp.h"
|
2021-06-12 08:52:23 +00:00
|
|
|
#include "usb.h"
|
2021-05-08 12:54:07 +00:00
|
|
|
#include "utils.h"
|
2021-05-01 10:05:21 +00:00
|
|
|
|
2021-05-25 11:04:20 +00:00
|
|
|
#define HV_TICK_RATE 1000
|
|
|
|
|
2021-09-15 14:16:28 +00:00
|
|
|
DECLARE_SPINLOCK(bhl);
|
|
|
|
|
2021-05-04 15:24:52 +00:00
|
|
|
void hv_enter_guest(u64 x0, u64 x1, u64 x2, u64 x3, void *entry);
|
2021-05-04 10:36:23 +00:00
|
|
|
|
|
|
|
extern char _hv_vectors_start[0];
|
|
|
|
|
2021-05-25 11:04:20 +00:00
|
|
|
u64 hv_tick_interval;
|
|
|
|
|
2021-09-15 13:03:39 +00:00
|
|
|
u64 hv_saved_sp[MAX_CPUS];
|
|
|
|
|
2021-05-01 10:05:21 +00:00
|
|
|
void hv_init(void)
|
|
|
|
{
|
2021-05-27 15:03:11 +00:00
|
|
|
pcie_shutdown();
|
2021-06-12 08:52:23 +00:00
|
|
|
// reenable hpm interrupts for the guest for unused iodevs
|
|
|
|
usb_hpm_restore_irqs(0);
|
2021-05-27 12:16:17 +00:00
|
|
|
smp_start_secondaries();
|
|
|
|
hv_wdt_init();
|
|
|
|
|
2021-05-01 10:05:21 +00:00
|
|
|
// Enable physical timer for EL1
|
2021-05-04 10:23:35 +00:00
|
|
|
msr(CNTHCTL_EL2, CNTHCTL_EL1PTEN | CNTHCTL_EL1PCTEN);
|
2021-05-01 10:05:21 +00:00
|
|
|
|
|
|
|
hv_pt_init();
|
|
|
|
|
|
|
|
// Configure hypervisor defaults
|
2021-06-21 16:14:53 +00:00
|
|
|
hv_write_hcr(HCR_API | // Allow PAuth instructions
|
|
|
|
HCR_APK | // Allow PAuth key registers
|
|
|
|
HCR_TEA | // Trap external aborts
|
|
|
|
HCR_E2H | // VHE mode (forced)
|
|
|
|
HCR_RW | // AArch64 guest
|
|
|
|
HCR_AMO | // Trap SError exceptions
|
|
|
|
HCR_VM); // Enable stage 2 translation
|
2021-05-01 10:05:21 +00:00
|
|
|
|
2021-05-04 10:36:23 +00:00
|
|
|
// No guest vectors initially
|
|
|
|
msr(VBAR_EL12, 0);
|
|
|
|
|
2021-05-25 11:04:20 +00:00
|
|
|
// Compute tick interval
|
|
|
|
hv_tick_interval = mrs(CNTFRQ_EL0) / HV_TICK_RATE;
|
|
|
|
|
2021-05-01 10:05:21 +00:00
|
|
|
sysop("dsb ishst");
|
|
|
|
sysop("tlbi alle1is");
|
|
|
|
sysop("dsb ish");
|
|
|
|
sysop("isb");
|
|
|
|
}
|
2021-05-04 10:36:23 +00:00
|
|
|
|
2021-05-27 12:11:49 +00:00
|
|
|
static void hv_set_gxf_vbar(void)
|
|
|
|
{
|
|
|
|
msr(SYS_IMP_APL_VBAR_GL1, _hv_vectors_start);
|
|
|
|
}
|
|
|
|
|
2021-05-04 10:36:23 +00:00
|
|
|
void hv_start(void *entry, u64 regs[4])
|
|
|
|
{
|
|
|
|
msr(VBAR_EL1, _hv_vectors_start);
|
|
|
|
|
2021-05-27 12:11:49 +00:00
|
|
|
if (gxf_enabled())
|
|
|
|
gl2_call(hv_set_gxf_vbar, 0, 0, 0, 0);
|
|
|
|
|
2021-05-25 11:04:20 +00:00
|
|
|
hv_arm_tick();
|
2021-05-04 10:36:23 +00:00
|
|
|
hv_enter_guest(regs[0], regs[1], regs[2], regs[3], entry);
|
2021-05-27 12:16:17 +00:00
|
|
|
hv_wdt_stop();
|
2021-05-04 15:24:52 +00:00
|
|
|
|
|
|
|
printf("Exiting hypervisor.\n");
|
2021-05-04 10:36:23 +00:00
|
|
|
}
|
2021-05-25 11:04:20 +00:00
|
|
|
|
2021-05-25 11:05:10 +00:00
|
|
|
void hv_write_hcr(u64 val)
|
|
|
|
{
|
|
|
|
if (gxf_enabled() && !in_gl12())
|
|
|
|
gl2_call(hv_write_hcr, val, 0, 0, 0);
|
|
|
|
else
|
|
|
|
msr(HCR_EL2, val);
|
|
|
|
}
|
|
|
|
|
2021-05-27 12:11:49 +00:00
|
|
|
u64 hv_get_spsr(void)
|
|
|
|
{
|
|
|
|
if (in_gl12())
|
|
|
|
return mrs(SYS_IMP_APL_SPSR_GL1);
|
|
|
|
else
|
|
|
|
return mrs(SPSR_EL2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hv_set_spsr(u64 val)
|
|
|
|
{
|
|
|
|
if (in_gl12())
|
|
|
|
return msr(SYS_IMP_APL_SPSR_GL1, val);
|
|
|
|
else
|
|
|
|
return msr(SPSR_EL2, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 hv_get_esr(void)
|
|
|
|
{
|
|
|
|
if (in_gl12())
|
|
|
|
return mrs(SYS_IMP_APL_ESR_GL1);
|
|
|
|
else
|
|
|
|
return mrs(ESR_EL2);
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 hv_get_far(void)
|
|
|
|
{
|
|
|
|
if (in_gl12())
|
|
|
|
return mrs(SYS_IMP_APL_FAR_GL1);
|
|
|
|
else
|
|
|
|
return mrs(FAR_EL2);
|
|
|
|
}
|
|
|
|
|
2021-05-29 18:29:52 +00:00
|
|
|
u64 hv_get_afsr1(void)
|
|
|
|
{
|
|
|
|
if (in_gl12())
|
|
|
|
return mrs(SYS_IMP_APL_AFSR1_GL1);
|
|
|
|
else
|
|
|
|
return mrs(AFSR1_EL2);
|
|
|
|
}
|
|
|
|
|
2021-05-27 12:11:49 +00:00
|
|
|
u64 hv_get_elr(void)
|
|
|
|
{
|
|
|
|
if (in_gl12())
|
|
|
|
return mrs(SYS_IMP_APL_ELR_GL1);
|
|
|
|
else
|
|
|
|
return mrs(ELR_EL2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hv_set_elr(u64 val)
|
|
|
|
{
|
|
|
|
if (in_gl12())
|
|
|
|
return msr(SYS_IMP_APL_ELR_GL1, val);
|
|
|
|
else
|
|
|
|
return msr(ELR_EL2, val);
|
|
|
|
}
|
|
|
|
|
2021-05-25 11:04:20 +00:00
|
|
|
void hv_arm_tick(void)
|
|
|
|
{
|
|
|
|
msr(CNTP_TVAL_EL0, hv_tick_interval);
|
|
|
|
msr(CNTP_CTL_EL0, CNTx_CTL_ENABLE);
|
|
|
|
}
|
|
|
|
|
2021-05-27 16:24:29 +00:00
|
|
|
void hv_tick(u64 *regs)
|
2021-05-25 11:04:20 +00:00
|
|
|
{
|
2021-05-27 12:16:17 +00:00
|
|
|
hv_wdt_pet();
|
2021-05-27 16:24:29 +00:00
|
|
|
iodev_handle_events(uartproxy_iodev);
|
|
|
|
if (iodev_can_read(uartproxy_iodev))
|
|
|
|
hv_exc_proxy(regs, START_HV, HV_USER_INTERRUPT, NULL);
|
2021-08-23 08:02:28 +00:00
|
|
|
hv_vuart_poll();
|
2021-05-25 11:04:20 +00:00
|
|
|
}
|