|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] libxl: build a device tree for ARM guests
commit 0c64527e7fc961372a398eb68e307c2b103f1a28
Author: Ian Campbell <ian.campbell@xxxxxxxxxx>
AuthorDate: Tue Nov 19 13:00:24 2013 +0000
Commit: Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Tue Nov 19 16:41:14 2013 +0000
libxl: build a device tree for ARM guests
Uses xc_dom_devicetree_mem which was just added. The call to this needs to
be
carefully sequenced to be after xc_dom_parse_image (so we can tell which
kind
of guest we are building, although we don't use this yet) and before
xc_dom_mem_init which tries to decide where to place the FDT in guest RAM.
Removes libxl_noarch which would only have been used by IA64 after this
change. Remove IA64 as part of this patch.
There is no attempt to expose this as a configuration setting for the user.
Includes a debug hook to dump the dtb to a file for inspection.
On v7 the CPU compat is currently hardcoded to cortex-a15. This likely wants
to change at some point.
Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Acked-by: Julien Grall <julien.grall@xxxxxxxxxx>
---
tools/libxl/Makefile | 6 +-
tools/libxl/libxl_arch.h | 3 +
tools/libxl/libxl_arm.c | 512 ++++++++++++++++++++++++++++++++++++++++++++
tools/libxl/libxl_dom.c | 4 +
tools/libxl/libxl_noarch.c | 8 -
tools/libxl/libxl_x86.c | 7 +
6 files changed, 530 insertions(+), 10 deletions(-)
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index cf214bb..d8495bb 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -28,9 +28,12 @@ CFLAGS_LIBXL += $(CFLAGS_libxenstore)
CFLAGS_LIBXL += $(CFLAGS_libblktapctl)
CFLAGS_LIBXL += -Wshadow
+LIBXL_LIBS-$(CONFIG_ARM) += -lfdt
+
CFLAGS += $(PTHREAD_CFLAGS)
LDFLAGS += $(PTHREAD_LDFLAGS)
LIBXL_LIBS += $(PTHREAD_LIBS)
+LIBXL_LIBS += $(LIBXL_LIBS-y)
LIBXLU_LIBS =
@@ -41,8 +44,7 @@ else
LIBXL_OBJS-y += libxl_noblktap2.o
endif
LIBXL_OBJS-$(CONFIG_X86) += libxl_cpuid.o libxl_x86.o
-LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o libxl_noarch.o
-LIBXL_OBJS-$(CONFIG_ARM) += libxl_nocpuid.o libxl_noarch.o
+LIBXL_OBJS-$(CONFIG_ARM) += libxl_nocpuid.o libxl_arm.o
ifeq ($(CONFIG_NetBSD),y)
LIBXL_OBJS-y += libxl_netbsd.o
diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
index abe6685..aee0a91 100644
--- a/tools/libxl/libxl_arch.h
+++ b/tools/libxl/libxl_arch.h
@@ -19,4 +19,7 @@
int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
uint32_t domid);
+int libxl__arch_domain_configure(libxl__gc *gc,
+ libxl_domain_build_info *info,
+ struct xc_dom_image *dom);
#endif
diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
new file mode 100644
index 0000000..0a1c8c5
--- /dev/null
+++ b/tools/libxl/libxl_arm.c
@@ -0,0 +1,512 @@
+#include "libxl_internal.h"
+#include "libxl_arch.h"
+
+#include <xc_dom.h>
+#include <libfdt.h>
+#include <assert.h>
+
+int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
+ uint32_t domid)
+{
+ return 0;
+}
+
+static struct arch_info {
+ const char *guest_type;
+ const char *timer_compat;
+ const char *cpu_compat;
+} arch_info[] = {
+ {"xen-3.0-armv7l", "arm,armv7-timer", "arm,cortex-a15" },
+ {"xen-3.0-aarch64", "arm,armv8-timer", "arm,armv8" },
+};
+
+enum {
+ PHANDLE_NONE = 0,
+ PHANDLE_GIC,
+};
+
+typedef uint32_t be32;
+typedef be32 gic_interrupt[3];
+
+#define ROOT_ADDRESS_CELLS 2
+#define ROOT_SIZE_CELLS 2
+
+static void set_cell(be32 **cellp, int size, uint64_t val)
+{
+ int cells = size;
+
+ while (size--) {
+ (*cellp)[size] = cpu_to_fdt32(val);
+ val >>= 32;
+ }
+
+ (*cellp) += cells;
+}
+
+static void set_interrupt_ppi(gic_interrupt interrupt, unsigned int irq,
+ unsigned int cpumask, unsigned int level)
+{
+ be32 *cells = interrupt;
+
+ /* See linux Documentation/devictree/bindings/arm/gic.txt */
+ set_cell(&cells, 1, 1); /* is a PPI */
+ set_cell(&cells, 1, irq - 16); /* PPIs start at 16 */
+ set_cell(&cells, 1, (cpumask << 8) | level);
+}
+
+static void set_range(be32 **cellp,
+ int address_cells, int size_cells,
+ uint64_t address, uint64_t size)
+{
+ set_cell(cellp, address_cells, address);
+ set_cell(cellp, size_cells, size);
+}
+
+static int fdt_property_compat(libxl__gc *gc, void *fdt, unsigned nr_compat,
...)
+{
+ const char *compats[nr_compat];
+ int i;
+ size_t sz;
+ va_list ap;
+ char *compat, *p;
+
+ va_start(ap, nr_compat);
+ sz = 0;
+ for (i = 0; i < nr_compat; i++) {
+ const char *c = va_arg(ap, const char *);
+ compats[i] = c;
+ sz += strlen(compats[i]) + 1;
+ }
+ va_end(ap);
+
+ p = compat = libxl__zalloc(gc, sz);
+ for (i = 0; i < nr_compat; i++) {
+ strcpy(p, compats[i]);
+ p += strlen(compats[i]) + 1;
+ }
+
+ return fdt_property(fdt, "compatible", compat, sz);
+}
+
+static int fdt_property_interrupts(libxl__gc *gc, void *fdt,
+ gic_interrupt *intr,
+ unsigned num_irq)
+{
+ int res;
+
+ res = fdt_property(fdt, "interrupts", intr, sizeof (intr[0]) * num_irq);
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "interrupt-parent", PHANDLE_GIC);
+ if (res) return res;
+
+ return 0;
+}
+
+static int fdt_property_regs(libxl__gc *gc, void *fdt,
+ unsigned addr_cells,
+ unsigned size_cells,
+ unsigned num_regs, ...)
+{
+ uint32_t regs[num_regs*(addr_cells+size_cells)];
+ be32 *cells = ®s[0];
+ int i;
+ va_list ap;
+ uint64_t base, size;
+
+ va_start(ap, num_regs);
+ for (i = 0 ; i < num_regs; i++) {
+ base = addr_cells ? va_arg(ap, uint64_t) : 0;
+ size = size_cells ? va_arg(ap, uint64_t) : 0;
+ set_range(&cells, addr_cells, size_cells, base, size);
+ }
+ va_end(ap);
+
+ return fdt_property(fdt, "reg", regs, sizeof(regs));
+}
+
+static int make_root_properties(libxl__gc *gc,
+ const libxl_version_info *vers,
+ void *fdt)
+{
+ int res;
+
+ res = fdt_property_string(fdt, "model", GCSPRINTF("XENVM-%d.%d",
+ vers->xen_version_major,
+
vers->xen_version_minor));
+ if (res) return res;
+
+ res = fdt_property_compat(gc, fdt, 2,
+ GCSPRINTF("xen,xenvm-%d.%d",
+ vers->xen_version_major,
+ vers->xen_version_minor),
+ "xen,xenvm");
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "interrupt-parent", PHANDLE_GIC);
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "#address-cells", ROOT_ADDRESS_CELLS);
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "#size-cells", ROOT_SIZE_CELLS);
+ if (res) return res;
+
+ return 0;
+}
+
+static int make_chosen_node(libxl__gc *gc, void *fdt,
+ const libxl_domain_build_info *info)
+{
+ int res;
+
+ /* See linux Documentation/devicetree/... */
+ res = fdt_begin_node(fdt, "chosen");
+ if (res) return res;
+
+ res = fdt_property_string(fdt, "bootargs", info->u.pv.cmdline);
+ if (res) return res;
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+
+ return 0;
+}
+
+static int make_cpus_node(libxl__gc *gc, void *fdt, int nr_cpus,
+ const struct arch_info *ainfo)
+{
+ int res, i;
+
+ res = fdt_begin_node(fdt, "cpus");
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "#address-cells", 1);
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "#size-cells", 0);
+ if (res) return res;
+
+ for (i = 0; i < nr_cpus; i++) {
+ const char *name = GCSPRINTF("cpu@%d", i);
+
+ res = fdt_begin_node(fdt, name);
+ if (res) return res;
+
+ res = fdt_property_string(fdt, "device_type", "cpu");
+ if (res) return res;
+
+ res = fdt_property_compat(gc, fdt, 1, ainfo->cpu_compat);
+ if (res) return res;
+
+ res = fdt_property_string(fdt, "enable-method", "psci");
+ if (res) return res;
+
+ res = fdt_property_regs(gc, fdt, 1, 0, 1, (uint64_t)i);
+ if (res) return res;
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+ }
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+
+ return 0;
+}
+
+static int make_psci_node(libxl__gc *gc, void *fdt)
+{
+ int res;
+
+ res = fdt_begin_node(fdt, "psci");
+ if (res) return res;
+
+ res = fdt_property_compat(gc, fdt, 1, "arm,psci");
+ if (res) return res;
+
+ res = fdt_property_string(fdt, "method", "hvc");
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "cpu_off", PSCI_cpu_off);
+ if (res) return res;
+
+ res = fdt_property_cell(fdt, "cpu_on", PSCI_cpu_on);
+ if (res) return res;
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+
+ return 0;
+}
+
+static int make_memory_node(libxl__gc *gc, void *fdt,
+ unsigned long long base,
+ unsigned long long size)
+{
+ int res;
+ const char *name = GCSPRINTF("memory@%08llx", base);
+
+ res = fdt_begin_node(fdt, name);
+ if (res) return res;
+
+ res = fdt_property_string(fdt, "device_type", "memory");
+ if (res) return res;
+
+ res = fdt_property_regs(gc, fdt, ROOT_ADDRESS_CELLS, ROOT_SIZE_CELLS,
+ 1, (uint64_t)base, (uint64_t)size);
+ if (res) return res;
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+
+ return 0;
+}
+
+static int make_intc_node(libxl__gc *gc, void *fdt,
+ unsigned long long gicd_base,
+ unsigned long long gicd_size,
+ unsigned long long gicc_base,
+ unsigned long long gicc_size)
+{
+ int res;
+ const char *name = GCSPRINTF("interrupt-controller@%08llx", gicd_base);
+
+ res = fdt_begin_node(fdt, name);
+ if (res) return res;
+
+ res = fdt_property_compat(gc, fdt, 2,
+ "arm,cortex-a15-gic",
+ "arm,cortex-a9-gic");
+ 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_regs(gc, fdt, ROOT_ADDRESS_CELLS, ROOT_SIZE_CELLS,
+ 2,
+ (uint64_t)gicd_base, (uint64_t)gicd_size,
+ (uint64_t)gicc_base, (uint64_t)gicc_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;
+ gic_interrupt ints[3];
+
+ res = fdt_begin_node(fdt, "timer");
+ if (res) return res;
+
+ res = fdt_property_compat(gc, fdt, 1, ainfo->timer_compat);
+ if (res) return res;
+
+ set_interrupt_ppi(ints[0], GUEST_TIMER_PHYS_S_PPI, 0xf, 0x8);
+ set_interrupt_ppi(ints[1], GUEST_TIMER_PHYS_NS_PPI, 0xf, 0x8);
+ set_interrupt_ppi(ints[2], GUEST_TIMER_VIRT_PPI, 0xf, 0x8);
+
+ res = fdt_property_interrupts(gc, fdt, ints, 3);
+ if (res) return res;
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+
+ return 0;
+}
+
+static int make_hypervisor_node(libxl__gc *gc, void *fdt,
+ const libxl_version_info *vers)
+{
+ int res;
+ gic_interrupt intr;
+
+ /* See linux Documentation/devicetree/bindings/arm/xen.txt */
+ res = fdt_begin_node(fdt, "hypervisor");
+ if (res) return res;
+
+ res = fdt_property_compat(gc, fdt, 2,
+ GCSPRINTF("xen,xen-%d.%d",
+ vers->xen_version_major,
+ vers->xen_version_minor),
+ "xen,xen");
+ if (res) return res;
+
+ /* reg 0 is grant table space */
+ res = fdt_property_regs(gc, fdt, ROOT_ADDRESS_CELLS, ROOT_SIZE_CELLS,
+ 1,GUEST_GNTTAB_BASE, GUEST_GNTTAB_SIZE);
+ if (res) return res;
+
+ /*
+ * interrupts is evtchn upcall:
+ * - Active-low level-sensitive
+ * - All cpus
+ */
+ set_interrupt_ppi(intr, GUEST_EVTCHN_PPI, 0xf, 0x8);
+
+ res = fdt_property_interrupts(gc, fdt, &intr, 1);
+ if (res) return res;
+
+ res = fdt_end_node(fdt);
+ if (res) return res;
+
+ return 0;
+}
+
+static const struct arch_info *get_arch_info(libxl__gc *gc,
+ const struct xc_dom_image *dom)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(arch_info); i++) {
+ const struct arch_info *info = &arch_info[i];
+ if (!strcmp(dom->guest_type, info->guest_type))
+ return info;
+ }
+ LOG(ERROR, "Unable to find arch FDT info for %s\n", dom->guest_type);
+ return NULL;
+}
+
+static void debug_dump_fdt(libxl__gc *gc, void *fdt)
+{
+ int fd = -1, rc, r;
+
+ const char *dtb = getenv("LIBXL_DEBUG_DUMP_DTB");
+
+ if (!dtb) goto out;
+
+ fd = open(dtb, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (fd < 0) {
+ LOGE(DEBUG, "cannot open %s for LIBXL_DEBUG_DUMP_DTB", dtb);
+ goto out;
+ }
+
+ rc = libxl_write_exactly(CTX, fd, fdt, fdt_totalsize(fdt), dtb, "dtb");
+ if (rc < 0) goto out;
+
+out:
+ if (fd >= 0) {
+ r = close(fd);
+ if (r < 0) LOGE(DEBUG, "failed to close DTB debug dump output");
+ }
+}
+
+#define FDT_MAX_SIZE (1<<20)
+
+int libxl__arch_domain_configure(libxl__gc *gc,
+ libxl_domain_build_info *info,
+ struct xc_dom_image *dom)
+{
+ void *fdt = NULL;
+ int rc, res;
+ size_t fdt_size = 0;
+
+ const libxl_version_info *vers;
+ const struct arch_info *ainfo;
+
+ assert(info->type == LIBXL_DOMAIN_TYPE_PV);
+
+ vers = libxl_get_version_info(CTX);
+ if (vers == NULL) return ERROR_FAIL;
+
+ ainfo = get_arch_info(gc, dom);
+ if (ainfo == NULL) return ERROR_FAIL;
+
+ LOG(DEBUG, "constructing DTB for Xen version %d.%d guest",
+ vers->xen_version_major, vers->xen_version_minor);
+
+/*
+ * Call "call" handling FDR_ERR_*. Will either:
+ * - loop back to retry_resize
+ * - set rc and goto out
+ * - fall through successfully
+ *
+ * On FDT_ERR_NOSPACE we start again from scratch rather than
+ * realloc+libfdt_open_into because "call" may have failed half way
+ * through a series of steps leaving the partial tree in an
+ * inconsistent state, e.g. leaving a node open.
+ */
+#define FDT( call ) do { \
+ int fdt_res = (call); \
+ if (fdt_res == -FDT_ERR_NOSPACE && fdt_size < FDT_MAX_SIZE) \
+ goto next_resize; \
+ else if (fdt_res < 0) { \
+ LOG(ERROR, "FDT: %s failed: %d = %s", \
+ #call, fdt_res, fdt_strerror(fdt_res)); \
+ rc = ERROR_FAIL; \
+ goto out; \
+ } \
+} while(0)
+
+ for (;;) {
+next_resize:
+ if (fdt_size) {
+ fdt_size <<= 1;
+ LOG(DEBUG, "Increasing FDT size to %zd and retrying", fdt_size);
+ } else {
+ fdt_size = 4096;
+ }
+
+ fdt = libxl__realloc(gc, fdt, fdt_size);
+
+ FDT( fdt_create(fdt, fdt_size) );
+
+ FDT( fdt_finish_reservemap(fdt) );
+
+ FDT( fdt_begin_node(fdt, "") );
+
+ FDT( make_root_properties(gc, vers, fdt) );
+ FDT( make_chosen_node(gc, fdt, info) );
+ FDT( make_cpus_node(gc, fdt, info->max_vcpus, ainfo) );
+ FDT( make_psci_node(gc, fdt) );
+
+ FDT( make_memory_node(gc, fdt,
+ dom->rambase_pfn << XC_PAGE_SHIFT,
+ info->target_memkb * 1024) );
+ FDT( make_intc_node(gc, fdt,
+ GUEST_GICD_BASE, GUEST_GICD_SIZE,
+ GUEST_GICC_BASE, GUEST_GICD_SIZE) );
+
+ FDT( make_timer_node(gc, fdt, ainfo) );
+ FDT( make_hypervisor_node(gc, fdt, vers) );
+
+ FDT( fdt_end_node(fdt) );
+
+ FDT( fdt_finish(fdt) );
+ break;
+ }
+#undef FDT
+
+ LOG(DEBUG, "fdt total size %d", fdt_totalsize(fdt));
+
+ res = xc_dom_devicetree_mem(dom, fdt, fdt_totalsize(fdt));
+ if (res) {
+ LOGE(ERROR, "xc_dom_devicetree_file failed");
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ debug_dump_fdt(gc, fdt);
+
+ rc = 0;
+
+out:
+ return rc;
+}
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index 521329e..72489f8 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -403,6 +403,10 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
LOGE(ERROR, "xc_dom_parse_image failed");
goto out;
}
+ if ( (ret = libxl__arch_domain_configure(gc, info, dom)) != 0 ) {
+ LOGE(ERROR, "libxl__arch_domain_configure failed");
+ goto out;
+ }
if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) {
LOGE(ERROR, "xc_dom_mem_init failed");
goto out;
diff --git a/tools/libxl/libxl_noarch.c b/tools/libxl/libxl_noarch.c
deleted file mode 100644
index 7893535..0000000
--- a/tools/libxl/libxl_noarch.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "libxl_internal.h"
-#include "libxl_arch.h"
-
-int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
- uint32_t domid)
-{
- return 0;
-}
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index 87a8110..e1c183f 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -310,3 +310,10 @@ int libxl__arch_domain_create(libxl__gc *gc,
libxl_domain_config *d_config,
return ret;
}
+
+int libxl__arch_domain_configure(libxl__gc *gc,
+ libxl_domain_build_info *info,
+ struct xc_dom_image *dom)
+{
+ return 0;
+}
--
generated by git-patchbot for /home/xen/git/xen.git#master
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |