|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT early RFC PATCH 08/11] plat/kvm/arm: Implement smp boot on arm64 kvm plat
Signed-off-by: Jia He <justin.he@xxxxxxx>
---
lib/ukboot/Makefile.uk | 1 +
lib/ukboot/boot.c | 15 ++++
plat/kvm/arm/setup.c | 188 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 204 insertions(+)
diff --git a/lib/ukboot/Makefile.uk b/lib/ukboot/Makefile.uk
index 55f205d..c8e0b44 100644
--- a/lib/ukboot/Makefile.uk
+++ b/lib/ukboot/Makefile.uk
@@ -1,6 +1,7 @@
$(eval $(call addlib_s,libukboot,$(CONFIG_LIBUKBOOT)))
CINCLUDES-$(CONFIG_LIBUKBOOT) += -I$(LIBUKBOOT_BASE)/include
+CINCLUDES-$(CONFIG_LIBUKBOOT) += -I$(UK_PLAT_COMMON_BASE)/include
CXXINCLUDES-$(CONFIG_LIBUKBOOT) += -I$(LIBUKBOOT_BASE)/include
LIBUKBOOT_SRCS-y += $(LIBUKBOOT_BASE)/boot.c
diff --git a/lib/ukboot/boot.c b/lib/ukboot/boot.c
index 4846782..d4d49c1 100644
--- a/lib/ukboot/boot.c
+++ b/lib/ukboot/boot.c
@@ -41,6 +41,10 @@
#include <stdio.h>
#include <errno.h>
+#if CONFIG_SMP
+#include <smp.h>
+#endif
+
#if CONFIG_LIBUKALLOC && CONFIG_LIBUKALLOCBBUDDY && CONFIG_LIBUKBOOT_INITALLOC
#include <uk/allocbbuddy.h>
#endif
@@ -255,6 +259,17 @@ void ukplat_entry(int argc, char *argv[])
tma.argc = argc;
tma.argv = argv;
+#if CONFIG_SMP
+ uk_pr_info("before start cpu\n");
+
+ for (i = 1; i < MAXCPU; i++) {
+ if (cpu_possible_map[i] != -1)
+ start_cpu(cpu_possible_map[i]);
+ }
+
+ release_aps();
+#endif
+
#if CONFIG_LIBUKSCHED
main_thread = uk_thread_create("main", main_thread_func, &tma);
if (unlikely(!main_thread))
diff --git a/plat/kvm/arm/setup.c b/plat/kvm/arm/setup.c
index 1f6e458..4035202 100644
--- a/plat/kvm/arm/setup.c
+++ b/plat/kvm/arm/setup.c
@@ -27,6 +27,29 @@
#include <arm/cpu.h>
#include <uk/arch/limits.h>
+#include <stdbool.h>
+#include <uk/plat/bootstrap.h>
+#include <uk/sched.h>
+
+#include <smp.h>
+#include <uk/plat/memory.h>
+#include <uk/plat/io.h>
+#include <uk/plat/lcpu.h>
+#include <arm/psci.h>
+#include <ofw/fdt.h>
+#include <time.h>
+
+#ifdef CONFIG_SMP
+int aps_ready;
+int smp_started;
+int mp_ncpus;
+int smp_cpus = 1; /* how many cpu's running */
+void mpentry(void);
+uint8_t secondary_stacks[MAXCPU - 1][__PAGE_SIZE * 4];
+int cpu_possible_map[MAXCPU];
+static int cpu0 = -1;
+#endif
+
void *_libkvmplat_pagetable;
void *_libkvmplat_heap_start;
void *_libkvmplat_stack_top;
@@ -191,6 +214,160 @@ static void _libkvmplat_entry2(void *arg
__attribute__((unused)))
ukplat_entry_argp(NULL, (char *)cmdline, strlen(cmdline));
}
+static void _init_dtb_cpu(void)
+{
+ int fdt_cpu;
+ int naddr, nsize;
+ uint64_t core_id, index;
+ int subnode;
+ int i;
+
+ /* Init the cpu_possible_map */
+ for (i = 0; i < MAXCPU; i++)
+ cpu_possible_map[i] = -1;
+
+ /* Search for assigned VM cpus in DTB */
+ fdt_cpu = fdt_path_offset(_libkvmplat_dtb, "/cpus");
+ if (fdt_cpu < 0)
+ uk_pr_warn("cpus node is not found in device tree\n");
+
+ /* Get address,size cell */
+ naddr = fdt_address_cells(_libkvmplat_dtb, fdt_cpu);
+ if (naddr < 0 || naddr >= FDT_MAX_NCELLS) {
+ UK_CRASH("Could not find cpu address!\n");
+ return;
+ }
+ nsize = fdt_size_cells(_libkvmplat_dtb, fdt_cpu);
+ if (nsize < 0 || nsize >= FDT_MAX_NCELLS) {
+ UK_CRASH("Could not find cpu size!\n");
+ return;
+ }
+
+ /* Search all the cpu nodes in DTB */
+ index = 0;
+ fdt_for_each_subnode(subnode, _libkvmplat_dtb, fdt_cpu) {
+ const struct fdt_property *prop;
+ int prop_len = 0;
+
+ index++;
+
+ prop = fdt_get_property(_libkvmplat_dtb, subnode,
+ "enable-method", NULL);
+ if (!prop || strcmp(prop->data, "psci")) {
+ uk_pr_err("Only support psci method!(%s)\n",
+ prop->data);
+ return;
+ }
+
+ prop = fdt_get_property(_libkvmplat_dtb, subnode,
+ "device_type", &prop_len);
+ if (!prop)
+ continue;
+ if (prop_len < 4)
+ continue;
+ if (strcmp(prop->data, "cpu"))
+ continue;
+
+ prop = fdt_get_property(_libkvmplat_dtb, subnode,
+ "reg", &prop_len);
+ if (prop == NULL || prop_len <= 0) {
+ uk_pr_err("Error when searching reg property\n");
+ return;
+ }
+
+ core_id = fdt_reg_read_number((const fdt32_t *)prop->data,
+ naddr);
+ cpu_possible_map[index-1] = core_id;
+ mp_ncpus++;
+ }
+}
+
+void release_aps(void)
+{
+ int i, started;
+
+ /* Only release CPUs if they exist */
+ if (mp_ncpus == 1)
+ return;
+
+ //TODO: make aps_ready atomic
+ aps_ready = 1;
+
+ /* Wake up the other CPUs */
+ __asm __volatile(
+ "dsb ishst \n"
+ "sev \n"
+ ::: "memory");
+
+ uk_pr_info("Release APs...");
+
+ started = 0;
+ for (i = 0; i < 20000; i++) {
+ if (smp_started) {
+ uk_pr_info("done\n");
+ return;
+ }
+ /*
+ * Don't time out while we are making progress. Some large
+ * systems can take a while to start all CPUs.
+ */
+ if (smp_cpus > started) {
+ i = 0;
+ started = smp_cpus;
+ }
+
+ uk_pr_info("sleep for a while\n");
+ mdelay(1);
+ }
+
+ uk_pr_err("APs not started\n");
+}
+
+void init_secondary(uint64_t cpu)
+{
+ struct uk_sched *s = NULL;
+ struct uk_alloc *a = NULL;
+
+ uk_pr_info("init secondary cpu=%lu\n", cpu);
+
+ /* Spin until the BSP releases the APs */
+ while (!aps_ready)
+ __asm __volatile("wfe");
+ uk_pr_info("after wfe cpu=%lu\n", cpu);
+
+ smp_cpus += 1;
+
+ if (smp_cpus == mp_ncpus)
+ smp_started = 1;
+}
+
+void start_cpu(uint64_t target_cpu)
+{
+
+ uint32_t pa;
+ int err;
+
+ /* Check we are able to start this cpu */
+ UK_ASSERT(target_cpu < MAXCPU);
+
+ uk_pr_info("Starting CPU %lu\n", target_cpu);
+
+ /* We are already running on cpu 0 */
+ if (target_cpu == (uint64_t)cpu0)
+ return;
+
+ pa = ukplat_virt_to_phys(mpentry);
+ err = psci_cpu_on(target_cpu, pa);
+ if (err != PSCI_RET_SUCCESS) {
+ mp_ncpus--;
+
+ /* Notify the user that the CPU failed to start */
+ uk_pr_info("Failed to start CPU (%lx)\n", target_cpu);
+ }
+
+ uk_pr_info("Starting CPU %lu successfully\n", target_cpu);
+}
+
void _libkvmplat_start(void *dtb_pointer)
{
_init_dtb(dtb_pointer);
@@ -214,6 +391,17 @@ void _libkvmplat_start(void *dtb_pointer)
uk_pr_info(" heap start: %p\n", _libkvmplat_heap_start);
uk_pr_info(" stack top: %p\n", _libkvmplat_stack_top);
+ _init_dtb_cpu();
+
+ if (cpu0 < 0) {
+ uint64_t mpidr_reg = SYSREG_READ32(mpidr_el1);
+
+ uk_pr_info("get mpidr_el1 0x%lx\n", mpidr_reg);
+
+ if ((mpidr_reg & 0xff00fffffful) == 0)
+ cpu0 = 0;
+ }
+
/*
* Switch away from the bootstrap stack as early as possible.
*/
--
2.17.1
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |