1 /*
2 * Copyright (c) 2019 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <string.h>
9 #include <zephyr/arch/x86/multiboot.h>
10 #include <zephyr/arch/x86/memmap.h>
11
12 struct multiboot_info multiboot_info;
13
14 /*
15 * called very early in the boot process to fetch data out of the multiboot
16 * info struct. we need to grab the relevant data before any dynamic memory
17 * allocation takes place, lest the struct itself or any data it points to
18 * be overwritten before we read it.
19 */
20
clear_memmap(int index)21 static inline void clear_memmap(int index)
22 {
23 while (index < CONFIG_X86_MEMMAP_ENTRIES) {
24 x86_memmap[index].type = X86_MEMMAP_ENTRY_UNUSED;
25 ++index;
26 }
27 }
28
z_multiboot_init(struct multiboot_info * info_pa)29 void z_multiboot_init(struct multiboot_info *info_pa)
30 {
31 struct multiboot_info *info;
32
33 #if defined(CONFIG_ARCH_MAPS_ALL_RAM) || !defined(CONFIG_X86_MMU)
34 /*
35 * Since the struct from bootloader resides in memory
36 * and all memory is mapped, there is no need to
37 * manually map it before accessing.
38 *
39 * Without MMU, all memory are identity-mapped already
40 * so there is no need to map them again.
41 */
42 info = info_pa;
43 #else
44 z_phys_map((uint8_t **)&info, POINTER_TO_UINT(info_pa),
45 sizeof(*info_pa), K_MEM_CACHE_NONE);
46 #endif /* CONFIG_ARCH_MAPS_ALL_RAM */
47
48 if (info == NULL) {
49 return;
50 }
51
52 memcpy(&multiboot_info, info, sizeof(*info));
53
54 #ifdef CONFIG_MULTIBOOT_MEMMAP
55 /*
56 * If the extended map (basically, the equivalent of
57 * the BIOS E820 map) is available, then use that.
58 */
59
60 if ((info->flags & MULTIBOOT_INFO_FLAGS_MMAP) &&
61 (x86_memmap_source < X86_MEMMAP_SOURCE_MULTIBOOT_MMAP)) {
62 uintptr_t address;
63 uintptr_t address_end;
64 struct multiboot_mmap *mmap;
65 int index = 0;
66 uint32_t type;
67
68 #if defined(CONFIG_ARCH_MAPS_ALL_RAM) || !defined(CONFIG_X86_MMU)
69 address = info->mmap_addr;
70 #else
71 uint8_t *address_va;
72
73 z_phys_map(&address_va, info->mmap_addr, info->mmap_length,
74 K_MEM_CACHE_NONE);
75
76 address = POINTER_TO_UINT(address_va);
77 #endif /* CONFIG_ARCH_MAPS_ALL_RAM */
78
79 address_end = address + info->mmap_length;
80
81 while ((address < address_end) &&
82 (index < CONFIG_X86_MEMMAP_ENTRIES)) {
83 mmap = UINT_TO_POINTER(address);
84
85 x86_memmap[index].base = mmap->base;
86 x86_memmap[index].length = mmap->length;
87
88 switch (mmap->type) {
89 case MULTIBOOT_MMAP_RAM:
90 type = X86_MEMMAP_ENTRY_RAM;
91 break;
92 case MULTIBOOT_MMAP_ACPI:
93 type = X86_MEMMAP_ENTRY_ACPI;
94 break;
95 case MULTIBOOT_MMAP_NVS:
96 type = X86_MEMMAP_ENTRY_NVS;
97 break;
98 case MULTIBOOT_MMAP_DEFECTIVE:
99 type = X86_MEMMAP_ENTRY_DEFECTIVE;
100 break;
101 default:
102 type = X86_MEMMAP_ENTRY_UNKNOWN;
103 }
104
105 x86_memmap[index].type = type;
106 ++index;
107 address += mmap->size + sizeof(mmap->size);
108 }
109
110 x86_memmap_source = X86_MEMMAP_SOURCE_MULTIBOOT_MMAP;
111 clear_memmap(index);
112 }
113
114 /* If no extended map is available, fall back to the basic map. */
115
116 if ((info->flags & MULTIBOOT_INFO_FLAGS_MEM) &&
117 (x86_memmap_source < X86_MEMMAP_SOURCE_MULTIBOOT_MEM)) {
118 x86_memmap[0].base = 0;
119 x86_memmap[0].length = info->mem_lower * 1024ULL;
120 x86_memmap[0].type = X86_MEMMAP_ENTRY_RAM;
121
122 if (CONFIG_X86_MEMMAP_ENTRIES > 1) {
123 x86_memmap[1].base = 1048576U; /* 1MB */
124 x86_memmap[1].length = info->mem_upper * 1024ULL;
125 x86_memmap[1].type = X86_MEMMAP_ENTRY_RAM;
126 clear_memmap(2);
127 }
128
129 x86_memmap_source = X86_MEMMAP_SOURCE_MULTIBOOT_MEM;
130 }
131 #endif /* CONFIG_MULTIBOOT_MEMMAP */
132 }
133