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