[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |