xref: /haiku/src/system/boot/platform/efi/arch/arm64/arch_start.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright 2019-2020 Haiku, Inc. All rights reserved.
3  * Released under the terms of the MIT License.
4  */
5 
6 
7 #include <boot/platform.h>
8 #include <boot/stage2.h>
9 #include <boot/stdio.h>
10 
11 #include "efi_platform.h"
12 
13 
14 extern "C" void arch_enter_kernel(struct kernel_args *kernelArgs,
15 	addr_t kernelEntry, addr_t kernelStackTop);
16 
17 
18 void
19 arch_start_kernel(addr_t kernelEntry)
20 {
21 	// Prepare to exit EFI boot services.
22 	// Read the memory map.
23 	// First call is to determine the buffer size.
24 	size_t memory_map_size = 0;
25 	efi_memory_descriptor dummy;
26 	efi_memory_descriptor *memory_map;
27 	size_t map_key;
28 	size_t descriptor_size;
29 	uint32_t descriptor_version;
30 	if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key,
31 			&descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) {
32 		panic("Unable to determine size of system memory map");
33 	}
34 
35 	// Allocate a buffer twice as large as needed just in case it gets bigger
36 	// between calls to ExitBootServices.
37 	size_t actual_memory_map_size = memory_map_size * 2;
38 	memory_map
39 		= (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size);
40 
41 	if (memory_map == NULL)
42 		panic("Unable to allocate memory map.");
43 
44 	// Read (and print) the memory map.
45 	memory_map_size = actual_memory_map_size;
46 	if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
47 			&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
48 		panic("Unable to fetch system memory map.");
49 	}
50 
51 	addr_t addr = (addr_t)memory_map;
52 	dprintf("System provided memory map:\n");
53 	for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) {
54 		efi_memory_descriptor *entry
55 			= (efi_memory_descriptor *)(addr + i * descriptor_size);
56 		dprintf("  %#lx-%#lx  %#lx %#x %#lx\n", entry->PhysicalStart,
57 			entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE,
58 			entry->VirtualStart, entry->Type, entry->Attribute);
59 	}
60 
61 	// Attempt to fetch the memory map and exit boot services.
62 	// This needs to be done in a loop, as ExitBootServices can change the
63 	// memory map.
64 	// Even better: Only GetMemoryMap and ExitBootServices can be called after
65 	// the first call to ExitBootServices, as the firmware is permitted to
66 	// partially exit. This is why twice as much space was allocated for the
67 	// memory map, as it's impossible to allocate more now.
68 	// A changing memory map shouldn't affect the generated page tables, as
69 	// they only needed to know about the maximum address, not any specific
70 	// entry.
71 	dprintf("Calling ExitBootServices. So long, EFI!\n");
72 	while (true) {
73 		if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) {
74 			// The console was provided by boot services, disable it.
75 			stdout = NULL;
76 			stderr = NULL;
77 			// Can we adjust gKernelArgs.platform_args.serial_base_ports[0]
78 			// to something fixed in qemu for debugging?
79 			break;
80 		}
81 
82 		memory_map_size = actual_memory_map_size;
83 		if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
84 				&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
85 			panic("Unable to fetch system memory map.");
86 		}
87 	}
88 
89 	// Update EFI, generate final kernel physical memory map, etc.
90 	//arch_mmu_post_efi_setup(memory_map_size, memory_map,
91 	//		descriptor_size, descriptor_version);
92 
93 	//smp_boot_other_cpus(final_pml4, kernelEntry);
94 
95 	// Enter the kernel!
96 	arch_enter_kernel(&gKernelArgs, kernelEntry,
97 		gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size);
98 }
99