1*32640292SAndy Fiddaman /*-
2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
3*32640292SAndy Fiddaman *
4*32640292SAndy Fiddaman * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
5*32640292SAndy Fiddaman * Author: Corvin Köhne <c.koehne@beckhoff.com>
6*32640292SAndy Fiddaman */
7*32640292SAndy Fiddaman
8*32640292SAndy Fiddaman #include <sys/types.h>
9*32640292SAndy Fiddaman #include <sys/queue.h>
10*32640292SAndy Fiddaman
11*32640292SAndy Fiddaman #include <machine/vmm.h>
12*32640292SAndy Fiddaman
13*32640292SAndy Fiddaman #include <assert.h>
14*32640292SAndy Fiddaman #include <err.h>
15*32640292SAndy Fiddaman #include <errno.h>
16*32640292SAndy Fiddaman #include <stdio.h>
17*32640292SAndy Fiddaman #include <stdlib.h>
18*32640292SAndy Fiddaman #include <string.h>
19*32640292SAndy Fiddaman
20*32640292SAndy Fiddaman #include "e820.h"
21*32640292SAndy Fiddaman #include "qemu_fwcfg.h"
22*32640292SAndy Fiddaman
23*32640292SAndy Fiddaman /*
24*32640292SAndy Fiddaman * E820 always uses 64 bit entries. Emulation code will use vm_paddr_t since it
25*32640292SAndy Fiddaman * works on physical addresses. If vm_paddr_t is larger than uint64_t E820 can't
26*32640292SAndy Fiddaman * hold all possible physical addresses and we can get into trouble.
27*32640292SAndy Fiddaman */
28*32640292SAndy Fiddaman static_assert(sizeof(vm_paddr_t) <= sizeof(uint64_t),
29*32640292SAndy Fiddaman "Unable to represent physical memory by E820 table");
30*32640292SAndy Fiddaman
31*32640292SAndy Fiddaman #define E820_FWCFG_FILE_NAME "etc/e820"
32*32640292SAndy Fiddaman
33*32640292SAndy Fiddaman #define KB (1024UL)
34*32640292SAndy Fiddaman #define MB (1024 * KB)
35*32640292SAndy Fiddaman #define GB (1024 * MB)
36*32640292SAndy Fiddaman
37*32640292SAndy Fiddaman /*
38*32640292SAndy Fiddaman * Fix E820 memory holes:
39*32640292SAndy Fiddaman * [ A0000, C0000) VGA
40*32640292SAndy Fiddaman * [ C0000, 100000) ROM
41*32640292SAndy Fiddaman */
42*32640292SAndy Fiddaman #define E820_VGA_MEM_BASE 0xA0000
43*32640292SAndy Fiddaman #define E820_VGA_MEM_END 0xC0000
44*32640292SAndy Fiddaman #define E820_ROM_MEM_BASE 0xC0000
45*32640292SAndy Fiddaman #define E820_ROM_MEM_END 0x100000
46*32640292SAndy Fiddaman
47*32640292SAndy Fiddaman struct e820_element {
48*32640292SAndy Fiddaman TAILQ_ENTRY(e820_element) chain;
49*32640292SAndy Fiddaman uint64_t base;
50*32640292SAndy Fiddaman uint64_t end;
51*32640292SAndy Fiddaman enum e820_memory_type type;
52*32640292SAndy Fiddaman };
53*32640292SAndy Fiddaman static TAILQ_HEAD(e820_table, e820_element) e820_table = TAILQ_HEAD_INITIALIZER(
54*32640292SAndy Fiddaman e820_table);
55*32640292SAndy Fiddaman
56*32640292SAndy Fiddaman static struct e820_element *
e820_element_alloc(uint64_t base,uint64_t end,enum e820_memory_type type)57*32640292SAndy Fiddaman e820_element_alloc(uint64_t base, uint64_t end, enum e820_memory_type type)
58*32640292SAndy Fiddaman {
59*32640292SAndy Fiddaman struct e820_element *element;
60*32640292SAndy Fiddaman
61*32640292SAndy Fiddaman element = calloc(1, sizeof(*element));
62*32640292SAndy Fiddaman if (element == NULL) {
63*32640292SAndy Fiddaman return (NULL);
64*32640292SAndy Fiddaman }
65*32640292SAndy Fiddaman
66*32640292SAndy Fiddaman element->base = base;
67*32640292SAndy Fiddaman element->end = end;
68*32640292SAndy Fiddaman element->type = type;
69*32640292SAndy Fiddaman
70*32640292SAndy Fiddaman return (element);
71*32640292SAndy Fiddaman }
72*32640292SAndy Fiddaman
73*32640292SAndy Fiddaman static const char *
e820_get_type_name(const enum e820_memory_type type)74*32640292SAndy Fiddaman e820_get_type_name(const enum e820_memory_type type)
75*32640292SAndy Fiddaman {
76*32640292SAndy Fiddaman switch (type) {
77*32640292SAndy Fiddaman case E820_TYPE_MEMORY:
78*32640292SAndy Fiddaman return ("RAM");
79*32640292SAndy Fiddaman case E820_TYPE_RESERVED:
80*32640292SAndy Fiddaman return ("Reserved");
81*32640292SAndy Fiddaman case E820_TYPE_ACPI:
82*32640292SAndy Fiddaman return ("ACPI");
83*32640292SAndy Fiddaman case E820_TYPE_NVS:
84*32640292SAndy Fiddaman return ("NVS");
85*32640292SAndy Fiddaman default:
86*32640292SAndy Fiddaman return ("Unknown");
87*32640292SAndy Fiddaman }
88*32640292SAndy Fiddaman }
89*32640292SAndy Fiddaman
90*32640292SAndy Fiddaman void
e820_dump_table(void)91*32640292SAndy Fiddaman e820_dump_table(void)
92*32640292SAndy Fiddaman {
93*32640292SAndy Fiddaman struct e820_element *element;
94*32640292SAndy Fiddaman uint64_t i;
95*32640292SAndy Fiddaman
96*32640292SAndy Fiddaman fprintf(stderr, "E820 map:\n");
97*32640292SAndy Fiddaman
98*32640292SAndy Fiddaman i = 0;
99*32640292SAndy Fiddaman TAILQ_FOREACH(element, &e820_table, chain) {
100*32640292SAndy Fiddaman fprintf(stderr, " (%4lu) [%16lx, %16lx] %s\n", i,
101*32640292SAndy Fiddaman element->base, element->end,
102*32640292SAndy Fiddaman e820_get_type_name(element->type));
103*32640292SAndy Fiddaman
104*32640292SAndy Fiddaman ++i;
105*32640292SAndy Fiddaman }
106*32640292SAndy Fiddaman }
107*32640292SAndy Fiddaman
108*32640292SAndy Fiddaman struct qemu_fwcfg_item *
e820_get_fwcfg_item(void)109*32640292SAndy Fiddaman e820_get_fwcfg_item(void)
110*32640292SAndy Fiddaman {
111*32640292SAndy Fiddaman struct qemu_fwcfg_item *fwcfg_item;
112*32640292SAndy Fiddaman struct e820_element *element;
113*32640292SAndy Fiddaman struct e820_entry *entries;
114*32640292SAndy Fiddaman int count, i;
115*32640292SAndy Fiddaman
116*32640292SAndy Fiddaman count = 0;
117*32640292SAndy Fiddaman TAILQ_FOREACH(element, &e820_table, chain) {
118*32640292SAndy Fiddaman ++count;
119*32640292SAndy Fiddaman }
120*32640292SAndy Fiddaman if (count == 0) {
121*32640292SAndy Fiddaman warnx("%s: E820 table empty", __func__);
122*32640292SAndy Fiddaman return (NULL);
123*32640292SAndy Fiddaman }
124*32640292SAndy Fiddaman
125*32640292SAndy Fiddaman fwcfg_item = calloc(1, sizeof(struct qemu_fwcfg_item));
126*32640292SAndy Fiddaman if (fwcfg_item == NULL) {
127*32640292SAndy Fiddaman return (NULL);
128*32640292SAndy Fiddaman }
129*32640292SAndy Fiddaman
130*32640292SAndy Fiddaman fwcfg_item->size = count * sizeof(struct e820_entry);
131*32640292SAndy Fiddaman fwcfg_item->data = calloc(count, sizeof(struct e820_entry));
132*32640292SAndy Fiddaman if (fwcfg_item->data == NULL) {
133*32640292SAndy Fiddaman free(fwcfg_item);
134*32640292SAndy Fiddaman return (NULL);
135*32640292SAndy Fiddaman }
136*32640292SAndy Fiddaman
137*32640292SAndy Fiddaman i = 0;
138*32640292SAndy Fiddaman entries = (struct e820_entry *)fwcfg_item->data;
139*32640292SAndy Fiddaman TAILQ_FOREACH(element, &e820_table, chain) {
140*32640292SAndy Fiddaman struct e820_entry *entry = &entries[i];
141*32640292SAndy Fiddaman
142*32640292SAndy Fiddaman entry->base = element->base;
143*32640292SAndy Fiddaman entry->length = element->end - element->base;
144*32640292SAndy Fiddaman entry->type = element->type;
145*32640292SAndy Fiddaman
146*32640292SAndy Fiddaman ++i;
147*32640292SAndy Fiddaman }
148*32640292SAndy Fiddaman
149*32640292SAndy Fiddaman return (fwcfg_item);
150*32640292SAndy Fiddaman }
151*32640292SAndy Fiddaman
152*32640292SAndy Fiddaman static int
e820_add_entry(const uint64_t base,const uint64_t end,const enum e820_memory_type type)153*32640292SAndy Fiddaman e820_add_entry(const uint64_t base, const uint64_t end,
154*32640292SAndy Fiddaman const enum e820_memory_type type)
155*32640292SAndy Fiddaman {
156*32640292SAndy Fiddaman struct e820_element *new_element;
157*32640292SAndy Fiddaman struct e820_element *element;
158*32640292SAndy Fiddaman struct e820_element *ram_element;
159*32640292SAndy Fiddaman
160*32640292SAndy Fiddaman assert(end >= base);
161*32640292SAndy Fiddaman
162*32640292SAndy Fiddaman new_element = e820_element_alloc(base, end, type);
163*32640292SAndy Fiddaman if (new_element == NULL) {
164*32640292SAndy Fiddaman return (ENOMEM);
165*32640292SAndy Fiddaman }
166*32640292SAndy Fiddaman
167*32640292SAndy Fiddaman /*
168*32640292SAndy Fiddaman * E820 table should always be sorted in ascending order. Therefore,
169*32640292SAndy Fiddaman * search for a range whose end is larger than the base parameter.
170*32640292SAndy Fiddaman */
171*32640292SAndy Fiddaman TAILQ_FOREACH(element, &e820_table, chain) {
172*32640292SAndy Fiddaman if (element->end > base) {
173*32640292SAndy Fiddaman break;
174*32640292SAndy Fiddaman }
175*32640292SAndy Fiddaman }
176*32640292SAndy Fiddaman
177*32640292SAndy Fiddaman /*
178*32640292SAndy Fiddaman * System memory requires special handling.
179*32640292SAndy Fiddaman */
180*32640292SAndy Fiddaman if (type == E820_TYPE_MEMORY) {
181*32640292SAndy Fiddaman /*
182*32640292SAndy Fiddaman * base is larger than of any existing element. Add new system
183*32640292SAndy Fiddaman * memory at the end of the table.
184*32640292SAndy Fiddaman */
185*32640292SAndy Fiddaman if (element == NULL) {
186*32640292SAndy Fiddaman TAILQ_INSERT_TAIL(&e820_table, new_element, chain);
187*32640292SAndy Fiddaman return (0);
188*32640292SAndy Fiddaman }
189*32640292SAndy Fiddaman
190*32640292SAndy Fiddaman /*
191*32640292SAndy Fiddaman * System memory shouldn't overlap with any existing element.
192*32640292SAndy Fiddaman */
193*32640292SAndy Fiddaman assert(end >= element->base);
194*32640292SAndy Fiddaman
195*32640292SAndy Fiddaman TAILQ_INSERT_BEFORE(element, new_element, chain);
196*32640292SAndy Fiddaman
197*32640292SAndy Fiddaman return (0);
198*32640292SAndy Fiddaman }
199*32640292SAndy Fiddaman
200*32640292SAndy Fiddaman assert(element != NULL);
201*32640292SAndy Fiddaman /* Non system memory should be allocated inside system memory. */
202*32640292SAndy Fiddaman assert(element->type == E820_TYPE_MEMORY);
203*32640292SAndy Fiddaman /* New element should fit into existing system memory element. */
204*32640292SAndy Fiddaman assert(base >= element->base && end <= element->end);
205*32640292SAndy Fiddaman
206*32640292SAndy Fiddaman if (base == element->base) {
207*32640292SAndy Fiddaman /*
208*32640292SAndy Fiddaman * New element at system memory base boundary. Add new
209*32640292SAndy Fiddaman * element before current and adjust the base of the old
210*32640292SAndy Fiddaman * element.
211*32640292SAndy Fiddaman *
212*32640292SAndy Fiddaman * Old table:
213*32640292SAndy Fiddaman * [ 0x1000, 0x4000] RAM <-- element
214*32640292SAndy Fiddaman * New table:
215*32640292SAndy Fiddaman * [ 0x1000, 0x2000] Reserved
216*32640292SAndy Fiddaman * [ 0x2000, 0x4000] RAM <-- element
217*32640292SAndy Fiddaman */
218*32640292SAndy Fiddaman TAILQ_INSERT_BEFORE(element, new_element, chain);
219*32640292SAndy Fiddaman element->base = end;
220*32640292SAndy Fiddaman } else if (end == element->end) {
221*32640292SAndy Fiddaman /*
222*32640292SAndy Fiddaman * New element at system memory end boundary. Add new
223*32640292SAndy Fiddaman * element after current and adjust the end of the
224*32640292SAndy Fiddaman * current element.
225*32640292SAndy Fiddaman *
226*32640292SAndy Fiddaman * Old table:
227*32640292SAndy Fiddaman * [ 0x1000, 0x4000] RAM <-- element
228*32640292SAndy Fiddaman * New table:
229*32640292SAndy Fiddaman * [ 0x1000, 0x3000] RAM <-- element
230*32640292SAndy Fiddaman * [ 0x3000, 0x4000] Reserved
231*32640292SAndy Fiddaman */
232*32640292SAndy Fiddaman TAILQ_INSERT_AFTER(&e820_table, element, new_element, chain);
233*32640292SAndy Fiddaman element->end = base;
234*32640292SAndy Fiddaman } else {
235*32640292SAndy Fiddaman /*
236*32640292SAndy Fiddaman * New element inside system memory entry. Split it by
237*32640292SAndy Fiddaman * adding a system memory element and the new element
238*32640292SAndy Fiddaman * before current.
239*32640292SAndy Fiddaman *
240*32640292SAndy Fiddaman * Old table:
241*32640292SAndy Fiddaman * [ 0x1000, 0x4000] RAM <-- element
242*32640292SAndy Fiddaman * New table:
243*32640292SAndy Fiddaman * [ 0x1000, 0x2000] RAM
244*32640292SAndy Fiddaman * [ 0x2000, 0x3000] Reserved
245*32640292SAndy Fiddaman * [ 0x3000, 0x4000] RAM <-- element
246*32640292SAndy Fiddaman */
247*32640292SAndy Fiddaman ram_element = e820_element_alloc(element->base, base,
248*32640292SAndy Fiddaman E820_TYPE_MEMORY);
249*32640292SAndy Fiddaman if (ram_element == NULL) {
250*32640292SAndy Fiddaman return (ENOMEM);
251*32640292SAndy Fiddaman }
252*32640292SAndy Fiddaman TAILQ_INSERT_BEFORE(element, ram_element, chain);
253*32640292SAndy Fiddaman TAILQ_INSERT_BEFORE(element, new_element, chain);
254*32640292SAndy Fiddaman element->base = end;
255*32640292SAndy Fiddaman }
256*32640292SAndy Fiddaman
257*32640292SAndy Fiddaman return (0);
258*32640292SAndy Fiddaman }
259*32640292SAndy Fiddaman
260*32640292SAndy Fiddaman static int
e820_add_memory_hole(const uint64_t base,const uint64_t end)261*32640292SAndy Fiddaman e820_add_memory_hole(const uint64_t base, const uint64_t end)
262*32640292SAndy Fiddaman {
263*32640292SAndy Fiddaman struct e820_element *element;
264*32640292SAndy Fiddaman struct e820_element *ram_element;
265*32640292SAndy Fiddaman
266*32640292SAndy Fiddaman assert(end >= base);
267*32640292SAndy Fiddaman
268*32640292SAndy Fiddaman /*
269*32640292SAndy Fiddaman * E820 table should be always sorted in ascending order. Therefore,
270*32640292SAndy Fiddaman * search for an element which end is larger than the base parameter.
271*32640292SAndy Fiddaman */
272*32640292SAndy Fiddaman TAILQ_FOREACH(element, &e820_table, chain) {
273*32640292SAndy Fiddaman if (element->end > base) {
274*32640292SAndy Fiddaman break;
275*32640292SAndy Fiddaman }
276*32640292SAndy Fiddaman }
277*32640292SAndy Fiddaman
278*32640292SAndy Fiddaman if (element == NULL || end <= element->base) {
279*32640292SAndy Fiddaman /* Nothing to do. Hole already exists */
280*32640292SAndy Fiddaman return (0);
281*32640292SAndy Fiddaman }
282*32640292SAndy Fiddaman
283*32640292SAndy Fiddaman /* Memory holes are only allowed in system memory */
284*32640292SAndy Fiddaman assert(element->type == E820_TYPE_MEMORY);
285*32640292SAndy Fiddaman
286*32640292SAndy Fiddaman if (base == element->base) {
287*32640292SAndy Fiddaman /*
288*32640292SAndy Fiddaman * New hole at system memory base boundary.
289*32640292SAndy Fiddaman *
290*32640292SAndy Fiddaman * Old table:
291*32640292SAndy Fiddaman * [ 0x1000, 0x4000] RAM
292*32640292SAndy Fiddaman * New table:
293*32640292SAndy Fiddaman * [ 0x2000, 0x4000] RAM
294*32640292SAndy Fiddaman */
295*32640292SAndy Fiddaman element->base = end;
296*32640292SAndy Fiddaman } else if (end == element->end) {
297*32640292SAndy Fiddaman /*
298*32640292SAndy Fiddaman * New hole at system memory end boundary.
299*32640292SAndy Fiddaman *
300*32640292SAndy Fiddaman * Old table:
301*32640292SAndy Fiddaman * [ 0x1000, 0x4000] RAM
302*32640292SAndy Fiddaman * New table:
303*32640292SAndy Fiddaman * [ 0x1000, 0x3000] RAM
304*32640292SAndy Fiddaman */
305*32640292SAndy Fiddaman element->end = base;
306*32640292SAndy Fiddaman } else {
307*32640292SAndy Fiddaman /*
308*32640292SAndy Fiddaman * New hole inside system memory entry. Split the system memory.
309*32640292SAndy Fiddaman *
310*32640292SAndy Fiddaman * Old table:
311*32640292SAndy Fiddaman * [ 0x1000, 0x4000] RAM <-- element
312*32640292SAndy Fiddaman * New table:
313*32640292SAndy Fiddaman * [ 0x1000, 0x2000] RAM
314*32640292SAndy Fiddaman * [ 0x3000, 0x4000] RAM <-- element
315*32640292SAndy Fiddaman */
316*32640292SAndy Fiddaman ram_element = e820_element_alloc(element->base, base,
317*32640292SAndy Fiddaman E820_TYPE_MEMORY);
318*32640292SAndy Fiddaman if (ram_element == NULL) {
319*32640292SAndy Fiddaman return (ENOMEM);
320*32640292SAndy Fiddaman }
321*32640292SAndy Fiddaman TAILQ_INSERT_BEFORE(element, ram_element, chain);
322*32640292SAndy Fiddaman element->base = end;
323*32640292SAndy Fiddaman }
324*32640292SAndy Fiddaman
325*32640292SAndy Fiddaman return (0);
326*32640292SAndy Fiddaman }
327*32640292SAndy Fiddaman
328*32640292SAndy Fiddaman static uint64_t
e820_alloc_highest(const uint64_t max_address,const uint64_t length,const uint64_t alignment,const enum e820_memory_type type)329*32640292SAndy Fiddaman e820_alloc_highest(const uint64_t max_address, const uint64_t length,
330*32640292SAndy Fiddaman const uint64_t alignment, const enum e820_memory_type type)
331*32640292SAndy Fiddaman {
332*32640292SAndy Fiddaman struct e820_element *element;
333*32640292SAndy Fiddaman
334*32640292SAndy Fiddaman TAILQ_FOREACH_REVERSE(element, &e820_table, e820_table, chain) {
335*32640292SAndy Fiddaman uint64_t address, base, end;
336*32640292SAndy Fiddaman
337*32640292SAndy Fiddaman end = MIN(max_address, element->end);
338*32640292SAndy Fiddaman base = roundup2(element->base, alignment);
339*32640292SAndy Fiddaman
340*32640292SAndy Fiddaman /*
341*32640292SAndy Fiddaman * If end - length == 0, we would allocate memory at address 0. This
342*32640292SAndy Fiddaman * address is mostly unusable and we should avoid allocating it.
343*32640292SAndy Fiddaman * Therefore, search for another block in that case.
344*32640292SAndy Fiddaman */
345*32640292SAndy Fiddaman if (element->type != E820_TYPE_MEMORY || end < base ||
346*32640292SAndy Fiddaman end - base < length || end - length == 0) {
347*32640292SAndy Fiddaman continue;
348*32640292SAndy Fiddaman }
349*32640292SAndy Fiddaman
350*32640292SAndy Fiddaman address = rounddown2(end - length, alignment);
351*32640292SAndy Fiddaman
352*32640292SAndy Fiddaman if (e820_add_entry(address, address + length, type) != 0) {
353*32640292SAndy Fiddaman return (0);
354*32640292SAndy Fiddaman }
355*32640292SAndy Fiddaman
356*32640292SAndy Fiddaman return (address);
357*32640292SAndy Fiddaman }
358*32640292SAndy Fiddaman
359*32640292SAndy Fiddaman return (0);
360*32640292SAndy Fiddaman }
361*32640292SAndy Fiddaman
362*32640292SAndy Fiddaman static uint64_t
e820_alloc_lowest(const uint64_t min_address,const uint64_t length,const uint64_t alignment,const enum e820_memory_type type)363*32640292SAndy Fiddaman e820_alloc_lowest(const uint64_t min_address, const uint64_t length,
364*32640292SAndy Fiddaman const uint64_t alignment, const enum e820_memory_type type)
365*32640292SAndy Fiddaman {
366*32640292SAndy Fiddaman struct e820_element *element;
367*32640292SAndy Fiddaman
368*32640292SAndy Fiddaman TAILQ_FOREACH(element, &e820_table, chain) {
369*32640292SAndy Fiddaman uint64_t base, end;
370*32640292SAndy Fiddaman
371*32640292SAndy Fiddaman end = element->end;
372*32640292SAndy Fiddaman base = MAX(min_address, roundup2(element->base, alignment));
373*32640292SAndy Fiddaman
374*32640292SAndy Fiddaman /*
375*32640292SAndy Fiddaman * If base == 0, we would allocate memory at address 0. This
376*32640292SAndy Fiddaman * address is mostly unusable and we should avoid allocating it.
377*32640292SAndy Fiddaman * Therefore, search for another block in that case.
378*32640292SAndy Fiddaman */
379*32640292SAndy Fiddaman if (element->type != E820_TYPE_MEMORY || end < base ||
380*32640292SAndy Fiddaman end - base < length || base == 0) {
381*32640292SAndy Fiddaman continue;
382*32640292SAndy Fiddaman }
383*32640292SAndy Fiddaman
384*32640292SAndy Fiddaman if (e820_add_entry(base, base + length, type) != 0) {
385*32640292SAndy Fiddaman return (0);
386*32640292SAndy Fiddaman }
387*32640292SAndy Fiddaman
388*32640292SAndy Fiddaman return (base);
389*32640292SAndy Fiddaman }
390*32640292SAndy Fiddaman
391*32640292SAndy Fiddaman return (0);
392*32640292SAndy Fiddaman }
393*32640292SAndy Fiddaman
394*32640292SAndy Fiddaman uint64_t
e820_alloc(const uint64_t address,const uint64_t length,const uint64_t alignment,const enum e820_memory_type type,const enum e820_allocation_strategy strategy)395*32640292SAndy Fiddaman e820_alloc(const uint64_t address, const uint64_t length,
396*32640292SAndy Fiddaman const uint64_t alignment, const enum e820_memory_type type,
397*32640292SAndy Fiddaman const enum e820_allocation_strategy strategy)
398*32640292SAndy Fiddaman {
399*32640292SAndy Fiddaman assert(powerof2(alignment));
400*32640292SAndy Fiddaman assert((address & (alignment - 1)) == 0);
401*32640292SAndy Fiddaman
402*32640292SAndy Fiddaman switch (strategy) {
403*32640292SAndy Fiddaman case E820_ALLOCATE_ANY:
404*32640292SAndy Fiddaman /*
405*32640292SAndy Fiddaman * Allocate any address. Therefore, ignore the address parameter
406*32640292SAndy Fiddaman * and reuse the code path for allocating the lowest address.
407*32640292SAndy Fiddaman */
408*32640292SAndy Fiddaman return (e820_alloc_lowest(0, length, alignment, type));
409*32640292SAndy Fiddaman case E820_ALLOCATE_LOWEST:
410*32640292SAndy Fiddaman return (e820_alloc_lowest(address, length, alignment, type));
411*32640292SAndy Fiddaman case E820_ALLOCATE_HIGHEST:
412*32640292SAndy Fiddaman return (e820_alloc_highest(address, length, alignment, type));
413*32640292SAndy Fiddaman case E820_ALLOCATE_SPECIFIC:
414*32640292SAndy Fiddaman if (e820_add_entry(address, address + length, type) != 0) {
415*32640292SAndy Fiddaman return (0);
416*32640292SAndy Fiddaman }
417*32640292SAndy Fiddaman
418*32640292SAndy Fiddaman return (address);
419*32640292SAndy Fiddaman }
420*32640292SAndy Fiddaman
421*32640292SAndy Fiddaman return (0);
422*32640292SAndy Fiddaman }
423*32640292SAndy Fiddaman
424*32640292SAndy Fiddaman int
e820_init(struct vmctx * const ctx)425*32640292SAndy Fiddaman e820_init(struct vmctx *const ctx)
426*32640292SAndy Fiddaman {
427*32640292SAndy Fiddaman uint64_t lowmem_size, highmem_size;
428*32640292SAndy Fiddaman int error;
429*32640292SAndy Fiddaman
430*32640292SAndy Fiddaman TAILQ_INIT(&e820_table);
431*32640292SAndy Fiddaman
432*32640292SAndy Fiddaman lowmem_size = vm_get_lowmem_size(ctx);
433*32640292SAndy Fiddaman error = e820_add_entry(0, lowmem_size, E820_TYPE_MEMORY);
434*32640292SAndy Fiddaman if (error) {
435*32640292SAndy Fiddaman warnx("%s: Could not add lowmem", __func__);
436*32640292SAndy Fiddaman return (error);
437*32640292SAndy Fiddaman }
438*32640292SAndy Fiddaman
439*32640292SAndy Fiddaman highmem_size = vm_get_highmem_size(ctx);
440*32640292SAndy Fiddaman if (highmem_size != 0) {
441*32640292SAndy Fiddaman error = e820_add_entry(4 * GB, 4 * GB + highmem_size,
442*32640292SAndy Fiddaman E820_TYPE_MEMORY);
443*32640292SAndy Fiddaman if (error) {
444*32640292SAndy Fiddaman warnx("%s: Could not add highmem", __func__);
445*32640292SAndy Fiddaman return (error);
446*32640292SAndy Fiddaman }
447*32640292SAndy Fiddaman }
448*32640292SAndy Fiddaman
449*32640292SAndy Fiddaman error = e820_add_memory_hole(E820_VGA_MEM_BASE, E820_VGA_MEM_END);
450*32640292SAndy Fiddaman if (error) {
451*32640292SAndy Fiddaman warnx("%s: Could not add VGA memory", __func__);
452*32640292SAndy Fiddaman return (error);
453*32640292SAndy Fiddaman }
454*32640292SAndy Fiddaman
455*32640292SAndy Fiddaman error = e820_add_memory_hole(E820_ROM_MEM_BASE, E820_ROM_MEM_END);
456*32640292SAndy Fiddaman if (error) {
457*32640292SAndy Fiddaman warnx("%s: Could not add ROM area", __func__);
458*32640292SAndy Fiddaman return (error);
459*32640292SAndy Fiddaman }
460*32640292SAndy Fiddaman
461*32640292SAndy Fiddaman return (0);
462*32640292SAndy Fiddaman }
463