git: 059af92a300f - main - bhyve: add common memory holes to E820 table

From: Corvin Köhne <corvink_at_FreeBSD.org>
Date: Wed, 26 Apr 2023 07:59:34 UTC
The branch main has been updated by corvink:

URL: https://cgit.FreeBSD.org/src/commit/?id=059af92a300f76653048c042559f7d7d8fd8f99c

commit 059af92a300f76653048c042559f7d7d8fd8f99c
Author:     Corvin Köhne <corvink@FreeBSD.org>
AuthorDate: 2021-09-09 09:37:03 +0000
Commit:     Corvin Köhne <corvink@FreeBSD.org>
CommitDate: 2023-04-26 07:58:31 +0000

    bhyve: add common memory holes to E820 table
    
    The VGA and the ROM memory ranges can't be used as system memory. For
    that reason, remove them from the E820 table.
    
    Reviewed by:            markj
    MFC after:              1 week
    Sponsored by:           Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D39546
---
 usr.sbin/bhyve/e820.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/usr.sbin/bhyve/e820.c b/usr.sbin/bhyve/e820.c
index 746d34d6521c..95b83c056b9b 100644
--- 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 @@ e820_add_entry(const uint64_t base, const uint64_t end,
 	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 @@ e820_init(struct vmctx *const ctx)
 		}
 	}
 
+	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);
 }