aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-01-08 15:27:20 +0000
committerKeir Fraser <keir.fraser@citrix.com>2009-01-08 15:27:20 +0000
commitad8b20cc859c75559f0ecbd699d1be8c34e50acd (patch)
tree5458d0b78e29dac0c771c3da166806dce309f8f2
parent85eff2ee28b69442131322664f9d72ff89df9fb2 (diff)
downloadxen-ad8b20cc859c75559f0ecbd699d1be8c34e50acd.tar.gz
xen-ad8b20cc859c75559f0ecbd699d1be8c34e50acd.tar.bz2
xen-ad8b20cc859c75559f0ecbd699d1be8c34e50acd.zip
x86, hvm: Move E820 table creation into hvmloader, extend
hvm_info_table to describe memory parameters in a simpler form from domain builder to hvmloader. Also move reserved special page mappings immediately below the 4GB boundary. Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
-rw-r--r--tools/firmware/hvmloader/config.h3
-rw-r--r--tools/firmware/hvmloader/hvmloader.c70
-rw-r--r--tools/firmware/hvmloader/util.c31
-rw-r--r--tools/libxc/xc_hvm_build.c163
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c10
-rw-r--r--xen/include/public/hvm/hvm_info_table.h28
6 files changed, 169 insertions, 136 deletions
diff --git a/tools/firmware/hvmloader/config.h b/tools/firmware/hvmloader/config.h
index 35edf1930e..7743af20c1 100644
--- a/tools/firmware/hvmloader/config.h
+++ b/tools/firmware/hvmloader/config.h
@@ -1,6 +1,9 @@
#ifndef __HVMLOADER_CONFIG_H__
#define __HVMLOADER_CONFIG_H__
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1ul << PAGE_SHIFT)
+
#define IOAPIC_BASE_ADDRESS 0xfec00000
#define IOAPIC_ID 0x01
#define IOAPIC_VERSION 0x11
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
index 463c1cc561..a271936d19 100644
--- a/tools/firmware/hvmloader/hvmloader.c
+++ b/tools/firmware/hvmloader/hvmloader.c
@@ -560,15 +560,67 @@ static void init_vm86_tss(void)
printf("vm86 TSS at %08x\n", tss);
}
-/*
- * Copy the E820 table provided by the HVM domain builder into the correct
- * place in the memory map we share with the rombios.
- */
-static void copy_e820_table(void)
+/* Create an E820 table based on memory parameters provided in hvm_info. */
+static void build_e820_table(void)
{
- uint8_t nr = *(uint8_t *)(HVM_E820_PAGE + HVM_E820_NR_OFFSET);
- BUG_ON(nr > 16);
- memcpy(E820, (char *)HVM_E820_PAGE + HVM_E820_OFFSET, nr * sizeof(*E820));
+ struct e820entry *e820 = E820;
+ unsigned int nr = 0;
+
+ /* 0x0-0x9FC00: Ordinary RAM. */
+ e820[nr].addr = 0x0;
+ e820[nr].size = 0x9FC00;
+ e820[nr].type = E820_RAM;
+ nr++;
+
+ /* 0x9FC00-0xA0000: Extended BIOS Data Area (EBDA). */
+ e820[nr].addr = 0x9FC00;
+ e820[nr].size = 0x400;
+ e820[nr].type = E820_RESERVED;
+ nr++;
+
+ /*
+ * Following regions are standard regions of the PC memory map.
+ * They are not covered by e820 regions. OSes will not use as RAM.
+ * 0xA0000-0xC0000: VGA memory-mapped I/O. Not covered by E820.
+ * 0xC0000-0xE0000: 16-bit devices, expansion ROMs (inc. vgabios).
+ * TODO: free pages which turn out to be unused.
+ */
+
+ /*
+ * 0xE0000-0x0F0000: PC-specific area. We place various tables here.
+ * 0xF0000-0x100000: System BIOS.
+ * TODO: free pages which turn out to be unused.
+ */
+ e820[nr].addr = 0xE0000;
+ e820[nr].size = 0x20000;
+ e820[nr].type = E820_RESERVED;
+ nr++;
+
+ /* Low RAM goes here. Reserve space for special pages. */
+ BUG_ON((hvm_info->low_mem_pgend << PAGE_SHIFT) < (2u << 20));
+ e820[nr].addr = 0x100000;
+ e820[nr].size = (hvm_info->low_mem_pgend << PAGE_SHIFT) - e820[nr].addr;
+ e820[nr].type = E820_RAM;
+ nr++;
+
+ if ( hvm_info->reserved_mem_pgstart )
+ {
+ /* Explicitly reserve space for special pages. */
+ e820[nr].addr = hvm_info->reserved_mem_pgstart << PAGE_SHIFT;
+ e820[nr].size = (uint32_t)-e820[nr].addr;
+ e820[nr].type = E820_RESERVED;
+ nr++;
+ }
+
+ if ( hvm_info->high_mem_pgend )
+ {
+ e820[nr].addr = ((uint64_t)1 << 32);
+ e820[nr].size =
+ ((uint64_t)hvm_info->high_mem_pgend << PAGE_SHIFT) - e820[nr].addr;
+ e820[nr].type = E820_RAM;
+ nr++;
+ }
+
*E820_NR = nr;
}
@@ -581,7 +633,7 @@ int main(void)
printf("HVM Loader\n");
- copy_e820_table();
+ build_e820_table();
init_hypercalls();
diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c
index 9889f619b8..b36513ef8f 100644
--- a/tools/firmware/hvmloader/util.c
+++ b/tools/firmware/hvmloader/util.c
@@ -542,27 +542,32 @@ void __bug(char *file, int line)
asm volatile ( "ud2" );
}
-static int validate_hvm_info(struct hvm_info_table *t)
+static void validate_hvm_info(struct hvm_info_table *t)
{
- char signature[] = "HVM INFO";
uint8_t *ptr = (uint8_t *)t;
uint8_t sum = 0;
int i;
- /* strncmp(t->signature, "HVM INFO", 8) */
- for ( i = 0; i < 8; i++ )
+ if ( strncmp(t->signature, "HVM INFO", 8) )
{
- if ( signature[i] != t->signature[i] )
- {
- printf("Bad hvm info signature\n");
- return 0;
- }
+ printf("Bad hvm info signature\n");
+ BUG();
+ }
+
+ if ( t->length < sizeof(struct hvm_info_table) )
+ {
+ printf("Bad hvm info length\n");
+ BUG();
}
for ( i = 0; i < t->length; i++ )
sum += ptr[i];
- return (sum == 0);
+ if ( sum != 0 )
+ {
+ printf("Bad hvm info checksum\n");
+ BUG();
+ }
}
struct hvm_info_table *get_hvm_info_table(void)
@@ -575,11 +580,7 @@ struct hvm_info_table *get_hvm_info_table(void)
t = (struct hvm_info_table *)HVM_INFO_PADDR;
- if ( !validate_hvm_info(t) )
- {
- printf("Bad hvm info table\n");
- BUG();
- }
+ validate_hvm_info(t);
table = t;
diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c
index 0b3bc61765..9cac09132b 100644
--- a/tools/libxc/xc_hvm_build.c
+++ b/tools/libxc/xc_hvm_build.c
@@ -15,100 +15,55 @@
#include <xen/foreign/x86_64.h>
#include <xen/hvm/hvm_info_table.h>
#include <xen/hvm/params.h>
-#include "xc_e820.h"
+#include <xen/hvm/e820.h>
#include <xen/libelf/libelf.h>
#define SUPERPAGE_PFN_SHIFT 9
#define SUPERPAGE_NR_PFNS (1UL << SUPERPAGE_PFN_SHIFT)
-#define SCRATCH_PFN 0xFFFFF
-
-#define SPECIALPAGE_GUARD 0
-#define SPECIALPAGE_BUFIOREQ 1
-#define SPECIALPAGE_XENSTORE 2
-#define SPECIALPAGE_IOREQ 3
-#define SPECIALPAGE_IDENT_PT 4
+#define SPECIALPAGE_BUFIOREQ 0
+#define SPECIALPAGE_XENSTORE 1
+#define SPECIALPAGE_IOREQ 2
+#define SPECIALPAGE_IDENT_PT 3
+#define SPECIALPAGE_SHINFO 4
#define NR_SPECIAL_PAGES 5
+#define special_pfn(x) (0x100000u - NR_SPECIAL_PAGES + (x))
-static void build_e820map(void *e820_page, unsigned long long mem_size)
+static void build_hvm_info(void *hvm_info_page, uint64_t mem_size)
{
- struct e820entry *e820entry =
- (struct e820entry *)(((unsigned char *)e820_page) + HVM_E820_OFFSET);
- unsigned long long extra_mem_size = 0;
- unsigned char nr_map = 0;
+ struct hvm_info_table *hvm_info = (struct hvm_info_table *)
+ (((unsigned char *)hvm_info_page) + HVM_INFO_OFFSET);
+ uint64_t lowmem_end = mem_size, highmem_end = 0;
+ uint8_t sum;
+ int i;
- /*
- * Physical address space from HVM_BELOW_4G_RAM_END to 4G is reserved
- * for PCI devices MMIO. So if HVM has more than HVM_BELOW_4G_RAM_END
- * RAM, memory beyond HVM_BELOW_4G_RAM_END will go to 4G above.
- */
- if ( mem_size > HVM_BELOW_4G_RAM_END )
+ if ( lowmem_end > HVM_BELOW_4G_RAM_END )
{
- extra_mem_size = mem_size - HVM_BELOW_4G_RAM_END;
- mem_size = HVM_BELOW_4G_RAM_END;
+ highmem_end = lowmem_end + (1ull<<32) - HVM_BELOW_4G_RAM_END;
+ lowmem_end = HVM_BELOW_4G_RAM_END;
}
- /* 0x0-0x9FC00: Ordinary RAM. */
- e820entry[nr_map].addr = 0x0;
- e820entry[nr_map].size = 0x9FC00;
- e820entry[nr_map].type = E820_RAM;
- nr_map++;
+ memset(hvm_info_page, 0, PAGE_SIZE);
- /* 0x9FC00-0xA0000: Extended BIOS Data Area (EBDA). */
- e820entry[nr_map].addr = 0x9FC00;
- e820entry[nr_map].size = 0x400;
- e820entry[nr_map].type = E820_RESERVED;
- nr_map++;
+ /* Fill in the header. */
+ strncpy(hvm_info->signature, "HVM INFO", 8);
+ hvm_info->length = sizeof(struct hvm_info_table);
- /*
- * Following regions are standard regions of the PC memory map.
- * They are not covered by e820 regions. OSes will not use as RAM.
- * 0xA0000-0xC0000: VGA memory-mapped I/O. Not covered by E820.
- * 0xC0000-0xE0000: 16-bit devices, expansion ROMs (inc. vgabios).
- * TODO: hvmloader should free pages which turn out to be unused.
- */
+ /* Sensible defaults: these can be overridden by the caller. */
+ hvm_info->acpi_enabled = 1;
+ hvm_info->apic_mode = 1;
+ hvm_info->nr_vcpus = 1;
- /*
- * 0xE0000-0x0F0000: PC-specific area. We place ACPI tables here.
- * We *cannot* mark as E820_ACPI, for two reasons:
- * 1. ACPI spec. says that E820_ACPI regions below
- * 16MB must clip INT15h 0x88 and 0xe801 queries.
- * Our rombios doesn't do this.
- * 2. The OS is allowed to reclaim ACPI memory after
- * parsing the tables. But our FACS is in this
- * region and it must not be reclaimed (it contains
- * the ACPI global lock!).
- * 0xF0000-0x100000: System BIOS.
- * TODO: hvmloader should free pages which turn out to be unused.
- */
- e820entry[nr_map].addr = 0xE0000;
- e820entry[nr_map].size = 0x20000;
- e820entry[nr_map].type = E820_RESERVED;
- nr_map++;
-
- /* Low RAM goes here. Reserve space for special pages. */
- e820entry[nr_map].addr = 0x100000;
- e820entry[nr_map].size = (mem_size - 0x100000 -
- PAGE_SIZE * NR_SPECIAL_PAGES);
- e820entry[nr_map].type = E820_RAM;
- nr_map++;
-
- /* Explicitly reserve space for special pages (excluding guard page). */
- e820entry[nr_map].addr = mem_size - PAGE_SIZE * (NR_SPECIAL_PAGES - 1);
- e820entry[nr_map].size = PAGE_SIZE * (NR_SPECIAL_PAGES - 1);
- e820entry[nr_map].type = E820_RESERVED;
- nr_map++;
-
- if ( extra_mem_size )
- {
- e820entry[nr_map].addr = (1ULL << 32);
- e820entry[nr_map].size = extra_mem_size;
- e820entry[nr_map].type = E820_RAM;
- nr_map++;
- }
+ /* Memory parameters. */
+ hvm_info->low_mem_pgend = lowmem_end >> PAGE_SHIFT;
+ hvm_info->high_mem_pgend = highmem_end >> PAGE_SHIFT;
+ hvm_info->reserved_mem_pgstart = special_pfn(0);
- *(((unsigned char *)e820_page) + HVM_E820_NR_OFFSET) = nr_map;
+ /* Finish with the checksum. */
+ for ( i = 0, sum = 0; i < hvm_info->length; i++ )
+ sum += ((uint8_t *)hvm_info)[i];
+ hvm_info->checksum = -sum;
}
static int loadelfimage(
@@ -153,10 +108,10 @@ static int setup_guest(int xc_handle,
unsigned long i, nr_pages = (unsigned long)memsize << (20 - PAGE_SHIFT);
unsigned long target_pages = (unsigned long)target << (20 - PAGE_SHIFT);
unsigned long pod_pages = 0;
- unsigned long special_page_nr, entry_eip, cur_pages;
+ unsigned long entry_eip, cur_pages;
struct xen_add_to_physmap xatp;
struct shared_info *shared_info;
- void *e820_page;
+ void *hvm_info_page;
uint32_t *ident_pt;
struct elf_binary elf;
uint64_t v_start, v_end;
@@ -289,23 +244,22 @@ static int setup_guest(int xc_handle,
if ( loadelfimage(&elf, xc_handle, dom, page_array) != 0 )
goto error_out;
- if ( (e820_page = xc_map_foreign_range(
+ if ( (hvm_info_page = xc_map_foreign_range(
xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
- HVM_E820_PAGE >> PAGE_SHIFT)) == NULL )
+ HVM_INFO_PFN)) == NULL )
goto error_out;
- memset(e820_page, 0, PAGE_SIZE);
- build_e820map(e820_page, v_end);
- munmap(e820_page, PAGE_SIZE);
+ build_hvm_info(hvm_info_page, v_end);
+ munmap(hvm_info_page, PAGE_SIZE);
/* Map and initialise shared_info page. */
xatp.domid = dom;
xatp.space = XENMAPSPACE_shared_info;
xatp.idx = 0;
- xatp.gpfn = SCRATCH_PFN;
+ xatp.gpfn = special_pfn(SPECIALPAGE_SHINFO);
if ( (xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp) != 0) ||
((shared_info = xc_map_foreign_range(
xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
- SCRATCH_PFN)) == NULL) )
+ special_pfn(SPECIALPAGE_SHINFO))) == NULL) )
goto error_out;
memset(shared_info, 0, PAGE_SIZE);
/* NB. evtchn_upcall_mask is unused: leave as zero. */
@@ -313,31 +267,28 @@ static int setup_guest(int xc_handle,
sizeof(shared_info->evtchn_mask));
munmap(shared_info, PAGE_SIZE);
- special_page_nr = (((v_end > HVM_BELOW_4G_RAM_END)
- ? (HVM_BELOW_4G_RAM_END >> PAGE_SHIFT)
- : (v_end >> PAGE_SHIFT))
- - NR_SPECIAL_PAGES);
-
- /* Paranoia: clean special pages. */
+ /* Allocate and clear special pages. */
for ( i = 0; i < NR_SPECIAL_PAGES; i++ )
- if ( xc_clear_domain_page(xc_handle, dom, special_page_nr + i) )
- goto error_out;
-
- /* Free the guard page that separates low RAM from special pages. */
- rc = xc_domain_memory_decrease_reservation(
- xc_handle, dom, 1, 0, &page_array[special_page_nr]);
- if ( rc != 0 )
{
- PERROR("Could not deallocate guard page for HVM guest.\n");
- goto error_out;
+ xen_pfn_t pfn = special_pfn(i);
+ if ( i == SPECIALPAGE_SHINFO )
+ continue;
+ rc = xc_domain_memory_populate_physmap(xc_handle, dom, 1, 0, 0, &pfn);
+ if ( rc != 0 )
+ {
+ PERROR("Could not allocate %d'th special page.\n", i);
+ goto error_out;
+ }
+ if ( xc_clear_domain_page(xc_handle, dom, special_pfn(i)) )
+ goto error_out;
}
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN,
- special_page_nr + SPECIALPAGE_XENSTORE);
+ special_pfn(SPECIALPAGE_XENSTORE));
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_BUFIOREQ_PFN,
- special_page_nr + SPECIALPAGE_BUFIOREQ);
+ special_pfn(SPECIALPAGE_BUFIOREQ));
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN,
- special_page_nr + SPECIALPAGE_IOREQ);
+ special_pfn(SPECIALPAGE_IOREQ));
/*
* Identity-map page table is required for running with CR0.PG=0 when
@@ -345,14 +296,14 @@ static int setup_guest(int xc_handle,
*/
if ( (ident_pt = xc_map_foreign_range(
xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
- special_page_nr + SPECIALPAGE_IDENT_PT)) == NULL )
+ special_pfn(SPECIALPAGE_IDENT_PT))) == NULL )
goto error_out;
for ( i = 0; i < PAGE_SIZE / sizeof(*ident_pt); i++ )
ident_pt[i] = ((i << 22) | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER |
_PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE);
munmap(ident_pt, PAGE_SIZE);
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IDENT_PT,
- (special_page_nr + SPECIALPAGE_IDENT_PT) << PAGE_SHIFT);
+ special_pfn(SPECIALPAGE_IDENT_PT) << PAGE_SHIFT);
/* Insert JMP <rel32> instruction at address 0x0 to reach entry point. */
entry_eip = elf_uval(&elf, elf.ehdr, e_entry);
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 9d549c66f6..2c5096fe69 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -903,26 +903,24 @@ static PyObject *pyxc_hvm_build(XcObject *self,
if ( target == -1 )
target = memsize;
- if ( xc_hvm_build_target_mem(self->xc_handle, dom, memsize, target, image) != 0 )
+ if ( xc_hvm_build_target_mem(self->xc_handle, dom, memsize,
+ target, image) != 0 )
return pyxc_error_to_exception();
#if !defined(__ia64__)
- /* Set up the HVM info table. */
+ /* Fix up the HVM info table. */
va_map = xc_map_foreign_range(self->xc_handle, dom, XC_PAGE_SIZE,
PROT_READ | PROT_WRITE,
HVM_INFO_PFN);
if ( va_map == NULL )
return PyErr_SetFromErrno(xc_error_obj);
va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET);
- memset(va_hvm, 0, sizeof(*va_hvm));
- strncpy(va_hvm->signature, "HVM INFO", 8);
- va_hvm->length = sizeof(struct hvm_info_table);
va_hvm->acpi_enabled = acpi;
va_hvm->apic_mode = apic;
va_hvm->nr_vcpus = vcpus;
for ( i = 0, sum = 0; i < va_hvm->length; i++ )
sum += ((uint8_t *)va_hvm)[i];
- va_hvm->checksum = -sum;
+ va_hvm->checksum -= sum;
munmap(va_map, XC_PAGE_SIZE);
#endif
diff --git a/xen/include/public/hvm/hvm_info_table.h b/xen/include/public/hvm/hvm_info_table.h
index dfe34db1e5..b89845515d 100644
--- a/xen/include/public/hvm/hvm_info_table.h
+++ b/xen/include/public/hvm/hvm_info_table.h
@@ -33,9 +33,37 @@ struct hvm_info_table {
char signature[8]; /* "HVM INFO" */
uint32_t length;
uint8_t checksum;
+
+ /* Should firmware build ACPI tables? */
uint8_t acpi_enabled;
+
+ /* Should firmware build APIC descriptors (APIC MADT / MP BIOS)? */
uint8_t apic_mode;
+
+ /* How many CPUs does this domain have? */
uint32_t nr_vcpus;
+
+ /*
+ * MEMORY MAP provided by HVM domain builder.
+ * Notes:
+ * 1. page_to_phys(x) = x << 12
+ * 2. If a field is zero, the corresponding range does not exist.
+ */
+ /*
+ * 0x0 to page_to_phys(low_mem_pgend)-1:
+ * RAM below 4GB (except for VGA hole 0xA0000-0xBFFFF)
+ */
+ uint32_t low_mem_pgend;
+ /*
+ * page_to_phys(reserved_mem_pgstart) to 0xFFFFFFFF:
+ * Reserved for special memory mappings
+ */
+ uint32_t reserved_mem_pgstart;
+ /*
+ * 0x100000000 to page_to_phys(high_mem_pgend)-1:
+ * RAM above 4GB
+ */
+ uint32_t high_mem_pgend;
};
#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */