1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <arch/x86/bootstrap16.h>
8 #include <arch/x86/feature.h>
9 #include <arch/x86/mmu.h>
10 #include <assert.h>
11 #include <dev/interrupt.h>
12 #include <efi/boot-services.h>
13 #include <err.h>
14 #include <fbl/algorithm.h>
15 #include <inttypes.h>
16 #include <lib/memory_limit.h>
17 #include <lk/init.h>
18 #include <platform.h>
19 #include <platform/pc/bootloader.h>
20 #include <string.h>
21 #include <trace.h>
22 #include <vm/vm.h>
23 #include <zircon/types.h>
24 #include <zircon/boot/e820.h>
25 #include <object/resource_dispatcher.h>
26 
27 #include "platform_p.h"
28 
29 #define LOCAL_TRACE 0
30 
31 struct addr_range {
32     uint64_t base;
33     uint64_t size;
34     bool is_mem;
35 };
36 
37 /* Values that will store the largest low-memory contiguous address space
38  * that we can let the PCIe bus driver use for allocations */
39 paddr_t pcie_mem_lo_base;
40 size_t pcie_mem_lo_size;
41 
42 // These are used to track memory arenas found during boot so they can
43 // be exclusively reserved within the resource system after the heap
44 // has been initialized.
45 constexpr uint8_t kMaxReservedMmioEntries = 64;
46 typedef struct reserved_mmio_space {
47     uint64_t base;
48     size_t len;
49     ResourceDispatcher::RefPtr dispatcher;;
50 } reserved_mmio_space_t;
51 reserved_mmio_space_t reserved_mmio_entries[kMaxReservedMmioEntries];
52 static uint8_t reserved_mmio_count = 0;
53 
mark_mmio_region_to_reserve(uint64_t base,size_t len)54 static void mark_mmio_region_to_reserve(uint64_t base, size_t len) {
55     reserved_mmio_entries[reserved_mmio_count].base = base;
56     reserved_mmio_entries[reserved_mmio_count].len = len;
57     reserved_mmio_count++;
58 }
59 
60 #define DEFAULT_MEMEND (16 * 1024 * 1024)
61 
62 /* boot_addr_range_t is an iterator which iterates over address ranges from
63  * the boot loader
64  */
65 struct boot_addr_range;
66 
67 typedef void (*boot_addr_range_advance_func)(
68     struct boot_addr_range* range_struct);
69 typedef void (*boot_addr_range_reset_func)(
70     struct boot_addr_range* range_struct);
71 
72 typedef struct boot_addr_range {
73     /* the base of the current address range */
74     uint64_t base;
75     /* the size of the current address range */
76     uint64_t size;
77     /* whether this range contains memory */
78     int is_mem;
79     /* whether this range is currently reset and invalid */
80     int is_reset;
81 
82     /* private information for the advance function to keep its place */
83     void* seq;
84     /* a function which advances this iterator to the next address range */
85     boot_addr_range_advance_func advance;
86     /* a function which resets this range and its sequencing information */
87     boot_addr_range_reset_func reset;
88 } boot_addr_range_t;
89 
90 /* a utility function to reset the common parts of a boot_addr_range_t */
boot_addr_range_reset(boot_addr_range_t * range)91 static void boot_addr_range_reset(boot_addr_range_t* range) {
92     range->base = 0;
93     range->size = 0;
94     range->is_mem = 0;
95     range->is_reset = 1;
96 }
97 
98 /* this function uses the boot_addr_range_t iterator to walk through address
99  * ranges described by the boot loader. it fills in the mem_arenas global
100  * array with the ranges of memory it finds, compacted to the start of the
101  * array. it returns the total count of arenas which have been populated.
102  */
mem_arena_init(boot_addr_range_t * range)103 static zx_status_t mem_arena_init(boot_addr_range_t* range) {
104     bool have_limit = (memory_limit_init() == ZX_OK);
105     // Create the kernel's singleton for address space management
106     // Set up a base arena template to use
107     pmm_arena_info_t base_arena;
108     snprintf(base_arena.name, sizeof(base_arena.name), "%s", "memory");
109     base_arena.priority = 1;
110     base_arena.flags = 0;
111 
112     zx_status_t status;
113     for (range->reset(range), range->advance(range); !range->is_reset; range->advance(range)) {
114         LTRACEF("Range at %#" PRIx64 " of %#" PRIx64 " bytes is %smemory.\n",
115                 range->base, range->size, range->is_mem ? "" : "not ");
116 
117         if (!range->is_mem) {
118             continue;
119         }
120 
121         // trim off parts of memory ranges that are smaller than a page
122         uint64_t base = ROUNDUP(range->base, PAGE_SIZE);
123         uint64_t size = ROUNDDOWN(range->base + range->size, PAGE_SIZE) -
124                         base;
125 
126         // trim any memory below 1MB for safety and SMP booting purposes
127         if (base < 1 * MB) {
128             uint64_t adjust = 1 * MB - base;
129             if (adjust >= size)
130                 continue;
131 
132             base += adjust;
133             size -= adjust;
134         }
135 
136         mark_mmio_region_to_reserve(base, static_cast<size_t>(size));
137         if (have_limit) {
138             status = memory_limit_add_range(base, size, base_arena);
139         }
140 
141         // If there is no limit, or we failed to add arenas from processing
142         // ranges then add the original range.
143         if (!have_limit || status != ZX_OK) {
144             auto arena = base_arena;
145             arena.base = base;
146             arena.size = size;
147 
148             LTRACEF("Adding pmm range at %#" PRIxPTR " of %#zx bytes.\n", arena.base, arena.size);
149             status = pmm_add_arena(&arena);
150 
151             // print a warning and continue
152             if (status != ZX_OK) {
153                 printf("MEM: Failed to add pmm range at %#" PRIxPTR " size %#zx\n", arena.base, arena.size);
154             }
155         }
156     }
157 
158     if (have_limit) {
159         memory_limit_add_arenas(base_arena);
160     }
161 
162     return ZX_OK;
163 }
164 
165 typedef struct e820_range_seq {
166     e820entry_t* map;
167     int index;
168     int count;
169 } e820_range_seq_t;
170 
e820_range_reset(boot_addr_range_t * range)171 static void e820_range_reset(boot_addr_range_t* range) {
172     boot_addr_range_reset(range);
173 
174     e820_range_seq_t* seq = (e820_range_seq_t*)(range->seq);
175     seq->index = -1;
176 }
177 
e820_range_advance(boot_addr_range_t * range)178 static void e820_range_advance(boot_addr_range_t* range) {
179     e820_range_seq_t* seq = (e820_range_seq_t*)(range->seq);
180 
181     seq->index++;
182 
183     if (seq->index == seq->count) {
184         /* reset range to signal that we're at the end of the map */
185         e820_range_reset(range);
186         return;
187     }
188 
189     e820entry_t* entry = &seq->map[seq->index];
190     range->base = entry->addr;
191     range->size = entry->size;
192     range->is_mem = (entry->type == E820_RAM) ? 1 : 0;
193     range->is_reset = 0;
194 }
195 
e820_range_init(boot_addr_range_t * range,e820_range_seq_t * seq)196 static zx_status_t e820_range_init(boot_addr_range_t* range, e820_range_seq_t* seq) {
197     range->seq = seq;
198     range->advance = &e820_range_advance;
199     range->reset = &e820_range_reset;
200 
201     if (bootloader.e820_count) {
202         seq->count = static_cast<int>(bootloader.e820_count);
203         seq->map = static_cast<e820entry_t*>(bootloader.e820_table);
204         range->reset(range);
205         return ZX_OK;
206     }
207 
208     return ZX_ERR_NO_MEMORY;
209 }
210 
211 typedef struct efi_range_seq {
212     void* base;
213     size_t entrysz;
214     int index;
215     int count;
216 } efi_range_seq_t;
217 
efi_range_reset(boot_addr_range_t * range)218 static void efi_range_reset(boot_addr_range_t* range) {
219     boot_addr_range_reset(range);
220 
221     efi_range_seq_t* seq = (efi_range_seq_t*)(range->seq);
222     seq->index = -1;
223 }
224 
efi_is_mem(uint32_t type)225 static int efi_is_mem(uint32_t type) {
226     switch (type) {
227     case EfiLoaderCode:
228     case EfiLoaderData:
229     case EfiBootServicesCode:
230     case EfiBootServicesData:
231     case EfiConventionalMemory:
232         return 1;
233     default:
234         return 0;
235     }
236 }
237 
efi_print(const char * tag,efi_memory_descriptor * e)238 static void efi_print(const char* tag, efi_memory_descriptor* e) {
239     bool mb = e->NumberOfPages > 256;
240     LTRACEF("%s%016lx %08x %lu%s\n",
241             tag, e->PhysicalStart, e->Type,
242             mb ? e->NumberOfPages / 256 : e->NumberOfPages * 4,
243             mb ? "MB" : "KB");
244 }
245 
efi_range_advance(boot_addr_range_t * range)246 static void efi_range_advance(boot_addr_range_t* range) {
247     efi_range_seq_t* seq = (efi_range_seq_t*)(range->seq);
248 
249     seq->index++;
250 
251     if (seq->index == seq->count) {
252         /* reset range to signal that we're at the end of the map */
253         efi_range_reset(range);
254         return;
255     }
256 
257     const uintptr_t addr = reinterpret_cast<uintptr_t>(seq->base) + (seq->index * seq->entrysz);
258     efi_memory_descriptor* entry = reinterpret_cast<efi_memory_descriptor*>(addr);
259     efi_print("EFI: ", entry);
260     range->base = entry->PhysicalStart;
261     range->size = entry->NumberOfPages * PAGE_SIZE;
262     range->is_reset = 0;
263     range->is_mem = efi_is_mem(entry->Type);
264 
265     // coalesce adjacent memory ranges
266     while ((seq->index + 1) < seq->count) {
267         const uintptr_t addr = reinterpret_cast<uintptr_t>(seq->base) +
268                                ((seq->index + 1) * seq->entrysz);
269         efi_memory_descriptor* next = reinterpret_cast<efi_memory_descriptor*>(addr);
270         if ((range->base + range->size) != next->PhysicalStart) {
271             break;
272         }
273         if (efi_is_mem(next->Type) != range->is_mem) {
274             break;
275         }
276         efi_print("EFI+ ", next);
277         range->size += next->NumberOfPages * PAGE_SIZE;
278         seq->index++;
279     }
280 }
281 
efi_range_init(boot_addr_range_t * range,efi_range_seq_t * seq)282 static zx_status_t efi_range_init(boot_addr_range_t* range, efi_range_seq_t* seq) {
283     range->seq = seq;
284     range->advance = &efi_range_advance;
285     range->reset = &efi_range_reset;
286 
287     if (bootloader.efi_mmap &&
288         (bootloader.efi_mmap_size > sizeof(uint64_t))) {
289         seq->entrysz = *((uint64_t*)bootloader.efi_mmap);
290         if (seq->entrysz < sizeof(efi_memory_descriptor)) {
291             return ZX_ERR_NO_MEMORY;
292         }
293 
294         seq->count = static_cast<int>((bootloader.efi_mmap_size - sizeof(uint64_t)) / seq->entrysz);
295         seq->base = reinterpret_cast<void*>(
296             reinterpret_cast<uintptr_t>(bootloader.efi_mmap) + sizeof(uint64_t));
297         range->reset(range);
298         return ZX_OK;
299     } else {
300         return ZX_ERR_NO_MEMORY;
301     }
302 }
303 
addr_range_cmp(const void * p1,const void * p2)304 static int addr_range_cmp(const void* p1, const void* p2) {
305     const struct addr_range* a1 = static_cast<const struct addr_range*>(p1);
306     const struct addr_range* a2 = static_cast<const struct addr_range*>(p2);
307 
308     if (a1->base < a2->base)
309         return -1;
310     else if (a1->base == a2->base)
311         return 0;
312     return 1;
313 }
314 
platform_mem_range_init(void)315 static zx_status_t platform_mem_range_init(void) {
316     zx_status_t status;
317     boot_addr_range_t range;
318 
319     /* first try the efi memory table */
320     efi_range_seq_t efi_seq;
321     status = efi_range_init(&range, &efi_seq);
322     if (status == ZX_OK) {
323         status = mem_arena_init(&range);
324         if (status != ZX_OK) {
325             printf("MEM: failure while adding EFI memory ranges\n");
326         }
327         return ZX_OK;
328     }
329 
330     /* then try getting range info from e820 */
331     e820_range_seq_t e820_seq;
332     status = e820_range_init(&range, &e820_seq);
333     if (status == ZX_OK) {
334         status = mem_arena_init(&range);
335         if (status != ZX_OK) {
336             printf("MEM: failure while adding e820 memory ranges\n");
337         }
338         return ZX_OK;
339     }
340 
341     /* if still no ranges were found, make a safe guess */
342     printf("MEM: no arena range source: falling back to fixed size\n");
343     e820_range_init(&range, &e820_seq);
344     e820entry_t entry = {
345         .addr = 0,
346         .size = DEFAULT_MEMEND,
347         .type = E820_RAM,
348     };
349     e820_seq.map = &entry;
350     e820_seq.count = 1;
351     return mem_arena_init(&range);
352 }
353 
354 static size_t cached_e820_entry_count;
355 static struct addr_range cached_e820_entries[64];
356 
enumerate_e820(enumerate_e820_callback callback,void * ctx)357 zx_status_t enumerate_e820(enumerate_e820_callback callback, void* ctx) {
358     if (callback == NULL)
359         return ZX_ERR_INVALID_ARGS;
360 
361     if (!cached_e820_entry_count)
362         return ZX_ERR_BAD_STATE;
363 
364     DEBUG_ASSERT(cached_e820_entry_count <= fbl::count_of(cached_e820_entries));
365     for (size_t i = 0; i < cached_e820_entry_count; ++i)
366         callback(cached_e820_entries[i].base, cached_e820_entries[i].size,
367                  cached_e820_entries[i].is_mem, ctx);
368 
369     return ZX_OK;
370 }
371 
372 /* Discover the basic memory map */
pc_mem_init(void)373 void pc_mem_init(void) {
374     if (platform_mem_range_init() != ZX_OK) {
375         TRACEF("Error adding arenas from provided memory tables.\n");
376     }
377 
378     // Cache the e820 entries so that they will be available for enumeration
379     // later in the boot.
380     //
381     // TODO(teisenbe, johngro): do not hardcode a limit on the number of
382     // entries we may have.  Find some other way to make this information
383     // available at any point in time after we boot.
384     boot_addr_range_t range;
385     efi_range_seq_t efi_seq;
386     e820_range_seq_t e820_seq;
387     bool initialized_bootstrap16 = false;
388 
389     cached_e820_entry_count = 0;
390     if ((efi_range_init(&range, &efi_seq) == ZX_OK) ||
391         (e820_range_init(&range, &e820_seq) == ZX_OK)) {
392         for (range.reset(&range),
393              range.advance(&range);
394              !range.is_reset; range.advance(&range)) {
395             if (cached_e820_entry_count >= fbl::count_of(cached_e820_entries)) {
396                 TRACEF("ERROR - Too many e820 entries to hold in the cache!\n");
397                 cached_e820_entry_count = 0;
398                 break;
399             }
400 
401             struct addr_range* entry = &cached_e820_entries[cached_e820_entry_count++];
402             entry->base = range.base;
403             entry->size = range.size;
404             entry->is_mem = range.is_mem ? true : false;
405 
406             const uint64_t alloc_size = 2 * PAGE_SIZE;
407             const uint64_t min_base = 2 * PAGE_SIZE;
408             if (!initialized_bootstrap16 && entry->is_mem &&
409                 entry->base <= 1 * MB - alloc_size && entry->size >= alloc_size) {
410 
411                 uint64_t adj_base = entry->base;
412                 if (entry->base < min_base) {
413                     uint64_t size_adj = min_base - entry->base;
414                     if (entry->size < size_adj + alloc_size) {
415                         continue;
416                     }
417                     adj_base = min_base;
418                 }
419 
420                 LTRACEF("Selected %" PRIxPTR " as bootstrap16 region\n", adj_base);
421                 x86_bootstrap16_init(adj_base);
422                 initialized_bootstrap16 = true;
423             }
424         }
425     } else {
426         TRACEF("ERROR - No e820 range entries found!  This is going to end badly for everyone.\n");
427     }
428 
429     if (!initialized_bootstrap16) {
430         TRACEF("WARNING - Failed to assign bootstrap16 region, SMP won't work\n");
431     }
432 }
433 
434 
435 
436 // Initialize the higher level PhysicalAspaceManager after the heap is initialized.
x86_resource_init_hook(unsigned int rl)437 static void x86_resource_init_hook(unsigned int rl) {
438     // An error is likely fatal if the bookkeeping is broken and driver
439     ResourceDispatcher::InitializeAllocator(ZX_RSRC_KIND_MMIO,
440                                             0,
441                                             (1ull << (x86_physical_address_width())) - 1);
442     ResourceDispatcher::InitializeAllocator(ZX_RSRC_KIND_IOPORT,
443                                             0,
444                                             UINT16_MAX);
445     ResourceDispatcher::InitializeAllocator(ZX_RSRC_KIND_IRQ,
446                                             interrupt_get_base_vector(),
447                                             interrupt_get_max_vector());
448 
449     // Exclusively reserve the regions marked as memory earlier so that physical
450     // vmos cannot be created against them.
451     for (uint8_t i = 0; i < reserved_mmio_count; i++) {
452         zx_rights_t rights;
453         auto& entry = reserved_mmio_entries[i];
454         zx_status_t st = ResourceDispatcher::Create(&entry.dispatcher, &rights, ZX_RSRC_KIND_MMIO,
455                                                     entry.base, entry.len, ZX_RSRC_FLAG_EXCLUSIVE,
456                                                     "platform_memory");
457         if (st == ZX_OK) {
458         } else {
459             TRACEF("failed to create backing resource for boot memory region %#lx - %#lx: %d\n",
460                    entry.base, entry.base + entry.len, st);
461         }
462 
463     }
464 }
465 
466 LK_INIT_HOOK(x86_resource_init, x86_resource_init_hook, LK_INIT_LEVEL_HEAP);
467