arm64: add spin table support

There was a hacky and one-off spin table support in tegra132.
Make this support generic for all arm64 chips.

BUG=chrome-os-partner:32082
BRANCH=None
TEST=Ran with and without secure monitor booting smp into the kernel.

Change-Id: I3425ab0c30983d4c74d0aa465dda38bb2c91c83b
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 024dc3f3e5262433a56ed14934db837b5feb1748
Original-Change-Id: If12083a9afc3b2be663d36cfeed10f9b74bae3c8
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/218654
Original-Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: http://review.coreboot.org/9084
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
diff --git a/src/arch/arm64/armv8/secmon_loader.c b/src/arch/arm64/armv8/secmon_loader.c
index 066f1c1..4d83764 100644
--- a/src/arch/arm64/armv8/secmon_loader.c
+++ b/src/arch/arm64/armv8/secmon_loader.c
@@ -24,6 +24,7 @@
 
 #include <arch/lib_helpers.h>
 #include <arch/secmon.h>
+#include <arch/spintable.h>
 #include <console/console.h>
 #include <rmodule.h>
 #include <string.h>
@@ -75,30 +76,24 @@
 	return rmodule_entry(&secmon_mod);
 }
 
-void secmon_run(void (*entry)(void *), void *cb_tables)
+struct secmon_runit {
+	secmon_entry_t entry;
+	struct secmon_params bsp_params;
+	struct secmon_params secondary_params;
+};
+
+static void secmon_start(void *arg)
 {
-	struct secmon_params params;
 	uint32_t scr;
+	struct secmon_params *p = NULL;
+	struct secmon_runit *r = arg;
 
-	printk(BIOS_SPEW, "payload jump @ %p\n", entry);
+	if (cpu_is_bsp())
+		p = &r->bsp_params;
+	else if (r->secondary_params.entry != NULL)
+		p = &r->secondary_params;
 
-	if (get_current_el() != EL3) {
-		printk(BIOS_DEBUG, "Secmon Error: Can only be loaded in EL3\n");
-		return;
-	}
-
-	secmon_entry_t doit = secmon_load_rmodule();
-
-	if (doit == NULL)
-		die("ARM64 Error: secmon load error");
-
-	printk(BIOS_DEBUG, "ARM64: Loaded the el3 monitor...jumping to %p\n",
-	       doit);
-
-	params.entry = entry;
-	params.arg = cb_tables;
-	params.elx_el = EL2;
-	params.elx_mode = SPSR_USE_L;
+	printk(BIOS_DEBUG, "CPU%x entering secure monitor.\n", cpu_info()->id);
 
 	/* We want to enforce the following policies:
 	 * NS bit is set for lower EL
@@ -107,5 +102,47 @@
 	scr |= SCR_NS;
 	raw_write_scr_el3(scr);
 
-	doit(&params);
+	r->entry(p);
+}
+
+void secmon_run(void (*entry)(void *), void *cb_tables)
+{
+	const struct spintable_attributes *spin_attrs;
+	static struct secmon_runit runit;
+	struct cpu_action action = {
+		.run = secmon_start,
+		.arg = &runit,
+	};
+
+	printk(BIOS_SPEW, "payload jump @ %p\n", entry);
+
+	if (get_current_el() != EL3) {
+		printk(BIOS_DEBUG, "Secmon Error: Can only be loaded in EL3\n");
+		return;
+	}
+
+	runit.entry = secmon_load_rmodule();
+
+	if (runit.entry == NULL)
+		die("ARM64 Error: secmon load error");
+
+	printk(BIOS_DEBUG, "ARM64: Loaded the el3 monitor...jumping to %p\n",
+	       runit.entry);
+
+	runit.bsp_params.entry = entry;
+	runit.bsp_params.arg = cb_tables;
+	runit.bsp_params.elx_el = EL2;
+	runit.bsp_params.elx_mode = SPSR_USE_L;
+	runit.secondary_params.elx_el = EL2;
+	runit.secondary_params.elx_mode = SPSR_USE_L;
+
+	spin_attrs = spintable_get_attributes();
+
+	if (spin_attrs != NULL) {
+		runit.secondary_params.entry = spin_attrs->entry;
+		runit.secondary_params.arg = spin_attrs->addr;
+	}
+
+	arch_run_on_all_cpus_but_self_async(&action);
+	secmon_start(&runit);
 }