|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 6/7] xen/arm: zynqmp: implement zynqmp_eemi
On Tue, 11 Dec 2018, Julien Grall wrote:
> Hi Stefano,
>
> On 03/12/2018 21:03, Stefano Stabellini wrote:
> > 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 v5:
> > - remove mmio_access handling
> >
> > Changes in v4:
> > - add #include as needed
> > - improve comment
> > - code style
> > ---
> > xen/arch/arm/platforms/xilinx-zynqmp-eemi.c | 181
> > +++++++++++++++++++---------
> > 1 file changed, 125 insertions(+), 56 deletions(-)
> >
> > diff --git a/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c
> > b/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c
> > index 92a02df..9ecf286 100644
> > --- a/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c
> > +++ b/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c
> > @@ -76,10 +76,10 @@
> > #include <xen/iocap.h>
> > #include <xen/sched.h>
> > +#include <asm/smccc.h>
> > #include <asm/regs.h>
> > #include <asm/platforms/xilinx-zynqmp-eemi.h>
> > -#if 0
> > struct pm_access
> > {
> > mfn_t mfn;
> > @@ -309,67 +309,136 @@ static bool domain_has_reset_access(struct domain *d,
> > uint32_t rst)
> > return pm_check_access(pm_reset_access, d, rst);
> > }
> > -/*
> > - * Check if a given domain has access to perform an indirect
> > - * MMIO access.
> > - *
> > - * If the provided mask is invalid, it will be fixed up.
> > - */
> > -static bool domain_has_mmio_access(struct domain *d,
> > - bool write, paddr_t addr,
> > - uint32_t *mask)
>
> Why do you remove code that you just introduced?
I am really sorry about this, it was error applying a patch. This code
should never have been introduced: the code should be removed from the
previous patch. I'll fix it.
> > +bool zynqmp_eemi(struct cpu_user_regs *regs)
> > {
> > - unsigned int i;
> > - bool ret = false;
> > - uint32_t prot_mask = 0;
> > -
> > - /*
> > - * The hardware domain gets read access to everything.
> > - * Lower layers will do further filtering.
> > - */
> > - if ( !write && is_hardware_domain(d) )
> > - return true;
> > + struct arm_smccc_res res;
> > + uint32_t fid = get_user_reg(regs, 0);
> > + uint32_t nodeid = get_user_reg(regs, 1);
>
> You didn't address my concern regarding SMC32 vs SMC64 convention. As I said
> earlier on, at least CALL_COUNT, UID and VERSION are only accessible using the
> SMC32 convention.
>
> I can't tell for the other as the EEMI spec does not seem to specify it. I
> would be surprised that EEMI would ignore tops bits of the ID given they
> convey different information (e.g fast/yielding call, 32/64-bit convention).
>
> Looking at the branch you mentioned earlier on, zynqmp_pm_invoke_fn
> (drivers/firmware/xilinx/zynqmp.c) is definitely using the SMC64 calling
> convention as described in the documentation above the function.
>
> So this needs to be fixed properly.
OK, I'll add a check for the mandatory smc32 calls and forward them to
firmware properly.
> > + unsigned int pm_fn = fid & 0xFFFF;
> > + enum pm_ret_status ret;
> > - /* Scan the ACL. */
> > - for ( i = 0; i < ARRAY_SIZE(pm_mmio_access); i++ )
> > + switch ( pm_fn )
> > {
> > - ASSERT(pm_mmio_access[i].start + pm_mmio_access[i].size >=
> > - pm_mmio_access[i].start);
> > -
> > - if ( addr < pm_mmio_access[i].start )
> > - return false;
> > - if ( addr >= pm_mmio_access[i].start + pm_mmio_access[i].size )
> > - continue;
> > -
> > - if ( write && pm_mmio_access[i].readonly )
> > - return false;
> > - if ( pm_mmio_access[i].hwdom_access && !is_hardware_domain(d) )
> > - return false;
> > - if ( !domain_has_node_access(d, pm_mmio_access[i].node) )
> > - return false;
> > -
> > - /* We've got access to this reg (or parts of it). */
> > - ret = true;
> > -
> > - /* Permit write access to selected bits. */
> > - prot_mask |= pm_mmio_access[i].mask ?: GENMASK(31, 0);
> > - break;
> > - }
> > -
> > /*
> > - * Masking only applies to writes: values are safe to read, but not
> > - * all bits are writeable.
> > + * 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.
> > */
> > - if ( write )
> > - *mask &= prot_mask;
> > -
> > - return ret;
> > -}
> > -#endif
> > + case PM_SELF_SUSPEND:
> > + ret = XST_PM_SUCCESS;
> > + goto done;
> > +
> > + case PM_GET_NODE_STATUS:
> > + /* API for PUs. */
> > + case PM_REQ_SUSPEND:
> > + case PM_FORCE_POWERDOWN:
> > + case PM_ABORT_SUSPEND:
> > + case PM_REQ_WAKEUP:
> > + case PM_SET_WAKEUP_SOURCE:
> > + /* API for slaves. */
> > + case PM_REQ_NODE:
> > + case PM_RELEASE_NODE:
> > + case PM_SET_REQUIREMENT:
> > + case 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 PM_RESET_ASSERT:
> > + case 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 ZYNQMP_SIP_SVC_CALL_COUNT:
> > + case ZYNQMP_SIP_SVC_UID:
> > + case ZYNQMP_SIP_SVC_VERSION:
> > + case PM_GET_TRUSTZONE_VERSION:
> > + case PM_GET_API_VERSION:
> > + case PM_GET_CHIPID:
> > + goto forward_to_fw;
> > +
> > + /* No MMIO access is allowed from non-secure domains */
> > + case PM_MMIO_WRITE:
> > + case 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 PM_INIT:
> > + case PM_SET_CONFIGURATION:
> > + case PM_FPGA_LOAD:
> > + case PM_FPGA_GET_STATUS:
> > + case PM_SECURE_SHA:
> > + case PM_SECURE_RSA:
> > + case PM_PINCTRL_SET_FUNCTION:
> > + case PM_PINCTRL_REQUEST:
> > + case PM_PINCTRL_RELEASE:
> > + case PM_PINCTRL_GET_FUNCTION:
> > + case PM_PINCTRL_CONFIG_PARAM_GET:
> > + case PM_PINCTRL_CONFIG_PARAM_SET:
> > + case PM_IOCTL:
> > + case PM_QUERY_DATA:
> > + case PM_CLOCK_ENABLE:
> > + case PM_CLOCK_DISABLE:
> > + case PM_CLOCK_GETSTATE:
> > + case PM_CLOCK_GETDIVIDER:
> > + case PM_CLOCK_SETDIVIDER:
> > + case PM_CLOCK_SETRATE:
> > + case PM_CLOCK_GETRATE:
> > + case PM_CLOCK_SETPARENT:
> > + case 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 PM_SYSTEM_SHUTDOWN:
> > + ret = XST_PM_NO_ACCESS;
> > + goto done;
> > +
> > + default:
> > + gprintk(XENLOG_WARNING, "zynqmp-pm: Unhandled PM Call: %u\n", fid);
> > + return false;
> > + }
> > -bool zynqmp_eemi(struct cpu_user_regs *regs)
> > -{
> > - return false;
> > +forward_to_fw:
> > + arm_smccc_1_1_smc(get_user_reg(regs, 0),
> > + get_user_reg(regs, 1),
> > + get_user_reg(regs, 2),value to
> > + 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);
>
> If you use always SMCCC 1.1, then you should add code to deny Xen boot on
> platform not supporting SMCCC 1.1 or later.
I can do that.
> Furthermore, you are forwarding unsanitized values to the firmware. For
> instance, what would happen if the number of parameters of the call are
> increased? How are you sure this will not open a hole?
EEMI is backward compatible and the implementation is tested with Xen
regularly. A change like the one you describe should be considered a
backward compatibility breakage.
> > + 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;
> > }
> > /*
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |