@@ -42,6 +42,14 @@
#define XEN_SMCCC_MINOR_REVISION 1
#define XEN_SMCCC_FUNCTION_COUNT 3
+#define SSC_SMCCC_UID ARM_SMCCC_UID(0xf863386f, 0x4b39, 0x4cbd, \
+ 0x92, 0x20, 0xce, 0x16, \
+ 0x41, 0xe5, 0x9f, 0x6f)
+
+#define SSC_SMCCC_MAJOR_REVISION 0
+#define SSC_SMCCC_MINOR_REVISION 1
+#define SSC_SMCCC_FUNCTION_COUNT 13
+
/* SMCCC interface for hypervisor. Tell about self */
static bool handle_hypervisor(struct cpu_user_regs *regs, const union hsr hsr)
{
@@ -64,6 +72,127 @@ static bool handle_hypervisor(struct cpu_user_regs *regs, const union hsr hsr)
return false;
}
+/* old (arvm7) PSCI interface */
+static bool handle_arch(struct cpu_user_regs *regs, const union hsr hsr)
+{
+ switch ( get_user_reg(regs,0) & 0xFFFFFFFF )
+ {
+ case PSCI_cpu_off:
+ {
+ uint32_t pstate = get_user_reg(regs, 1);
+ perfc_incr(vpsci_cpu_off);
+ set_user_reg(regs, 0, do_psci_cpu_off(pstate));
+ }
+ return true;
+ case PSCI_cpu_on:
+ {
+ uint32_t vcpuid = get_user_reg(regs, 1);
+ register_t epoint = get_user_reg(regs, 2);
+ perfc_incr(vpsci_cpu_on);
+ set_user_reg(regs, 0, do_psci_cpu_on(vcpuid, epoint));
+ }
+ return true;
+ }
+ return false;
+}
+
+/* helper function for checking arm mode 32/64 bit */
+static inline int psci_mode_check(struct domain *d, register_t fid)
+{
+ return !( is_64bit_domain(d)^( (fid & PSCI_0_2_64BIT) >> 30 ) );
+}
+
+/* PSCI 2.0 interface */
+static bool handle_ssc(struct cpu_user_regs *regs, const union hsr hsr)
+{
+ register_t fid = get_user_reg(regs, 0);
+
+ switch ( ARM_SMCCC_FUNC_NUM(fid) )
+ {
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_PSCI_VERSION):
+ perfc_incr(vpsci_version);
+ set_user_reg(regs, 0, do_psci_0_2_version());
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_CPU_OFF):
+ perfc_incr(vpsci_cpu_off);
+ set_user_reg(regs, 0, do_psci_0_2_cpu_off());
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_MIGRATE_INFO_TYPE):
+ perfc_incr(vpsci_migrate_info_type);
+ set_user_reg(regs, 0, do_psci_0_2_migrate_info_type());
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_MIGRATE_INFO_UP_CPU):
+ perfc_incr(vpsci_migrate_info_up_cpu);
+ if ( psci_mode_check(current->domain, fid) )
+ set_user_reg(regs, 0, do_psci_0_2_migrate_info_up_cpu());
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_SYSTEM_OFF):
+ perfc_incr(vpsci_system_off);
+ do_psci_0_2_system_off();
+ set_user_reg(regs, 0, PSCI_INTERNAL_FAILURE);
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_SYSTEM_RESET):
+ perfc_incr(vpsci_system_reset);
+ do_psci_0_2_system_reset();
+ set_user_reg(regs, 0, PSCI_INTERNAL_FAILURE);
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_CPU_ON):
+ perfc_incr(vpsci_cpu_on);
+ if ( psci_mode_check(current->domain, fid) )
+ {
+ register_t vcpuid = get_user_reg(regs,1);
+ register_t epoint = get_user_reg(regs,2);
+ register_t cid = get_user_reg(regs,3);
+ set_user_reg(regs, 0,
+ do_psci_0_2_cpu_on(vcpuid, epoint, cid));
+ }
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_CPU_SUSPEND):
+ perfc_incr(vpsci_cpu_suspend);
+ if ( psci_mode_check(current->domain, fid) )
+ {
+ uint32_t pstate = get_user_reg(regs,1) & 0xFFFFFFFF;
+ register_t epoint = get_user_reg(regs,2);
+ register_t cid = get_user_reg(regs,3);
+ set_user_reg(regs, 0,
+ do_psci_0_2_cpu_suspend(pstate, epoint, cid));
+ }
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_AFFINITY_INFO):
+ perfc_incr(vpsci_cpu_affinity_info);
+ if ( psci_mode_check(current->domain, fid) )
+ {
+ register_t taff = get_user_reg(regs,1);
+ uint32_t laff = get_user_reg(regs,2) & 0xFFFFFFFF;
+ set_user_reg(regs, 0,
+ do_psci_0_2_affinity_info(taff, laff));
+ }
+ return true;
+ case ARM_SMCCC_FUNC_NUM(PSCI_0_2_FN_MIGRATE):
+ perfc_incr(vpsci_cpu_migrate);
+ if ( psci_mode_check(current->domain, fid) )
+ {
+ uint32_t tcpu = get_user_reg(regs,1) & 0xFFFFFFFF;
+ set_user_reg(regs, 0, do_psci_0_2_migrate(tcpu));
+ }
+ return true;
+ case ARM_SMCCC_FUNC_CALL_COUNT:
+ set_user_reg(regs, 0, SSC_SMCCC_FUNCTION_COUNT);
+ return true;
+ case ARM_SMCCC_FUNC_CALL_UID:
+ set_user_reg(regs, 0, SSC_SMCCC_UID.a[0]);
+ set_user_reg(regs, 1, SSC_SMCCC_UID.a[1]);
+ set_user_reg(regs, 2, SSC_SMCCC_UID.a[2]);
+ set_user_reg(regs, 3, SSC_SMCCC_UID.a[3]);
+ return true;
+ case ARM_SMCCC_FUNC_CALL_REVISION:
+ set_user_reg(regs, 0, SSC_SMCCC_MAJOR_REVISION);
+ set_user_reg(regs, 1, SSC_SMCCC_MINOR_REVISION);
+ return true;
+ }
+ return false;
+}
+
/**
* smccc_handle_call() - handle SMC/HVC call according to ARM SMCCC
*/
@@ -76,6 +205,12 @@ void smccc_handle_call(struct cpu_user_regs *regs, const union hsr hsr)
case ARM_SMCCC_OWNER_HYPERVISOR:
handled = handle_hypervisor(regs, hsr);
break;
+ case ARM_SMCCC_OWNER_ARCH:
+ handled = handle_arch(regs, hsr);
+ break;
+ case ARM_SMCCC_OWNER_STANDARD:
+ handled = handle_ssc(regs, hsr);
+ break;
}
if ( !handled )
@@ -39,7 +39,6 @@
#include <asm/event.h>
#include <asm/regs.h>
#include <asm/cpregs.h>
-#include <asm/psci.h>
#include <asm/mmio.h>
#include <asm/cpufeature.h>
#include <asm/flushtlb.h>
@@ -1451,123 +1450,6 @@ static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
#endif
#ifdef CONFIG_ARM_64
-#define PSCI_RESULT_REG(reg) (reg)->x0
-#define PSCI_ARG(reg,n) (reg)->x##n
-#define PSCI_ARG32(reg,n) (uint32_t)( (reg)->x##n & 0x00000000FFFFFFFF )
-#else
-#define PSCI_RESULT_REG(reg) (reg)->r0
-#define PSCI_ARG(reg,n) (reg)->r##n
-#define PSCI_ARG32(reg,n) PSCI_ARG(reg,n)
-#endif
-
-/* helper function for checking arm mode 32/64 bit */
-static inline int psci_mode_check(struct domain *d, register_t fid)
-{
- return !( is_64bit_domain(d)^( (fid & PSCI_0_2_64BIT) >> 30 ) );
-}
-
-static void do_trap_psci(struct cpu_user_regs *regs)
-{
- register_t fid = PSCI_ARG(regs,0);
-
- /* preloading in case psci_mode_check fails */
- PSCI_RESULT_REG(regs) = PSCI_INVALID_PARAMETERS;
- switch( fid )
- {
- case PSCI_cpu_off:
- {
- uint32_t pstate = PSCI_ARG32(regs,1);
- perfc_incr(vpsci_cpu_off);
- PSCI_RESULT_REG(regs) = do_psci_cpu_off(pstate);
- }
- break;
- case PSCI_cpu_on:
- {
- uint32_t vcpuid = PSCI_ARG32(regs,1);
- register_t epoint = PSCI_ARG(regs,2);
- perfc_incr(vpsci_cpu_on);
- PSCI_RESULT_REG(regs) = do_psci_cpu_on(vcpuid, epoint);
- }
- break;
- case PSCI_0_2_FN_PSCI_VERSION:
- perfc_incr(vpsci_version);
- PSCI_RESULT_REG(regs) = do_psci_0_2_version();
- break;
- case PSCI_0_2_FN_CPU_OFF:
- perfc_incr(vpsci_cpu_off);
- PSCI_RESULT_REG(regs) = do_psci_0_2_cpu_off();
- break;
- case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
- perfc_incr(vpsci_migrate_info_type);
- PSCI_RESULT_REG(regs) = do_psci_0_2_migrate_info_type();
- break;
- case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
- case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
- perfc_incr(vpsci_migrate_info_up_cpu);
- if ( psci_mode_check(current->domain, fid) )
- PSCI_RESULT_REG(regs) = do_psci_0_2_migrate_info_up_cpu();
- break;
- case PSCI_0_2_FN_SYSTEM_OFF:
- perfc_incr(vpsci_system_off);
- do_psci_0_2_system_off();
- PSCI_RESULT_REG(regs) = PSCI_INTERNAL_FAILURE;
- break;
- case PSCI_0_2_FN_SYSTEM_RESET:
- perfc_incr(vpsci_system_reset);
- do_psci_0_2_system_reset();
- PSCI_RESULT_REG(regs) = PSCI_INTERNAL_FAILURE;
- break;
- case PSCI_0_2_FN_CPU_ON:
- case PSCI_0_2_FN64_CPU_ON:
- perfc_incr(vpsci_cpu_on);
- if ( psci_mode_check(current->domain, fid) )
- {
- register_t vcpuid = PSCI_ARG(regs,1);
- register_t epoint = PSCI_ARG(regs,2);
- register_t cid = PSCI_ARG(regs,3);
- PSCI_RESULT_REG(regs) =
- do_psci_0_2_cpu_on(vcpuid, epoint, cid);
- }
- break;
- case PSCI_0_2_FN_CPU_SUSPEND:
- case PSCI_0_2_FN64_CPU_SUSPEND:
- perfc_incr(vpsci_cpu_suspend);
- if ( psci_mode_check(current->domain, fid) )
- {
- uint32_t pstate = PSCI_ARG32(regs,1);
- register_t epoint = PSCI_ARG(regs,2);
- register_t cid = PSCI_ARG(regs,3);
- PSCI_RESULT_REG(regs) =
- do_psci_0_2_cpu_suspend(pstate, epoint, cid);
- }
- break;
- case PSCI_0_2_FN_AFFINITY_INFO:
- case PSCI_0_2_FN64_AFFINITY_INFO:
- perfc_incr(vpsci_cpu_affinity_info);
- if ( psci_mode_check(current->domain, fid) )
- {
- register_t taff = PSCI_ARG(regs,1);
- uint32_t laff = PSCI_ARG32(regs,2);
- PSCI_RESULT_REG(regs) =
- do_psci_0_2_affinity_info(taff, laff);
- }
- break;
- case PSCI_0_2_FN_MIGRATE:
- case PSCI_0_2_FN64_MIGRATE:
- perfc_incr(vpsci_cpu_migrate);
- if ( psci_mode_check(current->domain, fid) )
- {
- uint32_t tcpu = PSCI_ARG32(regs,1);
- PSCI_RESULT_REG(regs) = do_psci_0_2_migrate(tcpu);
- }
- break;
- default:
- domain_crash_synchronous();
- return;
- }
-}
-
-#ifdef CONFIG_ARM_64
#define HYPERCALL_RESULT_REG(r) (r)->x0
#define HYPERCALL_ARG1(r) (r)->x0
#define HYPERCALL_ARG2(r) (r)->x1
@@ -2890,8 +2772,12 @@ asmlinkage void do_trap_guest_sync(struct cpu_user_regs *regs)
return do_debug_trap(regs, hsr.iss & 0x00ff);
#endif
if ( hsr.iss == 0 )
- return do_trap_psci(regs);
- do_trap_hypercall(regs, (register_t *)®s->r12, hsr.iss);
+ {
+ if ( !smccc_handle_call(regs, hsr) )
+ domain_crash_synchronous();
+ }
+ else
+ do_trap_hypercall(regs, (register_t *)®s->r12, hsr.iss);
break;
#ifdef CONFIG_ARM_64
case HSR_EC_HVC64:
@@ -2902,8 +2788,12 @@ asmlinkage void do_trap_guest_sync(struct cpu_user_regs *regs)
return do_debug_trap(regs, hsr.iss & 0x00ff);
#endif
if ( hsr.iss == 0 )
- return do_trap_psci(regs);
- do_trap_hypercall(regs, ®s->x16, hsr.iss);
+ {
+ if ( !smccc_handle_call(regs, hsr) )
+ domain_crash_synchronous();
+ }
+ else
+ do_trap_hypercall(regs, ®s->x16, hsr.iss);
break;
case HSR_EC_SMC64:
/*