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..1e9072fd6f02 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, "iomem %"PRIx64, _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, 128); + 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, "Partial FDT is not a valid Flat Device Tree"); + return ERROR_FAIL; + } + + r = fdt_check_header(fdt); + if (r) { + LOG(ERROR, "Failed to check the partial 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("/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..8f64e09e06b4 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,16 @@ 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; +#endif /* CONFIG_ARM_SCI */ + return 0; +} + + long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) { @@ -176,9 +187,20 @@ 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); } + } } void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c) 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; };