2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
5 * Author: Corvin Köhne <c.koehne@beckhoff.com>
11 #include <machine/vmm.h>
21 #include "qemu_fwcfg.h"
24 * E820 always uses 64 bit entries. Emulation code will use vm_paddr_t since it
25 * works on physical addresses. If vm_paddr_t is larger than uint64_t E820 can't
26 * hold all possible physical addresses and we can get into trouble.
28 static_assert(sizeof(vm_paddr_t) <= sizeof(uint64_t),
29 "Unable to represent physical memory by E820 table");
31 #define E820_FWCFG_FILE_NAME "etc/e820"
34 #define MB (1024 * KB)
35 #define GB (1024 * MB)
38 * Fix E820 memory holes:
40 * [ C0000, 100000) ROM
42 #define E820_VGA_MEM_BASE 0xA0000
43 #define E820_VGA_MEM_END 0xC0000
44 #define E820_ROM_MEM_BASE 0xC0000
45 #define E820_ROM_MEM_END 0x100000
48 TAILQ_ENTRY(e820_element) chain;
51 enum e820_memory_type type;
53 static TAILQ_HEAD(e820_table, e820_element) e820_table = TAILQ_HEAD_INITIALIZER(
56 static struct e820_element *
57 e820_element_alloc(uint64_t base, uint64_t end, enum e820_memory_type type)
59 struct e820_element *element;
61 element = calloc(1, sizeof(*element));
62 if (element == NULL) {
74 e820_get_type_name(const enum e820_memory_type type)
77 case E820_TYPE_MEMORY:
79 case E820_TYPE_RESERVED:
93 struct e820_element *element;
96 fprintf(stderr, "E820 map:\n");
99 TAILQ_FOREACH(element, &e820_table, chain) {
100 fprintf(stderr, " (%4lu) [%16lx, %16lx] %s\n", i,
101 element->base, element->end,
102 e820_get_type_name(element->type));
108 struct qemu_fwcfg_item *
109 e820_get_fwcfg_item(void)
111 struct qemu_fwcfg_item *fwcfg_item;
112 struct e820_element *element;
113 struct e820_entry *entries;
117 TAILQ_FOREACH(element, &e820_table, chain) {
121 warnx("%s: E820 table empty", __func__);
125 fwcfg_item = calloc(1, sizeof(struct qemu_fwcfg_item));
126 if (fwcfg_item == NULL) {
130 fwcfg_item->size = count * sizeof(struct e820_entry);
131 fwcfg_item->data = calloc(count, sizeof(struct e820_entry));
132 if (fwcfg_item->data == NULL) {
138 entries = (struct e820_entry *)fwcfg_item->data;
139 TAILQ_FOREACH(element, &e820_table, chain) {
140 struct e820_entry *entry = &entries[i];
142 entry->base = element->base;
143 entry->length = element->end - element->base;
144 entry->type = element->type;
153 e820_add_entry(const uint64_t base, const uint64_t end,
154 const enum e820_memory_type type)
156 struct e820_element *new_element;
157 struct e820_element *element;
158 struct e820_element *ram_element;
162 new_element = e820_element_alloc(base, end, type);
163 if (new_element == NULL) {
168 * E820 table should always be sorted in ascending order. Therefore,
169 * search for a range whose end is larger than the base parameter.
171 TAILQ_FOREACH(element, &e820_table, chain) {
172 if (element->end > base) {
178 * System memory requires special handling.
180 if (type == E820_TYPE_MEMORY) {
182 * base is larger than of any existing element. Add new system
183 * memory at the end of the table.
185 if (element == NULL) {
186 TAILQ_INSERT_TAIL(&e820_table, new_element, chain);
191 * System memory shouldn't overlap with any existing element.
193 assert(end >= element->base);
195 TAILQ_INSERT_BEFORE(element, new_element, chain);
201 * If some one tries to allocate a specific address, it could happen, that
202 * this address is not allocatable. Therefore, do some checks. If the
203 * address is not allocatable, don't panic. The user may have a fallback and
204 * tries to allocate another address. This is true for the GVT-d emulation
205 * which tries to reuse the host address of the graphics stolen memory and
206 * falls back to allocating the highest address below 4 GB.
208 if (element == NULL || element->type != E820_TYPE_MEMORY ||
209 (base < element->base || end > element->end))
212 if (base == element->base) {
214 * New element at system memory base boundary. Add new
215 * element before current and adjust the base of the old
219 * [ 0x1000, 0x4000] RAM <-- element
221 * [ 0x1000, 0x2000] Reserved
222 * [ 0x2000, 0x4000] RAM <-- element
224 TAILQ_INSERT_BEFORE(element, new_element, chain);
226 } else if (end == element->end) {
228 * New element at system memory end boundary. Add new
229 * element after current and adjust the end of the
233 * [ 0x1000, 0x4000] RAM <-- element
235 * [ 0x1000, 0x3000] RAM <-- element
236 * [ 0x3000, 0x4000] Reserved
238 TAILQ_INSERT_AFTER(&e820_table, element, new_element, chain);
242 * New element inside system memory entry. Split it by
243 * adding a system memory element and the new element
247 * [ 0x1000, 0x4000] RAM <-- element
249 * [ 0x1000, 0x2000] RAM
250 * [ 0x2000, 0x3000] Reserved
251 * [ 0x3000, 0x4000] RAM <-- element
253 ram_element = e820_element_alloc(element->base, base,
255 if (ram_element == NULL) {
258 TAILQ_INSERT_BEFORE(element, ram_element, chain);
259 TAILQ_INSERT_BEFORE(element, new_element, chain);
267 e820_add_memory_hole(const uint64_t base, const uint64_t end)
269 struct e820_element *element;
270 struct e820_element *ram_element;
275 * E820 table should be always sorted in ascending order. Therefore,
276 * search for an element which end is larger than the base parameter.
278 TAILQ_FOREACH(element, &e820_table, chain) {
279 if (element->end > base) {
284 if (element == NULL || end <= element->base) {
285 /* Nothing to do. Hole already exists */
289 /* Memory holes are only allowed in system memory */
290 assert(element->type == E820_TYPE_MEMORY);
292 if (base == element->base) {
294 * New hole at system memory base boundary.
297 * [ 0x1000, 0x4000] RAM
299 * [ 0x2000, 0x4000] RAM
302 } else if (end == element->end) {
304 * New hole at system memory end boundary.
307 * [ 0x1000, 0x4000] RAM
309 * [ 0x1000, 0x3000] RAM
314 * New hole inside system memory entry. Split the system memory.
317 * [ 0x1000, 0x4000] RAM <-- element
319 * [ 0x1000, 0x2000] RAM
320 * [ 0x3000, 0x4000] RAM <-- element
322 ram_element = e820_element_alloc(element->base, base,
324 if (ram_element == NULL) {
327 TAILQ_INSERT_BEFORE(element, ram_element, chain);
335 e820_alloc_highest(const uint64_t max_address, const uint64_t length,
336 const uint64_t alignment, const enum e820_memory_type type)
338 struct e820_element *element;
340 TAILQ_FOREACH_REVERSE(element, &e820_table, e820_table, chain) {
341 uint64_t address, base, end;
343 end = MIN(max_address, element->end);
344 base = roundup2(element->base, alignment);
347 * If end - length == 0, we would allocate memory at address 0. This
348 * address is mostly unusable and we should avoid allocating it.
349 * Therefore, search for another block in that case.
351 if (element->type != E820_TYPE_MEMORY || end < base ||
352 end - base < length || end - length == 0) {
356 address = rounddown2(end - length, alignment);
358 if (e820_add_entry(address, address + length, type) != 0) {
369 e820_alloc_lowest(const uint64_t min_address, const uint64_t length,
370 const uint64_t alignment, const enum e820_memory_type type)
372 struct e820_element *element;
374 TAILQ_FOREACH(element, &e820_table, chain) {
378 base = MAX(min_address, roundup2(element->base, alignment));
381 * If base == 0, we would allocate memory at address 0. This
382 * address is mostly unusable and we should avoid allocating it.
383 * Therefore, search for another block in that case.
385 if (element->type != E820_TYPE_MEMORY || end < base ||
386 end - base < length || base == 0) {
390 if (e820_add_entry(base, base + length, type) != 0) {
401 e820_alloc(const uint64_t address, const uint64_t length,
402 const uint64_t alignment, const enum e820_memory_type type,
403 const enum e820_allocation_strategy strategy)
405 assert(powerof2(alignment));
406 assert((address & (alignment - 1)) == 0);
409 case E820_ALLOCATE_ANY:
411 * Allocate any address. Therefore, ignore the address parameter
412 * and reuse the code path for allocating the lowest address.
414 return (e820_alloc_lowest(0, length, alignment, type));
415 case E820_ALLOCATE_LOWEST:
416 return (e820_alloc_lowest(address, length, alignment, type));
417 case E820_ALLOCATE_HIGHEST:
418 return (e820_alloc_highest(address, length, alignment, type));
419 case E820_ALLOCATE_SPECIFIC:
420 if (e820_add_entry(address, address + length, type) != 0) {
431 e820_init(struct vmctx *const ctx)
433 uint64_t lowmem_size, highmem_size;
436 TAILQ_INIT(&e820_table);
438 lowmem_size = vm_get_lowmem_size(ctx);
439 error = e820_add_entry(0, lowmem_size, E820_TYPE_MEMORY);
441 warnx("%s: Could not add lowmem", __func__);
445 highmem_size = vm_get_highmem_size(ctx);
446 if (highmem_size != 0) {
447 error = e820_add_entry(4 * GB, 4 * GB + highmem_size,
450 warnx("%s: Could not add highmem", __func__);
455 error = e820_add_memory_hole(E820_VGA_MEM_BASE, E820_VGA_MEM_END);
457 warnx("%s: Could not add VGA memory", __func__);
461 error = e820_add_memory_hole(E820_ROM_MEM_BASE, E820_ROM_MEM_END);
463 warnx("%s: Could not add ROM area", __func__);