xen/arm: Add support for GICv3 for domU
authorJulien Grall <julien.grall@linaro.org>
Wed, 5 Nov 2014 13:04:22 +0000 (13:04 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Mon, 10 Nov 2014 12:03:35 +0000 (12:03 +0000)
The vGIC will emulate the same version as the hardware. The toolstack has
to retrieve the version of the vGIC in order to be able to create the
corresponding device tree node.

A new DOMCTL has been introduced for ARM to configure the domain. For now
it only allow the toolstack to retrieve the version of vGIC.
This DOMCTL will be extend later to let the user choose the version of the
emulated GIC.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Signed-off-by: Julien Grall <julien.grall@linaro.org>
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Jan Beulich <jbeulich@suse.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Cc: Wei Liu <wei.liu2@citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
tools/flask/policy/policy/modules/xen/xen.if
tools/libxc/include/xenctrl.h
tools/libxc/xc_domain.c
tools/libxl/libxl_arm.c
xen/arch/arm/domctl.c
xen/arch/arm/gic-v3.c
xen/include/public/arch-arm.h
xen/include/public/domctl.h
xen/xsm/flask/hooks.c
xen/xsm/flask/policy/access_vectors

index 641c7979947007108902d3d40b7519530ebc0b84..fa69c9d3dccc05cc8b34b3844d389c49d51f6867 100644 (file)
@@ -49,7 +49,7 @@ define(`create_domain_common', `
                        getdomaininfo hypercall setvcpucontext setextvcpucontext
                        getscheduler getvcpuinfo getvcpuextstate getaddrsize
                        getaffinity setaffinity };
-       allow $1 $2:domain2 { set_cpuid settsc setscheduler setclaim set_max_evtchn set_vnumainfo get_vnumainfo psr_cmt_op };
+       allow $1 $2:domain2 { set_cpuid settsc setscheduler setclaim set_max_evtchn set_vnumainfo get_vnumainfo psr_cmt_op configure_domain };
        allow $1 $2:security check_context;
        allow $1 $2:shadow enable;
        allow $1 $2:mmu { map_read map_write adjust memorymap physmap pinpage mmuext_op };
index 564e18750e9dc160af24fef8cfc82ebb0db48321..45e282c956a611acf5fee3448d19b796a1cfdaa6 100644 (file)
@@ -483,6 +483,12 @@ int xc_domain_create(xc_interface *xch,
                      uint32_t flags,
                      uint32_t *pdomid);
 
+#if defined(__arm__) || defined(__aarch64__)
+typedef xen_domctl_arm_configuredomain_t xc_domain_configuration_t;
+
+int xc_domain_configure(xc_interface *xch, uint32_t domid,
+                        xc_domain_configuration_t *config);
+#endif
 
 /* Functions to produce a dump of a given domain
  *  xc_domain_dumpcore - produces a dump to a specified file
index a9bcd4a0bfe7780bfb5c3397088439b8a8d5f53c..b071dea08323b7655c5d5ee1008c23ad4f75d2e7 100644 (file)
@@ -48,6 +48,26 @@ int xc_domain_create(xc_interface *xch,
     return 0;
 }
 
+#if defined(__arm__) || defined(__aarch64__)
+int xc_domain_configure(xc_interface *xch, uint32_t domid,
+                        xc_domain_configuration_t *config)
+{
+    int rc;
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_arm_configure_domain;
+    domctl.domain = (domid_t)domid;
+    /* xc_domain_configure_t is an alias of xen_domctl_arm_configuredomain */
+    memcpy(&domctl.u.configuredomain, config, sizeof(*config));
+
+    rc = do_domctl(xch, &domctl);
+    if ( !rc )
+        memcpy(config, &domctl.u.configuredomain, sizeof(*config));
+
+    return rc;
+}
+#endif
+
 int xc_domain_cacheflush(xc_interface *xch, uint32_t domid,
                          xen_pfn_t start_pfn, xen_pfn_t nr_pfns)
 {
index a122e4aac616e56fe839648ae452731d1ec2c593..448ac078d72e70854f17418e5a330a808bd7be15 100644 (file)
 #define DT_IRQ_TYPE_LEVEL_HIGH     0x00000004
 #define DT_IRQ_TYPE_LEVEL_LOW      0x00000008
 
+static const char *gicv_to_string(uint8_t gic_version)
+{
+    switch (gic_version) {
+    case XEN_DOMCTL_CONFIG_GIC_V2:
+        return "V2";
+    case XEN_DOMCTL_CONFIG_GIC_V3:
+        return "V3";
+    default:
+        return "unknown";
+    }
+}
+
 int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
                               uint32_t domid)
 {
@@ -307,9 +319,9 @@ static int make_memory_nodes(libxl__gc *gc, void *fdt,
     return 0;
 }
 
-static int make_intc_node(libxl__gc *gc, void *fdt,
-                          uint64_t gicd_base, uint64_t gicd_size,
-                          uint64_t gicc_base, uint64_t gicc_size)
+static int make_gicv2_node(libxl__gc *gc, void *fdt,
+                           uint64_t gicd_base, uint64_t gicd_size,
+                           uint64_t gicc_base, uint64_t gicc_size)
 {
     int res;
     const char *name = GCSPRINTF("interrupt-controller@%"PRIx64, gicd_base);
@@ -350,6 +362,56 @@ static int make_intc_node(libxl__gc *gc, void *fdt,
     return 0;
 }
 
+static int make_gicv3_node(libxl__gc *gc, void *fdt)
+{
+    int res;
+    const uint64_t gicd_base = GUEST_GICV3_GICD_BASE;
+    const uint64_t gicd_size = GUEST_GICV3_GICD_SIZE;
+    const uint64_t gicr0_base = GUEST_GICV3_GICR0_BASE;
+    const uint64_t gicr0_size = GUEST_GICV3_GICR0_SIZE;
+    const char *name = GCSPRINTF("interrupt-controller@%"PRIx64, gicd_base);
+
+    res = fdt_begin_node(fdt, name);
+    if (res) return res;
+
+    res = fdt_property_compat(gc, fdt, 1, "arm,gic-v3");
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "#interrupt-cells", 3);
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "#address-cells", 0);
+    if (res) return res;
+
+    res = fdt_property(fdt, "interrupt-controller", NULL, 0);
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "redistributor-stride",
+                            GUEST_GICV3_RDIST_STRIDE);
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "#redistributor-regions",
+                            GUEST_GICV3_RDIST_REGIONS);
+    if (res) return res;
+
+    res = fdt_property_regs(gc, fdt, ROOT_ADDRESS_CELLS, ROOT_SIZE_CELLS,
+                            2,
+                            gicd_base, gicd_size,
+                            gicr0_base, gicr0_size);
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "linux,phandle", PHANDLE_GIC);
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "phandle", PHANDLE_GIC);
+    if (res) return res;
+
+    res = fdt_end_node(fdt);
+    if (res) return res;
+
+    return 0;
+}
+
 static int make_timer_node(libxl__gc *gc, void *fdt, const struct arch_info *ainfo)
 {
     int res;
@@ -456,6 +518,7 @@ int libxl__arch_domain_init_hw_description(libxl__gc *gc,
                                            libxl_domain_build_info *info,
                                            struct xc_dom_image *dom)
 {
+    xc_domain_configuration_t config;
     void *fdt = NULL;
     int rc, res;
     size_t fdt_size = 0;
@@ -471,8 +534,16 @@ int libxl__arch_domain_init_hw_description(libxl__gc *gc,
     ainfo = get_arch_info(gc, dom);
     if (ainfo == NULL) return ERROR_FAIL;
 
+    LOG(DEBUG, "configure the domain");
+    config.gic_version = XEN_DOMCTL_CONFIG_GIC_DEFAULT;
+    if (xc_domain_configure(CTX->xch, dom->guest_domid, &config) != 0) {
+        LOG(ERROR, "couldn't configure the domain");
+        return ERROR_FAIL;
+    }
+
     LOG(DEBUG, "constructing DTB for Xen version %d.%d guest",
         vers->xen_version_major, vers->xen_version_minor);
+    LOG(DEBUG, "  - vGIC version: %s", gicv_to_string(config.gic_version));
 
 /*
  * Call "call" handling FDR_ERR_*. Will either:
@@ -520,9 +591,21 @@ next_resize:
         FDT( make_psci_node(gc, fdt) );
 
         FDT( make_memory_nodes(gc, fdt, dom) );
-        FDT( make_intc_node(gc, fdt,
-                            GUEST_GICD_BASE, GUEST_GICD_SIZE,
-                            GUEST_GICC_BASE, GUEST_GICD_SIZE) );
+
+        switch (config.gic_version) {
+        case XEN_DOMCTL_CONFIG_GIC_V2:
+            FDT( make_gicv2_node(gc, fdt,
+                                 GUEST_GICD_BASE, GUEST_GICD_SIZE,
+                                 GUEST_GICC_BASE, GUEST_GICC_SIZE) );
+            break;
+        case XEN_DOMCTL_CONFIG_GIC_V3:
+            FDT( make_gicv3_node(gc, fdt) );
+            break;
+        default:
+            LOG(ERROR, "Unknown GIC version %d", config.gic_version);
+            rc = ERROR_FAIL;
+            goto out;
+        }
 
         FDT( make_timer_node(gc, fdt, ainfo) );
         FDT( make_hypervisor_node(gc, fdt, vers) );
index 45974e735fdba1939c80de78ac6fa03f8ccc995c..d246e84590af5de6b1dc7052bc908bac95a02dff 100644 (file)
@@ -10,6 +10,8 @@
 #include <xen/errno.h>
 #include <xen/sched.h>
 #include <xen/hypercall.h>
+#include <asm/gic.h>
+#include <xen/guest_access.h>
 #include <public/domctl.h>
 
 long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
@@ -30,6 +32,39 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
 
         return p2m_cache_flush(d, s, e);
     }
+    case XEN_DOMCTL_arm_configure_domain:
+    {
+        uint8_t gic_version;
+
+        /*
+         * Currently the vGIC is emulating the same version of the
+         * hardware GIC. Only the value XEN_DOMCTL_CONFIG_GIC_DEFAULT
+         * is allowed. The DOMCTL will return the actual version of the
+         * GIC.
+         */
+        if ( domctl->u.configuredomain.gic_version != XEN_DOMCTL_CONFIG_GIC_DEFAULT )
+            return -EOPNOTSUPP;
+
+        switch ( gic_hw_version() )
+        {
+        case GIC_V3:
+            gic_version = XEN_DOMCTL_CONFIG_GIC_V3;
+            break;
+        case GIC_V2:
+            gic_version = XEN_DOMCTL_CONFIG_GIC_V2;
+            break;
+        default:
+            BUG();
+        }
+
+        domctl->u.configuredomain.gic_version = gic_version;
+
+        /* TODO: Make the copy generic for all ARCH domctl */
+        if ( __copy_to_guest(u_domctl, domctl, 1) )
+            return -EFAULT;
+
+        return 0;
+    }
 
     default:
         return subarch_do_domctl(domctl, d, u_domctl);
index 91161a2225f1eb19e6a7ff6e3bc4094ebeb7e90e..076aa627fb6ceca79e19390919faa76ea22dada4 100644 (file)
@@ -906,7 +906,21 @@ static int gicv_v3_init(struct domain *d)
         d->arch.vgic.rdist_count = gicv3.rdist_count;
     }
     else
-        d->arch.vgic.dbase = GUEST_GICD_BASE;
+    {
+        d->arch.vgic.dbase = GUEST_GICV3_GICD_BASE;
+        d->arch.vgic.dbase_size = GUEST_GICV3_GICD_SIZE;
+
+        /* XXX: Only one Re-distributor region mapped for the guest */
+        BUILD_BUG_ON(GUEST_GICV3_RDIST_REGIONS != 1);
+
+        d->arch.vgic.rdist_count = GUEST_GICV3_RDIST_REGIONS;
+        d->arch.vgic.rdist_stride = GUEST_GICV3_RDIST_STRIDE;
+
+        /* The first redistributor should contain enough space for all CPUs */
+        BUILD_BUG_ON((GUEST_GICV3_GICR0_SIZE / GUEST_GICV3_RDIST_STRIDE) < MAX_VIRT_CPUS);
+        d->arch.vgic.rbase[0] = GUEST_GICV3_GICR0_BASE;
+        d->arch.vgic.rbase_size[0] = GUEST_GICV3_GICR0_SIZE;
+    }
 
     d->arch.vgic.nr_lines = 0;
 
index ac54cd61e0f664668b850aedda786976796e4bc8..e7116064c72e985e88a162bf4a838e178dc68377 100644 (file)
@@ -364,11 +364,27 @@ typedef uint64_t xen_callback_t;
  */
 
 /* Physical Address Space */
+
+/* vGIC mappings: Only one set of mapping is used by the guest.
+ * Therefore they can overlap.
+ */
+
+/* vGIC v2 mappings */
 #define GUEST_GICD_BASE   0x03001000ULL
 #define GUEST_GICD_SIZE   0x00001000ULL
 #define GUEST_GICC_BASE   0x03002000ULL
 #define GUEST_GICC_SIZE   0x00000100ULL
 
+/* vGIC v3 mappings */
+#define GUEST_GICV3_GICD_BASE      0x03001000ULL
+#define GUEST_GICV3_GICD_SIZE      0x00010000ULL
+
+#define GUEST_GICV3_RDIST_STRIDE   0x20000ULL
+#define GUEST_GICV3_RDIST_REGIONS  1
+
+#define GUEST_GICV3_GICR0_BASE     0x03020000ULL    /* vCPU0 - vCPU7 */
+#define GUEST_GICV3_GICR0_SIZE     0x00100000ULL
+
 /* 16MB == 4096 pages reserved for guest to use as a region to map its
  * grant table in.
  */
index 58b19e7c1fb102ea8a47e58a8aa85b94549f49f3..8da204e41e158d51f84ca2b13c16fee11793444c 100644 (file)
@@ -68,6 +68,19 @@ struct xen_domctl_createdomain {
 typedef struct xen_domctl_createdomain xen_domctl_createdomain_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_createdomain_t);
 
+#if defined(__arm__) || defined(__aarch64__)
+#define XEN_DOMCTL_CONFIG_GIC_DEFAULT   0
+#define XEN_DOMCTL_CONFIG_GIC_V2        1
+#define XEN_DOMCTL_CONFIG_GIC_V3        2
+/* XEN_DOMCTL_configure_domain */
+struct xen_domctl_arm_configuredomain {
+    /* IN/OUT parameters */
+    uint8_t gic_version;
+};
+typedef struct xen_domctl_arm_configuredomain xen_domctl_arm_configuredomain_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_arm_configuredomain_t);
+#endif
+
 /* XEN_DOMCTL_getdomaininfo */
 struct xen_domctl_getdomaininfo {
     /* OUT variables. */
@@ -1056,6 +1069,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_set_vcpu_msrs                 73
 #define XEN_DOMCTL_setvnumainfo                  74
 #define XEN_DOMCTL_psr_cmt_op                    75
+#define XEN_DOMCTL_arm_configure_domain          76
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1064,6 +1078,9 @@ struct xen_domctl {
     domid_t  domain;
     union {
         struct xen_domctl_createdomain      createdomain;
+#if defined(__arm__) || defined(__aarch64__)
+        struct xen_domctl_arm_configuredomain configuredomain;
+#endif
         struct xen_domctl_getdomaininfo     getdomaininfo;
         struct xen_domctl_getmemlist        getmemlist;
         struct xen_domctl_getpageframeinfo  getpageframeinfo;
index 6d0fe72859a4e5053af215e8773aaa61343482c3..846cf88abba855e3d8e8a2c3e8919d53bf58ec23 100644 (file)
@@ -727,6 +727,9 @@ static int flask_domctl(struct domain *d, int cmd)
     case XEN_DOMCTL_psr_cmt_op:
         return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__PSR_CMT_OP);
 
+    case XEN_DOMCTL_configure_domain:
+        return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__CONFIGURE_DOMAIN);
+
     default:
         printk("flask_domctl: Unknown op %d\n", cmd);
         return -EPERM;
index de0c707fdf692f359dcee6c321c9a3136a4b5752..bfe2fa5638349ff200026fbc2c97bc52eabfe865 100644 (file)
@@ -216,6 +216,8 @@ class domain2
     get_vnumainfo
 # XEN_DOMCTL_psr_cmt_op
     psr_cmt_op
+# XEN_DOMCTL_configure_domain
+    configure_domain
 }
 
 # Similar to class domain, but primarily contains domctls related to HVM domains