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