xref: /haiku/src/system/boot/platform/efi/arch/arm/arch_start.cpp (revision 901fc0c75ff0285552d9099b5c61f2af8cd26f07)
1 /*
2  * Copyright 2019-2021 Haiku, Inc. All rights reserved.
3  * Released under the terms of the MIT License.
4  */
5 
6 
7 #include <kernel.h>
8 #include <boot/platform.h>
9 #include <boot/stage2.h>
10 #include <boot/stdio.h>
11 
12 #include "efi_platform.h"
13 #include "mmu.h"
14 
15 
16 #define ALIGN_MEMORY_MAP	4
17 
18 
19 extern "C" void arch_enter_kernel(uint32_t ttbr, struct kernel_args *kernelArgs,
20 	addr_t kernelEntry, addr_t kernelStackTop);
21 
22 // From arch_mmu.cpp
23 extern void arch_mmu_post_efi_setup(size_t memory_map_size,
24 	efi_memory_descriptor *memory_map, size_t descriptor_size,
25 	uint32_t descriptor_version);
26 
27 extern uint32_t arch_mmu_generate_post_efi_page_tables(size_t memory_map_size,
28 	efi_memory_descriptor *memory_map, size_t descriptor_size,
29 	uint32_t descriptor_version);
30 
31 
32 void
33 arch_convert_kernel_args(void)
34 {
35 	fix_address(gKernelArgs.arch_args.fdt);
36 }
37 
38 
39 static const char*
40 memory_region_type_str(int type)
41 {
42 	switch (type)	{
43 	case EfiReservedMemoryType:
44 		return "ReservedMemoryType";
45 	case EfiLoaderCode:
46 		return "LoaderCode";
47 	case EfiLoaderData:
48 		return "LoaderData";
49 	case EfiBootServicesCode:
50 		return "BootServicesCode";
51 	case EfiBootServicesData:
52 		return "BootServicesData";
53 	case EfiRuntimeServicesCode:
54 		return "RuntimeServicesCode";
55 	case EfiRuntimeServicesData:
56 		return "RuntimeServicesData";
57 	case EfiConventionalMemory:
58 		return "ConventionalMemory";
59 	case EfiUnusableMemory:
60 		return "UnusableMemory";
61 	case EfiACPIReclaimMemory:
62 		return "ACPIReclaimMemory";
63 	case EfiACPIMemoryNVS:
64 		return "ACPIMemoryNVS";
65 	case EfiMemoryMappedIO:
66 		return "MMIO";
67 	case EfiMemoryMappedIOPortSpace:
68 		return "MMIOPortSpace";
69 	case EfiPalCode:
70 		return "PalCode";
71 	case EfiPersistentMemory:
72 		return "PersistentMemory";
73 	default:
74 		return "unknown";
75 	}
76 }
77 
78 
79 void
80 arch_start_kernel(addr_t kernelEntry)
81 {
82 	// Prepare to exit EFI boot services.
83 	// Read the memory map.
84 	// First call is to determine the buffer size.
85 	size_t memory_map_size = 0;
86 	efi_memory_descriptor dummy;
87 	efi_memory_descriptor *memory_map;
88 	size_t map_key;
89 	size_t descriptor_size;
90 	uint32_t descriptor_version;
91 	if (kBootServices->GetMemoryMap(&memory_map_size, &dummy, &map_key,
92 			&descriptor_size, &descriptor_version) != EFI_BUFFER_TOO_SMALL) {
93 		panic("Unable to determine size of system memory map");
94 	}
95 
96 	// Allocate a buffer twice as large as needed just in case it gets bigger
97 	// between calls to ExitBootServices.
98 	size_t actual_memory_map_size = memory_map_size * 2;
99 	memory_map
100 		= (efi_memory_descriptor *)kernel_args_malloc(actual_memory_map_size +
101 			ALIGN_MEMORY_MAP);
102 
103 	// align memory_map to 4-byte boundary
104 	// otherwise we get alignment exception when calling GetMemoryMap below
105 	memory_map = (efi_memory_descriptor *)ROUNDUP((uint32_t)memory_map, ALIGN_MEMORY_MAP);
106 
107 	if (memory_map == NULL)
108 		panic("Unable to allocate memory map.");
109 
110 	// Read (and print) the memory map.
111 	memory_map_size = actual_memory_map_size;
112 	if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
113 			&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
114 		panic("Unable to fetch system memory map.");
115 	}
116 
117 	addr_t addr = (addr_t)memory_map;
118 	dprintf("System provided memory map:\n");
119 	for (size_t i = 0; i < memory_map_size / descriptor_size; ++i) {
120 		efi_memory_descriptor *entry
121 			= (efi_memory_descriptor *)(addr + i * descriptor_size);
122 		dprintf("  phys: 0x%08llx-0x%08llx, virt: 0x%08llx-0x%08llx, type: %s (%#x), attr: %#llx\n",
123 			entry->PhysicalStart,
124 			entry->PhysicalStart + entry->NumberOfPages * B_PAGE_SIZE,
125 			entry->VirtualStart,
126 			entry->VirtualStart + entry->NumberOfPages * B_PAGE_SIZE,
127 			memory_region_type_str(entry->Type), entry->Type,
128 			entry->Attribute);
129 	}
130 
131 	// Generate page tables for use after ExitBootServices.
132 	uint32_t final_ttbr0 = arch_mmu_generate_post_efi_page_tables(
133 		memory_map_size, memory_map, descriptor_size, descriptor_version);
134 
135 	// Attempt to fetch the memory map and exit boot services.
136 	// This needs to be done in a loop, as ExitBootServices can change the
137 	// memory map.
138 	// Even better: Only GetMemoryMap and ExitBootServices can be called after
139 	// the first call to ExitBootServices, as the firmware is permitted to
140 	// partially exit. This is why twice as much space was allocated for the
141 	// memory map, as it's impossible to allocate more now.
142 	// A changing memory map shouldn't affect the generated page tables, as
143 	// they only needed to know about the maximum address, not any specific
144 	// entry.
145 	dprintf("Calling ExitBootServices. So long, EFI!\n");
146 	while (true) {
147 		if (kBootServices->ExitBootServices(kImage, map_key) == EFI_SUCCESS) {
148 			// The console was provided by boot services, disable it.
149 			stdout = NULL;
150 			stderr = NULL;
151 			// Can we adjust gKernelArgs.platform_args.serial_base_ports[0]
152 			// to something fixed in qemu for debugging?
153 			break;
154 		}
155 
156 		memory_map_size = actual_memory_map_size;
157 		if (kBootServices->GetMemoryMap(&memory_map_size, memory_map, &map_key,
158 				&descriptor_size, &descriptor_version) != EFI_SUCCESS) {
159 			panic("Unable to fetch system memory map.");
160 		}
161 	}
162 
163 	// Update EFI, generate final kernel physical memory map, etc.
164 	arch_mmu_post_efi_setup(memory_map_size, memory_map,
165 			descriptor_size, descriptor_version);
166 
167 	//smp_boot_other_cpus(final_pml4, kernelEntry);
168 
169 	// Enter the kernel!
170 	dprintf("arch_enter_kernel(ttbr0: 0x%08x, kernelArgs: 0x%08x, "
171 		"kernelEntry: 0x%08x, sp: 0x%08x)\n",
172 		final_ttbr0, (uint32_t)&gKernelArgs, (uint32_t)kernelEntry,
173 		(uint32_t)(gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size));
174 
175 	arch_enter_kernel(final_ttbr0, &gKernelArgs, kernelEntry,
176 		gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size);
177 }
178