obj-y := entry.o dbg-write.o exception.o setup.o control.o lib.o
obj-y += traps.o mmio.o
obj-y += paging.o mmu_hyp.o mmu_cell.o caches.o
-obj-y += psci.o psci_low.o spin.o
+obj-y += psci.o psci_low.o smp.o
obj-y += irqchip.o gic-common.o
obj-$(CONFIG_ARM_GIC_V3) += gic-v3.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += dbg-write-pl011.o
+obj-$(CONFIG_ARCH_VEXPRESS) += smp-vexpress.o
if (err)
printk("IRQ setup failed\n");
- if (cpu_data->cell == &root_cell)
- /* Wait for the driver to call cpu_up */
- reset_address = arch_cpu_spin();
+ /* Wait for the driver to call cpu_up */
+ if (cell == &root_cell)
+ reset_address = arch_smp_spin(cpu_data, root_cell.arch.smp);
else
- reset_address = 0;
+ reset_address = arch_smp_spin(cpu_data, cell->arch.smp);
/* Set the new MPIDR */
arm_write_sysreg(VMPIDR_EL2, cpu_data->virt_id | MPIDR_MP_BIT);
irqchip_cell_init(cell);
irqchip_root_cell_shrink(cell);
+ register_smp_ops(cell);
+
return 0;
}
#define _JAILHOUSE_ASM_CELL_H
#include <jailhouse/types.h>
+#include <asm/smp.h>
#include <asm/spinlock.h>
#ifndef __ASSEMBLY__
struct arch_cell {
struct paging_structures mm;
+ struct smp_ops *smp;
spinlock_t caches_lock;
bool needs_flush;
int arch_mmu_cpu_cell_init(struct per_cpu *cpu_data);
void arch_handle_sgi(struct per_cpu *cpu_data, u32 irqn);
void arch_handle_trap(struct per_cpu *cpu_data, struct registers *guest_regs);
-int arch_spin_init(void);
-unsigned long arch_cpu_spin(void);
struct registers* arch_handle_exit(struct per_cpu *cpu_data,
struct registers *regs);
void arch_reset_self(struct per_cpu *cpu_data);
# endif /* GIC */
# define MAINTENANCE_IRQ 25
-# define HOTPLUG_MBOX ((void *)0x1c010030)
+# define SYSREGS_BASE 0x1c010000
#endif /* CONFIG_ARCH_VEXPRESS */
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) ARM Limited, 2014
+ *
+ * Authors:
+ * Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef JAILHOUSE_ASM_SMP_H_
+#define JAILHOUSE_ASM_SMP_H_
+
+#ifndef __ASSEMBLY__
+
+enum smp_type {
+ SMP_PSCI,
+ SMP_SPIN
+};
+
+struct mmio_access;
+struct per_cpu;
+struct cell;
+
+struct smp_ops {
+ enum smp_type type;
+ int (*init)(struct cell *cell);
+
+ /*
+ * Uses the MMIO trap interface:
+ * returns TRAP_HANDLED when the mailbox is targeted, or else
+ * TRAP_UNHANDLED.
+ */
+ int (*mmio_handler)(struct per_cpu *cpu_data,
+ struct mmio_access *access);
+ /* Returns an address */
+ unsigned long (*cpu_spin)(struct per_cpu *cpu_data);
+};
+
+int arch_generic_smp_init(unsigned long mbox);
+int arch_generic_smp_mmio(struct per_cpu *cpu_data, struct mmio_access *access,
+ unsigned long mbox);
+unsigned long arch_generic_smp_spin(unsigned long mbox);
+
+int arch_smp_mmio_access(struct per_cpu *cpu_data, struct mmio_access *access);
+unsigned long arch_smp_spin(struct per_cpu *cpu_data, struct smp_ops *ops);
+void register_smp_ops(struct cell *cell);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* !JAILHOUSE_ASM_SMP_H_ */
#include <jailhouse/mmio.h>
#include <asm/irqchip.h>
#include <asm/processor.h>
+#include <asm/smp.h>
#include <asm/traps.h>
/* Taken from the ARM ARM pseudocode for taking a data abort */
access.size = size;
ret = irqchip_mmio_access(cpu_data, &access);
+ if (ret == TRAP_UNHANDLED)
+ ret = arch_smp_mmio_access(cpu_data, &access);
if (ret == TRAP_HANDLED) {
/* Put the read value into the dest register */
/* Setup guest traps */
arm_write_sysreg(HCR, hcr);
- err = arch_spin_init();
- if (err)
- return err;
-
err = arch_mmu_cpu_cell_init(cpu_data);
if (err)
return err;
int arch_init_late(void)
{
+ int err;
+
/* Setup the SPI bitmap */
irqchip_cell_init(&root_cell);
+ /* Platform-specific SMP operations */
+ register_smp_ops(&root_cell);
+
+ err = root_cell.arch.smp->init(&root_cell);
+ if (err)
+ return err;
+
return map_root_memory_regions();
}
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) ARM Limited, 2014
+ *
+ * Authors:
+ * Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <jailhouse/processor.h>
+#include <asm/control.h>
+#include <asm/irqchip.h>
+#include <asm/paging.h>
+#include <asm/platform.h>
+#include <asm/smp.h>
+
+static unsigned long hotplug_mbox;
+
+static int smp_init(struct cell *cell)
+{
+ /* vexpress SYSFLAGS */
+ hotplug_mbox = SYSREGS_BASE + 0x30;
+
+ /* Map the mailbox page */
+ arch_generic_smp_init(hotplug_mbox);
+
+ return 0;
+}
+
+static unsigned long smp_spin(struct per_cpu *cpu_data)
+{
+ return arch_generic_smp_spin(hotplug_mbox);
+}
+
+static int smp_mmio(struct per_cpu *cpu_data, struct mmio_access *access)
+{
+ return arch_generic_smp_mmio(cpu_data, access, hotplug_mbox);
+}
+
+static struct smp_ops vexpress_smp_ops = {
+ .type = SMP_SPIN,
+ .init = smp_init,
+ .mmio_handler = smp_mmio,
+ .cpu_spin = smp_spin,
+};
+
+/*
+ * Store the guest's secondaries into our PSCI, and wake them up when we catch
+ * an access to the mbox from the primary.
+ */
+static struct smp_ops vexpress_guest_smp_ops = {
+ .type = SMP_SPIN,
+ .init = psci_cell_init,
+ .mmio_handler = smp_mmio,
+ .cpu_spin = psci_emulate_spin,
+};
+
+void register_smp_ops(struct cell *cell)
+{
+ /*
+ * mach-vexpress only writes the SYS_FLAGS once at boot, so the root
+ * cell cannot rely on this write to guess where the secondary CPUs
+ * should return.
+ */
+ if (cell == &root_cell)
+ cell->arch.smp = &vexpress_smp_ops;
+ else
+ cell->arch.smp = &vexpress_guest_smp_ops;
+}
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) ARM Limited, 2014
+ *
+ * Authors:
+ * Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <jailhouse/control.h>
+#include <jailhouse/mmio.h>
+#include <jailhouse/printk.h>
+#include <asm/control.h>
+#include <asm/psci.h>
+#include <asm/setup.h>
+#include <asm/smp.h>
+#include <asm/traps.h>
+
+int arch_generic_smp_init(unsigned long mbox)
+{
+ void *mbox_page = (void *)(mbox & PAGE_MASK);
+ int err = arch_map_device(mbox_page, mbox_page, PAGE_SIZE);
+
+ if (err)
+ printk("Unable to map spin mbox page\n");
+
+ return err;
+}
+
+unsigned long arch_generic_smp_spin(unsigned long mbox)
+{
+ /*
+ * This is super-dodgy: we assume nothing wrote to the flag register
+ * since the kernel called smp_prepare_cpus, at initialisation.
+ */
+ return mmio_read32((void *)mbox);
+}
+
+int arch_generic_smp_mmio(struct per_cpu *cpu_data, struct mmio_access *access,
+ unsigned long mbox)
+{
+ unsigned int cpu;
+ unsigned long mbox_page = mbox & PAGE_MASK;
+
+ if (access->addr < mbox_page || access->addr >= mbox_page + PAGE_SIZE)
+ return TRAP_UNHANDLED;
+
+ if (access->addr != mbox || !access->is_write)
+ /* Ignore all other accesses */
+ return TRAP_HANDLED;
+
+ for_each_cpu_except(cpu, cpu_data->cell->cpu_set, cpu_data->cpu_id) {
+ per_cpu(cpu)->guest_mbox.entry = access->val;
+ psci_try_resume(cpu);
+ }
+
+ return TRAP_HANDLED;
+}
+
+unsigned long arch_smp_spin(struct per_cpu *cpu_data, struct smp_ops *ops)
+{
+ /*
+ * Hotplugging CPU0 is not currently supported. It is always assumed to
+ * be the primary CPU. This is consistent with the linux behavior on
+ * most platforms.
+ * The guest image always starts at virtual address 0.
+ */
+ if (cpu_data->virt_id == 0)
+ return 0;
+
+ return ops->cpu_spin(cpu_data);
+}
+
+int arch_smp_mmio_access(struct per_cpu *cpu_data, struct mmio_access *access)
+{
+ struct smp_ops *smp_ops = cpu_data->cell->arch.smp;
+
+ if (smp_ops->mmio_handler)
+ return smp_ops->mmio_handler(cpu_data, access);
+
+ return TRAP_UNHANDLED;
+}
+++ /dev/null
-/*
- * Jailhouse, a Linux-based partitioning hypervisor
- *
- * Copyright (c) ARM Limited, 2014
- *
- * Authors:
- * Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-#include <jailhouse/mmio.h>
-#include <jailhouse/printk.h>
-#include <asm/platform.h>
-#include <asm/setup.h>
-#include <asm/control.h>
-
-#if HOTPLUG_SPIN == 1
-int arch_spin_init(void)
-{
- unsigned long mbox = (unsigned long)HOTPLUG_MBOX;
- void *mbox_page = (void *)(mbox & PAGE_MASK);
- int err = arch_map_device(mbox_page, mbox_page, PAGE_SIZE);
-
- if (err)
- printk("Unable to map spin mbox page\n");
-
- return err;
-}
-
-
-unsigned long arch_cpu_spin(void)
-{
- u32 address;
-
- /*
- * This is super-dodgy: we assume nothing wrote to the flag register
- * since the kernel called smp_prepare_cpus, at initialisation.
- */
- do {
- wfe();
- address = mmio_read32((void *)HOTPLUG_MBOX);
- cpu_relax();
- } while (address == 0);
-
- return address;
-}
-
-#elif HOTPLUG_PSCI == 1
-int arch_spin_init(void)
-{
-}
-
-unsigned long arch_cpu_spin(void)
-{
- /* FIXME: wait for a PSCI hvc */
-}
-#endif