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