Merge pull request #927 from jeenu-arm/state-switch
[project/bcm63xx/atf.git] / plat / arm / common / arm_sip_svc.c
index 90997e32148057ec2532cff3d7494852850ec376..7fe61019e28c1e92e76be811dfcfe0953c2de6ae 100644 (file)
@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <arm_sip_svc.h>
 #include <debug.h>
+#include <plat_arm.h>
 #include <pmf.h>
 #include <runtime_svc.h>
 #include <stdint.h>
@@ -36,6 +37,8 @@ static uintptr_t arm_sip_handler(unsigned int smc_fid,
                        void *handle,
                        u_register_t flags)
 {
+       int call_count = 0;
+
        /*
         * Dispatch PMF calls to PMF SMC handler and return its return
         * value
@@ -46,12 +49,34 @@ static uintptr_t arm_sip_handler(unsigned int smc_fid,
        }
 
        switch (smc_fid) {
-       case ARM_SIP_SVC_CALL_COUNT:
+       case ARM_SIP_SVC_EXE_STATE_SWITCH: {
+               u_register_t pc;
+
+               /* Allow calls from non-secure only */
+               if (!is_caller_non_secure(flags))
+                       SMC_RET1(handle, STATE_SW_E_DENIED);
+
+               /* Validate supplied entry point */
+               pc = (u_register_t) ((x1 << 32) | (uint32_t) x2);
+               if (arm_validate_ns_entrypoint(pc))
+                       SMC_RET1(handle, STATE_SW_E_PARAM);
+
                /*
-                * Return the number of SiP Service Calls. PMF is the only
-                * SiP service implemented; so return number of PMF calls
+                * Pointers used in execution state switch are all 32 bits wide
                 */
-               SMC_RET1(handle, PMF_NUM_SMC_CALLS);
+               return arm_execution_state_switch(smc_fid, (uint32_t) x1,
+                               (uint32_t) x2, (uint32_t) x3, (uint32_t) x4,
+                               handle);
+               }
+
+       case ARM_SIP_SVC_CALL_COUNT:
+               /* PMF calls */
+               call_count += PMF_NUM_SMC_CALLS;
+
+               /* State switch call */
+               call_count += 1;
+
+               SMC_RET1(handle, call_count);
 
        case ARM_SIP_SVC_UID:
                /* Return UID to the caller */