]> xenbits.xensource.com Git - xen.git/commitdiff
HVM firmware passthrough control tools support
authorRoss Philipson <ross.philipson@citrix.com>
Thu, 10 Jan 2013 17:17:21 +0000 (17:17 +0000)
committerRoss Philipson <ross.philipson@citrix.com>
Thu, 10 Jan 2013 17:17:21 +0000 (17:17 +0000)
Xen control tools support for loading the firmware passthrough blocks
during domain construction. SMBIOS and ACPI blocks are passed in using
the new xc_hvm_build_args structure. Each block is read and loaded
into the new domain address space behind the HVMLOADER image. The base
address for the two blocks is returned as an out parameter to the
caller via the args structure.

Signed-off-by: Ross Philipson <ross.philipson@citrix.com>
Committed-by: Keir Fraser <keir@xen.org>
tools/libxc/xc_hvm_build_arm.c
tools/libxc/xc_hvm_build_x86.c
tools/libxc/xenguest.h
tools/libxc/xg_private.c

index 254b6eec94c48fc809ac2105dac7ae3cf837cfd8..c2def3ba4703293c492eaeac23727bc281354a60 100644 (file)
@@ -22,7 +22,7 @@
 #include <xenguest.h>
 
 int xc_hvm_build(xc_interface *xch, uint32_t domid,
-                 const struct xc_hvm_build_args *hvm_args)
+                 struct xc_hvm_build_args *hvm_args)
 {
     errno = ENOSYS;
     return -1;
index cf5d7fb0f61f540163ddf779babce65acc2ba4ac..f0caf6610e4c18d5b7811bd434c4a9b28e978ee4 100644 (file)
 #define NR_SPECIAL_PAGES     8
 #define special_pfn(x) (0xff000u - NR_SPECIAL_PAGES + (x))
 
+static int modules_init(struct xc_hvm_build_args *args,
+                        uint64_t vend, struct elf_binary *elf,
+                        uint64_t *mstart_out, uint64_t *mend_out)
+{
+#define MODULE_ALIGN 1UL << 7
+#define MB_ALIGN     1UL << 20
+#define MKALIGN(x, a) (((uint64_t)(x) + (a) - 1) & ~(uint64_t)((a) - 1))
+    uint64_t total_len = 0, offset1 = 0;
+
+    if ( (args->acpi_module.length == 0)&&(args->smbios_module.length == 0) )
+        return 0;
+
+    /* Find the total length for the firmware modules with a reasonable large
+     * alignment size to align each the modules.
+     */
+    total_len = MKALIGN(args->acpi_module.length, MODULE_ALIGN);
+    offset1 = total_len;
+    total_len += MKALIGN(args->smbios_module.length, MODULE_ALIGN);
+
+    /* Want to place the modules 1Mb+change behind the loader image. */
+    *mstart_out = MKALIGN(elf->pend, MB_ALIGN) + (MB_ALIGN);
+    *mend_out = *mstart_out + total_len;
+
+    if ( *mend_out > vend )    
+        return -1;
+
+    if ( args->acpi_module.length != 0 )
+        args->acpi_module.guest_addr_out = *mstart_out;
+    if ( args->smbios_module.length != 0 )
+        args->smbios_module.guest_addr_out = *mstart_out + offset1;
+
+    return 0;
+}
+
 static void build_hvm_info(void *hvm_info_page, uint64_t mem_size,
                            uint64_t mmio_start, uint64_t mmio_size)
 {
@@ -86,9 +120,8 @@ static void build_hvm_info(void *hvm_info_page, uint64_t mem_size,
     hvm_info->checksum = -sum;
 }
 
-static int loadelfimage(
-    xc_interface *xch,
-    struct elf_binary *elf, uint32_t dom, unsigned long *parray)
+static int loadelfimage(xc_interface *xch, struct elf_binary *elf,
+                        uint32_t dom, unsigned long *parray)
 {
     privcmd_mmap_entry_t *entries = NULL;
     unsigned long pfn_start = elf->pstart >> PAGE_SHIFT;
@@ -126,6 +159,66 @@ static int loadelfimage(
     return rc;
 }
 
+static int loadmodules(xc_interface *xch,
+                       struct xc_hvm_build_args *args,
+                       uint64_t mstart, uint64_t mend,
+                       uint32_t dom, unsigned long *parray)
+{
+    privcmd_mmap_entry_t *entries = NULL;
+    unsigned long pfn_start;
+    unsigned long pfn_end;
+    size_t pages;
+    uint32_t i;
+    uint8_t *dest;
+    int rc = -1;
+
+    if ( (mstart == 0)||(mend == 0) )
+        return 0;
+
+    pfn_start = (unsigned long)(mstart >> PAGE_SHIFT);
+    pfn_end = (unsigned long)((mend + PAGE_SIZE - 1) >> PAGE_SHIFT);
+    pages = pfn_end - pfn_start;
+
+    /* Map address space for module list. */
+    entries = calloc(pages, sizeof(privcmd_mmap_entry_t));
+    if ( entries == NULL )
+        goto error_out;
+
+    for ( i = 0; i < pages; i++ )
+        entries[i].mfn = parray[(mstart >> PAGE_SHIFT) + i];
+
+    dest = xc_map_foreign_ranges(
+        xch, dom, pages << PAGE_SHIFT, PROT_READ | PROT_WRITE, 1 << PAGE_SHIFT,
+        entries, pages);
+    if ( dest == NULL )
+        goto error_out;
+
+    /* Zero the range so padding is clear between modules */
+    memset(dest, 0, pages << PAGE_SHIFT);
+
+    /* Load modules into range */    
+    if ( args->acpi_module.length != 0 )
+    {
+        memcpy(dest,
+               args->acpi_module.data,
+               args->acpi_module.length);
+    }
+    if ( args->smbios_module.length != 0 )
+    {
+        memcpy(dest + (args->smbios_module.guest_addr_out - mstart),
+               args->smbios_module.data,
+               args->smbios_module.length);
+    }
+
+    munmap(dest, pages << PAGE_SHIFT);
+    rc = 0;
+
+ error_out:
+    free(entries);
+
+    return rc;
+}
+
 /*
  * Check whether there exists mmio hole in the specified memory range.
  * Returns 1 if exists, else returns 0.
@@ -140,7 +233,7 @@ static int check_mmio_hole(uint64_t start, uint64_t memsize,
 }
 
 static int setup_guest(xc_interface *xch,
-                       uint32_t dom, const struct xc_hvm_build_args *args,
+                       uint32_t dom, struct xc_hvm_build_args *args,
                        char *image, unsigned long image_size)
 {
     xen_pfn_t *page_array = NULL;
@@ -153,6 +246,7 @@ static int setup_guest(xc_interface *xch,
     uint32_t *ident_pt;
     struct elf_binary elf;
     uint64_t v_start, v_end;
+    uint64_t m_start = 0, m_end = 0;
     int rc;
     xen_capabilities_info_t caps;
     unsigned long stat_normal_pages = 0, stat_2mb_pages = 0, 
@@ -178,11 +272,19 @@ static int setup_guest(xc_interface *xch,
         goto error_out;
     }
 
+    if ( modules_init(args, v_end, &elf, &m_start, &m_end) != 0 )
+    {
+        ERROR("Insufficient space to load modules.");
+        goto error_out;
+    }
+
     IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
             "  Loader:        %016"PRIx64"->%016"PRIx64"\n"
+            "  Modules:       %016"PRIx64"->%016"PRIx64"\n"
             "  TOTAL:         %016"PRIx64"->%016"PRIx64"\n"
             "  ENTRY ADDRESS: %016"PRIx64"\n",
             elf.pstart, elf.pend,
+            m_start, m_end,
             v_start, v_end,
             elf_uval(&elf, elf.ehdr, e_entry));
 
@@ -337,6 +439,9 @@ static int setup_guest(xc_interface *xch,
     if ( loadelfimage(xch, &elf, dom, page_array) != 0 )
         goto error_out;
 
+    if ( loadmodules(xch, args, m_start, m_end, dom, page_array) != 0 )
+        goto error_out;    
+
     if ( (hvm_info_page = xc_map_foreign_range(
               xch, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
               HVM_INFO_PFN)) == NULL )
@@ -413,7 +518,7 @@ static int setup_guest(xc_interface *xch,
  * Create a domain for a virtualized Linux, using files/filenames.
  */
 int xc_hvm_build(xc_interface *xch, uint32_t domid,
-                 const struct xc_hvm_build_args *hvm_args)
+                 struct xc_hvm_build_args *hvm_args)
 {
     struct xc_hvm_build_args args = *hvm_args;
     void *image;
@@ -441,6 +546,15 @@ int xc_hvm_build(xc_interface *xch, uint32_t domid,
 
     sts = setup_guest(xch, domid, &args, image, image_size);
 
+    if (!sts)
+    {
+        /* Return module load addresses to caller */
+        hvm_args->acpi_module.guest_addr_out = 
+            args.acpi_module.guest_addr_out;
+        hvm_args->smbios_module.guest_addr_out = 
+            args.smbios_module.guest_addr_out;
+    }
+
     free(image);
 
     return sts;
@@ -461,6 +575,7 @@ int xc_hvm_build_target_mem(xc_interface *xch,
 {
     struct xc_hvm_build_args args = {};
 
+    memset(&args, 0, sizeof(struct xc_hvm_build_args));
     args.mem_size = (uint64_t)memsize << 20;
     args.mem_target = (uint64_t)target << 20;
     args.image_file_name = image_name;
index 707e31cc5fddeca5da86cc6673b61210c16dff81..1597e5c93ce5d90507d940e57d2fac44648a76e1 100644 (file)
@@ -211,11 +211,23 @@ int xc_linux_build_mem(xc_interface *xch,
                        unsigned int console_evtchn,
                        unsigned long *console_mfn);
 
+struct xc_hvm_firmware_module {
+    uint8_t  *data;
+    uint32_t  length;
+    uint64_t  guest_addr_out;
+};
+
 struct xc_hvm_build_args {
     uint64_t mem_size;           /* Memory size in bytes. */
     uint64_t mem_target;         /* Memory target in bytes. */
     uint64_t mmio_size;          /* Size of the MMIO hole in bytes. */
     const char *image_file_name; /* File name of the image to load. */
+
+    /* Extra ACPI tables passed to HVMLOADER */
+    struct xc_hvm_firmware_module acpi_module;
+
+    /* Extra SMBIOS structures passed to HVMLOADER */
+    struct xc_hvm_firmware_module smbios_module;
 };
 
 /**
@@ -228,7 +240,7 @@ struct xc_hvm_build_args {
  * are optional.
  */
 int xc_hvm_build(xc_interface *xch, uint32_t domid,
-                 const struct xc_hvm_build_args *hvm_args);
+                 struct xc_hvm_build_args *hvm_args);
 
 int xc_hvm_build_target_mem(xc_interface *xch,
                             uint32_t domid,
index 3864bc7c40d036e0730af236d55e059fdf3f56c7..ef1c49d54f0e2475ff6708a61a17af3f4b8026ce 100644 (file)
@@ -192,7 +192,7 @@ unsigned long csum_page(void *page)
 __attribute__((weak)) 
     int xc_hvm_build(xc_interface *xch,
                      uint32_t domid,
-                     const struct xc_hvm_build_args *hvm_args)
+                     struct xc_hvm_build_args *hvm_args)
 {
     errno = ENOSYS;
     return -1;