[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v7 4/6] xen/arm: zynqmp: implement zynqmp_eemi



From: "Edgar E. Iglesias" <edgar.iglesias@xxxxxxxxxx>

From: Edgar E. Iglesias <edgar.iglesias@xxxxxxxxxx>

zynqmp_eemi uses the defined functions and structs to decide whether to
make a call to the firmware, or to simply return a predefined value.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xxxxxxxxxx>
Signed-off-by: Stefano Stabellini <stefanos@xxxxxxxxxx>
---
Changes in v7:
- add in-code comment
- remove tabs
- use EEMI_FID

Changes in v6:
- mmio_access removal moved to previous patch
- forward to firmware mandatory smc32 calls
- check that the function id belongs to the right range before
  proceeding
- basic is_hardware_domain implementation for domain_has_node_access and
  domain_has_reset_access

Changes in v5:
- remove mmio_access handling

Changes in v4:
- add #include as needed
- improve comment
- code style
---
 xen/arch/arm/platforms/xilinx-zynqmp-eemi.c | 171 +++++++++++++++++++++++++++-
 1 file changed, 170 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c 
b/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c
index 369bb3f..f2fc5b5 100644
--- a/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c
+++ b/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c
@@ -17,11 +17,180 @@
  */
 
 #include <asm/regs.h>
+#include <xen/sched.h>
+#include <asm/smccc.h>
 #include <asm/platforms/xilinx-zynqmp-eemi.h>
 
+/*
+ * EEMI firmware API:
+ * https://www.xilinx.com/support/documentation/user_guides/ug1200-eemi-api.pdf
+ *
+ * Power domain node_ids identify the area of effect of the power
+ * management operations. They are the first parameter passed to power
+ * management EEMI calls.
+ *
+ * Reset IDs identify the area of effect of a reset operation. They are
+ * the first parameter passed to reset EEMI calls.
+ *
+ * For now, let the hardware domain access to all power domain nodes and
+ * all reset lines. In the future, we'll check for ownership of
+ * resources by specific virtual machines.
+ */
+static inline bool domain_has_node_access(struct domain *d, uint32_t nodeid)
+{
+    return is_hardware_domain(d);
+}
+
+static inline bool domain_has_reset_access(struct domain *d, uint32_t rst)
+{
+    return is_hardware_domain(d);
+}
+
 bool zynqmp_eemi(struct cpu_user_regs *regs)
 {
-    return false;
+    struct arm_smccc_res res;
+    uint32_t fid = get_user_reg(regs, 0);
+    uint32_t nodeid = get_user_reg(regs, 1);
+    unsigned int pm_fn = fid & 0xFFFF;
+    enum pm_ret_status ret;
+
+    switch ( fid )
+    {
+    /* Mandatory SMC32 functions. */
+    case ARM_SMCCC_CALL_COUNT_FID(SIP):
+    case ARM_SMCCC_CALL_UID_FID(SIP):
+    case ARM_SMCCC_REVISION_FID(SIP):
+        goto forward_to_fw;
+    /*
+     * We can't allow CPUs to suspend without Xen knowing about it.
+     * We accept but ignore the request and wait for the guest to issue
+     * a WFI or PSCI call which Xen will trap and act accordingly upon.
+     */
+    case EEMI_FID(PM_SELF_SUSPEND):
+        ret = XST_PM_SUCCESS;
+        goto done;
+
+    case EEMI_FID(PM_GET_NODE_STATUS):
+    /* API for PUs.  */
+    case EEMI_FID(PM_REQ_SUSPEND):
+    case EEMI_FID(PM_FORCE_POWERDOWN):
+    case EEMI_FID(PM_ABORT_SUSPEND):
+    case EEMI_FID(PM_REQ_WAKEUP):
+    case EEMI_FID(PM_SET_WAKEUP_SOURCE):
+    /* API for slaves.  */
+    case EEMI_FID(PM_REQ_NODE):
+    case EEMI_FID(PM_RELEASE_NODE):
+    case EEMI_FID(PM_SET_REQUIREMENT):
+    case EEMI_FID(PM_SET_MAX_LATENCY):
+        if ( !domain_has_node_access(current->domain, nodeid) )
+        {
+            gprintk(XENLOG_WARNING,
+                    "zynqmp-pm: fn=%u No access to node %u\n", pm_fn, nodeid);
+            ret = XST_PM_NO_ACCESS;
+            goto done;
+        }
+        goto forward_to_fw;
+
+    case EEMI_FID(PM_RESET_ASSERT):
+    case EEMI_FID(PM_RESET_GET_STATUS):
+        if ( !domain_has_reset_access(current->domain, nodeid) )
+        {
+            gprintk(XENLOG_WARNING,
+                    "zynqmp-pm: fn=%u No access to reset %u\n", pm_fn, nodeid);
+            ret = XST_PM_NO_ACCESS;
+            goto done;
+        }
+        goto forward_to_fw;
+
+    /* These calls are safe and always allowed.  */
+    case EEMI_FID(ZYNQMP_SIP_SVC_CALL_COUNT):
+    case EEMI_FID(ZYNQMP_SIP_SVC_UID):
+    case EEMI_FID(ZYNQMP_SIP_SVC_VERSION):
+    case EEMI_FID(PM_GET_TRUSTZONE_VERSION):
+    case EEMI_FID(PM_GET_API_VERSION):
+    case EEMI_FID(PM_GET_CHIPID):
+        goto forward_to_fw;
+
+    /* No MMIO access is allowed from non-secure domains */
+    case EEMI_FID(PM_MMIO_WRITE):
+    case EEMI_FID(PM_MMIO_READ):
+        gprintk(XENLOG_WARNING,
+                "zynqmp-pm: fn=%u No MMIO access to %u\n", pm_fn, nodeid);
+        ret = XST_PM_NO_ACCESS;
+        goto done;
+
+    /* Exclusive to the hardware domain.  */
+    case EEMI_FID(PM_INIT):
+    case EEMI_FID(PM_SET_CONFIGURATION):
+    case EEMI_FID(PM_FPGA_LOAD):
+    case EEMI_FID(PM_FPGA_GET_STATUS):
+    case EEMI_FID(PM_SECURE_SHA):
+    case EEMI_FID(PM_SECURE_RSA):
+    case EEMI_FID(PM_PINCTRL_SET_FUNCTION):
+    case EEMI_FID(PM_PINCTRL_REQUEST):
+    case EEMI_FID(PM_PINCTRL_RELEASE):
+    case EEMI_FID(PM_PINCTRL_GET_FUNCTION):
+    case EEMI_FID(PM_PINCTRL_CONFIG_PARAM_GET):
+    case EEMI_FID(PM_PINCTRL_CONFIG_PARAM_SET):
+    case EEMI_FID(PM_IOCTL):
+    case EEMI_FID(PM_QUERY_DATA):
+    case EEMI_FID(PM_CLOCK_ENABLE):
+    case EEMI_FID(PM_CLOCK_DISABLE):
+    case EEMI_FID(PM_CLOCK_GETSTATE):
+    case EEMI_FID(PM_CLOCK_GETDIVIDER):
+    case EEMI_FID(PM_CLOCK_SETDIVIDER):
+    case EEMI_FID(PM_CLOCK_SETRATE):
+    case EEMI_FID(PM_CLOCK_GETRATE):
+    case EEMI_FID(PM_CLOCK_SETPARENT):
+    case EEMI_FID(PM_CLOCK_GETPARENT):
+        if ( !is_hardware_domain(current->domain) )
+        {
+            gprintk(XENLOG_WARNING, "eemi: fn=%u No access", pm_fn);
+            ret = XST_PM_NO_ACCESS;
+            goto done;
+        }
+        goto forward_to_fw;
+
+    /* These calls are never allowed.  */
+    case EEMI_FID(PM_SYSTEM_SHUTDOWN):
+        ret = XST_PM_NO_ACCESS;
+        goto done;
+
+    default:
+        gprintk(XENLOG_WARNING, "zynqmp-pm: Unhandled PM Call: %u\n", fid);
+        return false;
+    }
+
+forward_to_fw:
+    /*
+     * ZynqMP firmware calls (EEMI) take an argument that specifies the
+     * area of effect of the function called. Specifically, node ids for
+     * power management functions and reset ids for reset functions.
+     *
+     * The code above checks if a virtual machine has access rights over
+     * the node id, reset id, etc. Now that the check has been done, we
+     * can forward the whole command to firmware without additional
+     * parameters checks.
+     */
+    arm_smccc_1_1_smc(get_user_reg(regs, 0),
+                      get_user_reg(regs, 1),
+                      get_user_reg(regs, 2),
+                      get_user_reg(regs, 3),
+                      get_user_reg(regs, 4),
+                      get_user_reg(regs, 5),
+                      get_user_reg(regs, 6),
+                      get_user_reg(regs, 7),
+                      &res);
+
+    set_user_reg(regs, 0, res.a0);
+    set_user_reg(regs, 1, res.a1);
+    set_user_reg(regs, 2, res.a2);
+    set_user_reg(regs, 3, res.a3);
+    return true;
+
+done:
+    set_user_reg(regs, 0, ret);
+    return true;
 }
 
 /*
-- 
1.9.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.