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 };
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
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)
{
#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)
{
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);
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;
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;
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:
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) );
#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,
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);
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;
*/
/* 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.
*/
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. */
#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
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;
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;
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