|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC v2 5/6] xen/arm: zynqmp: Forward plaform specific firmware calls
Hi Edgar, On 07/02/17 19:42, Edgar E. Iglesias wrote: From: "Edgar E. Iglesias" <edgar.iglesias@xxxxxxxxxx> Implement an EEMI mediator and forward platform specific firmware calls from guests to firmware. The EEMI mediator is responsible for implementing access controls modifying or blocking calls that try to operate on setup for devices that are not under the calling guest's control. EEMI: https://www.xilinx.com/support/documentation/user_guides/ug1200-eemi-api.pdf Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xxxxxxxxxx> --- xen/arch/arm/platforms/Makefile | 1 + xen/arch/arm/platforms/xilinx-zynqmp-eemi.c | 794 +++++++++++++++++++++ xen/arch/arm/platforms/xilinx-zynqmp.c | 18 + xen/include/asm-arm/platforms/xilinx-zynqmp-eemi.h | 337 +++++++++ xen/include/asm-arm/platforms/xilinx-zynqmp-mm.h | 284 ++++++++ 5 files changed, 1434 insertions(+) create mode 100644 xen/arch/arm/platforms/xilinx-zynqmp-eemi.c create mode 100644 xen/include/asm-arm/platforms/xilinx-zynqmp-eemi.h create mode 100644 xen/include/asm-arm/platforms/xilinx-zynqmp-mm.h diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile index 49fa683..b58b71f 100644 --- a/xen/arch/arm/platforms/Makefile +++ b/xen/arch/arm/platforms/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_ARM_64) += seattle.o obj-$(CONFIG_ARM_32) += sunxi.o obj-$(CONFIG_ARM_64) += xgene-storm.o obj-$(CONFIG_ARM_64) += xilinx-zynqmp.o +obj-$(CONFIG_ARM_64) += xilinx-zynqmp-eemi.o diff --git a/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c b/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c new file mode 100644 index 0000000..c2c184d --- /dev/null +++ b/xen/arch/arm/platforms/xilinx-zynqmp-eemi.c As you introduce another file for Xilinx, it might be worth considering a new directory xilinx in the platforms. @@ -0,0 +1,794 @@ +/* + * xen/arch/arm/platforms/xilinx-zynqmp-eemi.c + * + * Xilinx ZynqMP EEMI API mediator. + * + * Copyright (c) 2017 Xilinx Inc. + * Written by Edgar E. Iglesias <edgar.iglesias@xxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. We had a bad habit on ARM to use "either version 2 of the License, or (at your option) any later version". However Xen is GPLv2 only (see CONTRIBUTING). Could you update the license to: "This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation." + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Mediator for the EEMI Power Mangement API. s/Mangement/Management/ + * + * Refs: + * https://www.xilinx.com/support/documentation/user_guides/ug1200-eemi-api.pdf + * + * Background: + * The ZynqMP has a subsystem named the PMU with a CPU and special devices + * dedicated to running Power Management Firmware. Other masters in the + * system need to send requests to the PMU in order to for example: + * * Manage power state + * * Configure clocks + * * Program bitstreams for the programmable logic + * * etc + * + * Allthough the details of the setup are configurable, in the common case s/Allthough/although/ + * the PMU lives in the Secure world. NS World cannot directly communicate + * with it and must use proxy services from ARM Trusted Firmware to reach + * the PMU. + * + * Power Management on the ZynqMP is implemented in a layered manner. + * The PMU knows about various masters and will enforce access controls + * based on a pre-configured partitioning. This configuration dictates + * which devices are owned by the various masters and the PMU FW makes sure + * that a given master cannot turn off a device that it does not own or that + * is in use by other masters. + * + * The PMU is not aware of multiple execution states in masters. + * For example, it treats the ARMv8 cores as single units and does not + * distinguish between Secure vs NS OS:s nor does it know about Hypervisors + * and multiple guests. It is up to software on the ARMv8 cores to present + * a unified view of its power requirements. + * + * To implement this unified view, ARM Trusted Firmware at EL3 provides + * access to the PM API via SMC calls. ARM Trusted Firmware is responsible + * for mediating between the Secure and the NS world, rejecting SMC calls + * that request changes that are not allowed. + * + * Xen running above ATF owns the NS world and is responsible for presenting + * unified PM requests taking all guests and the hypervisor into account. + * + * Implementation: + * The PM API contains different classes of calls. + * Certain calls are harmless to expose to any guest. + * These include calls to get the PM API Version, or to read out the version + * of the chip we're running on. + * + * Other calls are more problematic. Here're some: I don't think you can the contraction "here're". Please use paddr_t here. + bool hwdom_access; /* HW domain gets access regardless. */ +}; [...] For both, s/uint64_t/paddr_t/ Could not we find all those information from the device-tree? acl[idx].addr may not be page aligned, so is there any possibility to have a same page permitted in multiple domain? + if ( !mfn ) + return false; + + return iomem_access_permitted(d, mfn, mfn); Who will give access to the MMIO region? Is it the toolstack via iomem="..."? Also, giving access to the MMIO also means the guest will be able to map it. After reading the comment at the top of the file, I am not sure this is what you want. Some compiler will complain of the first check because the enum is always positive. Also, what are you trying to check given the node is an enum and should fall into the array? + return false; + + /* NODE_UNKNOWN is treated as a wildcard. */ + if ( node == NODE_UNKNOWN ) + return true; Which means every domain will access to it. I think this is easily error-prone because NODE_UNKOWN is 0. So you may give access to anyone by mistake. Looking at the pm_mmio_access list, my understanding is NODE_UNKNOWN will be used when only the hardware domain can access it or the region is read-only. So I would use the read-only property to know whether any domain has access. Same question as above for the bound check. + return false; + + return pm_check_access(pm_reset_access, d, rst_idx); +} + +/* + * 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_mediate_mmio_access(struct domain *d, + bool write, uint64_t addr, s/uint64_t/paddr_t/ Are the single register only a byte? If not, in the case of a region is it safe to access in a middle of a register? + if ( addr != pm_mmio_access[i].start ) + continue; + } I would drop the single register case and use make .end = .start. This would avoid potentially mistake in the code. If you are concern about the readability of the array, you could use a macro. + + if ( write && pm_mmio_access[i].readonly ) + continue; + if ( pm_mmio_access[i].hwdom_access && !is_hardware_domain(d) ) + continue; + + /* Unlimited access is represented by a zero mask. */ + ASSERT( pm_mmio_access[i].mask != 0xFFFFFFFF ); Why? Would not it make the logic easier to handle unlimited access using 0xFFFFFFFF? You could use macro for that purpose. If you do that a guest could potentially read some memory it is not allowed. Don't you expect sensitive data in the MMIO? I am not sure to understand this, above you loop over until you may get prot_mask full. But here you exist as soon as one mask may not be valid. + return false; + } + } + } + + /* Masking only applies to writes. */ + if ( write ) + *mask &= prot_mask; Newline here please. What PUs stand for?
Coding style:
if ( ... )
{
Printk is not rate-limited, this means a guest could flood Xen with error message if it does not have access to the region. Please use gprintk() here, it will print the domain ID and also rate-limit the log. Also, pm_fn and pm_arg are unsigned, so please use %u. Coding style. Same as above for the printk. See above for the coding style. See above for the printk. Also, please use %#x if you print hexa to not confuse with decimal. But why do you print pm_arg in hexa here and decimal above? See above for the coding style. See above for the printk. See above for the printk. Also why do you cast fid? This function should be static. Newline here please. [...] I looked at the spec you provide in the commit message and I cannot find those name. Is it related to EEMI_SUCCESS? If so, I would prefer if we use the name from the spec. Furthermore, it does not seem that values are provided in the spec. + PM_RET_ERROR_ARGS, + PM_RET_ERROR_ACCESS, + PM_RET_ERROR_TIMEOUT, + PM_RET_ERROR_NOTSUPPORTED, + PM_RET_ERROR_PROC, + PM_RET_ERROR_API_ID, + PM_RET_ERROR_FAILURE, + PM_RET_ERROR_COMMUNIC, + PM_RET_ERROR_DOUBLEREQ, + PM_RET_ERROR_OTHER, +}; [...] diff --git a/xen/include/asm-arm/platforms/xilinx-zynqmp-mm.h b/xen/include/asm-arm/platforms/xilinx-zynqmp-mm.h new file mode 100644 index 0000000..4fb1695 --- /dev/null +++ b/xen/include/asm-arm/platforms/xilinx-zynqmp-mm.h I feel a bit unsure to see that many hardcoded values in Xen. Is it the only way to retrieve the mmio/power information? Regards, -- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |