[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.