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
#ifndef __ASSEMBLY__
#include <asm/cell.h>
+#include <asm/psci.h>
#include <asm/spinlock.h>
#include <asm/sysregs.h>
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;
--- /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_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 */
--- /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 <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;
+}
--- /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 <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
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