test-runner: SMP support
Start secondary CPUs before running tests. Currently hardcoded to 4 CPUs
and current qemu gic address.
Bug: 116851819
Change-Id: I68011ccb8d0cff02e888ac2bae69d5f1aa9de4ab
diff --git a/test-runner/arm64/asm.S b/test-runner/arm64/asm.S
index 2b396ef..2f32751 100644
--- a/test-runner/arm64/asm.S
+++ b/test-runner/arm64/asm.S
@@ -24,6 +24,19 @@
.text
+#define CPU_COUNT (4)
+#define STACK_SIZE (4096)
+
+#define GICD_BASE (0x08000000)
+#define GICD_SGIR (0xf00)
+
+.macro get_cpu_num, reg
+ /* Get cpu number */
+ mrs \reg, mpidr_el1
+ bic \reg, \reg, #(1<<24) /* Clear MT */
+ bic \reg, \reg, #(3<<30) /* Clear RES1 and U */
+.endm
+
.globl _start
_start:
/* Set exception vector base */
@@ -39,9 +52,17 @@
msr vbar_el1, x0
vbar_setup_done:
+ get_cpu_num x0
+
/* Setup stack */
- adr x0, stack
- mov sp, x0
+ mov x1, #STACK_SIZE
+ mul x1, x1, x0
+ adr x2, stack
+ add x2, x2, x1
+ adr x1, stack_space_end
+ cmp x2, x1
+ bhi error
+ mov sp, x2
/* Jump to c-code */
bl boot
@@ -61,11 +82,6 @@
.quad 0x20026 /* ADP_Stopped_ApplicationExit */
.quad 2 /* exit code */
-.globl trusty_idle
-trusty_idle:
- wfi
- ret
-
/*
* Catch exceptions (except sync-sp_el0 as we don't use that mode and it would
* jump to our entry point) and exit in case there is a bug.
@@ -91,7 +107,56 @@
exception 0x700
exception 0x780
+.globl trusty_idle
+trusty_idle:
+ // x1 = event_poll
+ adr x0, skip_cpu0_wfi // x0 = &skip_cpu0_wfi
+ get_cpu_num x2 // x2 = cpunum
+ cbz x2, cpu0_idle // if cpunum == 0 goto cpu0_idle
+
+ // skip_cpu0_wfi = cpunum (any value non-0 would work)
+ stlr x2, [x0]
+
+ // Send int 15 to cpu 0 to take it out of wfi
+ ldr x3, =GICD_BASE
+ ldr x4, =0x1800f
+ str x4, [x3, GICD_SGIR]
+
+ b wfi
+
+cpu0_idle:
+ cbz x1, wfi // only clear and skip event_poll wfi
+ ldaxr x3, [x0] // x1 = skip_cpu0_wfi
+ stxr w4, xzr, [x0] // skip_cpu0_wfi = 0
+ cbnz x3, no_wfi
+wfi:
+ wfi
+no_wfi:
+ ret
+
+.globl arch_start_secondary_cpus
+arch_start_secondary_cpus:
+ sub sp, sp, #8
+ mov x1, #1
+ str x1, [sp]
+start_secondary_cpu_loop:
+ ldr x0, =0xC4000003 /* psci CPU_ON */
+ adr x2, _start
+ mov x3, #0
+ smc 0
+ ldr x1, [sp]
+ add x1, x1, #1
+ str x1, [sp]
+ cmp x1, #CPU_COUNT
+ blo start_secondary_cpu_loop
+ add sp, sp, #8
+ ret
.data
- .space 4096
+ .space STACK_SIZE
stack:
+ .space STACK_SIZE * (CPU_COUNT - 1)
+stack_space_end:
+
+skip_cpu0_wfi:
+ .long 0
diff --git a/test-runner/include/test-runner-arch.h b/test-runner/include/test-runner-arch.h
index 6ea4a5f..4a26e28 100644
--- a/test-runner/include/test-runner-arch.h
+++ b/test-runner/include/test-runner-arch.h
@@ -55,6 +55,8 @@
int host_write(int handle, const void* data, size_t size);
int host_system(const char* cmd);
+int arch_start_secondary_cpus(void);
+
/*
* Boot next operating system.
*/
diff --git a/test-runner/test-runner.c b/test-runner/test-runner.c
index 87d5728..dd966a9 100644
--- a/test-runner/test-runner.c
+++ b/test-runner/test-runner.c
@@ -57,9 +57,9 @@
* responsible for reporting the error. It currently returns to the host with
* 2 as the exit code.
*/
-void boot(void) {
+void boot(int cpu) {
int ret;
- int stdout;
+ static int stdout;
int chan;
int status;
char cmdline[256];
@@ -71,10 +71,21 @@
.base = test_result,
.len = sizeof(test_result),
};
- struct trusty_dev trusty_dev;
+ static struct trusty_dev trusty_dev;
struct trusty_ipc_dev* ipc_dev;
struct trusty_ipc_chan test_chan;
+ if (cpu) {
+ while (true) {
+ ret = trusty_dev_nop(&trusty_dev);
+ if (!ret) {
+ trusty_idle(&trusty_dev, false);
+ } else {
+ write_str(stdout, "Secondary cpu unexpected error code\n");
+ }
+ }
+ }
+
/* Read test arguments from host (port name of test server to connect to) */
cmdline_len = host_get_cmdline(cmdline, sizeof(cmdline));
if (!starts_with(boottest_cmd, cmdline, cmdline_len)) {
@@ -105,6 +116,12 @@
return;
}
+ ret = arch_start_secondary_cpus();
+ if (ret) {
+ write_str(stdout, "Failed to start secondary CPUs\n");
+ return;
+ }
+
/* Create connection to test server */
trusty_ipc_chan_init(&test_chan, ipc_dev);
chan = trusty_ipc_connect(&test_chan, port, true);