Skip to content

Commit 9f846b1

Browse files
dberlinmarcan
authored andcommitted
Support boot CPU not being 0.
Right now, we assume the boot cpu is cpu0. That is not true on m3 max, where it is CPU 4. To figure out which CPU is the boot CPU, we check to see which CPU is running before we start any other CPUs, and record the MPIDR/idx. Without this patch, four issues happen on m3 max: 1. We try to start the boot CPU again, crashing it 2. We skip the real CPU 0 3. We start m1n1 again on CPU0 when we boot it 4. We enable interrupts on CPU0 because we think it's the primary CPU. Signed-off-by: Daniel Berlin <[email protected]>
1 parent 736acde commit 9f846b1

9 files changed

Lines changed: 69 additions & 21 deletions

File tree

src/exception.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void exception_initialize(void)
134134
reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK);
135135
msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING);
136136

137-
if (is_primary_core())
137+
if (is_boot_cpu())
138138
msr(DAIF, 0 << 6); // Enable SError, IRQ and FIQ
139139
else
140140
msr(DAIF, 3 << 6); // Disable IRQ and FIQ

src/hv.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,15 @@ static void hv_set_gxf_vbar(void)
111111

112112
void hv_start(void *entry, u64 regs[4])
113113
{
114+
if (boot_cpu_idx == -1) {
115+
printf("Boot CPU has not been found, can't start hypervisor\n");
116+
return;
117+
}
118+
114119
memset(hv_should_exit, 0, sizeof(hv_should_exit));
115120
memset(hv_started_cpus, 0, sizeof(hv_started_cpus));
116-
hv_started_cpus[0] = 1;
121+
122+
hv_started_cpus[boot_cpu_idx] = true;
117123

118124
msr(VBAR_EL1, _hv_vectors_start);
119125

@@ -155,9 +161,12 @@ void hv_start(void *entry, u64 regs[4])
155161
udelay(200000);
156162
spin_lock(&bhl);
157163

158-
hv_started_cpus[0] = false;
164+
hv_started_cpus[boot_cpu_idx] = false;
159165

160-
for (int i = 1; i < MAX_CPUS; i++) {
166+
for (int i = 0; i < MAX_CPUS; i++) {
167+
if (i == boot_cpu_idx) {
168+
continue;
169+
}
161170
hv_should_exit[i] = true;
162171
if (hv_started_cpus[i]) {
163172
printf("HV: Waiting for CPU %d to exit\n", i);

src/hv_wdt.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,12 @@ void hv_wdt_breadcrumb(char c)
129129

130130
void hv_wdt_init(void)
131131
{
132-
int node = adt_path_offset(adt, "/cpus/cpu0");
132+
char boot_cpu_name[32];
133+
134+
snprintf(boot_cpu_name, sizeof(boot_cpu_name), "/cpus/cpu%d", boot_cpu_idx);
135+
int node = adt_path_offset(adt, boot_cpu_name);
133136
if (node < 0) {
134-
printf("Error getting /cpus/cpu0 node\n");
137+
printf("Error getting %s node\n", boot_cpu_name);
135138
return;
136139
}
137140

src/iodev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ void iodev_console_write(const void *buf, size_t length)
150150
{
151151
bool do_lock = mmu_active();
152152

153-
if (!do_lock && !is_primary_core()) {
153+
if (!do_lock && !is_boot_cpu()) {
154154
if (length && iodevs[IODEV_UART]->usage & USAGE_CONSOLE) {
155155
iodevs[IODEV_UART]->ops->write(iodevs[IODEV_UART]->opaque, "*", 1);
156156
iodevs[IODEV_UART]->ops->write(iodevs[IODEV_UART]->opaque, buf, length);

src/payload.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,9 @@ int payload_run(void)
290290
if (enable_tso) {
291291

292292
do_enable_tso();
293-
for (int i = 1; i < MAX_CPUS; i++) {
293+
for (int i = 0; i < MAX_CPUS; i++) {
294+
if (i == boot_cpu_idx)
295+
continue;
294296
if (smp_is_alive(i)) {
295297
smp_call0(i, do_enable_tso);
296298
smp_wait(i);

src/smp.c

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ static u64 pmgr_reg;
4343
static u64 cpu_start_off;
4444

4545
extern u8 _vectors_start[0];
46+
int boot_cpu_idx = -1;
47+
u64 boot_cpu_mpidr = 0;
4648

4749
void smp_secondary_entry(void)
4850
{
@@ -238,17 +240,46 @@ void smp_start_secondaries(void)
238240
cpu_nodes[cpu_id] = node;
239241
}
240242

241-
for (int i = 1; i < MAX_CPUS; i++) {
242-
int node = cpu_nodes[i];
243+
/* The boot cpu id never changes once set */
244+
if (boot_cpu_idx == -1) {
245+
/* Figure out which CPU we are on by seeing which CPU is running */
246+
247+
/* This seems silly but it's what XNU does */
248+
for (int i = 0; i < MAX_CPUS; i++) {
249+
int cpu_node = cpu_nodes[i];
250+
if (!cpu_node)
251+
continue;
252+
const char *state = adt_getprop(adt, cpu_node, "state", NULL);
253+
if (!state)
254+
continue;
255+
if (strcmp(state, "running") == 0) {
256+
boot_cpu_idx = i;
257+
boot_cpu_mpidr = mrs(MPIDR_EL1);
258+
break;
259+
}
260+
}
261+
}
243262

244-
if (!node)
263+
if (boot_cpu_idx == -1) {
264+
printf(
265+
"Could not find currently running CPU in cpu table, can't start other processors!\n");
266+
return;
267+
}
268+
269+
for (int i = 0; i < MAX_CPUS; i++) {
270+
271+
if (i == boot_cpu_idx)
272+
continue;
273+
int cpu_node = cpu_nodes[i];
274+
275+
if (!cpu_node)
245276
continue;
246277

247278
u32 reg;
248279
u64 cpu_impl_reg[2];
249-
if (ADT_GETPROP(adt, node, "reg", &reg) < 0)
280+
if (ADT_GETPROP(adt, cpu_node, "reg", &reg) < 0)
250281
continue;
251-
if (ADT_GETPROP_ARRAY(adt, node, "cpu-impl-reg", cpu_impl_reg) < 0)
282+
if (ADT_GETPROP_ARRAY(adt, cpu_node, "cpu-impl-reg", cpu_impl_reg) < 0)
252283
continue;
253284

254285
u8 core = FIELD_GET(CPU_REG_CORE, reg);
@@ -258,15 +289,15 @@ void smp_start_secondaries(void)
258289
smp_start_cpu(i, die, cluster, core, cpu_impl_reg[0], pmgr_reg + cpu_start_off);
259290
}
260291

261-
spin_table[0].mpidr = mrs(MPIDR_EL1) & 0xFFFFFF;
292+
spin_table[boot_cpu_idx].mpidr = mrs(MPIDR_EL1) & 0xFFFFFF;
262293
}
263294

264295
void smp_stop_secondaries(bool deep_sleep)
265296
{
266297
printf("Stopping secondary CPUs...\n");
267298
smp_set_wfe_mode(true);
268299

269-
for (int i = 1; i < MAX_CPUS; i++) {
300+
for (int i = 0; i < MAX_CPUS; i++) {
270301
int node = cpu_nodes[i];
271302

272303
if (!node)
@@ -342,8 +373,8 @@ void smp_set_wfe_mode(bool new_mode)
342373
wfe_mode = new_mode;
343374
sysop("dsb sy");
344375

345-
for (int cpu = 1; cpu < MAX_CPUS; cpu++)
346-
if (smp_is_alive(cpu))
376+
for (int cpu = 0; cpu < MAX_CPUS; cpu++)
377+
if (cpu != boot_cpu_idx && smp_is_alive(cpu))
347378
smp_send_ipi(cpu);
348379

349380
sysop("sev");

src/smp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ static inline int smp_id(void)
3939
return mrs(TPIDR_EL1);
4040
}
4141

42+
extern int boot_cpu_idx;
4243
#endif

src/startup.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ void _start_c(void *boot_args, void *base)
106106
/* Secondary SMP core boot */
107107
void _cpu_reset_c(void *stack)
108108
{
109-
if (mrs(MPIDR_EL1) & 0xffffff)
109+
if (!is_boot_cpu())
110110
uart_puts("RVBAR entry on secondary CPU");
111111
else
112112
uart_puts("RVBAR entry on primary CPU");
@@ -118,7 +118,7 @@ void _cpu_reset_c(void *stack)
118118

119119
exception_initialize();
120120

121-
if (mrs(MPIDR_EL1) & 0xffffff)
121+
if (!is_boot_cpu())
122122
smp_secondary_entry();
123123
else
124124
m1n1_main();

src/utils.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,11 @@ static inline int in_el2(void)
334334
return (mrs(CurrentEL) >> 2) == 2;
335335
}
336336

337-
static inline int is_primary_core(void)
337+
extern int boot_cpu_idx;
338+
extern u64 boot_cpu_mpidr;
339+
static inline int is_boot_cpu(void)
338340
{
339-
return mrs(MPIDR_EL1) == 0x80000000;
341+
return boot_cpu_idx == -1 || boot_cpu_mpidr == mrs(MPIDR_EL1);
340342
}
341343

342344
extern char _base[];

0 commit comments

Comments
 (0)