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