|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 2/2] xen/arm : emulation of arm's PSCI v0.2 standard
Arm based virtual machines dom0/guest will request power related functionality
from xen through PSCI interface. This patch implements version 0.2 of
PSCI standard specified by arm for 64bit and 32 bit arm machines.
- modified arm_psci_fn_t to take three arguments
- implemented psci_cpu_on with additional error conditions
- removed switch-case in do_trap_psci function
- added PSCI v0.2 macros in psci.h
- added seperate tables for PSCI v0.1 and v0.2
- implemented affinity_info
Signed-off-by: Parth Dixit <parth.dixit@xxxxxxxxxx>
---
Changelog v3
- moved wfi helper to seperate patch
- replaced new wfi function in traps.c
- removed defining power_state variable using value directly
- added new line between declaration
- merged PSCI v0.1 and v0.2 cpu_on function to avoid duplication
- removed spurious change
- renamed PSCI return values to reflect v0.2 moved them to top
- removed PSCI v0.1 version declaration for now, will introduce it when needed
- removed hard tabs in the code lifted from linux
- removed PSCI_0_1_MAX
- did not retained copyright header from linux as most of functions are removed
- added two function tables for PSCI v0.1 and PSCI v0.2
- added compatibility string to libxl_arm to expose new functionality
- refactored affinity_info code
- added table for masking function
- removed definitions of unused PSCI v0.2 functions
- removed function id's of unused PSCI v0.2 functions
- renamed constant PSCI_0_2_TOS_MP ( multicore aware) as per spec
tools/libxl/libxl_arm.c | 2 +-
xen/arch/arm/domain.c | 2 +
xen/arch/arm/domain_build.c | 5 +-
xen/arch/arm/traps.c | 45 +++++++++++--
xen/arch/arm/vpsci.c | 138 +++++++++++++++++++++++++++++++++++++---
xen/include/asm-arm/domain.h | 3 +
xen/include/asm-arm/processor.h | 3 +
xen/include/asm-arm/psci.h | 45 +++++++++++--
8 files changed, 222 insertions(+), 21 deletions(-)
diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index 4f0f0e2..e8bcd05 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -237,7 +237,7 @@ static int make_psci_node(libxl__gc *gc, void *fdt)
res = fdt_begin_node(fdt, "psci");
if (res) return res;
- res = fdt_property_compat(gc, fdt, 1, "arm,psci");
+ res = fdt_property_compat(gc, fdt, 2, "arm,psci-0.2","arm,psci");
if (res) return res;
res = fdt_property_string(fdt, "method", "hvc");
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index bc5e56d..f19cc1d 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -504,6 +504,8 @@ int arch_domain_create(struct domain *d, unsigned int
domcr_flags)
/* Default the virtual ID to match the physical */
d->arch.vpidr = boot_cpu_data.midr.bits;
+ d->arch.vpsci_ver = 0;
+
clear_page(d->shared_info);
share_xen_page_with_guest(
virt_to_page(d->shared_info), d, XENSHARE_writable);
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c424793..ebd4170 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -388,6 +388,9 @@ static int make_hypervisor_node(struct domain *d,
static int make_psci_node(void *fdt, const struct dt_device_node *parent)
{
int res;
+ const char compat[] =
+ "arm,psci-0.2""\0"
+ "arm,psci";
DPRINT("Create PSCI node\n");
@@ -396,7 +399,7 @@ static int make_psci_node(void *fdt, const struct
dt_device_node *parent)
if ( res )
return res;
- res = fdt_property_string(fdt, "compatible", "arm,psci");
+ res = fdt_property(fdt, "compatible", compat, sizeof(compat));
if ( res )
return res;
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 8d2e308..b441e51 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1030,7 +1030,7 @@ static arm_hypercall_t arm_hypercall_table[] = {
HYPERCALL_ARM(vcpu_op, 3),
};
-typedef int (*arm_psci_fn_t)(uint32_t, register_t);
+typedef int (*arm_psci_fn_t)(register_t, register_t, register_t);
typedef struct {
arm_psci_fn_t fn;
@@ -1043,11 +1043,30 @@ typedef struct {
.nr_args = _nr_args, \
}
+#define PSCI_0_2(_name, _nr_args) \
+ { \
+ .fn = (arm_psci_fn_t) &do_psci_0_2_ ## _name, \
+ .nr_args = _nr_args, \
+ }
+
static arm_psci_t arm_psci_table[] = {
PSCI(cpu_off, 1),
PSCI(cpu_on, 2),
};
+static arm_psci_t arm_psci_0_2_table[] = {
+ PSCI_0_2(version, 0),
+ PSCI_0_2(cpu_suspend, 3),
+ PSCI_0_2(cpu_off, 0),
+ PSCI_0_2(cpu_on, 3),
+ PSCI_0_2(affinity_info, 2),
+ PSCI_0_2(migrate, 1),
+ PSCI_0_2(migrate_info_type, 0),
+ PSCI_0_2(migrate_info_up_cpu, 0),
+ PSCI_0_2(system_off, 0),
+ PSCI_0_2(system_reset, 0),
+};
+
#ifndef NDEBUG
static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
{
@@ -1082,24 +1101,36 @@ static void do_debug_trap(struct cpu_user_regs *regs,
unsigned int code)
#ifdef CONFIG_ARM_64
#define PSCI_OP_REG(r) (r)->x0
#define PSCI_RESULT_REG(r) (r)->x0
-#define PSCI_ARGS(r) (r)->x1, (r)->x2
+#define PSCI_ARGS(r) (r)->x1, (r)->x2, (r)->x3
#else
#define PSCI_OP_REG(r) (r)->r0
#define PSCI_RESULT_REG(r) (r)->r0
-#define PSCI_ARGS(r) (r)->r1, (r)->r2
+#define PSCI_ARGS(r) (r)->r1, (r)->r2, (r)->r3
#endif
static void do_trap_psci(struct cpu_user_regs *regs)
{
arm_psci_fn_t psci_call = NULL;
- if ( PSCI_OP_REG(regs) >= ARRAY_SIZE(arm_psci_table) )
+ if ( PSCI_OP_REG(regs) < PSCI_migrate )
{
- domain_crash_synchronous();
- return;
+ if ( PSCI_OP_REG(regs) >= ARRAY_SIZE(arm_psci_table) )
+ {
+ domain_crash_synchronous();
+ return;
+ }
+ psci_call = arm_psci_table[PSCI_OP_REG(regs)].fn;
+ }
+ else
+ {
+ if ( ( PSCI_OP_REG(regs) & PSCI_FN_MASK ) >=
ARRAY_SIZE(arm_psci_0_2_table) )
+ {
+ domain_crash_synchronous();
+ return;
+ }
+ psci_call = arm_psci_0_2_table[ ( PSCI_OP_REG(regs) & PSCI_FN_MASK )
].fn;
}
- psci_call = arm_psci_table[PSCI_OP_REG(regs)].fn;
if ( psci_call == NULL )
{
domain_crash_synchronous();
diff --git a/xen/arch/arm/vpsci.c b/xen/arch/arm/vpsci.c
index 1ceb8cb..859bb7e 100644
--- a/xen/arch/arm/vpsci.c
+++ b/xen/arch/arm/vpsci.c
@@ -17,24 +17,85 @@
#include <asm/current.h>
#include <asm/gic.h>
#include <asm/psci.h>
+#include <public/sched.h>
+#include <asm-arm/event.h>
int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
{
+ return do_psci_0_2_cpu_on(vcpuid,entry_point,0);
+}
+
+int do_psci_cpu_off(uint32_t power_state)
+{
+ struct vcpu *v = current;
+ if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
+ vcpu_sleep_nosync(v);
+ return PSCI_SUCCESS;
+}
+
+int do_psci_0_2_version(void)
+{
+ struct domain *d = current->domain;
+
+ return ( d->arch.vpsci_ver = XEN_PSCI_V_0_2 );
+}
+
+int do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point,
+ register_t context_id)
+{
+ struct vcpu *v = current;
+ struct domain *d = v->domain;
+ struct cpu_user_regs *regs = &v->arch.cpu_info->guest_cpu_user_regs;
+
+ if ( is_32bit_domain(d) )
+ {
+ regs->pc32 = entry_point;
+ regs->r0 = context_id;
+ }
+#ifdef CONFIG_ARM_64
+ else
+ {
+ regs->pc = entry_point;
+ regs->x0 = context_id;
+ }
+#endif
+ vcpu_block_event(v);
+ return PSCI_SUCCESS;
+}
+
+int do_psci_0_2_cpu_off(void)
+{
+ return do_psci_cpu_off(0);
+}
+
+int do_psci_0_2_cpu_on(register_t target_cpu, register_t entry_point,
+ register_t context_id)
+{
struct vcpu *v;
struct domain *d = current->domain;
struct vcpu_guest_context *ctxt;
int rc;
int is_thumb = entry_point & 1;
+ uint32_t vcpuid ;
+
+ if( d->arch.vpsci_ver == XEN_PSCI_V_0_2 )
+ vcpuid = (u32)(target_cpu & MPIDR_HWID_MASK);
+ else
+ vcpuid = target_cpu;
if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
- return PSCI_EINVAL;
+ return PSCI_INVALID_PARAMETERS;
if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
- return PSCI_EINVAL;
+ return PSCI_INVALID_PARAMETERS;
/* THUMB set is not allowed with 64-bit domain */
if ( is_64bit_domain(d) && is_thumb )
- return PSCI_EINVAL;
+ return PSCI_INVALID_PARAMETERS;
+
+ if( ( d->arch.vpsci_ver == XEN_PSCI_V_0_2 ) &&
+ ( !test_bit(_VPF_down, &v->pause_flags) ) )
+ return PSCI_ALREADY_ON;
if ( (ctxt = alloc_vcpu_guest_context()) == NULL )
return PSCI_DENIED;
@@ -48,10 +109,18 @@ int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
ctxt->ttbr1 = 0;
ctxt->ttbcr = 0; /* Defined Reset Value */
if ( is_32bit_domain(d) )
+ {
ctxt->user_regs.cpsr = PSR_GUEST32_INIT;
+ if( d->arch.vpsci_ver == XEN_PSCI_V_0_2 )
+ ctxt->user_regs.r0_usr = context_id;
+ }
#ifdef CONFIG_ARM_64
else
+ {
ctxt->user_regs.cpsr = PSR_GUEST64_INIT;
+ if( d->arch.vpsci_ver == XEN_PSCI_V_0_2 )
+ ctxt->user_regs.x0 = context_id;
+ }
#endif
/* Start the VCPU with THUMB set if it's requested by the kernel */
@@ -75,12 +144,65 @@ int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
return PSCI_SUCCESS;
}
-int do_psci_cpu_off(uint32_t power_state)
+static const unsigned long target_affinity_mask[] = {
+ ( MPIDR_HWID_MASK & AFFINITY_MASK( 0 ) ),
+ ( MPIDR_HWID_MASK & AFFINITY_MASK( 1 ) ),
+ ( MPIDR_HWID_MASK & AFFINITY_MASK( 2 ) )
+#ifdef CONFIG_ARM_64
+ ,( MPIDR_HWID_MASK & AFFINITY_MASK( 3 ) )
+#endif
+};
+
+int do_psci_0_2_affinity_info(register_t target_affinity,
+ uint32_t lowest_affinity_level)
{
- struct vcpu *v = current;
- if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
- vcpu_sleep_nosync(v);
- return PSCI_SUCCESS;
+ struct domain *d = current->domain;
+ struct vcpu *v;
+ uint32_t vcpuid;
+
+ if ( lowest_affinity_level < ARRAY_SIZE(target_affinity_mask) )
+ target_affinity &= target_affinity_mask[lowest_affinity_level];
+ else
+ return PSCI_INVALID_PARAMETERS;
+
+ for ( vcpuid = 0; vcpuid < d->max_vcpus; vcpuid++ )
+ {
+ v = d->vcpu[vcpuid];
+
+ if ( ( ( v->arch.vmpidr & target_affinity_mask[lowest_affinity_level] )
+ == target_affinity )
+ && ( !test_bit(_VPF_down, &v->pause_flags) ) )
+ return PSCI_0_2_AFFINITY_LEVEL_ON;
+ }
+
+ return PSCI_0_2_AFFINITY_LEVEL_OFF;
+}
+
+int do_psci_0_2_migrate(uint32_t target_cpu)
+{
+ return PSCI_NOT_SUPPORTED;
+}
+
+int do_psci_0_2_migrate_info_type(void)
+{
+ return PSCI_0_2_TOS_MP_OR_NOT_PRESENT;
+}
+
+register_t do_psci_0_2_migrate_info_up_cpu(void)
+{
+ return PSCI_NOT_SUPPORTED;
+}
+
+void do_psci_0_2_system_off( void )
+{
+ struct domain *d = current->domain;
+ domain_shutdown(d,SHUTDOWN_poweroff);
+}
+
+void do_psci_0_2_system_reset(void)
+{
+ struct domain *d = current->domain;
+ domain_shutdown(d,SHUTDOWN_reboot);
}
/*
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index b296923..53dbe27 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -124,6 +124,9 @@ struct arch_domain
/* Virtual CPUID */
uint32_t vpidr;
+ /* PSCI version */
+ uint32_t vpsci_ver;
+
struct {
uint64_t offset;
} phys_timer_base;
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 9267c1b..8a237c4 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -16,6 +16,9 @@
#define MPIDR_AFF0_MASK (_AC(0xff,U) << MPIDR_AFF0_SHIFT)
#define MPIDR_HWID_MASK _AC(0xffffff,U)
#define MPIDR_INVALID (~MPIDR_HWID_MASK)
+#define MPIDR_LEVEL_BITS (8)
+#define AFFINITY_MASK(level) ~((_AC(0x1,U) << ((level) * MPIDR_LEVEL_BITS))
- 1)
+
/* TTBCR Translation Table Base Control Register */
#define TTBCR_EAE _AC(0x80000000,U)
diff --git a/xen/include/asm-arm/psci.h b/xen/include/asm-arm/psci.h
index 189964b..e8d870f 100644
--- a/xen/include/asm-arm/psci.h
+++ b/xen/include/asm-arm/psci.h
@@ -1,10 +1,16 @@
#ifndef __ASM_PSCI_H__
#define __ASM_PSCI_H__
-#define PSCI_SUCCESS 0
-#define PSCI_ENOSYS -1
-#define PSCI_EINVAL -2
-#define PSCI_DENIED -3
+/* PSCI return values (inclusive of all PSCI versions) */
+#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
/* availability of PSCI on the host for SMP bringup */
extern bool_t psci_available;
@@ -18,6 +24,37 @@ int do_psci_cpu_off(uint32_t power_state);
int do_psci_cpu_suspend(uint32_t power_state, register_t entry_point);
int do_psci_migrate(uint32_t vcpuid);
+/* PSCI 0.2 functions to handle guest PSCI requests */
+int do_psci_0_2_version(void);
+int do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point,
+ register_t context_id);
+int do_psci_0_2_cpu_off(void);
+int do_psci_0_2_cpu_on(register_t target_cpu, register_t entry_point,
+ register_t context_id);
+int do_psci_0_2_affinity_info(register_t target_affinity,
+ uint32_t lowest_affinity_level);
+int do_psci_0_2_migrate(uint32_t target_cpu);
+int do_psci_0_2_migrate_info_type(void);
+register_t do_psci_0_2_migrate_info_up_cpu(void);
+void do_psci_0_2_system_off(void);
+void do_psci_0_2_system_reset(void);
+
+/* PSCI version */
+#define XEN_PSCI_V_0_2 2
+
+/* PSCI v0.2 xen mapping mask */
+#define PSCI_FN_MASK 0x0000000F
+
+/* PSCI v0.2 affinity level state returned by AFFINITY_INFO */
+#define PSCI_0_2_AFFINITY_LEVEL_ON 0
+#define PSCI_0_2_AFFINITY_LEVEL_OFF 1
+#define PSCI_0_2_AFFINITY_LEVEL_ON_PENDING 2
+
+/* PSCI v0.2 multicore support in Trusted OS returned by MIGRATE_INFO_TYPE */
+#define PSCI_0_2_TOS_UP_MIGRATE_CAPABLE 0
+#define PSCI_0_2_TOS_UP_NOT_MIGRATE_CAPABLE 1
+#define PSCI_0_2_TOS_MP_OR_NOT_PRESENT 2
+
#endif /* __ASM_PSCI_H__ */
/*
--
1.9.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |