]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
arm: minimal PSCI implementation
authorJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Wed, 25 Jun 2014 15:43:00 +0000 (16:43 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Fri, 19 Dec 2014 10:04:07 +0000 (11:04 +0100)
This is not the final thing: it can only be used internally for
suspending, resuming and parking CPUs while reconfiguring the cells.
Using this base, a trivial PSCI 0.2 emulation can be added by implementing
the appropriate trap hooks.

The mailbox in the per_cpu structure is used to store the address and
context where psci_cpu_off returns.
CPUs doing reconfiguration on the cells can use the psci_suspend and
psci_resume wrappers to store all affected cores.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/arm/Makefile
hypervisor/arch/arm/include/asm/percpu.h
hypervisor/arch/arm/include/asm/psci.h [new file with mode: 0644]
hypervisor/arch/arm/psci.c [new file with mode: 0644]
hypervisor/arch/arm/psci_low.S [new file with mode: 0644]
hypervisor/arch/arm/setup.c

index e733cf6d10f2b896ad567229eb29ac7c26afcc8e..3f356b20ce1ae8e3cc8484cd0abe71eb85e0c438 100644 (file)
@@ -18,6 +18,7 @@ always := built-in.o
 
 obj-y := entry.o dbg-write.o exception.o setup.o control.o lib.o traps.o
 obj-y += paging.o mmu_hyp.o mmu_cell.o
+obj-y += psci.o psci_low.o
 obj-y += irqchip.o
 obj-$(CONFIG_ARM_GIC_V3) += gic-v3.o
 obj-$(CONFIG_SERIAL_AMBA_PL011) += dbg-write-pl011.o
index 2f5506f33bf098b4a7486c63abd3c2c72c347ab5..5f9580e11b693303b83ea9e069f15f3169ba6a1b 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/cell.h>
+#include <asm/psci.h>
 #include <asm/spinlock.h>
 #include <asm/sysregs.h>
 
@@ -54,6 +55,9 @@ struct per_cpu {
 
        bool initialized;
 
+       /* The mbox will be accessed with a ldrd, which requires alignment */
+       __attribute__((aligned(8))) struct psci_mbox psci_mbox;
+
        bool flush_caches;
        bool shutdown_cpu;
        int shutdown_state;
diff --git a/hypervisor/arch/arm/include/asm/psci.h b/hypervisor/arch/arm/include/asm/psci.h
new file mode 100644 (file)
index 0000000..1883a6d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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_PSCI_H
+#define _JAILHOUSE_ASM_PSCI_H
+
+#define PSCI_VERSION                   0x84000000
+#define PSCI_CPU_SUSPEND_32            0x84000001
+#define PSCI_CPU_SUSPEND_64            0xc4000001
+#define PSCI_CPU_OFF                   0x84000002
+#define PSCI_CPU_ON_32                 0x84000003
+#define PSCI_CPU_ON_64                 0xc4000003
+#define PSCI_AFFINITY_INFO_32          0x84000004
+#define PSCI_AFFINITY_INFO_64          0xc4000004
+#define PSCI_MIGRATE_32                        0x84000005
+#define PSCI_MIGRATE_64                        0xc4000005
+#define PSCI_MIGRATE_INFO_TYPE         0x84000006
+#define PSCI_MIGRATE_INFO_UP_CPU_32    0x84000007
+#define PSCI_MIGRATE_INFO_UP_CPU_64    0xc4000007
+#define PSCI_SYSTEM_OFF                        0x84000008
+#define PSCI_SYSTEM_RESET              0x84000009
+
+#define PSCI_SUCCESS           0
+#define PSCI_NOT_SUPPORTED     (-1)
+#define PSCI_INVALID_PARAMETERS        (-2)
+#define PSCI_DENIED            (-3)
+#define PSCI_ALREADY_ON                (-4)
+#define PSCI_ON_PENDING                (-5)
+#define PSCI_INTERNAL_FAILURE  (-6)
+#define PSCI_NOT_PRESENT       (-7)
+#define PSCI_DISABLED          (-8)
+
+#define PSCI_INVALID_ADDRESS   0xffffffff
+
+#ifndef __ASSEMBLY__
+
+struct trap_context;
+struct per_cpu;
+struct psci_mbox {
+       unsigned long entry;
+       unsigned long context;
+};
+
+void psci_cpu_off(struct per_cpu *cpu_data);
+long psci_cpu_on(unsigned int target, unsigned long entry,
+                unsigned long context);
+bool psci_cpu_stopped(unsigned int cpu_id);
+int psci_wait_cpu_stopped(unsigned int cpu_id);
+
+void psci_suspend(struct per_cpu *cpu_data);
+long psci_resume(unsigned int target);
+long psci_try_resume(unsigned int cpu_id);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _JAILHOUSE_ASM_PSCI_H */
diff --git a/hypervisor/arch/arm/psci.c b/hypervisor/arch/arm/psci.c
new file mode 100644 (file)
index 0000000..132d6a0
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 <asm/control.h>
+#include <asm/psci.h>
+#include <asm/traps.h>
+
+void _psci_cpu_off(struct psci_mbox *);
+long _psci_cpu_on(struct psci_mbox *, unsigned long, unsigned long);
+void _psci_suspend(struct psci_mbox *, unsigned long *address);
+void _psci_suspend_return(void);
+
+void psci_cpu_off(struct per_cpu *cpu_data)
+{
+       _psci_cpu_off(&cpu_data->psci_mbox);
+}
+
+long psci_cpu_on(unsigned int target, unsigned long entry,
+                       unsigned long context)
+{
+       struct per_cpu *cpu_data = per_cpu(target);
+       struct psci_mbox *mbox = &cpu_data->psci_mbox;
+
+       return _psci_cpu_on(mbox, entry, context);
+}
+
+/*
+ * Not a real psci_cpu_suspend implementation. Only used to semantically
+ * differentiate from `cpu_off'. Return is done via psci_resume.
+ */
+void psci_suspend(struct per_cpu *cpu_data)
+{
+       psci_cpu_off(cpu_data);
+}
+
+long psci_resume(unsigned int target)
+{
+       psci_wait_cpu_stopped(target);
+       return psci_cpu_on(target, (unsigned long)&_psci_suspend_return, 0);
+}
+
+bool psci_cpu_stopped(unsigned int cpu_id)
+{
+       return per_cpu(cpu_id)->psci_mbox.entry == PSCI_INVALID_ADDRESS;
+}
+
+long psci_try_resume(unsigned int cpu_id)
+{
+       if (psci_cpu_stopped(cpu_id))
+               return psci_resume(cpu_id);
+
+       return -EBUSY;
+}
+
+int psci_wait_cpu_stopped(unsigned int cpu_id)
+{
+       /* FIXME: add a delay */
+       do {
+               if (psci_cpu_stopped(cpu_id))
+                       return 0;
+               cpu_relax();
+       } while (1);
+
+       return -EBUSY;
+}
diff --git a/hypervisor/arch/arm/psci_low.S b/hypervisor/arch/arm/psci_low.S
new file mode 100644 (file)
index 0000000..76eeaba
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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 <asm/head.h>
+#include <asm/psci.h>
+
+       .global _psci_cpu_off
+       /* r0: struct psci_mbox* */
+_psci_cpu_off:
+       ldr     r2, =PSCI_INVALID_ADDRESS
+       /* Clear mbox */
+       str     r2, [r0]
+       /*
+        * No reordering against the ldr below for the PEs in our domain, so no
+        * need for a barrier. Other CPUs will wait for an invalid address
+        * before issuing a CPU_ON.
+        */
+
+       /* Wait for a CPU_ON call that updates the mbox */
+1:     wfe
+       ldr     r1, [r0]
+       cmp     r1, r2
+       beq     1b
+
+       /* Jump to the requested entry, with a parameter */
+       ldr     r0, [r0, #4]
+       bx      r1
+
+       .global _psci_cpu_on
+       /* r0: struct psci_mbox*, r1: entry, r2: context */
+_psci_cpu_on:
+       push    {r4, r5, lr}
+       /* strd needs to start with an even register */
+       mov     r3, r2
+       mov     r2, r1
+       ldr     r1, =PSCI_INVALID_ADDRESS
+
+       ldrexd  r4, r5, [r0]
+       cmp     r4, r1
+       bne     store_failed
+       strexd  r1, r2, r3, [r0]
+       /* r1 contains the ex store flag */
+       cmp     r1, #0
+       bne     store_failed
+
+       /*
+        * Ensure that the stopped CPU can read the new address when receiving
+        * the event.
+        */
+       dsb     ish
+       sev
+       mov     r0, #0
+       pop     {r4, r5, pc}
+
+store_failed:
+       clrex
+       mov     r0, #PSCI_ALREADY_ON
+       pop     {r4, r5, pc}
+
+       .global _psci_suspend_return
+_psci_suspend_return:
+       bx      lr
index 2b9b6758fa95a348221f48c9ab8c75eddf59314f..e614e007e8e859e899e3a2322d1f413e1f5c6a20 100644 (file)
@@ -53,6 +53,8 @@ int arch_cpu_init(struct per_cpu *cpu_data)
        int err = 0;
        unsigned long hcr = HCR_VM_BIT | HCR_IMO_BIT | HCR_FMO_BIT;
 
+       cpu_data->psci_mbox.entry = 0;
+
        /*
         * Copy the registers to restore from the linux stack here, because we
         * won't be able to access it later