diff --git a/tools/libxc/xc_hvm_build_arm.c b/tools/libxc/xc_hvm_build_arm.c index 254b6eec94..c2def3ba47 100644 --- a/tools/libxc/xc_hvm_build_arm.c +++ b/tools/libxc/xc_hvm_build_arm.c @@ -22,7 +22,7 @@ #include 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; diff --git a/tools/libxc/xc_hvm_build_x86.c b/tools/libxc/xc_hvm_build_x86.c index cf5d7fb0f6..f0caf6610e 100644 --- a/tools/libxc/xc_hvm_build_x86.c +++ b/tools/libxc/xc_hvm_build_x86.c @@ -49,6 +49,40 @@ #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; diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h index 707e31cc5f..1597e5c93c 100644 --- a/tools/libxc/xenguest.h +++ b/tools/libxc/xenguest.h @@ -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, diff --git a/tools/libxc/xg_private.c b/tools/libxc/xg_private.c index 3864bc7c40..ef1c49d54f 100644 --- a/tools/libxc/xg_private.c +++ b/tools/libxc/xg_private.c @@ -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;