xref: /haiku/src/system/boot/platform/efi/start.cpp (revision 15fb7d88e971c4d6c787c6a3a5c159afb1ebf77b)
1 /*
2  * Copyright 2014-2016 Haiku, Inc. All rights reserved.
3  * Copyright 2013-2014, Fredrik Holmqvist, fredrik.holmqvist@gmail.com.
4  * Copyright 2014, Henry Harrington, henry.harrington@gmail.com.
5  * All rights reserved.
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include <string.h>
11 
12 #include <KernelExport.h>
13 
14 #include <arch/cpu.h>
15 #include <kernel.h>
16 
17 #include <boot/arch/x86/arch_cpu.h>
18 #include <boot/kernel_args.h>
19 #include <boot/platform.h>
20 #include <boot/stage2.h>
21 #include <boot/stdio.h>
22 
23 #include "arch_mmu.h"
24 #include "acpi.h"
25 #include "console.h"
26 #include "efi_platform.h"
27 #include "mmu.h"
28 #include "serial.h"
29 #include "smp.h"
30 #include "timer.h"
31 
32 
33 extern void (*__ctor_list)(void);
34 extern void (*__ctor_end)(void);
35 
36 
37 const efi_system_table		*kSystemTable;
38 const efi_boot_services		*kBootServices;
39 const efi_runtime_services	*kRuntimeServices;
40 efi_handle kImage;
41 
42 
43 static uint32 sBootOptions;
44 static uint64 gLongKernelEntry;
45 
46 
47 extern "C" int main(stage2_args *args);
48 extern "C" void _start(void);
49 extern "C" void efi_enter_kernel(uint64 pml4, uint64 entry_point, uint64 stack);
50 
51 
52 static void
53 call_ctors(void)
54 {
55 	void (**f)(void);
56 
57 	for (f = &__ctor_list; f < &__ctor_end; f++)
58 		(**f)();
59 }
60 
61 
62 extern "C" uint32
63 platform_boot_options()
64 {
65 	return sBootOptions;
66 }
67 
68 
69 static void
70 convert_preloaded_image(preloaded_elf64_image* image)
71 {
72 	fix_address(image->next);
73 	fix_address(image->name);
74 	fix_address(image->debug_string_table);
75 	fix_address(image->syms);
76 	fix_address(image->rel);
77 	fix_address(image->rela);
78 	fix_address(image->pltrel);
79 	fix_address(image->debug_symbols);
80 }
81 
82 
83 /*!	Convert all addresses in kernel_args to 64-bit addresses. */
84 static void
85 convert_kernel_args()
86 {
87 	fix_address(gKernelArgs.boot_volume);
88 	fix_address(gKernelArgs.vesa_modes);
89 	fix_address(gKernelArgs.edid_info);
90 	fix_address(gKernelArgs.debug_output);
91 	fix_address(gKernelArgs.boot_splash);
92 	#if defined(__x86_64__) || defined(__x86__)
93 	fix_address(gKernelArgs.arch_args.apic);
94 	fix_address(gKernelArgs.arch_args.hpet);
95 	#endif
96 
97 	convert_preloaded_image(static_cast<preloaded_elf64_image*>(
98 		gKernelArgs.kernel_image.Pointer()));
99 	fix_address(gKernelArgs.kernel_image);
100 
101 	// Iterate over the preloaded images. Must save the next address before
102 	// converting, as the next pointer will be converted.
103 	preloaded_image* image = gKernelArgs.preloaded_images;
104 	fix_address(gKernelArgs.preloaded_images);
105 	while (image != NULL) {
106 		preloaded_image* next = image->next;
107 		convert_preloaded_image(static_cast<preloaded_elf64_image*>(image));
108 		image = next;
109 	}
110 
111 	// Fix driver settings files.
112 	driver_settings_file* file = gKernelArgs.driver_settings;
113 	fix_address(gKernelArgs.driver_settings);
114 	while (file != NULL) {
115 		driver_settings_file* next = file->next;
116 		fix_address(file->next);
117 		fix_address(file->buffer);
118 		file = next;
119 	}
120 }
121 
122 
123 extern "C" void
124 platform_start_kernel(void)
125 {
126 	if (gKernelArgs.kernel_image->elf_class != ELFCLASS64)
127 		panic("32-bit kernels not supported with EFI");
128 
129 	smp_init_other_cpus();
130 
131 	preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>(
132 		gKernelArgs.kernel_image.Pointer());
133 
134 	arch_mmu_init();
135 	convert_kernel_args();
136 
137 	// Save the kernel entry point address.
138 	gLongKernelEntry = image->elf_header.e_entry;
139 	dprintf("kernel entry at %#lx\n", gLongKernelEntry);
140 
141 	// map in a kernel stack
142 	void *stack_address = NULL;
143 	if (platform_allocate_region(&stack_address,
144 		KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE, 0, false)
145 		!= B_OK) {
146 		panic("Unabled to allocate a stack");
147 	}
148 	gKernelArgs.cpu_kstack[0].start = fix_address((uint64_t)stack_address);
149 	gKernelArgs.cpu_kstack[0].size = KERNEL_STACK_SIZE
150 		+ KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
151 	dprintf("Kernel stack at %#lx\n", gKernelArgs.cpu_kstack[0].start);
152 
153 	// Prepare to exit EFI boot services.
154 	// Read the memory map.
155 	// First call is to determine the buffer size.
156 	size_t memory_map_size = 0;
157 	efi_memory_descriptor dummy;
158 	efi_memory_descriptor *memory_map;
159 	size_t map_key;
160 	size_t descriptor_size;
161 	uint32_t descriptor_version;
162 	if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key,
163 		&descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) {
164 		panic("Unable to determine size of system memory map");
165 	}
166 
167 	// Allocate a buffer twice as large as needed just in case it gets bigger between
168 	// calls to ExitBootServices.
169 	size_t actual_memory_map_size = memory_map_size * 2;
170 	memory_map
171 		= (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size);
172 
173 	if (memory_map == NULL)
174 		panic("Unable to allocate memory map.");
175 
176 	// Read (and print) the memory map.
177 	memory_map_size = actual_memory_map_size;
178 	if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
179 		&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
180 		panic("Unable to fetch system memory map.");
181 	}
182 
183 	addr_t addr = (addr_t)memory_map;
184 	dprintf("System provided memory map:\n");
185 	for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) {
186 		efi_memory_descriptor *entry
187 			= (efi_memory_descriptor *)(addr + i * descriptor_size);
188 		dprintf("  %#lx-%#lx  %#lx %#x %#lx\n", entry->PhysicalStart,
189 			entry->PhysicalStart + entry->NumberOfPages * 4096,
190 			entry->VirtualStart, entry->Type, entry->Attribute);
191 	}
192 
193 	// Generate page tables for use after ExitBootServices.
194 	uint64_t final_pml4 = mmu_generate_post_efi_page_tables(memory_map_size,
195 		memory_map, descriptor_size, descriptor_version);
196 	dprintf("Final PML4 at %#lx\n", final_pml4);
197 
198 	// Attempt to fetch the memory map and exit boot services.
199 	// This needs to be done in a loop, as ExitBootServices can change the
200 	// memory map.
201 	// Even better: Only GetMemoryMap and ExitBootServices can be called after
202 	// the first call to ExitBootServices, as the firmware is permitted to
203 	// partially exit. This is why twice as much space was allocated for the
204 	// memory map, as it's impossible to allocate more now.
205 	// A changing memory map shouldn't affect the generated page tables, as
206 	// they only needed to know about the maximum address, not any specific
207 	// entry.
208 	dprintf("Calling ExitBootServices. So long, EFI!\n");
209 	while (true) {
210 		if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) {
211 			// The console was provided by boot services, disable it.
212 			stdout = NULL;
213 			stderr = NULL;
214 			// Also switch to legacy serial output (may not work on all systems)
215 			serial_switch_to_legacy();
216 			dprintf("Switched to legacy serial output\n");
217 			break;
218 		}
219 
220 		memory_map_size = actual_memory_map_size;
221 		if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
222 			&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
223 			panic("Unable to fetch system memory map.");
224 		}
225 	}
226 
227 	// Update EFI, generate final kernel physical memory map, etc.
228 	mmu_post_efi_setup(memory_map_size, memory_map,
229 		descriptor_size, descriptor_version);
230 
231 	smp_boot_other_cpus(final_pml4, gLongKernelEntry);
232 
233 	// Enter the kernel!
234 	efi_enter_kernel(final_pml4, gLongKernelEntry,
235 		gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size);
236 
237 	panic("Shouldn't get here");
238 }
239 
240 
241 extern "C" void
242 platform_exit(void)
243 {
244 	return;
245 }
246 
247 
248 /**
249  * efi_main - The entry point for the EFI application
250  * @image: firmware-allocated handle that identifies the image
251  * @systemTable: EFI system table
252  */
253 extern "C" efi_status
254 efi_main(efi_handle image, efi_system_table *systemTable)
255 {
256 	stage2_args args;
257 
258 	memset(&args, 0, sizeof(stage2_args));
259 
260 	kImage = image;
261 	kSystemTable = systemTable;
262 	kBootServices = systemTable->BootServices;
263 	kRuntimeServices = systemTable->RuntimeServices;
264 
265 	call_ctors();
266 
267 	console_init();
268 	serial_init();
269 	serial_enable();
270 
271 	sBootOptions = console_check_boot_keys();
272 
273 	// disable apm in case we ever load a 32-bit kernel...
274 	gKernelArgs.platform_args.apm.version = 0;
275 
276 	gKernelArgs.num_cpus = 1;
277 	#if defined(__x86_64__) || defined(__x86__)
278 	gKernelArgs.arch_args.hpet_phys = 0;
279 	gKernelArgs.arch_args.hpet = NULL;
280 	#endif
281 
282 	cpu_init();
283 	acpi_init();
284 	timer_init();
285 	smp_init();
286 
287 	main(&args);
288 
289 	return EFI_SUCCESS;
290 }
291