]>
Commit | Line | Data |
---|---|---|
1bfda055 | 1 | /** @file |
2 | * | |
3 | * Copyright (c) 2011, 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" | |
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 | |
a355a365 | 78 | //TODO: Check there is no overlapping between kernel and Atag |
1bfda055 | 79 | |
a355a365 | 80 | // |
81 | // Switch off interrupts, caches, mmu, etc | |
82 | // | |
83 | Status = PreparePlatformHardware (); | |
84 | ASSERT_EFI_ERROR(Status); | |
1bfda055 | 85 | |
a355a365 | 86 | // Register and print out performance information |
87 | PERF_END (NULL, "BDS", NULL, 0); | |
88 | if (PerformanceMeasurementEnabled ()) { | |
89 | PrintPerformance (); | |
90 | } | |
1bfda055 | 91 | |
a355a365 | 92 | // |
93 | // Start the Linux Kernel | |
94 | // | |
1bfda055 | 95 | |
a355a365 | 96 | // Outside BootServices, so can't use Print(); |
97 | DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); | |
1bfda055 | 98 | |
a355a365 | 99 | // jump to kernel with register set |
76d17c31 | 100 | LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress); |
1bfda055 | 101 | |
a355a365 | 102 | // Kernel should never exit |
103 | // After Life services are not provided | |
104 | ASSERT(FALSE); | |
1bfda055 | 105 | |
106 | Exit: | |
a355a365 | 107 | // Only be here if we fail to start Linux |
108 | Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status); | |
109 | ||
110 | // Free Runtimee Memory (kernel and FDT) | |
111 | return Status; | |
1bfda055 | 112 | } |
76d17c31 | 113 | |
114 | /** | |
115 | Start a Linux kernel from a Device Path | |
116 | ||
117 | @param LinuxKernel Device Path to the Linux Kernel | |
118 | @param Parameters Linux kernel agruments | |
119 | @param Fdt Device Path to the Flat Device Tree | |
120 | ||
121 | @retval EFI_SUCCESS All drivers have been connected | |
122 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found | |
123 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. | |
124 | ||
125 | **/ | |
126 | EFI_STATUS | |
127 | BdsBootLinuxAtag ( | |
128 | IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, | |
129 | IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, | |
130 | IN CONST CHAR8* Arguments | |
131 | ) | |
132 | { | |
133 | EFI_STATUS Status; | |
134 | UINT32 LinuxImageSize; | |
135 | UINT32 InitrdImageSize = 0; | |
136 | UINT32 KernelParamsSize; | |
137 | EFI_PHYSICAL_ADDRESS KernelParamsAddress; | |
138 | EFI_PHYSICAL_ADDRESS LinuxImage; | |
139 | EFI_PHYSICAL_ADDRESS InitrdImage; | |
140 | ||
141 | PERF_START (NULL, "BDS", NULL, 0); | |
142 | ||
143 | // Load the Linux kernel from a device path | |
144 | LinuxImage = LINUX_KERNEL_MAX_OFFSET; | |
145 | Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); | |
146 | if (EFI_ERROR(Status)) { | |
147 | Print (L"ERROR: Did not find Linux kernel.\n"); | |
148 | return Status; | |
149 | } | |
150 | ||
151 | if (InitrdDevicePath) { | |
152 | Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); | |
153 | if (EFI_ERROR(Status)) { | |
154 | Print (L"ERROR: Did not find initrd image.\n"); | |
155 | return Status; | |
156 | } | |
157 | } | |
158 | ||
159 | // | |
160 | // Setup the Linux Kernel Parameters | |
161 | // | |
162 | ||
163 | // By setting address=0 we leave the memory allocation to the function | |
19a7404a | 164 | Status = PrepareAtagList (Arguments, InitrdImage, InitrdImageSize, &KernelParamsAddress, &KernelParamsSize); |
76d17c31 | 165 | if (EFI_ERROR(Status)) { |
166 | Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); | |
167 | return Status; | |
168 | } | |
169 | ||
170 | return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, PcdGet32(PcdArmMachineType)); | |
171 | } | |
172 | ||
173 | /** | |
174 | Start a Linux kernel from a Device Path | |
175 | ||
176 | @param LinuxKernel Device Path to the Linux Kernel | |
177 | @param Parameters Linux kernel agruments | |
178 | @param Fdt Device Path to the Flat Device Tree | |
179 | ||
180 | @retval EFI_SUCCESS All drivers have been connected | |
181 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found | |
182 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. | |
183 | ||
184 | **/ | |
185 | EFI_STATUS | |
186 | BdsBootLinuxFdt ( | |
187 | IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, | |
188 | IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, | |
189 | IN CONST CHAR8* Arguments, | |
190 | IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath | |
191 | ) | |
192 | { | |
193 | EFI_STATUS Status; | |
194 | UINT32 LinuxImageSize; | |
195 | UINT32 InitrdImageSize = 0; | |
196 | UINT32 KernelParamsSize; | |
197 | EFI_PHYSICAL_ADDRESS KernelParamsAddress; | |
198 | UINT32 FdtMachineType; | |
199 | EFI_PHYSICAL_ADDRESS LinuxImage; | |
200 | EFI_PHYSICAL_ADDRESS InitrdImage; | |
201 | ||
202 | FdtMachineType = 0xFFFFFFFF; | |
203 | ||
204 | PERF_START (NULL, "BDS", NULL, 0); | |
205 | ||
206 | // Load the Linux kernel from a device path | |
207 | LinuxImage = LINUX_KERNEL_MAX_OFFSET; | |
208 | Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); | |
209 | if (EFI_ERROR(Status)) { | |
210 | Print (L"ERROR: Did not find Linux kernel.\n"); | |
211 | return Status; | |
212 | } | |
213 | ||
214 | if (InitrdDevicePath) { | |
215 | Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); | |
216 | if (EFI_ERROR(Status)) { | |
217 | Print (L"ERROR: Did not find initrd image.\n"); | |
218 | return Status; | |
219 | } | |
220 | } | |
221 | ||
222 | // Load the FDT binary from a device path | |
223 | KernelParamsAddress = LINUX_ATAG_MAX_OFFSET; | |
224 | Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, &KernelParamsAddress, &KernelParamsSize); | |
225 | if (EFI_ERROR(Status)) { | |
226 | Print (L"ERROR: Did not find Device Tree blob.\n"); | |
227 | return Status; | |
228 | } | |
229 | return StartLinux (LinuxImage, LinuxImageSize, KernelParamsAddress, KernelParamsSize, FdtMachineType); | |
230 | } | |
231 |