diff --git a/usr.sbin/bhyve/e820.c b/usr.sbin/bhyve/e820.c --- a/usr.sbin/bhyve/e820.c +++ b/usr.sbin/bhyve/e820.c @@ -26,6 +26,16 @@ #define MB (1024 * KB) #define GB (1024 * MB) +/* + * Fix E820 memory holes: + * [ A0000, C0000) VGA + * [ C0000, 100000) ROM + */ +#define E820_VGA_MEM_BASE 0xA0000 +#define E820_VGA_MEM_END 0xC0000 +#define E820_ROM_MEM_BASE 0xC0000 +#define E820_ROM_MEM_END 0x100000 + struct e820_element { TAILQ_ENTRY(e820_element) chain; uint64_t base; @@ -204,6 +214,74 @@ return (0); } +static int +e820_add_memory_hole(const uint64_t base, const uint64_t end) +{ + struct e820_element *element; + struct e820_element *ram_element; + + assert(end >= base); + + /* + * E820 table should be always sorted in ascending order. Therefore, + * search for an element which end is larger than the base parameter. + */ + TAILQ_FOREACH(element, &e820_table, chain) { + if (element->end > base) { + break; + } + } + + if (element == NULL || end <= element->base) { + /* Nothing to do. Hole already exists */ + return (0); + } + + /* Memory holes are only allowed in system memory */ + assert(element->type == E820_TYPE_MEMORY); + + if (base == element->base) { + /* + * New hole at system memory base boundary. + * + * Old table: + * [ 0x1000, 0x4000] RAM + * New table: + * [ 0x2000, 0x4000] RAM + */ + element->base = end; + } else if (end == element->end) { + /* + * New hole at system memory end boundary. + * + * Old table: + * [ 0x1000, 0x4000] RAM + * New table: + * [ 0x1000, 0x3000] RAM + */ + element->end = base; + } else { + /* + * New hole inside system memory entry. Split the system memory. + * + * Old table: + * [ 0x1000, 0x4000] RAM <-- element + * New table: + * [ 0x1000, 0x2000] RAM + * [ 0x3000, 0x4000] RAM <-- element + */ + ram_element = e820_element_alloc(element->base, base, + E820_TYPE_MEMORY); + if (ram_element == NULL) { + return (ENOMEM); + } + TAILQ_INSERT_BEFORE(element, ram_element, chain); + element->base = end; + } + + return (0); +} + int e820_init(struct vmctx *const ctx) { @@ -229,5 +307,17 @@ } } + error = e820_add_memory_hole(E820_VGA_MEM_BASE, E820_VGA_MEM_END); + if (error) { + warnx("%s: Could not add VGA memory", __func__); + return (error); + } + + error = e820_add_memory_hole(E820_ROM_MEM_BASE, E820_ROM_MEM_END); + if (error) { + warnx("%s: Could not add ROM area", __func__); + return (error); + } + return (0); }