[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 |