[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 4/6] target-arm: add emulation of PSCI calls for
From: |
Rob Herring |
Subject: |
[Qemu-devel] [PATCH v2 4/6] target-arm: add emulation of PSCI calls for system emulation |
Date: |
Thu, 22 May 2014 21:30:07 -0500 |
From: Rob Herring <address@hidden>
Add support for handling PSCI calls in system emulation. Both version
0.1 and 0.2 of the PSCI spec are supported. Platforms can enable support
by setting "psci-method" QOM property on the cpus to SMC or HVC
emulation and having PSCI binding in their dtb.
Signed-off-by: Rob Herring <address@hidden>
---
v2:
- Add reference to PSCI spec
- Add target_cs instead of cs when doing operations on a different core.
- Move arm_cpu_do_hvc/smc contents from previous patch.
- Set context_id on both x0 and r0.
target-arm/Makefile.objs | 2 +-
target-arm/cpu-qom.h | 6 ++
target-arm/cpu.c | 1 +
target-arm/helper.c | 12 ++++
target-arm/kvm-consts.h | 6 ++
target-arm/psci.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 183 insertions(+), 1 deletion(-)
create mode 100644 target-arm/psci.c
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index dcd167e..50f6c43 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -1,5 +1,5 @@
obj-y += arm-semi.o
-obj-$(CONFIG_SOFTMMU) += machine.o
+obj-$(CONFIG_SOFTMMU) += machine.o psci.o
obj-$(CONFIG_KVM) += kvm.o
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index d2ff087..56999f1 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -105,6 +105,11 @@ typedef struct ARMCPU {
/* CPU currently in PSCI powered-off state */
bool powered_off;
+ /* PSCI emulation state
+ * 0 - disabled, 1 - smc, 2 - hvc
+ */
+ uint32_t psci_method;
+
/* [QEMU_]KVM_ARM_TARGET_* constant for this CPU, or
* QEMU_KVM_ARM_TARGET_NONE if the kernel doesn't support this CPU type.
*/
@@ -195,6 +200,7 @@ extern const struct VMStateDescription vmstate_arm_cpu;
void register_cp_regs_for_features(ARMCPU *cpu);
void init_cpreg_list(ARMCPU *cpu);
+bool arm_handle_psci(CPUState *cs);
bool arm_cpu_do_hvc(CPUState *cs);
bool arm_cpu_do_smc(CPUState *cs);
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index a0f9916..64f1157 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -1024,6 +1024,7 @@ static const ARMCPUInfo arm_cpus[] = {
static Property arm_cpu_properties[] = {
DEFINE_PROP_BOOL("start-powered-off", ARMCPU, start_powered_off, false),
+ DEFINE_PROP_UINT32("psci-method", ARMCPU, psci_method, 0),
DEFINE_PROP_UINT32("midr", ARMCPU, midr, 0),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 552e601..c1be201 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3257,11 +3257,23 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
bool arm_cpu_do_hvc(CPUState *cs)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ if (cpu->psci_method == QEMU_PSCI_METHOD_HVC) {
+ return arm_handle_psci(cs);
+ }
+
return false;
}
bool arm_cpu_do_smc(CPUState *cs)
{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ if (cpu->psci_method == QEMU_PSCI_METHOD_SMC) {
+ return arm_handle_psci(cs);
+ }
+
return false;
}
diff --git a/target-arm/kvm-consts.h b/target-arm/kvm-consts.h
index 6009a33..d25b9b8 100644
--- a/target-arm/kvm-consts.h
+++ b/target-arm/kvm-consts.h
@@ -50,6 +50,12 @@ MISMATCH_CHECK(PSCI_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
MISMATCH_CHECK(PSCI_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
MISMATCH_CHECK(PSCI_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
+enum {
+ QEMU_PSCI_METHOD_DISABLED = 0,
+ QEMU_PSCI_METHOD_SMC = 1,
+ QEMU_PSCI_METHOD_HVC = 2,
+};
+
/* Note that KVM uses overlapping values for AArch32 and AArch64
* target CPU numbers. AArch32 targets:
*/
diff --git a/target-arm/psci.c b/target-arm/psci.c
new file mode 100644
index 0000000..88af3f9
--- /dev/null
+++ b/target-arm/psci.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 - Linaro
+ * Author: Rob Herring <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <cpu.h>
+#include <cpu-qom.h>
+#include <kvm-consts.h>
+#include <sysemu/sysemu.h>
+#include <linux/psci.h>
+
+/*
+ * This function implements emulation of ARM Power State Coordination
+ * Interface (PSCI) version 0.2. Details of the PSCI functionality can be
+ * found at:
+ * http://infocenter.arm.com/help//topic/com.arm.doc.den0022b/index.html
+ */
+bool arm_handle_psci(CPUState *cs)
+{
+ CPUState *target_cs;
+ CPUClass *cc;
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ uint64_t param[4];
+ uint64_t context_id, mpidr;
+ target_ulong entry;
+ int32_t ret = 0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ /* Zero extending registers on 32-bit is okay for PSCI */
+ param[i] = is_a64(env) ? env->xregs[i] : env->regs[i];
+ }
+
+ if ((param[0] & PSCI_0_2_64BIT) && !is_a64(env)) {
+ ret = PSCI_RET_INVALID_PARAMS;
+ goto err;
+ }
+
+ switch (param[0]) {
+ case PSCI_0_2_FN_PSCI_VERSION:
+ ret = PSCI_VERSION_MAJOR(0) | PSCI_VERSION_MINOR(2);
+ break;
+ case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+ ret = PSCI_0_2_TOS_MP; /* No trusted OS */
+ break;
+ case PSCI_0_2_FN_AFFINITY_INFO:
+ case PSCI_0_2_FN64_AFFINITY_INFO:
+ mpidr = param[1];
+
+ switch (param[2]) {
+ case 0:
+ /* Get the target cpu */
+ target_cs = qemu_get_cpu(mpidr & 0xff);
+ if (!target_cs) {
+ ret = PSCI_RET_INVALID_PARAMS;
+ break;
+ }
+ cpu = ARM_CPU(target_cs);
+ ret = cpu->powered_off ? 1 : 0;
+ break;
+ default:
+ /* Everything above affinity level 0 is always on. */
+ ret = 0;
+ }
+ break;
+ case PSCI_0_2_FN_SYSTEM_RESET:
+ qemu_system_reset_request();
+ break;
+ case PSCI_0_2_FN_SYSTEM_OFF:
+ qemu_system_powerdown_request();
+ break;
+ case PSCI_FN_CPU_ON:
+ case PSCI_0_2_FN_CPU_ON:
+ case PSCI_0_2_FN64_CPU_ON:
+ mpidr = param[1];
+ entry = param[2];
+ context_id = param[3];
+
+ /* change to the cpu we are powering up */
+ target_cs = qemu_get_cpu(mpidr & 0xff);
+ if (!target_cs) {
+ ret = PSCI_RET_INVALID_PARAMS;
+ break;
+ }
+ cpu = ARM_CPU(target_cs);
+
+ if (!cpu->powered_off) {
+ ret = PSCI_RET_ALREADY_ON;
+ break;
+ }
+
+ /* Initialize the cpu we are turning on */
+ cpu_reset(target_cs);
+ cc = CPU_GET_CLASS(target_cs);
+ cc->set_pc(target_cs, entry);
+
+ cpu->powered_off = false;
+ target_cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+
+ /* Set the context_id in r0/x0 */
+ cpu->env.xregs[0] = cpu->env.regs[0] = context_id;
+
+ ret = 0;
+ break;
+ case PSCI_FN_CPU_OFF:
+ case PSCI_0_2_FN_CPU_OFF:
+ cpu->powered_off = true;
+ cs->exit_request = 1;
+ cs->halted = 1;
+
+ /* CPU_OFF should never return, but if it does return an error */
+ ret = PSCI_RET_DENIED;
+ break;
+ case PSCI_FN_CPU_SUSPEND:
+ case PSCI_0_2_FN_CPU_SUSPEND:
+ case PSCI_0_2_FN64_CPU_SUSPEND:
+ /* Affinity levels are not supported in QEMU */
+ if (param[1] & 0xfffe0000) {
+ ret = PSCI_RET_INVALID_PARAMS;
+ break;
+ }
+ /* Powerdown is not supported, we always go into WFI */
+ cs->halted = 1;
+ cs->exit_request = 1;
+
+ /* Return success when we wakeup */
+ ret = 0;
+ break;
+ case PSCI_FN_MIGRATE:
+ case PSCI_0_2_FN_MIGRATE:
+ ret = PSCI_RET_NOT_SUPPORTED;
+ break;
+ default:
+ return false;
+ }
+
+err:
+ if (is_a64(env)) {
+ env->xregs[0] = ret;
+ } else {
+ env->regs[0] = ret;
+ }
+ return true;
+}
--
1.9.1
- [Qemu-devel] [PATCH v2 0/6] ARM: add PSCI emulation support, Rob Herring, 2014/05/22
- [Qemu-devel] [PATCH v2 4/6] target-arm: add emulation of PSCI calls for system emulation,
Rob Herring <=
- [Qemu-devel] [PATCH v2 1/6] target-arm: don't set cpu do_interrupt handler for user mode emulation, Rob Herring, 2014/05/22
- [Qemu-devel] [PATCH v2 2/6] target-arm: add powered off cpu state, Rob Herring, 2014/05/22
- [Qemu-devel] [PATCH v2 3/6] target-arm: add hvc and smc exception emulation handling infrastructure, Rob Herring, 2014/05/22
- [Qemu-devel] [PATCH v2 5/6] arm/virt: enable PSCI emulation support for system emulation, Rob Herring, 2014/05/22
- [Qemu-devel] [PATCH v2 6/6] arm/highbank: enable PSCI emulation support, Rob Herring, 2014/05/22