|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v1 20/20] libxl/acpi: Build ACPI tables for HVMlite guests
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
---
Changes in v1:
* Move to libxl
* Added populate_acpi_pages()
* Stash location/size of tables in xc_dom_image (to be used in constructing
e820 map)
* Use libxl allocator
* Only set XEN_X86_EMU_LAPIC flag if 'apic' option is set.
* Make acpi_build_tables() return error code
.gitignore | 4 +
tools/libacpi/build.c | 7 +-
tools/libacpi/libacpi.h | 15 ++-
tools/libxl/Makefile | 17 +++-
tools/libxl/libxl_arch.h | 3 +
tools/libxl/libxl_dom.c | 1 +
tools/libxl/libxl_x86.c | 29 +++--
tools/libxl/libxl_x86_acpi.c | 292 ++++++++++++++++++++++++++++++++++++++++++
tools/libxl/libxl_x86_acpi.h | 21 +++
9 files changed, 373 insertions(+), 16 deletions(-)
create mode 100644 tools/libxl/libxl_x86_acpi.c
create mode 100644 tools/libxl/libxl_x86_acpi.h
diff --git a/.gitignore b/.gitignore
index 9dd2086..d4da37f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,6 +179,10 @@ tools/libxl/testenum.c
tools/libxl/tmp.*
tools/libxl/_libxl.api-for-check
tools/libxl/*.api-ok
+tools/libxl/mk_dsdt
+tools/libxl/dsdt*.c
+tools/libxl/dsdt_*.asl
+tools/libxl/ssdt_*.h
tools/misc/cpuperf/cpuperf-perfcntr
tools/misc/cpuperf/cpuperf-xen
tools/misc/xc_shadow
diff --git a/tools/libacpi/build.c b/tools/libacpi/build.c
index 290f005..a6ddf53 100644
--- a/tools/libacpi/build.c
+++ b/tools/libacpi/build.c
@@ -23,6 +23,7 @@
#include "ssdt_tpm.h"
#include "ssdt_pm.h"
#include "x86.h"
+#include <xen/hvm/hvm_info_table.h>
#include <xen/hvm/hvm_xs_strings.h>
#include <xen/hvm/params.h>
@@ -473,7 +474,7 @@ static int new_vm_gid(struct acpi_ctxt *ctxt,
return 1;
}
-void acpi_build_tables(struct acpi_ctxt *ctxt, struct acpi_config *config)
+int acpi_build_tables(struct acpi_ctxt *ctxt, struct acpi_config *config)
{
struct acpi_20_rsdp *rsdp;
struct acpi_20_rsdt *rsdt;
@@ -594,11 +595,11 @@ void acpi_build_tables(struct acpi_ctxt *ctxt, struct
acpi_config *config)
*(struct acpi_info *)config->ainfop = config->ainfo;
- return;
+ return 0;
oom:
printf("unable to build ACPI tables: out of memory\n");
-
+ return -1;
}
/*
diff --git a/tools/libacpi/libacpi.h b/tools/libacpi/libacpi.h
index 87a2937..791ebac 100644
--- a/tools/libacpi/libacpi.h
+++ b/tools/libacpi/libacpi.h
@@ -69,6 +69,15 @@ struct acpi_ctxt {
void *(*alloc)(struct acpi_ctxt *ctxt, uint32_t size, uint32_t align);
unsigned long (*v2p)(struct acpi_ctxt *ctxt, void *v);
} mem_ops;
+
+ unsigned int page_size;
+ unsigned int page_shift;
+
+ /* Memory allocator */
+ unsigned long alloc_base_paddr;
+ unsigned long alloc_base_vaddr;
+ unsigned long alloc_currp;
+ unsigned long alloc_end;
};
struct acpi_config {
@@ -98,13 +107,13 @@ struct acpi_config {
* This must match the OperationRegion(BIOS, SystemMemory, ....)
* definition in the DSDT
*/
- unsigned int ainfop;
+ unsigned long ainfop;
/* RSDP address */
- unsigned int rsdp;
+ unsigned long rsdp;
};
-void acpi_build_tables(struct acpi_ctxt *ctxt, struct acpi_config *config);
+int acpi_build_tables(struct acpi_ctxt *ctxt, struct acpi_config *config);
#endif /* __LIBACPI_H__ */
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 3a2d64a..18be2e7 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -75,7 +75,20 @@ else
LIBXL_OBJS-y += libxl_no_colo.o
endif
-LIBXL_OBJS-$(CONFIG_X86) += libxl_cpuid.o libxl_x86.o libxl_psr.o
+ACPI_PATH = $(XEN_ROOT)/tools/libacpi
+ACPI_FILES = dsdt_pvh.c build.c static_tables.c
+ACPI_OBJS = $(patsubst %.c,%.o,$(ACPI_FILES))
+$(ACPI_FILES): acpi
+$(ACPI_OBJS): CFLAGS += -I. -DSTDUTILS=\"$(CURDIR)/libxl_x86_acpi.h\"
+vpath build.c $(ACPI_PATH)/
+vpath static_tables.c $(ACPI_PATH)/
+LIBXL_OBJS-$(CONFIG_X86) += $(ACPI_OBJS)
+
+.PHONY: acpi
+acpi:
+ $(MAKE) -C $(ACPI_PATH) ACPI_BUILD_DIR=$(shell pwd)
+
+LIBXL_OBJS-$(CONFIG_X86) += libxl_cpuid.o libxl_x86.o libxl_psr.o
libxl_x86_acpi.o
LIBXL_OBJS-$(CONFIG_ARM) += libxl_nocpuid.o libxl_arm.o libxl_libfdt_compat.o
ifeq ($(CONFIG_NetBSD),y)
@@ -166,6 +179,7 @@ $(XL_OBJS): CFLAGS += $(CFLAGS_XL)
$(XL_OBJS): CFLAGS += -include $(XEN_ROOT)/tools/config.h # libxl_json.h needs
it.
libxl_dom.o: CFLAGS += -I$(XEN_ROOT)/tools # include libacpi/x86.h
+libxl_x86_acpi.o: CFLAGS += -I$(XEN_ROOT)/tools
SAVE_HELPER_OBJS = libxl_save_helper.o _libxl_save_msgs_helper.o
$(SAVE_HELPER_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenevtchn)
@@ -308,6 +322,7 @@ clean:
$(RM) -f testidl.c.new testidl.c *.api-ok
$(RM) -f xenlight.pc
$(RM) -f xlutil.pc
+ $(MAKE) -C $(ACPI_PATH) ACPI_BUILD_DIR=$(shell pwd) clean
distclean: clean
$(RM) -f xenlight.pc.in xlutil.pc.in
diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
index 34a853c..7c6536b 100644
--- a/tools/libxl/libxl_arch.h
+++ b/tools/libxl/libxl_arch.h
@@ -62,4 +62,7 @@ int libxl__arch_domain_construct_memmap(libxl__gc *gc,
uint32_t domid,
struct xc_dom_image *dom);
+int libxl__dom_load_acpi(libxl__gc *gc,
+ libxl_domain_build_info *info,
+ struct xc_dom_image *dom);
#endif
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index ba3472e..7e4e289 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -657,6 +657,7 @@ static int libxl__build_dom(libxl__gc *gc, uint32_t domid,
LOGE(ERROR, "xc_dom_build_image failed");
goto out;
}
+
if ( (ret = xc_dom_boot_image(dom)) != 0 ) {
LOGE(ERROR, "xc_dom_boot_image failed");
goto out;
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index 32ce1d2..7201dbb 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -8,15 +8,18 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
xc_domain_configuration_t *xc_config)
{
- if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM &&
- d_config->b_info.device_model_version !=
- LIBXL_DEVICE_MODEL_VERSION_NONE) {
- /* HVM domains with a device model. */
- xc_config->emulation_flags = XEN_X86_EMU_ALL;
- } else {
- /* PV or HVM domains without a device model. */
+ if (d_config->c_info.type == LIBXL_DOMAIN_TYPE_HVM) {
+ if (d_config->b_info.device_model_version !=
+ LIBXL_DEVICE_MODEL_VERSION_NONE)
+ xc_config->emulation_flags = XEN_X86_EMU_ALL;
+ else if (libxl_defbool_val(d_config->b_info.u.hvm.apic))
+ /*
+ * HVM guests without device model may want
+ * to have LAPIC emulation.
+ */
+ xc_config->emulation_flags = XEN_X86_EMU_LAPIC;
+ } else
xc_config->emulation_flags = 0;
- }
return 0;
}
@@ -366,7 +369,15 @@ int libxl__arch_domain_finalise_hw_description(libxl__gc
*gc,
libxl_domain_build_info *info,
struct xc_dom_image *dom)
{
- return 0;
+ int ret = 0;
+
+ if ((info->type == LIBXL_DOMAIN_TYPE_HVM) &&
+ (info->device_model_version == LIBXL_DEVICE_MODEL_VERSION_NONE)) {
+ if ( (ret = libxl__dom_load_acpi(gc, info, dom)) != 0 )
+ LOGE(ERROR, "libxl_dom_load_acpi failed");
+ }
+
+ return ret;
}
/* Return 0 on success, ERROR_* on failure. */
diff --git a/tools/libxl/libxl_x86_acpi.c b/tools/libxl/libxl_x86_acpi.c
new file mode 100644
index 0000000..144f063
--- /dev/null
+++ b/tools/libxl/libxl_x86_acpi.c
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "libxl_internal.h"
+#include "libxl_arch.h"
+#include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/e820.h>
+#include "libacpi/libacpi.h"
+
+#include <xc_dom.h>
+
+#define NUM_ACPI_PAGES 16 /* Number of pages holding ACPI tables */
+#define RSDP_ADDRESS (0xffffful - 64) /* Last doubleword of BIOS RO memory */
+#define ACPI_INFO_PHYSICAL_ADDRESS 0xfc000000
+
+extern const unsigned char dsdt_pvh[];
+extern const unsigned int dsdt_pvh_len;
+
+/* Assumes contiguous physical space */
+static unsigned long virt_to_phys(struct acpi_ctxt *ctxt, void *v)
+{
+ return (((unsigned long)v - ctxt->alloc_base_vaddr) +
+ ctxt->alloc_base_paddr);
+}
+
+static void *mem_alloc(struct acpi_ctxt *ctxt, uint32_t size, uint32_t align)
+{
+ unsigned long s, e;
+
+ /* Align to at least 16 bytes. */
+ if (align < 16)
+ align = 16;
+
+ s = (ctxt->alloc_currp + align) & ~((unsigned long)align - 1);
+ e = s + size - 1;
+
+ /* TODO: Reallocate memory */
+ if ((e < s) || (e >= ctxt->alloc_end)) return NULL;
+
+ while (ctxt->alloc_currp >> ctxt->page_shift !=
+ e >> ctxt->page_shift)
+ ctxt->alloc_currp += ctxt->page_size;
+
+ ctxt->alloc_currp = e;
+
+ return (void *)s;
+}
+
+static int init_acpi_config(libxl__gc *gc,
+ struct xc_dom_image *dom,
+ libxl_domain_build_info *b_info,
+ struct acpi_config *config)
+{
+ xc_interface *xch = dom->xch;
+ uint32_t domid = dom->guest_domid;
+ xc_dominfo_t info;
+ int i, rc;
+
+ config->dsdt_anycpu = config->dsdt_15cpu = dsdt_pvh;
+ config->dsdt_anycpu_len = config->dsdt_15cpu_len = dsdt_pvh_len;
+
+ rc = xc_domain_getinfo(xch, domid, 1, &info);
+ if (rc < 0) {
+ LOG(ERROR, "%s: getdomaininfo failed (rc=%d)", __FUNCTION__, rc);
+ return rc;
+ }
+
+ config->hvminfo = libxl__zalloc(gc, sizeof(*config->hvminfo));
+
+ config->hvminfo->apic_mode = libxl_defbool_val(b_info->u.hvm.apic);
+
+ if (dom->nr_vnodes) {
+ struct acpi_numa *numa = &config->numa;
+
+ rc = xc_domain_getvnuma(xch, domid, &numa->nr_vnodes,
+ &numa->nr_vmemranges,
+ &config->hvminfo->nr_vcpus, NULL, NULL, NULL);
+ if (rc) {
+ LOG(ERROR, "%s: xc_domain_getvnuma failed (rc=%d)",
+ __FUNCTION__, rc);
+ return rc;
+ }
+
+ numa->vmemrange = libxl__zalloc(gc, dom->nr_vmemranges *
+ sizeof(*numa->vmemrange));
+ numa->vdistance = libxl__zalloc(gc, dom->nr_vnodes *
+ sizeof(*numa->vdistance));
+ numa->vcpu_to_vnode = libxl__zalloc(gc, config->hvminfo->nr_vcpus *
+ sizeof(*numa->vcpu_to_vnode));
+ rc = xc_domain_getvnuma(xch, domid, &numa->nr_vnodes,
+ &numa->nr_vmemranges,
+ &config->hvminfo->nr_vcpus, numa->vmemrange,
+ numa->vdistance, numa->vcpu_to_vnode);
+ if (rc) {
+ LOG(ERROR, "%s: xc_domain_getvnuma failed (rc=%d)",
+ __FUNCTION__, rc);
+ return rc;
+ }
+ }
+ else
+ config->hvminfo->nr_vcpus = info.max_vcpu_id + 1;
+
+ for (i=0; i<config->hvminfo->nr_vcpus; i++)
+ config->hvminfo->vcpu_online[i / 8] |= 1 << (i & 7);
+
+ return 0;
+}
+
+static int populate_acpi_pages(struct xc_dom_image *dom,
+ xen_pfn_t *extents,
+ unsigned int num_pages,
+ struct acpi_ctxt *ctxt)
+{
+ int rc;
+ xc_interface *xch = dom->xch;
+ uint32_t domid = dom->guest_domid;
+ unsigned long idx, first_high_idx = (1ull << (32 - ctxt->page_shift));
+
+ for (; num_pages; num_pages--, extents++) {
+
+ if (xc_domain_populate_physmap(xch, domid, 1, 0, 0, extents) == 1)
+ continue;
+
+ if (dom->highmem_end) {
+ idx = --dom->highmem_end;
+ if ( idx == first_high_idx )
+ dom->highmem_end = 0;
+ } else
+ idx = --dom->lowmem_end;
+
+ rc = xc_domain_add_to_physmap(xch, domid,
+ XENMAPSPACE_gmfn,
+ idx, *extents);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+int libxl__dom_load_acpi(libxl__gc *gc,
+ libxl_domain_build_info *info,
+ struct xc_dom_image *dom)
+{
+ struct acpi_config config = {0};
+ struct acpi_ctxt ctxt;
+ uint32_t domid = dom->guest_domid;
+ xc_interface *xch = dom->xch;
+ int rc, i, acpi_pages_num;
+ xen_pfn_t extent, *extents;
+ void *acpi_pages, *guest_acpi_pages = NULL;
+ unsigned long page_mask;
+
+ if ((info->type != LIBXL_DOMAIN_TYPE_HVM) ||
+ (info->device_model_version != LIBXL_DEVICE_MODEL_VERSION_NONE))
+ return 0;
+
+ ctxt.page_size = XC_DOM_PAGE_SIZE(dom);
+ ctxt.page_shift = XC_DOM_PAGE_SHIFT(dom);
+ page_mask = (1UL << ctxt.page_shift) - 1;
+
+ ctxt.mem_ops.alloc = mem_alloc;
+ ctxt.mem_ops.v2p = virt_to_phys;
+
+ rc = init_acpi_config(gc, dom, info, &config);
+ if (rc) {
+ LOG(ERROR, "%s: init_acpi_config failed (rc=%d)", __FUNCTION__, rc);
+ return rc;
+ }
+
+ /* Map page that will hold RSDP */
+ extent = RSDP_ADDRESS >> ctxt.page_shift;
+ rc = populate_acpi_pages(dom, &extent, 1, &ctxt);
+ if (rc) {
+ LOG(ERROR, "%s: populate_acpi_pages for rsdp failed with %d",
+ __FUNCTION__, rc);
+ goto out;
+ }
+ config.rsdp = (unsigned long)xc_map_foreign_range(xch, domid,
+ ctxt.page_size,
+ PROT_READ | PROT_WRITE,
+ RSDP_ADDRESS >>
ctxt.page_shift);
+ if (!config.rsdp) {
+ LOG(ERROR, "%s: Can't map acpi_physical", __FUNCTION__);
+ rc = -1;
+ goto out;
+ }
+
+ /* Map acpi_info page */
+ extent = ACPI_INFO_PHYSICAL_ADDRESS >> ctxt.page_shift;
+ rc = populate_acpi_pages(dom, &extent, 1, &ctxt);
+ if (rc) {
+ LOG(ERROR, "%s: populate_acpi_pages for acpi_info failed with %d",
+ __FUNCTION__, rc);
+ goto out;
+ }
+
+ config.ainfop = (unsigned long)xc_map_foreign_range(xch, domid,
+ ctxt.page_size,
+ PROT_READ | PROT_WRITE,
+
ACPI_INFO_PHYSICAL_ADDRESS >> ctxt.page_shift);
+ if (!config.ainfop) {
+ LOG(ERROR, "%s: Can't map acpi_info_page", __FUNCTION__);
+ rc = -1;
+ goto out;
+ }
+
+ /* Pages to hold ACPI tables */
+ acpi_pages = libxl__malloc(gc, (NUM_ACPI_PAGES + 1) * ctxt.page_size);
+ while ((unsigned long)acpi_pages & page_mask)
+ acpi_pages++;
+
+ /*
+ * Set up allocator memory.
+ * Start next to acpi_info page to avoid fracturing e820.
+ */
+ ctxt.alloc_base_paddr = ACPI_INFO_PHYSICAL_ADDRESS + ctxt.page_size;
+ ctxt.alloc_base_vaddr = ctxt.alloc_currp = (unsigned long)acpi_pages;
+ ctxt.alloc_end = (unsigned long)acpi_pages +
+ (NUM_ACPI_PAGES * ctxt.page_size);
+
+ /* Build the tables */
+ rc = acpi_build_tables(&ctxt, &config);
+ if (rc) {
+ LOG(ERROR, "%s: acpi_build_tables failed with %d",
+ __FUNCTION__, rc);
+ goto out;
+ }
+
+ /* Copy ACPI tables into guest's memory */
+ acpi_pages_num =
+ ((ctxt.alloc_currp - (unsigned long)acpi_pages) >> ctxt.page_shift) +
+ ((ctxt.alloc_currp & page_mask) ? 1 : 0);
+ extents = libxl__malloc(gc, acpi_pages_num * sizeof(*extents));
+ for (i = 0; i < acpi_pages_num; i++)
+ extents[i] = (ctxt.alloc_base_paddr >> ctxt.page_shift) + i;
+ rc = populate_acpi_pages(dom, extents, acpi_pages_num, &ctxt);
+ if (rc) {
+ LOG(ERROR, "%s: populate_acpi_pages for APCI tables failed with %d",
+ __FUNCTION__, rc);
+ goto out;
+ }
+ guest_acpi_pages = xc_map_foreign_range(xch, domid,
+ ctxt.page_size * acpi_pages_num,
+ PROT_READ | PROT_WRITE,
+ ctxt.alloc_base_paddr >>
ctxt.page_shift);
+ if (!guest_acpi_pages) {
+ LOG(ERROR, "%s Can't map guest_acpi_pages", __FUNCTION__);
+ rc = -1;
+ goto out;
+ }
+
+ memcpy(guest_acpi_pages, acpi_pages, acpi_pages_num * ctxt.page_size);
+
+ dom->acpi_pfn = ACPI_INFO_PHYSICAL_ADDRESS >> ctxt.page_shift;
+ dom->acpi_pages = acpi_pages_num + 1;
+
+out:
+ munmap(guest_acpi_pages, acpi_pages_num * ctxt.page_size);
+ munmap((void *)config.ainfop, ctxt.page_size);
+ munmap((void *)config.rsdp, ctxt.page_size);
+
+ return rc;
+
+}
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxl/libxl_x86_acpi.h b/tools/libxl/libxl_x86_acpi.h
new file mode 100644
index 0000000..1899ec1
--- /dev/null
+++ b/tools/libxl/libxl_x86_acpi.h
@@ -0,0 +1,21 @@
+#ifndef LIBXL_X86_ACPI_H
+#define LIBXL_X86_ACPI_H
+
+#include "libxl_internal.h"
+
+#define ASSERT(x) assert(x)
+
+static inline int test_bit(unsigned int b, void *p)
+{
+ return !!(((uint8_t *)p)[b>>3] & (1u<<(b&7)));
+}
+
+#endif /* LIBXL_X_86_ACPI_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
1.7.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |