Skip to content

Commit 747da3b

Browse files
committed
baremetal: aarch64 multicore works!!!
1 parent 2b10066 commit 747da3b

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

README.adoc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10557,17 +10557,16 @@ output:
1055710557

1055810558
==== ARM multicore
1055910559

10560-
TODO get working on QEMU, CPU 1 not waking up. gem5 works:
10561-
1056210560
....
1056310561
./run --arch aarch64 --baremetal arch/aarch64/multicore --cpus 2
10562+
./run --arch aarch64 --baremetal arch/aarch64/multicore --cpus 2 --gem5
1056410563
....
1056510564

1056610565
Source: link:baremetal/arch/aarch64/multicore.S[]
1056710566

1056810567
CPU 0 of this program enters a spinlock loop: it repeatedly checks if a given memory address is `1`.
1056910568

10570-
So, we need CPU 1 to come to the rescue to that memory address be `1`, otherwise CPU 0 will be stuck there forever.
10569+
So, we need CPU 1 to come to the rescue and set that memory address to `1`, otherwise CPU 0 will be stuck there forever!
1057110570

1057210571
Don't believe me? Then try:
1057310572

@@ -10584,6 +10583,17 @@ Bibliography:
1058410583
* https://stackoverflow.com/questions/20055754/arm-start-wakeup-bringup-the-other-cpu-cores-aps-and-pass-execution-start-addre
1058510584
* https://stackoverflow.com/questions/980999/what-does-multicore-assembly-language-look-like/33651438#33651438
1058610585

10586+
===== WFE and SEV
10587+
10588+
The `WFE` and `SEV` instructions are just hints: a compliant implementation can treat them as NOPs.
10589+
10590+
However, likely no implementation likely does (TODO confirm), since:
10591+
10592+
* `WFE` puts the core in a low power mode
10593+
* `SEV` wakes up cores from a low power mode
10594+
10595+
and power consumption is key in ARM applications.
10596+
1058710597
=== How we got some baremetal stuff to work
1058810598

1058910599
It is nice when thing just work.

baremetal/arch/aarch64/multicore.S

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,60 @@ main:
99

1010
/* Read cpu id into x1. */
1111
mrs x1, mpidr_el1
12-
and x1, x1, #3
13-
cbz x1, 1f
12+
and x1, x1, 3
13+
cbz x1, cpu0_only
14+
cpu1_only:
1415
/* Only CPU 1 reaches this point and sets the spinlock. */
15-
mov x0, #1
16+
mov x0, 1
1617
ldr x1, =spinlock
1718
str x0, [x1]
18-
b .
19-
1:
19+
/* Ensure that CPU 0 sees the write right now.
20+
* Optional, but could save some useless CPU 1 loops.
21+
*/
22+
dmb sy
23+
/* Wake up CPU 0 if it is sleeping on wfe.
24+
* Optional, but could save power on a real system.
25+
*/
26+
sev
27+
cpu1_sleep_forever:
28+
/* Hint CPU 1 to enter low power mode.
29+
* Optional, but could save power on a real system.
30+
*/
31+
wfe
32+
b cpu1_sleep_forever
33+
cpu0_only:
2034
/* Only CPU 0 reaches this point. */
35+
36+
#if !defined(GEM5)
37+
/* Wake up CPU 1 from initial sleep!
38+
* In gem5, CPU 1 starts woken up from the start,
39+
* so this is not needed.
40+
*/
41+
/* Function identifier: PCSI CPU_ON. */
42+
ldr w0, =0xc4000003
43+
/* Argument 1: target_cpu */
44+
mov x1, 1
45+
/* Argument 2: entry_point_address */
46+
ldr x2, =cpu1_only
47+
/* Argument 3: context_id */
48+
mov x3, 0
49+
/* Unused hvc args: the Linux kernel zeroes them,
50+
* but I don't think it is required.
51+
*/
52+
#if 0
53+
mov x4, 0
54+
mov x5, 0
55+
mov x6, 0
56+
mov x7, 0
57+
#endif
58+
hvc 0
59+
#endif
60+
61+
spinlock_start:
2162
ldr x0, spinlock
22-
cbz x0, 1b
63+
/* Hint CPU 0 to enter low power mode. */
64+
wfe
65+
cbz x0, spinlock_start
2366

2467
ret
2568

0 commit comments

Comments
 (0)