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