From d87f9755a9d1464aacf819647275726f10a86818 Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Wed, 2 Feb 2022 11:50:09 +0200 Subject: [PATCH 1/8] libs: libxenhypfs - handle blob properties libxenhypfs will return blob properties as is. This output can be used to retrieve information from the hypfs. Caller is responsible for parsing property value. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- tools/libs/hypfs/core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/libs/hypfs/core.c b/tools/libs/hypfs/core.c index 52b30db8d777..d09bba7d8c86 100644 --- a/tools/libs/hypfs/core.c +++ b/tools/libs/hypfs/core.c @@ -307,8 +307,6 @@ char *xenhypfs_read(xenhypfs_handle *fshdl, const char *path) errno = EISDIR; break; case xenhypfs_type_blob: - errno = EDOM; - break; case xenhypfs_type_string: ret_buf = buf; buf = NULL; From b4209254735566bbf2ff5e177464cd1d7774427d Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Fri, 4 Feb 2022 15:30:45 +0200 Subject: [PATCH 2/8] xen/arm: Export host device-tree to hypfs If enabled, host device-tree will be exported to hypfs and can be accessed through /devicetree path. Exported device-tree has the same format, as the device-tree exported to the sysfs by the Linux kernel. This is useful when XEN toolstack needs an access to the host device-tree. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- xen/arch/arm/Kconfig | 16 ++++++++++++++++ xen/arch/arm/Makefile | 1 + xen/arch/arm/host_dtb_export.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 xen/arch/arm/host_dtb_export.c diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index e81c16316929..9c3fcd23a748 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -96,6 +96,22 @@ config DOM0LESS_BOOT Xen boot without the need of a control domain (Dom0), which could be present anyway. +config HOST_DTB_EXPORT + bool "Export host device tree to hypfs if enabled" + depends on ARM && HYPFS && !ACPI + ---help--- + + Export host device-tree to hypfs so toolstack can have an access for the + host device tree from Dom0. If you unsure say N. + +config HOST_DTB_MAX_SIZE + int "Max host dtb export size" + depends on HOST_DTB_EXPORT + default 8192 + ---help--- + + Maximum size of the host device-tree exported to hypfs. + config GICV3 bool "GICv3 driver" depends on !NEW_VGIC diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 56a136e929dd..3e3551047b79 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -22,6 +22,7 @@ obj-y += domain.o obj-y += domain_build.init.o obj-$(CONFIG_ARCH_MAP_DOMAIN_PAGE) += domain_page.o obj-y += domctl.o +obj-$(CONFIG_HOST_DTB_EXPORT) += host_dtb_export.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-y += efi/ obj-y += gic.o diff --git a/xen/arch/arm/host_dtb_export.c b/xen/arch/arm/host_dtb_export.c new file mode 100644 index 000000000000..c9beb2803883 --- /dev/null +++ b/xen/arch/arm/host_dtb_export.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Export host FDT to the hypfs + * + * Copyright (C) 2024 EPAM Systems + */ + +#include +#include +#include +#include + +static HYPFS_VARSIZE_INIT(dt_prop, XEN_HYPFS_TYPE_BLOB, + "devicetree", CONFIG_HOST_DTB_MAX_SIZE, + &hypfs_leaf_ro_funcs); + +static int __init host_dtb_export_init(void) +{ + ASSERT(dt_host && (dt_host->sibling == NULL)); + + dt_prop.u.content = device_tree_flattened; + dt_prop.e.size = fdt_totalsize(device_tree_flattened); + hypfs_add_leaf(&hypfs_root, &dt_prop, true); + + return 0; +} + +__initcall(host_dtb_export_init); From e6bb9cb0bcfa8a9c2161cd5bc76b3ce35cf190e3 Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Wed, 8 Dec 2021 15:23:18 +0200 Subject: [PATCH 3/8] tools/arm: add "arm_sci" option to xl.cfg This enumeration sets SCI type for the domain. Currently there is two possible options: either 'none' or 'scmi_smc'. 'none' is the default value and it disables SCI support at all. 'scmi_smc' enables access to the Firmware from the domains using SCMI protocol and SMC as transport. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- docs/man/xl.cfg.5.pod.in | 22 ++++++++++++++++++++++ tools/golang/xenlight/helpers.gen.go | 3 +++ tools/golang/xenlight/types.gen.go | 7 +++++++ tools/include/libxl.h | 5 +++++ tools/libs/light/libxl_types.idl | 6 ++++++ tools/xl/xl_parse.c | 9 +++++++++ 6 files changed, 52 insertions(+) diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in index cc2e0f626717..5c4dc244f4d1 100644 --- a/docs/man/xl.cfg.5.pod.in +++ b/docs/man/xl.cfg.5.pod.in @@ -1715,6 +1715,28 @@ Specifies OS ID. =back +=item B + +B Set ARM_SCI type for the guest. ARM_SCI is System Control Protocol +allows domain to manage various functions that are provided by HW platform. + +=over 4 + +=item B + +Don't allow guest to use ARM_SCI if present on the platform. This is the +default value. + +=item B + +Enables SCMI_SMC support for the guest. SCMI is System Control Management +Inferface - allows domain to manage various functions that are provided by HW +platform, such as clocks, resets and power-domains. Xen will mediate access to +clocks, power-domains and resets between Domains and ATF. Disabled by default. +SCP is used as transport. + +=back + =back =head2 Paravirtualised (PV) Guest Specific Options diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go index 768ab0f56602..7990cac40a09 100644 --- a/tools/golang/xenlight/helpers.gen.go +++ b/tools/golang/xenlight/helpers.gen.go @@ -1127,6 +1127,8 @@ if err := x.DmRestrict.fromC(&xc.dm_restrict);err != nil { return fmt.Errorf("converting field DmRestrict: %v", err) } x.Tee = TeeType(xc.tee) +x.ArmSci = ArmSciType(xc.arm_sci) + x.Type = DomainType(xc._type) switch x.Type{ case DomainTypeHvm: @@ -1485,6 +1487,7 @@ if err := x.DmRestrict.toC(&xc.dm_restrict); err != nil { return fmt.Errorf("converting field DmRestrict: %v", err) } xc.tee = C.libxl_tee_type(x.Tee) +xc.arm_sci = C.libxl_arm_sci_type(x.ArmSci) xc._type = C.libxl_domain_type(x.Type) switch x.Type{ case DomainTypeHvm: diff --git a/tools/golang/xenlight/types.gen.go b/tools/golang/xenlight/types.gen.go index 0b712d2aa462..b90def380d60 100644 --- a/tools/golang/xenlight/types.gen.go +++ b/tools/golang/xenlight/types.gen.go @@ -513,6 +513,12 @@ SveType1920 SveType = 1920 SveType2048 SveType = 2048 ) +type ArmSciType int +const( +ArmSciTypeNone ArmSciType = 0 +ArmSciTypeScmi ArmSciType = 1 +) + type RdmReserve struct { Strategy RdmReserveStrategy Policy RdmReservePolicy @@ -584,6 +590,7 @@ NestedHvm Defbool Apic Defbool DmRestrict Defbool Tee TeeType +ArmSci ArmSciType Type DomainType TypeUnion DomainBuildInfoTypeUnion ArchArm struct { diff --git a/tools/include/libxl.h b/tools/include/libxl.h index d34d09eaaa16..3c2b211345e9 100644 --- a/tools/include/libxl.h +++ b/tools/include/libxl.h @@ -308,6 +308,11 @@ */ #define LIBXL_HAVE_BUILDINFO_ARCH_ARM_SVE_VL 1 +/* + * libxl_domain_build_info has the arch_arm.sci field. + */ +#define LIBXL_HAVE_BUILDINFO_ARCH_ARM_SCI 1 + /* * LIBXL_HAVE_SOFT_RESET indicates that libxl supports performing * 'soft reset' for domains and there is 'soft_reset' shutdown reason diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl index 7ed9e7bf76a7..59c35059cea5 100644 --- a/tools/libs/light/libxl_types.idl +++ b/tools/libs/light/libxl_types.idl @@ -552,6 +552,11 @@ libxl_sve_type = Enumeration("sve_type", [ (2048, "2048") ], init_val = "LIBXL_SVE_TYPE_DISABLED") +libxl_arm_sci_type = Enumeration("arm_sci_type", [ + (0, "none"), + (1, "scmi_smc") + ], init_val = "LIBXL_ARM_SCI_TYPE_NONE") + libxl_rdm_reserve = Struct("rdm_reserve", [ ("strategy", libxl_rdm_reserve_strategy), ("policy", libxl_rdm_reserve_policy), @@ -655,6 +660,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("tee", libxl_tee_type), ("tpm", libxl_defbool), ("virtio_pci_hosts", Array(libxl_virtio_pci_host, "num_virtio_pci_hosts")), + ("arm_sci", libxl_arm_sci_type), ("u", KeyedUnion(None, libxl_domain_type, "type", [("hvm", Struct(None, [("firmware", string), ("bios", libxl_bios_type), diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c index 97cc865145a4..dc81dc11cf7a 100644 --- a/tools/xl/xl_parse.c +++ b/tools/xl/xl_parse.c @@ -3285,6 +3285,15 @@ void parse_config_data(const char *config_source, } } + if (!xlu_cfg_get_string (config, "arm_sci", &buf, 1)) { + e = libxl_arm_sci_type_from_string(buf, &b_info->arm_sci); + if (e) { + fprintf(stderr, + "Unknown arm_sci \"%s\" specified\n", buf); + exit(-ERROR_FAIL); + } + } + parse_vkb_list(config, d_config); parse_vgsx_list(config, d_config); parse_vcamera_list(config, d_config); From 8b4c6d1e55ee6379e910e965c66251acb6113f07 Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Mon, 23 Sep 2024 00:34:13 +0300 Subject: [PATCH 4/8] xen: arch: scmi_smc: remove memory mapping for hardware domain Mapping for the hardware domain should be done during domain construciton as it is done for other domains. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- xen/arch/arm/domain_build.c | 29 ++++++++++++++ xen/arch/arm/sci/scmi_smc.c | 75 ------------------------------------- 2 files changed, 29 insertions(+), 75 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 667421a54b3f..d469b6573bb7 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -1590,6 +1590,29 @@ int __init make_chosen_node(const struct kernel_info *kinfo) return res; } +#ifdef CONFIG_SCMI_SMC +static int __init mem_permit_access(struct domain *d, uint64_t addr, uint64_t len) +{ + int res, rc; + res = iomem_permit_access(d, paddr_to_pfn(addr), + paddr_to_pfn(PAGE_ALIGN(addr + len - 1))); + if ( res ) + return res; + + res = map_regions_p2mt(d, gaddr_to_gfn(addr), PFN_DOWN(len), + maddr_to_mfn(addr), p2m_mmio_direct_nc); + if ( res ) + { + rc = iomem_deny_access(d, paddr_to_pfn(addr), + paddr_to_pfn(PAGE_ALIGN(addr + len -1))); + if ( rc ) + printk(XENLOG_ERR "Unable to deny iomem access , err = %d\n", rc); + } + + return res; +} +#endif /* CONFIG_SCMI_SMC */ + static int __init handle_node(struct domain *d, struct kernel_info *kinfo, struct dt_device_node *node, p2m_type_t p2mt) @@ -1741,6 +1764,12 @@ static int __init handle_node(struct domain *d, struct kernel_info *kinfo, */ evtchn_allocate(d); +#ifdef CONFIG_SCMI_SMC + res = mem_permit_access(kinfo->d, kinfo->d->arch.sci_channel.paddr, + PAGE_SIZE); + if ( res ) + return res; +#endif /* * The hypervisor node should always be created after all nodes * from the host DT have been parsed. diff --git a/xen/arch/arm/sci/scmi_smc.c b/xen/arch/arm/sci/scmi_smc.c index 01d7894392b6..144902576b19 100644 --- a/xen/arch/arm/sci/scmi_smc.c +++ b/xen/arch/arm/sci/scmi_smc.c @@ -454,58 +454,6 @@ static struct scmi_channel *smc_create_channel(uint8_t agent_id, return channel; } -static int mem_permit_access(struct domain *d, uint64_t addr, uint64_t len) -{ - return iomem_permit_access(d, paddr_to_pfn(addr), - paddr_to_pfn(PAGE_ALIGN(addr + len -1))); -} - -static int mem_deny_access(struct domain *d, uint64_t addr, - uint64_t len) -{ - return iomem_deny_access(d, paddr_to_pfn(addr), - paddr_to_pfn(PAGE_ALIGN(addr + len -1))); -} - -static int dt_update_domain_range(uint64_t addr, uint64_t size) -{ - struct dt_device_node *scmi_node, *shmem_node; - const __be32 *shmem_phandle; - __be32 *hw_reg; - const struct dt_property *pp; - uint32_t len; - - scmi_node = dt_find_compatible_node(NULL, NULL, "arm,scmi-smc"); - if ( !scmi_node ) - { - printk(XENLOG_ERR "scmi: Unable to find scmi node in DT\n"); - return -EINVAL; - } - - shmem_phandle = dt_get_property(scmi_node, "shmem", NULL); - if ( !shmem_phandle ) - { - printk(XENLOG_ERR "scmi: No shmem property in scmi node\n"); - return -ENOENT; - } - - shmem_node = dt_find_node_by_phandle(be32_to_cpup(shmem_phandle)); - if ( !shmem_node ) - return -ENOENT; - - pp = dt_find_property(shmem_node, "reg", &len); - if ( !pp ) - { - printk(XENLOG_ERR "scmi: Unable to find regs entry in shmem node\n"); - return -ENOENT; - } - - hw_reg = pp->value; - dt_set_range(&hw_reg, shmem_node, addr, size); - - return 0; -} - static void free_channel_list(void) { struct scmi_channel *curr, *_curr; @@ -729,7 +677,6 @@ static int scmi_domain_init(struct domain *d, struct xen_arch_domainconfig *config) { struct scmi_channel *channel; - int ret; if ( !scmi_data.initialized ) return 0; @@ -742,32 +689,11 @@ static int scmi_domain_init(struct domain *d, "scmi: Aquire SCMI channel id = 0x%x , domain_id = %d paddr = 0x%lx\n", channel->agent_id, channel->domain_id, channel->paddr); - if ( is_hardware_domain(d) ) - { - ret = mem_permit_access(d, channel->paddr, PAGE_SIZE); - if ( IS_ERR_VALUE(ret) ) - goto error; - - ret = dt_update_domain_range(channel->paddr, PAGE_SIZE); - if ( IS_ERR_VALUE(ret) ) - { - int rc = mem_deny_access(d, channel->paddr, PAGE_SIZE); - if ( rc ) - printk(XENLOG_ERR "Unable to mem_deny_access\n"); - - goto error; - } - } - d->arch.sci = channel; d->arch.sci_channel.paddr = channel->paddr; d->arch.sci_channel.guest_func_id = scmi_data.func_id; return 0; -error: - relinquish_scmi_channel(channel); - - return ret; } static int scmi_add_device_by_devid(struct domain *d, uint32_t scmi_devid) @@ -857,7 +783,6 @@ static void scmi_domain_destroy(struct domain *d) d->arch.sci = NULL; - mem_deny_access(d, channel->paddr, PAGE_SIZE); spin_unlock(&channel->lock); } From e225a05f3d020cae4b59658c749c58937855316e Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Mon, 23 Sep 2024 11:36:11 +0300 Subject: [PATCH 5/8] xen: domain_build: Integration of the SCMI mediator to Domain-0 Integration of the SCMI-Mediator feature to the Domain-0 construction process. It includes shared memory node creation and mapping with phandle update on the scmi node. When creating hardware domain there is a need to set correct phandle to the "shmem" property on the scmi node. Shared memory node is generated while scmi node is copied as is from Xen device-tree. Correct shmem phandle is set during domain device-tree processing. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- xen/arch/arm/domain_build.c | 27 ++++++++++++++++++++- xen/drivers/passthrough/arm/scmi_dt_maker.c | 13 ++++++++++ xen/include/xen/scmi_dt_maker.h | 3 +++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index d469b6573bb7..229e043a88f0 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -38,6 +38,7 @@ #include #include #include +#include #include static unsigned int __initdata opt_dom0_max_vcpus; @@ -1636,7 +1637,7 @@ static int __init handle_node(struct domain *d, struct kernel_info *kinfo, DT_MATCH_TYPE("memory"), /* The memory mapped timer is not supported by Xen. */ DT_MATCH_COMPATIBLE("arm,armv7-timer-mem"), - /* SCPI shared memory is handled by Xen */ + /* SCMI shared memory is handled by Xen */ DT_MATCH_COMPATIBLE("arm,scmi-shmem"), { /* sentinel */ }, }; @@ -1652,6 +1653,13 @@ static int __init handle_node(struct domain *d, struct kernel_info *kinfo, DT_MATCH_PATH("/hypervisor"), { /* sentinel */ }, }; +#ifdef CONFIG_SCMI_SMC + static const struct dt_device_match scmi_matches[] __initconst = + { + DT_MATCH_PATH("/firmware/scmi"), + { /* sentinel */ }, + }; +#endif /* CONFIG_SCMI_SMC */ struct dt_device_node *child; int res, i, nirq, irq_id; const char *name; @@ -1765,6 +1773,10 @@ static int __init handle_node(struct domain *d, struct kernel_info *kinfo, evtchn_allocate(d); #ifdef CONFIG_SCMI_SMC + res = scmi_dt_make_shmem_node(kinfo); + if ( res ) + return res; + res = mem_permit_access(kinfo->d, kinfo->d->arch.sci_channel.paddr, PAGE_SIZE); if ( res ) @@ -1808,6 +1820,15 @@ static int __init handle_node(struct domain *d, struct kernel_info *kinfo, return res; } +#ifdef CONFIG_SCMI_SMC + if ( dt_match_node(scmi_matches, node) ) + { + res = scmi_dt_set_phandle(kinfo, dt_node_full_name(node)); + if ( res ) + return res; + } +#endif + res = fdt_end_node(kinfo->fdt); return res; @@ -1823,6 +1844,8 @@ static int __init prepare_dtb_hwdom(struct domain *d, struct kernel_info *kinfo) ASSERT(dt_host && (dt_host->sibling == NULL)); kinfo->phandle_gic = dt_interrupt_controller->phandle; + kinfo->phandle_sci_shmem = GUEST_PHANDLE_SCMI; + fdt = device_tree_flattened; new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; @@ -2121,9 +2144,11 @@ static int __init construct_dom0(struct domain *d) if ( rc < 0 ) return rc; +#if CONFIG_ARM_SCI rc = sci_domain_init(d, sci_get_type(), NULL); if ( rc < 0 ) return rc; +#endif if ( acpi_disabled ) { diff --git a/xen/drivers/passthrough/arm/scmi_dt_maker.c b/xen/drivers/passthrough/arm/scmi_dt_maker.c index f088acb4ee3d..8e60a9b1114b 100644 --- a/xen/drivers/passthrough/arm/scmi_dt_maker.c +++ b/xen/drivers/passthrough/arm/scmi_dt_maker.c @@ -311,3 +311,16 @@ int __init scmi_dt_scan_node(struct kernel_info *kinfo, void *pfdt, clean_handles(); return rc; } + +int __init scmi_dt_set_phandle(struct kernel_info *kinfo, + const char *name) +{ + int offset = fdt_path_offset(kinfo->fdt, name); + __be32 val = cpu_to_be32(kinfo->phandle_sci_shmem); + + if ( !offset ) + return -ENODEV; + + return fdt_setprop_inplace(kinfo->fdt, offset, "shmem", + &val,sizeof(val)); +} diff --git a/xen/include/xen/scmi_dt_maker.h b/xen/include/xen/scmi_dt_maker.h index 5675351a8bba..f9f60a990cd1 100644 --- a/xen/include/xen/scmi_dt_maker.h +++ b/xen/include/xen/scmi_dt_maker.h @@ -16,10 +16,13 @@ int __init scmi_dt_make_shmem_node(struct kernel_info *kinfo); int __init scmi_dt_create_node(struct kernel_info *kinfo); int __init scmi_dt_scan_node(struct kernel_info *kinfo, void *pfdt, int nodeoff); +int __init scmi_dt_set_phandle(struct kernel_info *kinfo, + const char *name); #else #define scmi_dt_make_shmem_node(kinfo) (0) #define scmi_dt_create_node(kinfo) (0) #define scmi_dt_scan_node(kinfo, pfdt, nodeoff) (0) +#define scmi_dt_set_phandle(kinfo, name) (0) #endif /* CONFIG_SCMI_SMC */ From ca70800644dcd6010cd79fbefc5118cd4c515905 Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Tue, 1 Oct 2024 16:59:54 +0300 Subject: [PATCH 6/8] xen: device_tree: Assign devices to the Domain-0 during build Assgin devices to the access-controller during Domain-0 build. This registers devices in the SCMI server for the Domain-0. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- xen/drivers/passthrough/device_tree.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c index 075fb25a3706..ace66b86296b 100644 --- a/xen/drivers/passthrough/device_tree.c +++ b/xen/drivers/passthrough/device_tree.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -318,6 +319,10 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d, break; } + ret = ac_assign_dt_device(dev, d); + if ( ret < 0 ) + return ret; + ret = iommu_assign_dt_device(d, dev); if ( ret ) From d627fd4aeb6dc2e22d66682d6a1332417c853cfb Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Tue, 1 Oct 2024 16:48:44 +0300 Subject: [PATCH 7/8] xen: scmi_dt_maker: Fix code style minor issue Remove space before function definition. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- xen/drivers/passthrough/arm/scmi_dt_maker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/drivers/passthrough/arm/scmi_dt_maker.c b/xen/drivers/passthrough/arm/scmi_dt_maker.c index 8e60a9b1114b..33587cab3466 100644 --- a/xen/drivers/passthrough/arm/scmi_dt_maker.c +++ b/xen/drivers/passthrough/arm/scmi_dt_maker.c @@ -25,7 +25,7 @@ struct scmi_phandle { LIST_HEAD(scmi_ph_list); - int __init scmi_dt_make_shmem_node(struct kernel_info *kinfo) +int __init scmi_dt_make_shmem_node(struct kernel_info *kinfo) { int res; void *fdt = kinfo->fdt; From f5007bbc068709b1feaf22ac766ada4f00603efd Mon Sep 17 00:00:00 2001 From: Oleksii Moisieiev Date: Wed, 8 Dec 2021 15:35:24 +0200 Subject: [PATCH 8/8] xen/arm: add SCI mediator support for DomUs Integration of the SCMI mediator with xen libs: - add hypercalls to aquire SCI channel and set device permissions for DomUs; - add SCMI_SMC nodes to DomUs device-tree based on partial device-tree; - SCI requests redirection from DomUs to Firmware. Signed-off-by: Oleksii Moisieiev Reviewed-by: Volodymyr Babchuk --- tools/include/xenctrl.h | 3 + tools/libs/ctrl/xc_domain.c | 18 ++ tools/libs/light/libxl_arm.c | 307 ++++++++++++++++++++++++++++-- tools/libs/light/libxl_create.c | 12 ++ tools/libs/light/libxl_internal.h | 3 + xen/arch/arm/domctl.c | 21 ++ xen/include/public/arch-arm.h | 7 +- xen/include/public/domctl.h | 9 + 8 files changed, 366 insertions(+), 14 deletions(-) diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index 2ef8b4e05422..13933d691a2a 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -1230,6 +1230,9 @@ int xc_domain_getvnuma(xc_interface *xch, int xc_domain_soft_reset(xc_interface *xch, uint32_t domid); +int xc_domain_get_sci_info(xc_interface *xch, uint32_t domid, + uint64_t *paddr, uint32_t *func_id); + #if defined(__i386__) || defined(__x86_64__) /* * PC BIOS standard E820 types and structure. diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c index f2d9d14b4d9f..09d328e0b490 100644 --- a/tools/libs/ctrl/xc_domain.c +++ b/tools/libs/ctrl/xc_domain.c @@ -2180,6 +2180,24 @@ int xc_domain_soft_reset(xc_interface *xch, domctl.domain = domid; return do_domctl(xch, &domctl); } + +int xc_domain_get_sci_info(xc_interface *xch, uint32_t domid, + uint64_t *paddr, uint32_t *func_id) +{ + struct xen_domctl domctl = {}; + + memset(&domctl, 0, sizeof(domctl)); + domctl.cmd = XEN_DOMCTL_get_sci_info; + domctl.domain = domid; + + if ( do_domctl(xch, &domctl) != 0 ) + return 1; + + *paddr = domctl.u.sci_info.paddr; + *func_id = domctl.u.sci_info.func_id; + return 0; +} + /* * Local variables: * mode: C diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c index 19dffe9dac91..c949f4acaf14 100644 --- a/tools/libs/light/libxl_arm.c +++ b/tools/libs/light/libxl_arm.c @@ -9,6 +9,7 @@ #include #include #include +#include /* * There is no clear requirements for the total size of Virtio MMIO region. @@ -351,6 +352,19 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc, } else config->arch.vgsx_osid = 0; + switch (d_config->b_info.arm_sci) { + case LIBXL_ARM_SCI_TYPE_NONE: + config->arch.arm_sci_type = XEN_DOMCTL_CONFIG_ARM_SCI_NONE; + break; + case LIBXL_ARM_SCI_TYPE_SCMI_SMC: + config->arch.arm_sci_type = XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC; + break; + default: + LOG(ERROR, "Unknown ARM_SCI type %d", + d_config->b_info.arm_sci); + return ERROR_FAIL; + } + return 0; } @@ -778,9 +792,6 @@ static int make_optee_node(libxl__gc *gc, void *fdt) int res; LOG(DEBUG, "Creating OP-TEE node in dtb"); - res = fdt_begin_node(fdt, "firmware"); - if (res) return res; - res = fdt_begin_node(fdt, "optee"); if (res) return res; @@ -793,9 +804,6 @@ static int make_optee_node(libxl__gc *gc, void *fdt) res = fdt_end_node(fdt); if (res) return res; - res = fdt_end_node(fdt); - if (res) return res; - return 0; } @@ -1545,10 +1553,9 @@ static int copy_node(libxl__gc *gc, void *fdt, void *pfdt, return 0; } -static int copy_node_by_path(libxl__gc *gc, const char *path, - void *fdt, void *pfdt) +static int get_path_nodeoff(const char *path, void *pfdt) { - int nodeoff, r; + int nodeoff; const char *name = strrchr(path, '/'); if (!name) @@ -1568,12 +1575,277 @@ static int copy_node_by_path(libxl__gc *gc, const char *path, if (strcmp(fdt_get_name(pfdt, nodeoff, NULL), name)) return -FDT_ERR_NOTFOUND; + return nodeoff; +} + +static int copy_node_by_path(libxl__gc *gc, const char *path, + void *fdt, void *pfdt) +{ + int nodeoff, r; + + nodeoff = get_path_nodeoff(path, pfdt); + if (nodeoff < 0) + return nodeoff; + r = copy_node(gc, fdt, pfdt, nodeoff, 0); if (r) return r; return 0; } +static int map_sci_page(libxl__gc *gc, uint32_t domid, uint64_t paddr, + uint64_t guest_addr) +{ + int ret; + uint64_t _paddr_pfn = paddr >> XC_PAGE_SHIFT; + uint64_t _guest_pfn = guest_addr >> XC_PAGE_SHIFT; + + assert(paddr && guest_addr); + LOG(DEBUG, "[%d] mapping sci shmem page %"PRIx64, domid, _paddr_pfn); + + ret = xc_domain_iomem_permission(CTX->xch, domid, _paddr_pfn, 1, 1); + if (ret < 0) { + LOG(ERROR, + "failed give domain access to iomem page %"PRIx64, + _paddr_pfn); + return ret; + } + + ret = xc_domain_memory_mapping(CTX->xch, domid, + _guest_pfn, _paddr_pfn, + 1, 1); + if (ret < 0) { + LOG(ERROR, + "failed to map to domain iomem page %"PRIx64 + " to guest address %"PRIx64, + _paddr_pfn, _guest_pfn); + return ret; + } + + return 0; +} + +static int scmi_dt_make_shmem_node(libxl__gc *gc, void *fdt) +{ + int res; + char buf[64]; + + snprintf(buf, sizeof(buf), "scmi-shmem@%llx", GUEST_SCI_SHMEM_BASE); + + res = fdt_begin_node(fdt, buf); + if (res) return res; + + res = fdt_property_compat(gc, fdt, 1, "arm,scmi-shmem"); + if (res) return res; + + res = fdt_property_regs(gc, fdt, GUEST_ROOT_ADDRESS_CELLS, + GUEST_ROOT_SIZE_CELLS, 1, + GUEST_SCI_SHMEM_BASE, GUEST_SCI_SHMEM_SIZE); + if (res) return res; + + res = fdt_property_cell(fdt, "phandle", GUEST_PHANDLE_SCMI); + if (res) return res; + + res = fdt_end_node(fdt); + if (res) return res; + + return 0; +} + +static const char *name_from_path(const char *path) +{ + return strrchr(path, '/') + 1; +} + +static int dt_copy_properties(libxl__gc *gc, void* fdt, void *xen_fdt, + const char *full_name) +{ + int propoff, nameoff, r, nodeoff; + const struct fdt_property *prop; + + LOG(DEBUG, "Copy properties for node: %s", full_name); + nodeoff = get_path_nodeoff(full_name, xen_fdt); + if (nodeoff < 0) + return -FDT_ERR_NOTFOUND; + + for (propoff = fdt_first_property_offset(xen_fdt, nodeoff); + propoff >= 0; + propoff = fdt_next_property_offset(xen_fdt, propoff)) { + + if (!(prop = fdt_get_property_by_offset(xen_fdt, propoff, NULL))) + return -FDT_ERR_INTERNAL; + + nameoff = fdt32_to_cpu(prop->nameoff); + + /* Skipping phandle nodes in xen device-tree */ + if (strcmp(fdt_string(xen_fdt,nameoff), "phandle") == 0 || + strcmp(fdt_string(xen_fdt, nameoff), "linux,phandle") == 0) + continue; + + r = fdt_property(fdt, fdt_string(xen_fdt, nameoff), + prop->data, fdt32_to_cpu(prop->len)); + if (r) return r; + } + + return (propoff != -FDT_ERR_NOTFOUND)? propoff : 0; +} + +static int scmi_dt_scan_node(libxl__gc *gc, void *fdt, void *pfdt, + void *xen_fdt, int nodeoff) +{ + int rc; + int node_next; + char full_name[128]; + uint32_t phandle; + + node_next = fdt_first_subnode(pfdt, nodeoff); + while (node_next > 0) + { + LOG(DEBUG,"Processing node %s", + fdt_get_name(pfdt, node_next, NULL)); + + phandle = fdt_get_phandle(pfdt, node_next); + + rc = fdt_get_path(pfdt, node_next, full_name, sizeof(full_name)); + if (rc) return rc; + + rc = fdt_begin_node(fdt, name_from_path(full_name)); + if (rc) return rc; + + rc = dt_copy_properties(gc, fdt, xen_fdt, full_name); + if (rc) return rc; + + if (phandle) { + rc = fdt_property_cell(fdt, "phandle", phandle); + if (rc) return rc; + } + + rc = scmi_dt_scan_node(gc, fdt, pfdt, xen_fdt, node_next); + if (rc) return rc; + + rc = fdt_end_node(fdt); + if (rc) return rc; + + node_next = fdt_next_subnode(pfdt, node_next); + } + + return 0; +} + +static int scmi_hypfs_fdt_check(libxl__gc *gc, void *fdt) +{ + int r; + + if (fdt_magic(fdt) != FDT_MAGIC) { + LOG(ERROR, "FDT is not a valid Flat Device Tree"); + return ERROR_FAIL; + } + + r = fdt_check_header(fdt); + if (r) { + LOG(ERROR, "Failed to check the FDT (%d)", r); + return ERROR_FAIL; + } + + return r; +} + +static int scmi_dt_copy_subnodes(libxl__gc *gc, void *fdt, void *pfdt) +{ + struct xenhypfs_handle *hdl; + struct xenhypfs_dirent *ent; + void *xen_fdt; + int rc, nodeoff; + + hdl = xenhypfs_open(NULL, 0); + if (!hdl) + return -EINVAL; + + xen_fdt = xenhypfs_read_raw(hdl, "/devicetree", &ent); + if (!xen_fdt) { + rc = errno; + LOG(ERROR, "Unable to read hypfs entry: %d", rc); + goto out; + } + + rc = scmi_hypfs_fdt_check(gc, xen_fdt); + if (rc) { + LOG(ERROR, "Hypfs device tree is invalid"); + goto out; + } + + nodeoff = get_path_nodeoff("/firmware/scmi", pfdt); + if (nodeoff <= 0) { + rc = -ENODEV; + goto out; + } + + rc = scmi_dt_scan_node(gc, fdt, pfdt, xen_fdt, nodeoff); + +out: + xenhypfs_close(hdl); + return rc; +} + +static int scmi_dt_create_node(libxl__gc *gc, void *fdt, void *pfdt, + uint32_t func_id) +{ + int rc = 0; + + rc = fdt_begin_node(fdt, "scmi"); + if (rc) return rc; + + rc = fdt_property_compat(gc, fdt, 1, "arm,scmi-smc"); + if (rc) return rc; + + rc = fdt_property_cell(fdt, "shmem", GUEST_PHANDLE_SCMI); + if (rc) return rc; + + rc = fdt_property_cell(fdt, "#addrets-cells", 1); + if (rc) return rc; + + rc = fdt_property_cell(fdt, "#size-cells", 0); + if (rc) return rc; + + rc = fdt_property_cell(fdt, "arm,smc-id", func_id); + if (rc) return rc; + + rc = scmi_dt_copy_subnodes(gc, fdt, pfdt); + if (rc) return rc; + + rc = fdt_end_node(fdt); + if (rc) return rc; + + return rc; +} + +static int make_firmware_node(libxl__gc *gc, void *fdt, void *pfdt, int tee, + int sci, uint32_t func_id) +{ + int res; + + if ((tee == LIBXL_TEE_TYPE_NONE) && (sci == LIBXL_ARM_SCI_TYPE_NONE)) + return 0; + + res = fdt_begin_node(fdt, "firmware"); + if (res) return res; + + if (tee == LIBXL_TEE_TYPE_OPTEE) { + res = make_optee_node(gc, fdt); + if (res) return res; + } + + if (sci == LIBXL_ARM_SCI_TYPE_SCMI_SMC) { + res = scmi_dt_create_node(gc, fdt, pfdt, func_id); + if (res) return res; + } + + res = fdt_end_node(fdt); + if (res) return res; + + return 0; +} + /* * The partial device tree is not copied entirely. Only the relevant bits are * copied to the guest device tree: @@ -1745,8 +2017,11 @@ static int libxl__prepare_dtb(libxl__gc *gc, libxl_domain_config *d_config, if (info->arch_arm.vuart == LIBXL_VUART_TYPE_SBSA_UART) FDT( make_vpl011_uart_node(gc, fdt, ainfo, dom) ); - if (info->tee == LIBXL_TEE_TYPE_OPTEE) - FDT( make_optee_node(gc, fdt) ); + if (info->arm_sci == LIBXL_ARM_SCI_TYPE_SCMI_SMC) + FDT( scmi_dt_make_shmem_node(gc, fdt) ); + + FDT( make_firmware_node(gc, fdt, pfdt, info->tee, info->arm_sci, + state->arm_sci_agent_funcid) ); if (d_config->num_pcidevs) FDT( make_vpci_node(gc, fdt, ainfo, dom) ); @@ -2034,6 +2309,16 @@ int libxl__arch_build_dom_finish(libxl__gc *gc, { int rc = 0, ret; + if (info->arm_sci == LIBXL_ARM_SCI_TYPE_SCMI_SMC) { + ret = map_sci_page(gc, dom->guest_domid, state->arm_sci_agent_paddr, + GUEST_SCI_SHMEM_BASE); + if (ret < 0) { + LOG(ERROR, "map_sci_page failed\n"); + rc = ERROR_FAIL; + goto out; + } + } + if (info->arch_arm.vuart != LIBXL_VUART_TYPE_SBSA_UART) { rc = 0; goto out; diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c index e7f5607cd68c..f11c7b1b842a 100644 --- a/tools/libs/light/libxl_create.c +++ b/tools/libs/light/libxl_create.c @@ -774,6 +774,18 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config, */ assert(libxl_domid_valid_guest(*domid)); + if (d_config->b_info.arm_sci == LIBXL_ARM_SCI_TYPE_SCMI_SMC) { + ret = xc_domain_get_sci_info(ctx->xch, *domid, &state->arm_sci_agent_paddr, + &state->arm_sci_agent_funcid); + LOGD(DEBUG, *domid,"sci_agent_paddr = %lx", state->arm_sci_agent_paddr); + if (ret) { + LOGED(ERROR, *domid, "failed to get sci paddr"); + rc = ERROR_FAIL; + goto out; + } + + } + dom_path = libxl__xs_get_dompath(gc, *domid); if (!dom_path) { rc = ERROR_FAIL; diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h index d1f086b1bd7d..07fbbdcbfba9 100644 --- a/tools/libs/light/libxl_internal.h +++ b/tools/libs/light/libxl_internal.h @@ -1409,6 +1409,9 @@ typedef struct { * applicable to the primary domain, not support domains (e.g. stub QEMU). */ bool restore; bool soft_reset; + + uint64_t arm_sci_agent_paddr; + uint32_t arm_sci_agent_funcid; } libxl__domain_build_state; _hidden void libxl__domain_build_state_init(libxl__domain_build_state *s); diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index ad56efb0f577..72efe66b9fa8 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -5,6 +5,7 @@ * Copyright (c) 2012, Citrix Systems */ +#include #include #include #include @@ -48,6 +49,17 @@ static int handle_vuart_init(struct domain *d, return rc; } +static int get_sci_info(struct domain *d, struct xen_domctl_sci_info *sci_info) +{ +#ifdef CONFIG_ARM_SCI + sci_info->paddr = d->arch.sci_channel.paddr; + sci_info->func_id = d->arch.sci_channel.guest_func_id; + return 0; +#else + return -ENODEV; +#endif +} + long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) { @@ -176,6 +188,15 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, return rc; } + case XEN_DOMCTL_get_sci_info: + { + int rc = get_sci_info(d, &domctl->u.sci_info); + + if ( !rc ) + rc = copy_to_guest(u_domctl, domctl, 1); + + return rc; + } default: return subarch_do_domctl(domctl, d, u_domctl); } diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h index 71e661df7668..24d730d4b39a 100644 --- a/xen/include/public/arch-arm.h +++ b/xen/include/public/arch-arm.h @@ -467,13 +467,14 @@ typedef uint64_t xen_callback_t; #define GUEST_ACPI_BASE xen_mk_ullong(0x20000000) #define GUEST_ACPI_SIZE xen_mk_ullong(0x02000000) -/* SCI mediator size */ -#define GUEST_SCI_SHMEM_SIZE xen_mk_ullong(0x01000) - /* PL011 mappings */ #define GUEST_PL011_BASE xen_mk_ullong(0x22000000) #define GUEST_PL011_SIZE xen_mk_ullong(0x00001000) +/* SCI mediator */ +#define GUEST_SCI_SHMEM_BASE xen_mk_ullong(0x22001000) +#define GUEST_SCI_SHMEM_SIZE xen_mk_ullong(0x01000) + /* Guest PCI-PCIe memory space where config space and BAR will be available.*/ #define GUEST_VPCI_ADDR_TYPE_MEM xen_mk_ullong(0x02000000) #define GUEST_VPCI_MEM_ADDR xen_mk_ullong(0x23000000) diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index a33f9ec32b08..571767606491 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -1187,6 +1187,13 @@ struct xen_domctl_vmtrace_op { #define XEN_DOMCTL_vmtrace_get_option 5 #define XEN_DOMCTL_vmtrace_set_option 6 }; + +/* XEN_DOMCTL_get_sci_info */ +struct xen_domctl_sci_info { + uint64_t paddr; + uint32_t func_id; +}; + typedef struct xen_domctl_vmtrace_op xen_domctl_vmtrace_op_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_vmtrace_op_t); @@ -1277,6 +1284,7 @@ struct xen_domctl { #define XEN_DOMCTL_vmtrace_op 84 #define XEN_DOMCTL_get_paging_mempool_size 85 #define XEN_DOMCTL_set_paging_mempool_size 86 +#define XEN_DOMCTL_get_sci_info 87 #define XEN_DOMCTL_gdbsx_guestmemio 1000 #define XEN_DOMCTL_gdbsx_pausevcpu 1001 #define XEN_DOMCTL_gdbsx_unpausevcpu 1002 @@ -1339,6 +1347,7 @@ struct xen_domctl { struct xen_domctl_vuart_op vuart_op; struct xen_domctl_vmtrace_op vmtrace_op; struct xen_domctl_paging_mempool paging_mempool; + struct xen_domctl_sci_info sci_info; uint8_t pad[128]; } u; };