mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-12-01 10:39:10 +00:00
hv: Implement emulated guest CPU shutdown
Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
4d7b18d382
commit
4638632657
7 changed files with 74 additions and 11 deletions
|
@ -107,7 +107,7 @@ class HV(Reloadable):
|
||||||
self.wdt_cpu = None
|
self.wdt_cpu = None
|
||||||
self.smp = True
|
self.smp = True
|
||||||
self.hook_exceptions = False
|
self.hook_exceptions = False
|
||||||
self.started_cpus = set()
|
self.started_cpus = {}
|
||||||
self.started = False
|
self.started = False
|
||||||
self.ctx = None
|
self.ctx = None
|
||||||
self.hvcall_handlers = {}
|
self.hvcall_handlers = {}
|
||||||
|
@ -658,7 +658,6 @@ class HV(Reloadable):
|
||||||
MDSCR_EL1,
|
MDSCR_EL1,
|
||||||
}
|
}
|
||||||
ro = {
|
ro = {
|
||||||
CYC_OVRD_EL1,
|
|
||||||
ACC_CFG_EL1,
|
ACC_CFG_EL1,
|
||||||
ACC_OVRD_EL1,
|
ACC_OVRD_EL1,
|
||||||
}
|
}
|
||||||
|
@ -673,7 +672,15 @@ class HV(Reloadable):
|
||||||
shadow.add(DBGWVRn_EL1(i))
|
shadow.add(DBGWVRn_EL1(i))
|
||||||
|
|
||||||
value = 0
|
value = 0
|
||||||
if enc in shadow:
|
if enc == CYC_OVRD_EL1 and iss.DIR == MSR_DIR.WRITE:
|
||||||
|
if iss.Rt != 31:
|
||||||
|
value = ctx.regs[iss.Rt]
|
||||||
|
self.log(f"Skip: msr {name}, x{iss.Rt} = {value:x}")
|
||||||
|
if value & 1:
|
||||||
|
self.log("Guest is shutting down CPU")
|
||||||
|
self.p.hv_exit_cpu()
|
||||||
|
del self.started_cpus[self.ctx.cpu_id]
|
||||||
|
elif enc in shadow:
|
||||||
if iss.DIR == MSR_DIR.READ:
|
if iss.DIR == MSR_DIR.READ:
|
||||||
value = self.sysreg[self.ctx.cpu_id].setdefault(enc, 0)
|
value = self.sysreg[self.ctx.cpu_id].setdefault(enc, 0)
|
||||||
self.log(f"Shadow: mrs x{iss.Rt}, {name} = {value:x}")
|
self.log(f"Shadow: mrs x{iss.Rt}, {name} = {value:x}")
|
||||||
|
@ -1503,6 +1510,34 @@ class HV(Reloadable):
|
||||||
self.map_hook(addr, 4, read=lambda base, off, width: pg_overrides[base + off])
|
self.map_hook(addr, 4, read=lambda base, off, width: pg_overrides[base + off])
|
||||||
self.add_tracer(irange(addr, 4), "PMGR HACK", TraceMode.RESERVED)
|
self.add_tracer(irange(addr, 4), "PMGR HACK", TraceMode.RESERVED)
|
||||||
|
|
||||||
|
cpu_hack = [
|
||||||
|
# 0x210e20020,
|
||||||
|
# 0x211e20020,
|
||||||
|
# 0x212e20020,
|
||||||
|
]
|
||||||
|
|
||||||
|
def wh(base, off, data, width):
|
||||||
|
if isinstance(data, list):
|
||||||
|
data = data[0]
|
||||||
|
self.log(f"CPU W {base:x}+{off:x}:{width} = 0x{data:x}: Dangerous write")
|
||||||
|
|
||||||
|
for addr in cpu_hack:
|
||||||
|
self.map_hook(addr, 8, write=wh)
|
||||||
|
self.add_tracer(irange(addr, 8), "CPU HACK", TraceMode.RESERVED)
|
||||||
|
|
||||||
|
def cpu_state_rh(base, off, width):
|
||||||
|
data = ret = self.p.read64(base + off)
|
||||||
|
die = base // 0x20_0000_0000
|
||||||
|
cluster = (base >> 24) & 0xf
|
||||||
|
cpu = (base >> 20) & 0xf
|
||||||
|
for i, j in self.started_cpus.items():
|
||||||
|
if j == (die, cluster, cpu):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
ret &= ~0xff
|
||||||
|
self.log(f"CPU STATE R {base:x}+{off:x}:{width} = 0x{data:x} -> 0x{ret:x}")
|
||||||
|
return ret
|
||||||
|
|
||||||
def cpustart_wh(base, off, data, width):
|
def cpustart_wh(base, off, data, width):
|
||||||
self.log(f"CPUSTART W {base:x}+{off:x}:{width} = 0x{data:x}")
|
self.log(f"CPUSTART W {base:x}+{off:x}:{width} = 0x{data:x}")
|
||||||
if off >= 8:
|
if off >= 8:
|
||||||
|
@ -1512,6 +1547,9 @@ class HV(Reloadable):
|
||||||
for i in range(32):
|
for i in range(32):
|
||||||
if data & (1 << i):
|
if data & (1 << i):
|
||||||
self.start_secondary(die, cluster, i)
|
self.start_secondary(die, cluster, i)
|
||||||
|
cpu_state = 0x210050100 | (die << 27) | (cluster << 24) | (i << 20)
|
||||||
|
self.map_hook(cpu_state, 8, read=cpu_state_rh)
|
||||||
|
self.add_tracer(irange(addr, 8), "CPU STATE HACK", TraceMode.RESERVED)
|
||||||
|
|
||||||
die_count = self.adt["/arm-io"].die_count if hasattr(self.adt["/arm-io"], "die-count") else 1
|
die_count = self.adt["/arm-io"].die_count if hasattr(self.adt["/arm-io"], "die-count") else 1
|
||||||
|
|
||||||
|
@ -1546,7 +1584,7 @@ class HV(Reloadable):
|
||||||
self.log(f" CPU #{index}: RVBAR = {entry:#x}")
|
self.log(f" CPU #{index}: RVBAR = {entry:#x}")
|
||||||
|
|
||||||
self.sysreg[index] = {}
|
self.sysreg[index] = {}
|
||||||
self.started_cpus.add(index)
|
self.started_cpus[index] = (die, cluster, cpu)
|
||||||
self.p.hv_start_secondary(index, entry)
|
self.p.hv_start_secondary(index, entry)
|
||||||
|
|
||||||
def setup_adt(self):
|
def setup_adt(self):
|
||||||
|
@ -1867,7 +1905,7 @@ class HV(Reloadable):
|
||||||
# Does not return
|
# Does not return
|
||||||
|
|
||||||
self.started = True
|
self.started = True
|
||||||
self.started_cpus.add(0)
|
self.started_cpus[0] = (0, 0, 0)
|
||||||
self.p.hv_start(self.entry, self.guest_base + self.bootargs_off)
|
self.p.hv_start(self.entry, self.guest_base + self.bootargs_off)
|
||||||
|
|
||||||
from .. import trace
|
from .. import trace
|
||||||
|
|
|
@ -597,6 +597,7 @@ class M1N1Proxy(Reloadable):
|
||||||
P_HV_WRITE_HCR = 0xc0c
|
P_HV_WRITE_HCR = 0xc0c
|
||||||
P_HV_MAP_VIRTIO = 0xc0d
|
P_HV_MAP_VIRTIO = 0xc0d
|
||||||
P_VIRTIO_PUT_BUFFER = 0xc0e
|
P_VIRTIO_PUT_BUFFER = 0xc0e
|
||||||
|
P_HV_EXIT_CPU = 0xc0f
|
||||||
|
|
||||||
P_FB_INIT = 0xd00
|
P_FB_INIT = 0xd00
|
||||||
P_FB_SHUTDOWN = 0xd01
|
P_FB_SHUTDOWN = 0xd01
|
||||||
|
@ -1038,6 +1039,8 @@ class M1N1Proxy(Reloadable):
|
||||||
return self.request(self.P_HV_MAP_VIRTIO, base, config)
|
return self.request(self.P_HV_MAP_VIRTIO, base, config)
|
||||||
def virtio_put_buffer(self, base, qu, idx, length):
|
def virtio_put_buffer(self, base, qu, idx, length):
|
||||||
return self.request(self.P_VIRTIO_PUT_BUFFER, base, qu, idx, length)
|
return self.request(self.P_VIRTIO_PUT_BUFFER, base, qu, idx, length)
|
||||||
|
def hv_exit_cpu(self, cpu=-1):
|
||||||
|
return self.request(self.P_HV_EXIT_CPU, cpu)
|
||||||
|
|
||||||
def fb_init(self):
|
def fb_init(self):
|
||||||
return self.request(self.P_FB_INIT)
|
return self.request(self.P_FB_INIT)
|
||||||
|
|
28
src/hv.c
28
src/hv.c
|
@ -29,7 +29,7 @@ int hv_pinned_cpu;
|
||||||
int hv_want_cpu;
|
int hv_want_cpu;
|
||||||
|
|
||||||
static bool hv_has_ecv;
|
static bool hv_has_ecv;
|
||||||
static bool hv_should_exit;
|
static bool hv_should_exit[MAX_CPUS];
|
||||||
bool hv_started_cpus[MAX_CPUS];
|
bool hv_started_cpus[MAX_CPUS];
|
||||||
u64 hv_cpus_in_guest;
|
u64 hv_cpus_in_guest;
|
||||||
u64 hv_saved_sp[MAX_CPUS];
|
u64 hv_saved_sp[MAX_CPUS];
|
||||||
|
@ -111,7 +111,7 @@ static void hv_set_gxf_vbar(void)
|
||||||
|
|
||||||
void hv_start(void *entry, u64 regs[4])
|
void hv_start(void *entry, u64 regs[4])
|
||||||
{
|
{
|
||||||
hv_should_exit = false;
|
memset(hv_should_exit, 0, sizeof(hv_should_exit));
|
||||||
memset(hv_started_cpus, 0, sizeof(hv_started_cpus));
|
memset(hv_started_cpus, 0, sizeof(hv_started_cpus));
|
||||||
hv_started_cpus[0] = 1;
|
hv_started_cpus[0] = 1;
|
||||||
|
|
||||||
|
@ -148,10 +148,17 @@ void hv_start(void *entry, u64 regs[4])
|
||||||
|
|
||||||
hv_wdt_stop();
|
hv_wdt_stop();
|
||||||
|
|
||||||
hv_should_exit = true;
|
|
||||||
printf("HV: Exiting hypervisor (main CPU)\n");
|
printf("HV: Exiting hypervisor (main CPU)\n");
|
||||||
|
|
||||||
for (int i = 0; i < MAX_CPUS; i++) {
|
spin_unlock(&bhl);
|
||||||
|
// Wait a bit for the guest CPUs to exit on their own if they are in the process.
|
||||||
|
udelay(200000);
|
||||||
|
spin_lock(&bhl);
|
||||||
|
|
||||||
|
hv_started_cpus[0] = false;
|
||||||
|
|
||||||
|
for (int i = 1; i < MAX_CPUS; i++) {
|
||||||
|
hv_should_exit[i] = true;
|
||||||
if (hv_started_cpus[i]) {
|
if (hv_started_cpus[i]) {
|
||||||
printf("HV: Waiting for CPU %d to exit\n", i);
|
printf("HV: Waiting for CPU %d to exit\n", i);
|
||||||
spin_unlock(&bhl);
|
spin_unlock(&bhl);
|
||||||
|
@ -201,11 +208,11 @@ static void hv_enter_secondary(void *entry, u64 regs[4])
|
||||||
|
|
||||||
spin_lock(&bhl);
|
spin_lock(&bhl);
|
||||||
|
|
||||||
hv_should_exit = true;
|
|
||||||
printf("HV: Exiting from CPU %d\n", smp_id());
|
printf("HV: Exiting from CPU %d\n", smp_id());
|
||||||
|
|
||||||
__atomic_and_fetch(&hv_cpus_in_guest, ~BIT(smp_id()), __ATOMIC_ACQUIRE);
|
__atomic_and_fetch(&hv_cpus_in_guest, ~BIT(smp_id()), __ATOMIC_ACQUIRE);
|
||||||
|
|
||||||
|
hv_started_cpus[smp_id()] = false;
|
||||||
spin_unlock(&bhl);
|
spin_unlock(&bhl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +235,15 @@ void hv_start_secondary(int cpu, void *entry, u64 regs[4])
|
||||||
smp_call4(cpu, hv_enter_secondary, (u64)entry, (u64)regs, 0, 0);
|
smp_call4(cpu, hv_enter_secondary, (u64)entry, (u64)regs, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hv_exit_cpu(int cpu)
|
||||||
|
{
|
||||||
|
if (cpu == -1)
|
||||||
|
cpu = smp_id();
|
||||||
|
|
||||||
|
printf("HV: Requesting exit of CPU#%d from the guest\n", cpu);
|
||||||
|
hv_should_exit[cpu] = true;
|
||||||
|
}
|
||||||
|
|
||||||
void hv_rendezvous(void)
|
void hv_rendezvous(void)
|
||||||
{
|
{
|
||||||
int timeout = 1000000;
|
int timeout = 1000000;
|
||||||
|
@ -343,7 +359,7 @@ void hv_arm_tick(bool secondary)
|
||||||
|
|
||||||
void hv_maybe_exit(void)
|
void hv_maybe_exit(void)
|
||||||
{
|
{
|
||||||
if (hv_should_exit) {
|
if (hv_should_exit[smp_id()]) {
|
||||||
hv_exit_guest();
|
hv_exit_guest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
src/hv.h
1
src/hv.h
|
@ -101,6 +101,7 @@ void hv_set_elr(u64 val);
|
||||||
void hv_init(void);
|
void hv_init(void);
|
||||||
void hv_start(void *entry, u64 regs[4]);
|
void hv_start(void *entry, u64 regs[4]);
|
||||||
void hv_start_secondary(int cpu, void *entry, u64 regs[4]);
|
void hv_start_secondary(int cpu, void *entry, u64 regs[4]);
|
||||||
|
void hv_exit_cpu(int cpu);
|
||||||
void hv_rendezvous(void);
|
void hv_rendezvous(void);
|
||||||
bool hv_switch_cpu(int cpu);
|
bool hv_switch_cpu(int cpu);
|
||||||
void hv_pin_cpu(int cpu);
|
void hv_pin_cpu(int cpu);
|
||||||
|
|
|
@ -385,6 +385,7 @@ static void hv_exc_exit(struct exc_info *ctx)
|
||||||
reg_set(SYS_IMP_APL_PMCR0, PERCPU(exc_entry_pmcr0_cnt));
|
reg_set(SYS_IMP_APL_PMCR0, PERCPU(exc_entry_pmcr0_cnt));
|
||||||
msr(CNTVOFF_EL2, stolen_time);
|
msr(CNTVOFF_EL2, stolen_time);
|
||||||
spin_unlock(&bhl);
|
spin_unlock(&bhl);
|
||||||
|
hv_maybe_exit();
|
||||||
__atomic_or_fetch(&hv_cpus_in_guest, BIT(smp_id()), __ATOMIC_ACQUIRE);
|
__atomic_or_fetch(&hv_cpus_in_guest, BIT(smp_id()), __ATOMIC_ACQUIRE);
|
||||||
|
|
||||||
hv_set_spsr(ctx->spsr);
|
hv_set_spsr(ctx->spsr);
|
||||||
|
|
|
@ -487,6 +487,9 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
||||||
case P_HV_WRITE_HCR:
|
case P_HV_WRITE_HCR:
|
||||||
hv_write_hcr(request->args[0]);
|
hv_write_hcr(request->args[0]);
|
||||||
break;
|
break;
|
||||||
|
case P_HV_EXIT_CPU:
|
||||||
|
hv_exit_cpu(request->args[0]);
|
||||||
|
break;
|
||||||
|
|
||||||
case P_FB_INIT:
|
case P_FB_INIT:
|
||||||
fb_init(request->args[0]);
|
fb_init(request->args[0]);
|
||||||
|
|
|
@ -133,6 +133,7 @@ typedef enum {
|
||||||
P_HV_WRITE_HCR,
|
P_HV_WRITE_HCR,
|
||||||
P_HV_MAP_VIRTIO,
|
P_HV_MAP_VIRTIO,
|
||||||
P_VIRTIO_PUT_BUFFER,
|
P_VIRTIO_PUT_BUFFER,
|
||||||
|
P_HV_EXIT_CPU,
|
||||||
|
|
||||||
P_FB_INIT = 0xd00,
|
P_FB_INIT = 0xd00,
|
||||||
P_FB_SHUTDOWN,
|
P_FB_SHUTDOWN,
|
||||||
|
|
Loading…
Reference in a new issue