Skip to content

Commit 4638632

Browse files
committed
hv: Implement emulated guest CPU shutdown
Signed-off-by: Hector Martin <[email protected]>
1 parent 4d7b18d commit 4638632

7 files changed

Lines changed: 74 additions & 11 deletions

File tree

proxyclient/m1n1/hv/__init__.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def __init__(self, iface, proxy, utils):
107107
self.wdt_cpu = None
108108
self.smp = True
109109
self.hook_exceptions = False
110-
self.started_cpus = set()
110+
self.started_cpus = {}
111111
self.started = False
112112
self.ctx = None
113113
self.hvcall_handlers = {}
@@ -658,7 +658,6 @@ def handle_msr(self, ctx, iss=None):
658658
MDSCR_EL1,
659659
}
660660
ro = {
661-
CYC_OVRD_EL1,
662661
ACC_CFG_EL1,
663662
ACC_OVRD_EL1,
664663
}
@@ -673,7 +672,15 @@ def handle_msr(self, ctx, iss=None):
673672
shadow.add(DBGWVRn_EL1(i))
674673

675674
value = 0
676-
if enc in shadow:
675+
if enc == CYC_OVRD_EL1 and iss.DIR == MSR_DIR.WRITE:
676+
if iss.Rt != 31:
677+
value = ctx.regs[iss.Rt]
678+
self.log(f"Skip: msr {name}, x{iss.Rt} = {value:x}")
679+
if value & 1:
680+
self.log("Guest is shutting down CPU")
681+
self.p.hv_exit_cpu()
682+
del self.started_cpus[self.ctx.cpu_id]
683+
elif enc in shadow:
677684
if iss.DIR == MSR_DIR.READ:
678685
value = self.sysreg[self.ctx.cpu_id].setdefault(enc, 0)
679686
self.log(f"Shadow: mrs x{iss.Rt}, {name} = {value:x}")
@@ -1503,6 +1510,34 @@ def hook_pmgr_dev(dev):
15031510
self.map_hook(addr, 4, read=lambda base, off, width: pg_overrides[base + off])
15041511
self.add_tracer(irange(addr, 4), "PMGR HACK", TraceMode.RESERVED)
15051512

1513+
cpu_hack = [
1514+
# 0x210e20020,
1515+
# 0x211e20020,
1516+
# 0x212e20020,
1517+
]
1518+
1519+
def wh(base, off, data, width):
1520+
if isinstance(data, list):
1521+
data = data[0]
1522+
self.log(f"CPU W {base:x}+{off:x}:{width} = 0x{data:x}: Dangerous write")
1523+
1524+
for addr in cpu_hack:
1525+
self.map_hook(addr, 8, write=wh)
1526+
self.add_tracer(irange(addr, 8), "CPU HACK", TraceMode.RESERVED)
1527+
1528+
def cpu_state_rh(base, off, width):
1529+
data = ret = self.p.read64(base + off)
1530+
die = base // 0x20_0000_0000
1531+
cluster = (base >> 24) & 0xf
1532+
cpu = (base >> 20) & 0xf
1533+
for i, j in self.started_cpus.items():
1534+
if j == (die, cluster, cpu):
1535+
break
1536+
else:
1537+
ret &= ~0xff
1538+
self.log(f"CPU STATE R {base:x}+{off:x}:{width} = 0x{data:x} -> 0x{ret:x}")
1539+
return ret
1540+
15061541
def cpustart_wh(base, off, data, width):
15071542
self.log(f"CPUSTART W {base:x}+{off:x}:{width} = 0x{data:x}")
15081543
if off >= 8:
@@ -1512,6 +1547,9 @@ def cpustart_wh(base, off, data, width):
15121547
for i in range(32):
15131548
if data & (1 << i):
15141549
self.start_secondary(die, cluster, i)
1550+
cpu_state = 0x210050100 | (die << 27) | (cluster << 24) | (i << 20)
1551+
self.map_hook(cpu_state, 8, read=cpu_state_rh)
1552+
self.add_tracer(irange(addr, 8), "CPU STATE HACK", TraceMode.RESERVED)
15151553

15161554
die_count = self.adt["/arm-io"].die_count if hasattr(self.adt["/arm-io"], "die-count") else 1
15171555

@@ -1546,7 +1584,7 @@ def start_secondary(self, die, cluster, cpu):
15461584
self.log(f" CPU #{index}: RVBAR = {entry:#x}")
15471585

15481586
self.sysreg[index] = {}
1549-
self.started_cpus.add(index)
1587+
self.started_cpus[index] = (die, cluster, cpu)
15501588
self.p.hv_start_secondary(index, entry)
15511589

15521590
def setup_adt(self):
@@ -1867,7 +1905,7 @@ def start(self):
18671905
# Does not return
18681906

18691907
self.started = True
1870-
self.started_cpus.add(0)
1908+
self.started_cpus[0] = (0, 0, 0)
18711909
self.p.hv_start(self.entry, self.guest_base + self.bootargs_off)
18721910

18731911
from .. import trace

proxyclient/m1n1/proxy.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ class M1N1Proxy(Reloadable):
597597
P_HV_WRITE_HCR = 0xc0c
598598
P_HV_MAP_VIRTIO = 0xc0d
599599
P_VIRTIO_PUT_BUFFER = 0xc0e
600+
P_HV_EXIT_CPU = 0xc0f
600601

601602
P_FB_INIT = 0xd00
602603
P_FB_SHUTDOWN = 0xd01
@@ -1038,6 +1039,8 @@ def hv_map_virtio(self, base, config):
10381039
return self.request(self.P_HV_MAP_VIRTIO, base, config)
10391040
def virtio_put_buffer(self, base, qu, idx, length):
10401041
return self.request(self.P_VIRTIO_PUT_BUFFER, base, qu, idx, length)
1042+
def hv_exit_cpu(self, cpu=-1):
1043+
return self.request(self.P_HV_EXIT_CPU, cpu)
10411044

10421045
def fb_init(self):
10431046
return self.request(self.P_FB_INIT)

src/hv.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ int hv_pinned_cpu;
2929
int hv_want_cpu;
3030

3131
static bool hv_has_ecv;
32-
static bool hv_should_exit;
32+
static bool hv_should_exit[MAX_CPUS];
3333
bool hv_started_cpus[MAX_CPUS];
3434
u64 hv_cpus_in_guest;
3535
u64 hv_saved_sp[MAX_CPUS];
@@ -111,7 +111,7 @@ static void hv_set_gxf_vbar(void)
111111

112112
void hv_start(void *entry, u64 regs[4])
113113
{
114-
hv_should_exit = false;
114+
memset(hv_should_exit, 0, sizeof(hv_should_exit));
115115
memset(hv_started_cpus, 0, sizeof(hv_started_cpus));
116116
hv_started_cpus[0] = 1;
117117

@@ -148,10 +148,17 @@ void hv_start(void *entry, u64 regs[4])
148148

149149
hv_wdt_stop();
150150

151-
hv_should_exit = true;
152151
printf("HV: Exiting hypervisor (main CPU)\n");
153152

154-
for (int i = 0; i < MAX_CPUS; i++) {
153+
spin_unlock(&bhl);
154+
// Wait a bit for the guest CPUs to exit on their own if they are in the process.
155+
udelay(200000);
156+
spin_lock(&bhl);
157+
158+
hv_started_cpus[0] = false;
159+
160+
for (int i = 1; i < MAX_CPUS; i++) {
161+
hv_should_exit[i] = true;
155162
if (hv_started_cpus[i]) {
156163
printf("HV: Waiting for CPU %d to exit\n", i);
157164
spin_unlock(&bhl);
@@ -201,11 +208,11 @@ static void hv_enter_secondary(void *entry, u64 regs[4])
201208

202209
spin_lock(&bhl);
203210

204-
hv_should_exit = true;
205211
printf("HV: Exiting from CPU %d\n", smp_id());
206212

207213
__atomic_and_fetch(&hv_cpus_in_guest, ~BIT(smp_id()), __ATOMIC_ACQUIRE);
208214

215+
hv_started_cpus[smp_id()] = false;
209216
spin_unlock(&bhl);
210217
}
211218

@@ -228,6 +235,15 @@ void hv_start_secondary(int cpu, void *entry, u64 regs[4])
228235
smp_call4(cpu, hv_enter_secondary, (u64)entry, (u64)regs, 0, 0);
229236
}
230237

238+
void hv_exit_cpu(int cpu)
239+
{
240+
if (cpu == -1)
241+
cpu = smp_id();
242+
243+
printf("HV: Requesting exit of CPU#%d from the guest\n", cpu);
244+
hv_should_exit[cpu] = true;
245+
}
246+
231247
void hv_rendezvous(void)
232248
{
233249
int timeout = 1000000;
@@ -343,7 +359,7 @@ void hv_arm_tick(bool secondary)
343359

344360
void hv_maybe_exit(void)
345361
{
346-
if (hv_should_exit) {
362+
if (hv_should_exit[smp_id()]) {
347363
hv_exit_guest();
348364
}
349365
}

src/hv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ void hv_set_elr(u64 val);
101101
void hv_init(void);
102102
void hv_start(void *entry, u64 regs[4]);
103103
void hv_start_secondary(int cpu, void *entry, u64 regs[4]);
104+
void hv_exit_cpu(int cpu);
104105
void hv_rendezvous(void);
105106
bool hv_switch_cpu(int cpu);
106107
void hv_pin_cpu(int cpu);

src/hv_exc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ static void hv_exc_exit(struct exc_info *ctx)
385385
reg_set(SYS_IMP_APL_PMCR0, PERCPU(exc_entry_pmcr0_cnt));
386386
msr(CNTVOFF_EL2, stolen_time);
387387
spin_unlock(&bhl);
388+
hv_maybe_exit();
388389
__atomic_or_fetch(&hv_cpus_in_guest, BIT(smp_id()), __ATOMIC_ACQUIRE);
389390

390391
hv_set_spsr(ctx->spsr);

src/proxy.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
487487
case P_HV_WRITE_HCR:
488488
hv_write_hcr(request->args[0]);
489489
break;
490+
case P_HV_EXIT_CPU:
491+
hv_exit_cpu(request->args[0]);
492+
break;
490493

491494
case P_FB_INIT:
492495
fb_init(request->args[0]);

src/proxy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ typedef enum {
133133
P_HV_WRITE_HCR,
134134
P_HV_MAP_VIRTIO,
135135
P_VIRTIO_PUT_BUFFER,
136+
P_HV_EXIT_CPU,
136137

137138
P_FB_INIT = 0xd00,
138139
P_FB_SHUTDOWN,

0 commit comments

Comments
 (0)