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 <oleksii_moisie...@epam.com>
---
tools/include/xenctrl.h | 3 +
tools/include/xenguest.h | 2 +
tools/libs/ctrl/xc_domain.c | 23 ++++++
tools/libs/guest/xg_dom_arm.c | 5 +-
tools/libs/light/libxl_arm.c | 122 +++++++++++++++++++++++++++---
tools/libs/light/libxl_create.c | 54 ++++++++++++-
tools/libs/light/libxl_dom.c | 1 +
tools/libs/light/libxl_internal.h | 4 +
xen/arch/arm/domctl.c | 15 ++++
xen/include/public/domctl.h | 9 +++
10 files changed, 223 insertions(+), 15 deletions(-)
diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h
index 07b96e6671..cdd14f465f 100644
--- a/tools/include/xenctrl.h
+++ b/tools/include/xenctrl.h
@@ -1238,6 +1238,9 @@ int xc_domain_getvnuma(xc_interface *xch,
int xc_domain_soft_reset(xc_interface *xch,
uint32_t domid);
+int xc_domain_add_sci_device(xc_interface *xch,
+ uint32_t domid, char *path);
+
#if defined(__i386__) || defined(__x86_64__)
/*
* PC BIOS standard E820 types and structure.
diff --git a/tools/include/xenguest.h b/tools/include/xenguest.h
index 61d0a82f48..35c611ac73 100644
--- a/tools/include/xenguest.h
+++ b/tools/include/xenguest.h
@@ -242,6 +242,8 @@ struct xc_dom_image {
/* Number of vCPUs */
unsigned int max_vcpus;
+
+ xen_pfn_t sci_shmem_gfn;
};
/* --- arch specific hooks ----------------------------------------- */
diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c
index b155d6afd2..07bb390e17 100644
--- a/tools/libs/ctrl/xc_domain.c
+++ b/tools/libs/ctrl/xc_domain.c
@@ -2206,6 +2206,29 @@ int xc_domain_soft_reset(xc_interface *xch,
domctl.domain = domid;
return do_domctl(xch, &domctl);
}
+
+int xc_domain_add_sci_device(xc_interface *xch,
+ uint32_t domid, char *path)
+{
+ size_t size = strlen(path);
+ int rc;
+ DECLARE_DOMCTL;
+ DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+ if ( xc_hypercall_bounce_pre(xch, path) )
+ return -1;
+
+ domctl.cmd = XEN_DOMCTL_add_sci_device;
+ domctl.domain = domid;
+ domctl.u.sci_device_op.size = size;
+ set_xen_guest_handle(domctl.u.sci_device_op.path, path);
+ rc = do_domctl(xch, &domctl);
+
+ xc_hypercall_bounce_post(xch, path);
+
+ return rc;
+}
+
/*
* Local variables:
* mode: C
diff --git a/tools/libs/guest/xg_dom_arm.c b/tools/libs/guest/xg_dom_arm.c
index 5e3b76355e..368a670c46 100644
--- a/tools/libs/guest/xg_dom_arm.c
+++ b/tools/libs/guest/xg_dom_arm.c
@@ -25,11 +25,12 @@
#include "xg_private.h"
-#define NR_MAGIC_PAGES 4
+#define NR_MAGIC_PAGES 5
#define CONSOLE_PFN_OFFSET 0
#define XENSTORE_PFN_OFFSET 1
#define MEMACCESS_PFN_OFFSET 2
#define VUART_PFN_OFFSET 3
+#define SCI_SHMEM_OFFSET 4
#define LPAE_SHIFT 9
@@ -69,11 +70,13 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
dom->console_pfn = base + CONSOLE_PFN_OFFSET;
dom->xenstore_pfn = base + XENSTORE_PFN_OFFSET;
dom->vuart_gfn = base + VUART_PFN_OFFSET;
+ dom->sci_shmem_gfn = base + SCI_SHMEM_OFFSET;
xc_clear_domain_page(dom->xch, dom->guest_domid, dom->console_pfn);
xc_clear_domain_page(dom->xch, dom->guest_domid, dom->xenstore_pfn);
xc_clear_domain_page(dom->xch, dom->guest_domid, base +
MEMACCESS_PFN_OFFSET);
xc_clear_domain_page(dom->xch, dom->guest_domid, dom->vuart_gfn);
+ xc_clear_domain_page(dom->xch, dom->guest_domid, dom->sci_shmem_gfn);
xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_PFN,
dom->console_pfn);
diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index eef1de0939..73ef591822 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -8,6 +8,8 @@
#include <assert.h>
#include <xen/device_tree_defs.h>
+#define SCMI_NODE_PATH "/firmware/scmi"
+
static const char *gicv_to_string(libxl_gic_version gic_version)
{
switch (gic_version) {
@@ -101,6 +103,19 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
return ERROR_FAIL;
}
+ switch (d_config->b_info.sci) {
+ case LIBXL_SCI_TYPE_NONE:
+ config->arch.sci_type = XEN_DOMCTL_CONFIG_SCI_NONE;
+ break;
+ case LIBXL_SCI_TYPE_SCMI_SMC:
+ config->arch.sci_type = XEN_DOMCTL_CONFIG_SCI_SCMI_SMC;
+ break;
+ default:
+ LOG(ERROR, "Unknown SCI type %d",
+ d_config->b_info.sci);
+ return ERROR_FAIL;
+ }
+
return 0;
}
@@ -122,6 +137,7 @@ int libxl__arch_domain_save_config(libxl__gc *gc,
}
state->clock_frequency = config->arch.clock_frequency;
+ state->sci_agent_paddr = config->arch.sci_agent_paddr;
return 0;
}
@@ -502,9 +518,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;
@@ -517,9 +530,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;
}
@@ -902,10 +912,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)
@@ -925,12 +934,101 @@ 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 get_node_phandle(const char *path, void *pfdt, uint32_t *phandle)
+{
+ int nodeoff;
+ const char *name = strrchr(path, '/');
+
+ if (!name)
+ return -FDT_ERR_INTERNAL;
+
+ name++;
+ nodeoff = fdt_path_offset(pfdt, path);
+ if (nodeoff < 0)
+ return nodeoff;
+
+ *phandle = fdt_get_phandle(pfdt, nodeoff);
+ return 0;
+}
+
+static int make_scmi_shmem_node(libxl__gc *gc, void *fdt, void *pfdt,
+ struct xc_dom_image *dom)
+{
+ int res;
+ char buf[64];
+ uint32_t phandle = 0;
+
+ res = get_node_phandle("/scp-shmem", pfdt, &phandle);
+ if (res) return res;
+
+ snprintf(buf, sizeof(buf), "scp-shmem@%lx",
+ dom->sci_shmem_gfn << XC_PAGE_SHIFT);
+ 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,
+ dom->sci_shmem_gfn << XC_PAGE_SHIFT, XC_PAGE_SHIFT);
+ if (res) return res;
+
+ LOG(DEBUG, "scmi: setting phandle = %u\n", phandle);
+ res = fdt_property_cell(fdt, "phandle", phandle);
+ if (res) return res;
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+
+ return 0;
+}
+
+static int make_firmware_node(libxl__gc *gc, void *fdt, void *pfdt, int tee,
+ int sci)
+{
+ int res;
+
+ if ((tee != LIBXL_TEE_TYPE_OPTEE) && (sci != LIBXL_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_SCI_TYPE_SCMI_SMC) {
+ res = copy_node_by_path(gc, SCMI_NODE_PATH, fdt, pfdt);
+ 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:
@@ -1088,8 +1186,10 @@ next_resize:
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) );
+ FDT( make_firmware_node(gc, fdt, pfdt, info->tee, info->sci) );
+
+ if (info->sci == LIBXL_SCI_TYPE_SCMI_SMC)
+ FDT( make_scmi_shmem_node(gc, fdt, pfdt, dom) );
if (d_config->num_pcidevs)
FDT( make_vpci_node(gc, fdt, ainfo, dom) );
diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index dcd09d32ba..c7372fd344 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -596,6 +596,37 @@ out:
return ret;
}
+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;
+
+ 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;
+}
+
int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
libxl__domain_build_state *state,
uint32_t *domid, bool soft_reset)
@@ -762,6 +793,16 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config
*d_config,
goto out;
}
+ if (state->sci_agent_paddr != 0) {
+ ret = map_sci_page(gc, *domid, state->sci_agent_paddr,
+ state->sci_shmem_gfn << XC_PAGE_SHIFT);
+ if (ret < 0) {
+ LOGED(ERROR, *domid, "map SCI page fail");
+ rc = ERROR_FAIL;
+ goto out;
+ }
+ }
+
dom_path = libxl__xs_get_dompath(gc, *domid);
if (!dom_path) {
rc = ERROR_FAIL;
@@ -1817,17 +1858,24 @@ static void libxl__add_dtdevs(libxl__egc *egc,
libxl__ao *ao, uint32_t domid,
{
AO_GC;
libxl__ao_device *aodev = libxl__multidev_prepare(multidev);
- int i, rc = 0;
+ int i, rc = 0, rc_sci = 0;
for (i = 0; i < d_config->num_dtdevs; i++) {
const libxl_device_dtdev *dtdev = &d_config->dtdevs[i];
LOGD(DEBUG, domid, "Assign device \"%s\" to domain", dtdev->path);
rc = xc_assign_dt_device(CTX->xch, domid, dtdev->path);
- if (rc < 0) {
- LOGD(ERROR, domid, "xc_assign_dtdevice failed: %d", rc);
+ rc_sci = xc_domain_add_sci_device(CTX->xch, domid, dtdev->path);
+
+ if ((rc < 0) && (rc_sci < 0)) {
+ LOGD(ERROR, domid, "xc_assign_dt_device failed: %d; "
+ "xc_domain_add_sci_device failed: %d",
+ rc, rc_sci);
goto out;
}
+
+ if (rc)
+ rc = rc_sci;