]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootOption.c
ArmPlatformPkg/Bds: Fix the Boot Manager option to set the FDT device path
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootOption.c
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"
16
17 extern EFI_HANDLE mImageHandle;
18
19 EFI_STATUS
20 BootOptionStart (
21 IN BDS_LOAD_OPTION *BootOption
22 )
23 {
24 EFI_STATUS Status;
25 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;
26 UINT32 LoaderType;
27 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
28 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
29 EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath;
30 EFI_DEVICE_PATH_PROTOCOL* DefaultFdtDevicePath;
31 UINTN FdtDevicePathSize;
32 UINTN CmdLineSize;
33 UINTN InitrdSize;
34 EFI_DEVICE_PATH* Initrd;
35
36 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
37 Status = EFI_UNSUPPORTED;
38 OptionalData = BootOption->OptionalData;
39 LoaderType = ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
40
41 if (LoaderType == BDS_LOADER_EFI_APPLICATION) {
42 // Need to connect every drivers to ensure no dependencies are missing for the application
43 BdsConnectAllDrivers();
44
45 Status = BdsStartEfiApplication (mImageHandle, BootOption->FilePathList, 0, NULL);
46 } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
47 LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
48 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
49 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
50
51 if (InitrdSize > 0) {
52 Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));
53 } else {
54 Initrd = NULL;
55 }
56
57 Status = BdsBootLinuxAtag (BootOption->FilePathList,
58 Initrd, // Initrd
59 (CHAR8*)(LinuxArguments + 1)); // CmdLine
60 } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
61 LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
62 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
63 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
64
65 if (InitrdSize > 0) {
66 Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));
67 } else {
68 Initrd = NULL;
69 }
70
71 // Get the default FDT device path
72 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
73 ASSERT_EFI_ERROR(Status);
74 DefaultFdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath));
75
76 // Get the FDT device path
77 FdtDevicePathSize = GetDevicePathSize (DefaultFdtDevicePath);
78 Status = GetEnvironmentVariable ((CHAR16 *)L"Fdt", DefaultFdtDevicePath, &FdtDevicePathSize, (VOID **)&FdtDevicePath);
79 ASSERT_EFI_ERROR(Status);
80
81 Status = BdsBootLinuxFdt (BootOption->FilePathList,
82 Initrd, // Initrd
83 (CHAR8*)(LinuxArguments + 1),
84 FdtDevicePath);
85 }
86 } else {
87 Status = BdsStartEfiApplication (mImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData);
88 }
89
90 return Status;
91 }
92
93 EFI_STATUS
94 BootOptionList (
95 IN OUT LIST_ENTRY *BootOptionList
96 )
97 {
98 EFI_STATUS Status;
99 UINTN Index;
100 UINT16* BootOrder;
101 UINTN BootOrderSize;
102 BDS_LOAD_OPTION* BdsLoadOption;
103 BDS_LOAD_OPTION_ENTRY* BdsLoadOptionEntry;
104
105 InitializeListHead (BootOptionList);
106
107 // Get the Boot Option Order from the environment variable
108 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
109 if (EFI_ERROR(Status)) {
110 return Status;
111 }
112
113 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
114 Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
115 if (!EFI_ERROR(Status)) {
116 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY));
117 BdsLoadOptionEntry->BdsLoadOption = BdsLoadOption;
118 InsertTailList (BootOptionList,&BdsLoadOptionEntry->Link);
119 }
120 }
121
122 return EFI_SUCCESS;
123 }
124
125 STATIC
126 EFI_STATUS
127 BootOptionSetFields (
128 IN BDS_LOAD_OPTION* BootOption,
129 IN UINT32 Attributes,
130 IN CHAR16* BootDescription,
131 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
132 IN ARM_BDS_LOADER_TYPE BootType,
133 IN ARM_BDS_LOADER_ARGUMENTS* BootArguments
134 )
135 {
136 EFI_LOAD_OPTION EfiLoadOption;
137 UINTN EfiLoadOptionSize;
138 UINTN BootDescriptionSize;
139 UINTN BootOptionalDataSize;
140 UINT16 FilePathListLength;
141 UINT8* EfiLoadOptionPtr;
142 UINT8* InitrdPathListPtr;
143 UINTN OptionalDataSize;
144 ARM_BDS_LINUX_ARGUMENTS* DestLinuxArguments;
145 ARM_BDS_LINUX_ARGUMENTS* SrcLinuxArguments;
146
147 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
148 if (BootOption->LoadOption) {
149 FreePool(BootOption->LoadOption);
150 }
151
152 BootDescriptionSize = StrSize (BootDescription);
153 BootOptionalDataSize = sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);
154 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
155 BootOptionalDataSize += sizeof(ARM_BDS_LINUX_ARGUMENTS) + BootArguments->LinuxArguments.CmdLineSize + BootArguments->LinuxArguments.InitrdSize;
156 }
157
158 // Compute the size of the FilePath list
159 FilePathListLength = GetUnalignedDevicePathSize (DevicePath);
160
161 // Allocate the memory for the EFI Load Option
162 EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + BootOptionalDataSize;
163 EfiLoadOption = (EFI_LOAD_OPTION)AllocatePool(EfiLoadOptionSize);
164 EfiLoadOptionPtr = EfiLoadOption;
165
166 //
167 // Populate the EFI Load Option and BDS Boot Option structures
168 //
169
170 // Attributes fields
171 BootOption->Attributes = Attributes;
172 *(UINT32*)EfiLoadOptionPtr = Attributes;
173 EfiLoadOptionPtr += sizeof(UINT32);
174
175 // FilePath List fields
176 BootOption->FilePathListLength = FilePathListLength;
177 *(UINT16*)EfiLoadOptionPtr = FilePathListLength;
178 EfiLoadOptionPtr += sizeof(UINT16);
179
180 // Boot description fields
181 BootOption->Description = (CHAR16*)EfiLoadOptionPtr;
182 CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);
183 EfiLoadOptionPtr += BootDescriptionSize;
184
185 // File path fields
186 BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;
187 CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);
188 EfiLoadOptionPtr += FilePathListLength;
189
190 // Optional Data fields, Do unaligned writes
191 BootOption->OptionalData = EfiLoadOptionPtr;
192 WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, ARM_BDS_OPTIONAL_DATA_SIGNATURE);
193 WriteUnaligned32 ((UINT32 *)(EfiLoadOptionPtr + 4), BootType);
194
195 OptionalDataSize = sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);
196
197 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
198 SrcLinuxArguments = &(BootArguments->LinuxArguments);
199 DestLinuxArguments = &((ARM_BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments.LinuxArguments;
200
201 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->CmdLineSize), SrcLinuxArguments->CmdLineSize);
202 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->InitrdSize), SrcLinuxArguments->InitrdSize);
203 OptionalDataSize += sizeof (ARM_BDS_LINUX_ARGUMENTS);
204
205 if (SrcLinuxArguments->CmdLineSize > 0) {
206 CopyMem ((VOID*)(DestLinuxArguments + 1), (VOID*)(SrcLinuxArguments + 1), SrcLinuxArguments->CmdLineSize);
207 OptionalDataSize += SrcLinuxArguments->CmdLineSize;
208 }
209
210 if (SrcLinuxArguments->InitrdSize > 0) {
211 InitrdPathListPtr = (UINT8*)((UINTN)(DestLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize);
212 CopyMem (InitrdPathListPtr, (VOID*)((UINTN)(SrcLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize), SrcLinuxArguments->InitrdSize);
213 }
214 }
215 BootOption->OptionalDataSize = OptionalDataSize;
216
217 // If this function is called at the creation of the Boot Device entry (not at the update) the
218 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
219 if (BootOption->LoadOptionSize == 0) {
220 BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
221 }
222
223 // Fill the EFI Load option fields
224 BootOption->LoadOption = EfiLoadOption;
225 BootOption->LoadOptionSize = EfiLoadOptionSize;
226
227 return EFI_SUCCESS;
228 }
229
230 EFI_STATUS
231 BootOptionCreate (
232 IN UINT32 Attributes,
233 IN CHAR16* BootDescription,
234 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
235 IN ARM_BDS_LOADER_TYPE BootType,
236 IN ARM_BDS_LOADER_ARGUMENTS* BootArguments,
237 OUT BDS_LOAD_OPTION** BdsLoadOption
238 )
239 {
240 EFI_STATUS Status;
241 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
242 BDS_LOAD_OPTION* BootOption;
243 CHAR16 BootVariableName[9];
244 UINT16* BootOrder;
245 UINTN BootOrderSize;
246
247 //
248 // Allocate and fill the memory for the BDS Load Option structure
249 //
250 BootOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY));
251 InitializeListHead (&BootOptionEntry->Link);
252 BootOptionEntry->BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
253
254 BootOption = BootOptionEntry->BdsLoadOption;
255 BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
256
257 //
258 // Set the related environment variables
259 //
260
261 // Create Boot#### environment variable
262 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
263 Status = gRT->SetVariable (
264 BootVariableName,
265 &gEfiGlobalVariableGuid,
266 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
267 BootOption->LoadOptionSize,
268 BootOption->LoadOption
269 );
270
271 // Add the new Boot Index to the list
272 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
273 if (!EFI_ERROR(Status)) {
274 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
275 // Add the new index at the end
276 BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;
277 BootOrderSize += sizeof(UINT16);
278 } else {
279 // BootOrder does not exist. Create it
280 BootOrderSize = sizeof(UINT16);
281 BootOrder = &(BootOption->LoadOptionIndex);
282 }
283
284 // Update (or Create) the BootOrder environment variable
285 Status = gRT->SetVariable (
286 L"BootOrder",
287 &gEfiGlobalVariableGuid,
288 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
289 BootOrderSize,
290 BootOrder
291 );
292
293 *BdsLoadOption = BootOption;
294 return Status;
295 }
296
297 EFI_STATUS
298 BootOptionUpdate (
299 IN BDS_LOAD_OPTION* BdsLoadOption,
300 IN UINT32 Attributes,
301 IN CHAR16* BootDescription,
302 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
303 IN ARM_BDS_LOADER_TYPE BootType,
304 IN ARM_BDS_LOADER_ARGUMENTS* BootArguments
305 )
306 {
307 EFI_STATUS Status;
308 CHAR16 BootVariableName[9];
309
310 // Update the BDS Load Option structure
311 BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
312
313 // Update the related environment variables
314 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
315
316 Status = gRT->SetVariable (
317 BootVariableName,
318 &gEfiGlobalVariableGuid,
319 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
320 BdsLoadOption->LoadOptionSize,
321 BdsLoadOption->LoadOption
322 );
323
324 return Status;
325 }
326
327 EFI_STATUS
328 BootOptionDelete (
329 IN BDS_LOAD_OPTION *BootOption
330 )
331 {
332 UINTN Index;
333 UINTN BootOrderSize;
334 UINT16* BootOrder;
335 UINTN BootOrderCount;
336 EFI_STATUS Status;
337
338 // Remove the entry from the BootOrder environment variable
339 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
340 if (!EFI_ERROR(Status)) {
341 BootOrderCount = BootOrderSize / sizeof(UINT16);
342
343 // Find the index of the removed entry
344 for (Index = 0; Index < BootOrderCount; Index++) {
345 if (BootOrder[Index] == BootOption->LoadOptionIndex) {
346 // If it the last entry we do not need to rearrange the BootOrder list
347 if (Index + 1 != BootOrderCount) {
348 CopyMem (&BootOrder[Index],&BootOrder[Index+1], BootOrderCount - (Index + 1));
349 }
350 break;
351 }
352 }
353
354 // Update the BootOrder environment variable
355 Status = gRT->SetVariable (
356 L"BootOrder",
357 &gEfiGlobalVariableGuid,
358 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
359 BootOrderSize - sizeof(UINT16),
360 BootOrder
361 );
362 }
363
364 return EFI_SUCCESS;
365 }