]>
Commit | Line | Data |
---|---|---|
1 | /** @file | |
2 | * | |
3 | * Copyright (c) 2011-2012, ARM Limited. All rights reserved. | |
4 | * | |
5 | * This program and the accompanying materials | |
6 | * are licensed and made available under the terms and conditions of the BSD License | |
7 | * which accompanies this distribution. The full text of the license may be found at | |
8 | * http://opensource.org/licenses/bsd-license.php | |
9 | * | |
10 | * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
12 | * | |
13 | **/ | |
14 | ||
15 | #include "BdsInternal.h" | |
16 | #include "BdsLinuxLoader.h" | |
17 | ||
18 | #define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32) | |
19 | ||
20 | STATIC | |
21 | EFI_STATUS | |
22 | PreparePlatformHardware ( | |
23 | VOID | |
24 | ) | |
25 | { | |
26 | //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called. | |
27 | ||
28 | // Clean, invalidate, disable data cache | |
29 | ArmDisableDataCache(); | |
30 | ArmCleanInvalidateDataCache(); | |
31 | ||
32 | // Invalidate and disable the Instruction cache | |
33 | ArmDisableInstructionCache (); | |
34 | ArmInvalidateInstructionCache (); | |
35 | ||
36 | // Turn off MMU | |
37 | ArmDisableMmu(); | |
38 | ||
39 | return EFI_SUCCESS; | |
40 | } | |
41 | ||
42 | STATIC | |
43 | EFI_STATUS | |
44 | StartLinux ( | |
45 | IN EFI_PHYSICAL_ADDRESS LinuxImage, | |
46 | IN UINTN LinuxImageSize, | |
47 | IN EFI_PHYSICAL_ADDRESS KernelParamsAddress, | |
48 | IN UINTN KernelParamsSize, | |
49 | IN UINT32 MachineType | |
50 | ) | |
51 | { | |
52 | EFI_STATUS Status; | |
53 | LINUX_KERNEL LinuxKernel; | |
54 | ||
55 | // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on | |
56 | // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event. | |
57 | Status = ShutdownUefiBootServices (); | |
58 | if(EFI_ERROR(Status)) { | |
59 | DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status)); | |
60 | goto Exit; | |
61 | } | |
62 | ||
63 | // Move the kernel parameters to any address inside the first 1MB. | |
64 | // This is necessary because the ARM Linux kernel requires | |
65 | // the FTD / ATAG List to reside entirely inside the first 1MB of | |
66 | // physical memory. | |
67 | if ((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) { | |
68 | //Note: There is no requirement on the alignment | |
69 | KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize); | |
70 | } | |
71 | ||
72 | if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) { | |
73 | //Note: There is no requirement on the alignment | |
74 | LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize); | |
75 | } else { | |
76 | LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage; | |
77 | } | |
78 | ||
79 | // Check if the Linux Image is a uImage | |
80 | if (*(UINT32*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) { | |
81 | // Assume the Image Entry Point is just after the uImage header (64-byte size) | |
82 | LinuxKernel = (LINUX_KERNEL)((UINTN)LinuxKernel + 64); | |
83 | LinuxImageSize -= 64; | |
84 | } | |
85 | ||
86 | //TODO: Check there is no overlapping between kernel and Atag | |
87 | ||
88 | // | |
89 | // Switch off interrupts, caches, mmu, etc | |
90 | // | |
91 | Status = PreparePlatformHardware (); | |
92 | ASSERT_EFI_ERROR(Status); | |
93 | ||
94 | // Register and print out performance information | |
95 | PERF_END (NULL, "BDS", NULL, 0); | |
96 | if (PerformanceMeasurementEnabled ()) { | |
97 | PrintPerformance (); | |
98 | } | |
99 | ||
100 | // | |
101 | // Start the Linux Kernel | |
102 | // | |
103 | ||
104 | // Outside BootServices, so can't use Print(); | |
105 | DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); | |
106 | ||
107 | // Jump to kernel with register set | |
108 | LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress); | |
109 | ||
110 | // Kernel should never exit | |
111 | // After Life services are not provided | |
112 | ASSERT(FALSE); | |
113 | ||
114 | Exit: | |
115 | // Only be here if we fail to start Linux | |
116 | Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status); | |
117 | ||
118 | // Free Runtimee Memory (kernel and FDT) | |
119 | return Status; | |
120 | } | |
121 | ||
122 | /** | |
123 | Start a Linux kernel from a Device Path | |
124 | ||
125 | @param LinuxKernel Device Path to the Linux Kernel | |
126 | @param Parameters Linux kernel arguments | |
127 | @param Fdt Device Path to the Flat Device Tree | |
128 | ||
129 | @retval EFI_SUCCESS All drivers have been connected | |
130 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found | |
131 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. | |
132 | ||
133 | **/ | |
134 | EFI_STATUS | |
135 | BdsBootLinuxAtag ( | |
136 | IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, | |
137 | IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, | |
138 | IN CONST CHAR8* Arguments | |
139 | ) | |
140 | { | |
141 | EFI_STATUS Status; | |
142 | UINT32 LinuxImageSize; | |
143 | UINT32 InitrdImageSize = 0; | |
144 | UINT32 KernelParamsSize; | |
145 | EFI_PHYSICAL_ADDRESS KernelParamsAddress; | |
146 | EFI_PHYSICAL_ADDRESS LinuxImage; | |
147 | EFI_PHYSICAL_ADDRESS InitrdImage; | |
148 | ||
149 | PERF_START (NULL, "BDS", NULL, 0); | |
150 | ||
151 | // Load the Linux kernel from a device path | |
152 | LinuxImage = LINUX_KERNEL_MAX_OFFSET; | |
153 | Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); | |
154 | if (EFI_ERROR(Status)) { | |
155 | Print (L"ERROR: Did not find Linux kernel.\n"); | |
156 | return Status; | |
157 | } | |
158 | ||
159 | if (InitrdDevicePath) { | |
160 | // Load the initrd near to the Linux kernel | |
161 | InitrdImage = LINUX_KERNEL_MAX_OFFSET; | |
162 | Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); | |
163 | if (Status == EFI_OUT_OF_RESOURCES) { | |
164 | Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); | |
165 | } | |
166 | if (EFI_ERROR(Status)) { | |
167 | Print (L"ERROR: Did not find initrd image.\n"); | |
168 | return Status; | |
169 | } | |
170 | ||
171 | // Check if the initrd is a uInitrd | |
172 | if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { | |
173 | // Skip the 64-byte image header | |
174 | InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); | |
175 | InitrdImageSize -= 64; | |
176 | } | |
177 | } | |
178 | ||
179 | // | |
180 | // Setup the Linux Kernel Parameters | |
181 | // | |
182 | ||
183 | // By setting address=0 we leave the memory allocation to the function | |
184 | Status = PrepareAtagList (Arguments, InitrdImage, InitrdImageSize, &KernelParamsAddress, &KernelParamsSize); | |
185 | if (EFI_ERROR(Status)) { | |
186 | Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); | |
187 | return Status; | |
188 | } | |
189 | ||
190 | return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, PcdGet32(PcdArmMachineType)); | |
191 | } | |
192 | ||
193 | /** | |
194 | Start a Linux kernel from a Device Path | |
195 | ||
196 | @param LinuxKernel Device Path to the Linux Kernel | |
197 | @param Parameters Linux kernel arguments | |
198 | @param Fdt Device Path to the Flat Device Tree | |
199 | ||
200 | @retval EFI_SUCCESS All drivers have been connected | |
201 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found | |
202 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. | |
203 | ||
204 | **/ | |
205 | EFI_STATUS | |
206 | BdsBootLinuxFdt ( | |
207 | IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, | |
208 | IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, | |
209 | IN CONST CHAR8* Arguments, | |
210 | IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath | |
211 | ) | |
212 | { | |
213 | EFI_STATUS Status; | |
214 | UINT32 LinuxImageSize; | |
215 | UINT32 InitrdImageSize = 0; | |
216 | UINT32 KernelParamsSize; | |
217 | EFI_PHYSICAL_ADDRESS KernelParamsAddress; | |
218 | UINT32 FdtMachineType; | |
219 | EFI_PHYSICAL_ADDRESS LinuxImage; | |
220 | EFI_PHYSICAL_ADDRESS InitrdImage; | |
221 | ||
222 | FdtMachineType = 0xFFFFFFFF; | |
223 | ||
224 | PERF_START (NULL, "BDS", NULL, 0); | |
225 | ||
226 | // Load the Linux kernel from a device path | |
227 | LinuxImage = LINUX_KERNEL_MAX_OFFSET; | |
228 | Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); | |
229 | if (EFI_ERROR(Status)) { | |
230 | Print (L"ERROR: Did not find Linux kernel.\n"); | |
231 | return Status; | |
232 | } | |
233 | ||
234 | if (InitrdDevicePath) { | |
235 | InitrdImage = LINUX_KERNEL_MAX_OFFSET; | |
236 | Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); | |
237 | if (Status == EFI_OUT_OF_RESOURCES) { | |
238 | Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); | |
239 | } | |
240 | if (EFI_ERROR(Status)) { | |
241 | Print (L"ERROR: Did not find initrd image.\n"); | |
242 | return Status; | |
243 | } | |
244 | ||
245 | // Check if the initrd is a uInitrd | |
246 | if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { | |
247 | // Skip the 64-byte image header | |
248 | InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); | |
249 | InitrdImageSize -= 64; | |
250 | } | |
251 | } | |
252 | ||
253 | // Load the FDT binary from a device path | |
254 | KernelParamsAddress = LINUX_ATAG_MAX_OFFSET; | |
255 | Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &KernelParamsAddress, &KernelParamsSize); | |
256 | if (EFI_ERROR(Status)) { | |
257 | Print (L"ERROR: Did not find Device Tree blob.\n"); | |
258 | return Status; | |
259 | } | |
260 | return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, FdtMachineType); | |
261 | } | |
262 |