mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-29 09:50:17 +00:00
hv_exc: Avoid delivering spurious HV-triggered IPIs to the guest
Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
098d394a5c
commit
a16731e8b3
5 changed files with 50 additions and 9 deletions
23
src/hv.c
23
src/hv.c
|
@ -215,6 +215,10 @@ void hv_rendezvous(void)
|
||||||
|
|
||||||
void hv_switch_cpu(int cpu)
|
void hv_switch_cpu(int cpu)
|
||||||
{
|
{
|
||||||
|
if (cpu > MAX_CPUS || cpu < 0 || !hv_started_cpus[cpu]) {
|
||||||
|
printf("HV: CPU #%d is inactive or invalid\n", cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
hv_rendezvous();
|
hv_rendezvous();
|
||||||
printf("HV: switching to CPU #%d\n", cpu);
|
printf("HV: switching to CPU #%d\n", cpu);
|
||||||
hv_want_cpu = cpu;
|
hv_want_cpu = cpu;
|
||||||
|
@ -297,6 +301,22 @@ void hv_rearm(void)
|
||||||
msr(CNTP_CTL_EL0, CNTx_CTL_ENABLE);
|
msr(CNTP_CTL_EL0, CNTx_CTL_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hv_check_rendezvous(u64 *regs)
|
||||||
|
{
|
||||||
|
if (hv_want_cpu == smp_id()) {
|
||||||
|
hv_want_cpu = -1;
|
||||||
|
hv_exc_proxy(regs, START_HV, HV_USER_INTERRUPT, NULL);
|
||||||
|
} else if (hv_want_cpu != -1) {
|
||||||
|
// Unlock the HV so the target CPU can get into the proxy
|
||||||
|
spin_unlock(&bhl);
|
||||||
|
while (hv_want_cpu != -1)
|
||||||
|
sysop("dmb sy");
|
||||||
|
spin_lock(&bhl);
|
||||||
|
// Make sure we tick at least once more before running the guest
|
||||||
|
hv_rearm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hv_tick(u64 *regs)
|
void hv_tick(u64 *regs)
|
||||||
{
|
{
|
||||||
if (hv_should_exit) {
|
if (hv_should_exit) {
|
||||||
|
@ -305,8 +325,7 @@ void hv_tick(u64 *regs)
|
||||||
}
|
}
|
||||||
hv_wdt_pet();
|
hv_wdt_pet();
|
||||||
iodev_handle_events(uartproxy_iodev);
|
iodev_handle_events(uartproxy_iodev);
|
||||||
if (hv_want_cpu == smp_id() || iodev_can_read(uartproxy_iodev)) {
|
if (iodev_can_read(uartproxy_iodev)) {
|
||||||
hv_want_cpu = -1;
|
|
||||||
hv_exc_proxy(regs, START_HV, HV_USER_INTERRUPT, NULL);
|
hv_exc_proxy(regs, START_HV, HV_USER_INTERRUPT, NULL);
|
||||||
}
|
}
|
||||||
hv_vuart_poll();
|
hv_vuart_poll();
|
||||||
|
|
1
src/hv.h
1
src/hv.h
|
@ -94,6 +94,7 @@ void hv_rendezvous(void);
|
||||||
void hv_switch_cpu(int cpu);
|
void hv_switch_cpu(int cpu);
|
||||||
void hv_arm_tick(void);
|
void hv_arm_tick(void);
|
||||||
void hv_rearm(void);
|
void hv_rearm(void);
|
||||||
|
void hv_check_rendezvous(u64 *regs);
|
||||||
void hv_tick(u64 *regs);
|
void hv_tick(u64 *regs);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
28
src/hv_exc.c
28
src/hv_exc.c
|
@ -22,6 +22,7 @@ extern spinlock_t bhl;
|
||||||
#define D_PERCPU(t, x) t x[MAX_CPUS]
|
#define D_PERCPU(t, x) t x[MAX_CPUS]
|
||||||
#define PERCPU(x) x[mrs(TPIDR_EL2)]
|
#define PERCPU(x) x[mrs(TPIDR_EL2)]
|
||||||
|
|
||||||
|
D_PERCPU(static bool, ipi_queued);
|
||||||
D_PERCPU(static bool, ipi_pending);
|
D_PERCPU(static bool, ipi_pending);
|
||||||
D_PERCPU(static bool, pmc_pending);
|
D_PERCPU(static bool, pmc_pending);
|
||||||
D_PERCPU(static u64, pmc_irq_mode);
|
D_PERCPU(static u64, pmc_irq_mode);
|
||||||
|
@ -184,9 +185,25 @@ static bool hv_handle_msr(u64 *regs, u64 iss)
|
||||||
* don't do any wfis that assume otherwise in m1n1. */
|
* don't do any wfis that assume otherwise in m1n1. */
|
||||||
SYSREG_PASS(SYS_IMP_APL_CYC_OVRD)
|
SYSREG_PASS(SYS_IMP_APL_CYC_OVRD)
|
||||||
/* IPI handling */
|
/* IPI handling */
|
||||||
SYSREG_PASS(SYS_IMP_APL_IPI_RR_LOCAL_EL1)
|
|
||||||
SYSREG_PASS(SYS_IMP_APL_IPI_RR_GLOBAL_EL1)
|
|
||||||
SYSREG_PASS(SYS_IMP_APL_IPI_CR_EL1)
|
SYSREG_PASS(SYS_IMP_APL_IPI_CR_EL1)
|
||||||
|
case SYSREG_ISS(SYS_IMP_APL_IPI_RR_LOCAL_EL1): {
|
||||||
|
assert(!is_read);
|
||||||
|
u64 mpidr = (regs[rt] & 0xff) | (mrs(MPIDR_EL1) & 0xffff00);
|
||||||
|
msr(SYS_IMP_APL_IPI_RR_LOCAL_EL1, regs[rt]);
|
||||||
|
for (int i = 0; i < MAX_CPUS; i++)
|
||||||
|
if (mpidr == smp_get_mpidr(i))
|
||||||
|
ipi_queued[i] = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SYSREG_ISS(SYS_IMP_APL_IPI_RR_GLOBAL_EL1):
|
||||||
|
assert(!is_read);
|
||||||
|
u64 mpidr = (regs[rt] & 0xff) | ((regs[rt] & 0xff0000) >> 8);
|
||||||
|
msr(SYS_IMP_APL_IPI_RR_LOCAL_EL1, regs[rt]);
|
||||||
|
for (int i = 0; i < MAX_CPUS; i++) {
|
||||||
|
if (mpidr == (smp_get_mpidr(i) & 0xffff))
|
||||||
|
ipi_queued[i] = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
case SYSREG_ISS(SYS_IMP_APL_IPI_SR_EL1):
|
case SYSREG_ISS(SYS_IMP_APL_IPI_SR_EL1):
|
||||||
if (is_read)
|
if (is_read)
|
||||||
regs[rt] = PERCPU(ipi_pending) ? IPI_SR_PENDING : 0;
|
regs[rt] = PERCPU(ipi_pending) ? IPI_SR_PENDING : 0;
|
||||||
|
@ -332,11 +349,14 @@ void hv_exc_fiq(u64 *regs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mrs(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) {
|
if (mrs(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) {
|
||||||
hv_tick(regs);
|
if (PERCPU(ipi_queued)) {
|
||||||
PERCPU(ipi_pending) = true;
|
PERCPU(ipi_pending) = true;
|
||||||
|
PERCPU(ipi_queued) = false;
|
||||||
|
}
|
||||||
msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING);
|
msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING);
|
||||||
sysop("isb");
|
sysop("isb");
|
||||||
}
|
}
|
||||||
|
hv_check_rendezvous(regs);
|
||||||
|
|
||||||
// Handles guest timers
|
// Handles guest timers
|
||||||
hv_exc_exit(regs);
|
hv_exc_exit(regs);
|
||||||
|
|
|
@ -168,7 +168,8 @@ void smp_start_secondaries(void)
|
||||||
|
|
||||||
void smp_send_ipi(int cpu)
|
void smp_send_ipi(int cpu)
|
||||||
{
|
{
|
||||||
msr(SYS_IMP_APL_IPI_RR_GLOBAL_EL1, spin_table[cpu].mpidr);
|
u64 mpidr = spin_table[cpu].mpidr;
|
||||||
|
msr(SYS_IMP_APL_IPI_RR_GLOBAL_EL1, (mpidr & 0xff) | ((mpidr & 0xff00) << 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
void smp_call4(int cpu, void *func, u64 arg0, u64 arg1, u64 arg2, u64 arg3)
|
void smp_call4(int cpu, void *func, u64 arg0, u64 arg1, u64 arg2, u64 arg3)
|
||||||
|
@ -220,7 +221,7 @@ bool smp_is_alive(int cpu)
|
||||||
return spin_table[cpu].flag;
|
return spin_table[cpu].flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
int smp_get_mpidr(int cpu)
|
uint64_t smp_get_mpidr(int cpu)
|
||||||
{
|
{
|
||||||
return spin_table[cpu].mpidr;
|
return spin_table[cpu].mpidr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ void smp_call4(int cpu, void *func, u64 arg0, u64 arg1, u64 arg2, u64 arg3);
|
||||||
u64 smp_wait(int cpu);
|
u64 smp_wait(int cpu);
|
||||||
|
|
||||||
bool smp_is_alive(int cpu);
|
bool smp_is_alive(int cpu);
|
||||||
int smp_get_mpidr(int cpu);
|
uint64_t smp_get_mpidr(int cpu);
|
||||||
u64 smp_get_release_addr(int cpu);
|
u64 smp_get_release_addr(int cpu);
|
||||||
void smp_set_wfe_mode(bool new_mode);
|
void smp_set_wfe_mode(bool new_mode);
|
||||||
void smp_send_ipi(int cpu);
|
void smp_send_ipi(int cpu);
|
||||||
|
|
Loading…
Reference in a new issue