]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootOption.c
ArmPlatformPkg/Bds: Add a signature in front of the Boot Argument propoer to this Bds
[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* FdtDevicePath;
26 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;
27 UINT32 LoaderType;
28 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
29 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
30 EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath;
31 EFI_DEVICE_PATH_PROTOCOL* DefaultFdtDevicePath;
32 UINTN FdtDevicePathSize;
33 UINTN CmdLineSize;
34 UINTN InitrdSize;
35 EFI_DEVICE_PATH* Initrd;
36
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 = BdsBootLinux (BootOption->FilePathList,
58 Initrd, // Initrd
59 (CHAR8*)(LinuxArguments + 1), // CmdLine
60 NULL);
61 } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
62 LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
63 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
64 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
65
66 if (InitrdSize > 0) {
67 Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));
68 } else {
69 Initrd = NULL;
70 }
71
72 // Get the default FDT device path
73 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
74 ASSERT_EFI_ERROR(Status);
75 DefaultFdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath));
76
77 // Get the FDT device path
78 FdtDevicePathSize = GetDevicePathSize (DefaultFdtDevicePath);
79 Status = GetEnvironmentVariable ((CHAR16 *)L"FDT", DefaultFdtDevicePath, &FdtDevicePathSize, (VOID **)&FdtDevicePath);
80 ASSERT_EFI_ERROR(Status);
81
82 Status = BdsBootLinux (BootOption->FilePathList,
83 Initrd, // Initrd
84 (CHAR8*)(LinuxArguments + 1),
85 FdtDevicePath);
86
87 return Status;
88 }
89
90 EFI_STATUS
91 BootOptionParseLoadOption (
92 IN EFI_LOAD_OPTION EfiLoadOption,
93 IN UINTN EfiLoadOptionSize,
94 OUT BDS_LOAD_OPTION **BdsLoadOption
95 )
96 {
97 BDS_LOAD_OPTION *LoadOption;
98 UINTN FilePathListLength;
99 UINTN DescriptionLength;
100
101 if (EfiLoadOption == NULL) {
102 return EFI_INVALID_PARAMETER;
103 }
104
105 if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
106 return EFI_BAD_BUFFER_SIZE;
107 }
108
109 LoadOption = (BDS_LOAD_OPTION*)AllocatePool(sizeof(BDS_LOAD_OPTION));
110 if (LoadOption == NULL) {
111 return EFI_OUT_OF_RESOURCES;
112 }
113
114 LoadOption->LoadOption = EfiLoadOption;
115 LoadOption->LoadOptionSize = EfiLoadOptionSize;
116
117 LoadOption->Attributes = *(UINT32*)EfiLoadOption;
118 FilePathListLength = *(UINT16*)(EfiLoadOption + sizeof(UINT32));
119 LoadOption->Description = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16));
120 DescriptionLength = StrSize (LoadOption->Description);
121 LoadOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);
122
123 if ((UINTN)((UINT8*)LoadOption->FilePathList + FilePathListLength - EfiLoadOption) == EfiLoadOptionSize) {
124 LoadOption->OptionalData = NULL;
125 } else {
126 LoadOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)((UINT8*)LoadOption->FilePathList + FilePathListLength);
127 }
128
129 *BdsLoadOption = LoadOption;
130 return EFI_SUCCESS;
131 }
132
133 EFI_STATUS
134 BootOptionFromLoadOptionVariable (
135 IN UINT16 LoadOptionIndex,
136 OUT BDS_LOAD_OPTION **BdsLoadOption
137 )
138 {
139 EFI_STATUS Status;
140 CHAR16 BootVariableName[9];
141 EFI_LOAD_OPTION EfiLoadOption;
142 UINTN EfiLoadOptionSize;
143
144 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);
145
146 Status = GetEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
147 if (!EFI_ERROR(Status)) {
148 Status = BootOptionParseLoadOption (EfiLoadOption,EfiLoadOptionSize,BdsLoadOption);
149 if (!EFI_ERROR(Status)) {
150 (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;
151 }
152 }
153
154 return Status;
155 }
156
157 EFI_STATUS
158 BootOptionList (
159 IN OUT LIST_ENTRY *BootOptionList
160 )
161 {
162 EFI_STATUS Status;
163 UINTN Index;
164 UINT16 *BootOrder;
165 UINTN BootOrderSize;
166 BDS_LOAD_OPTION *BdsLoadOption;
167
168 InitializeListHead (BootOptionList);
169
170 // Get the Boot Option Order from the environment variable
171 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
172 if (EFI_ERROR(Status)) {
173 return Status;
174 }
175
176 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
177 Status = BootOptionFromLoadOptionVariable (BootOrder[Index],&BdsLoadOption);
178 if (!EFI_ERROR(Status)) {
179 InsertTailList (BootOptionList,&BdsLoadOption->Link);
180 }
181 }
182
183 return EFI_SUCCESS;
184 }
185
186 UINT16
187 BootOptionAllocateBootIndex (
188 VOID
189 )
190 {
191 EFI_STATUS Status;
192 UINTN Index;
193 UINT32 BootIndex;
194 UINT16 *BootOrder;
195 UINTN BootOrderSize;
196 BOOLEAN Found;
197
198 // Get the Boot Option Order from the environment variable
199 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
200 if (!EFI_ERROR(Status)) {
201 for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {
202 Found = FALSE;
203 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
204 if (BootOrder[Index] == BootIndex) {
205 Found = TRUE;
206 break;
207 }
208 }
209 if (!Found) {
210 return BootIndex;
211 }
212 }
213 }
214 // Return the first index
215 return 0;
216 }
217
218 STATIC
219 EFI_STATUS
220 BootOptionSetFields (
221 IN BDS_LOAD_OPTION* BootOption,
222 IN UINT32 Attributes,
223 IN CHAR16* BootDescription,
224 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
225 IN ARM_BDS_LOADER_TYPE BootType,
226 IN ARM_BDS_LOADER_ARGUMENTS* BootArguments
227 )
228 {
229 EFI_LOAD_OPTION EfiLoadOption;
230 UINTN EfiLoadOptionSize;
231 UINTN BootDescriptionSize;
232 UINTN BootOptionalDataSize;
233 UINT16 FilePathListLength;
234 UINT8* EfiLoadOptionPtr;
235 UINT8* InitrdPathListPtr;
236 UINTN OptionalDataSize;
237 ARM_BDS_LINUX_ARGUMENTS* DestLinuxArguments;
238 ARM_BDS_LINUX_ARGUMENTS* SrcLinuxArguments;
239
240 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
241 if (BootOption->LoadOption) {
242 FreePool(BootOption->LoadOption);
243 }
244
245 BootDescriptionSize = StrSize (BootDescription);
246 BootOptionalDataSize = sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);
247 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
248 BootOptionalDataSize += sizeof(ARM_BDS_LINUX_ARGUMENTS) + BootArguments->LinuxArguments.CmdLineSize + BootArguments->LinuxArguments.InitrdSize;
249 }
250
251 // Compute the size of the FilePath list
252 FilePathListLength = GetUnalignedDevicePathSize (DevicePath);
253
254 // Allocate the memory for the EFI Load Option
255 EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + BootOptionalDataSize;
256 EfiLoadOption = (EFI_LOAD_OPTION)AllocatePool(EfiLoadOptionSize);
257 EfiLoadOptionPtr = EfiLoadOption;
258
259 //
260 // Populate the EFI Load Option and BDS Boot Option structures
261 //
262
263 // Attributes fields
264 BootOption->Attributes = Attributes;
265 *(UINT32*)EfiLoadOptionPtr = Attributes;
266 EfiLoadOptionPtr += sizeof(UINT32);
267
268 // FilePath List fields
269 BootOption->FilePathListLength = FilePathListLength;
270 *(UINT16*)EfiLoadOptionPtr = FilePathListLength;
271 EfiLoadOptionPtr += sizeof(UINT16);
272
273 // Boot description fields
274 BootOption->Description = (CHAR16*)EfiLoadOptionPtr;
275 CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);
276 EfiLoadOptionPtr += BootDescriptionSize;
277
278 // File path fields
279 BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;
280 CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);
281 EfiLoadOptionPtr += FilePathListLength;
282
283 // Optional Data fields, Do unaligned writes
284 BootOption->OptionalData = EfiLoadOptionPtr;
285 WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, ARM_BDS_OPTIONAL_DATA_SIGNATURE);
286 WriteUnaligned32 ((UINT32 *)(EfiLoadOptionPtr + 4), BootType);
287
288 OptionalDataSize = sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);
289
290 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
291 SrcLinuxArguments = &(BootArguments->LinuxArguments);
292 DestLinuxArguments = &((ARM_BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments.LinuxArguments;
293
294 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->CmdLineSize), SrcLinuxArguments->CmdLineSize);
295 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->InitrdSize), SrcLinuxArguments->InitrdSize);
296 OptionalDataSize += sizeof (ARM_BDS_LINUX_ARGUMENTS);
297
298 if (SrcLinuxArguments->CmdLineSize > 0) {
299 CopyMem ((VOID*)(DestLinuxArguments + 1), (VOID*)(SrcLinuxArguments + 1), SrcLinuxArguments->CmdLineSize);
300 OptionalDataSize += SrcLinuxArguments->CmdLineSize;
301 }
302
303 if (SrcLinuxArguments->InitrdSize > 0) {
304 InitrdPathListPtr = (UINT8*)((UINTN)(DestLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize);
305 CopyMem (InitrdPathListPtr, (VOID*)((UINTN)(SrcLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize), SrcLinuxArguments->InitrdSize);
306 }
307 }
308 BootOption->OptionalDataSize = OptionalDataSize;
309
310 // If this function is called at the creation of the Boot Device entry (not at the update) the
311 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
312 if (BootOption->LoadOptionSize == 0) {
313 BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
314 }
315
316 // Fill the EFI Load option fields
317 BootOption->LoadOption = EfiLoadOption;
318 BootOption->LoadOptionSize = EfiLoadOptionSize;
319
320 return EFI_SUCCESS;
321 }
322
323 EFI_STATUS
324 BootOptionCreate (
325 IN UINT32 Attributes,
326 IN CHAR16* BootDescription,
327 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
328 IN ARM_BDS_LOADER_TYPE BootType,
329 IN ARM_BDS_LOADER_ARGUMENTS* BootArguments,
330 OUT BDS_LOAD_OPTION **BdsLoadOption
331 )
332 {
333 EFI_STATUS Status;
334 BDS_LOAD_OPTION *BootOption;
335 CHAR16 BootVariableName[9];
336 UINT16 *BootOrder;
337 UINTN BootOrderSize;
338
339 //
340 // Allocate and fill the memory for the BDS Load Option structure
341 //
342 BootOption = (BDS_LOAD_OPTION*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION));
343
344 InitializeListHead (&BootOption->Link);
345 BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
346
347 //
348 // Set the related environment variables
349 //
350
351 // Create Boot#### environment variable
352 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
353 Status = gRT->SetVariable (
354 BootVariableName,
355 &gEfiGlobalVariableGuid,
356 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
357 BootOption->LoadOptionSize,
358 BootOption->LoadOption
359 );
360
361 // Add the new Boot Index to the list
362 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
363 if (!EFI_ERROR(Status)) {
364 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
365 // Add the new index at the end
366 BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;
367 BootOrderSize += sizeof(UINT16);
368 } else {
369 // BootOrder does not exist. Create it
370 BootOrderSize = sizeof(UINT16);
371 BootOrder = &(BootOption->LoadOptionIndex);
372 }
373
374 // Update (or Create) the BootOrder environment variable
375 Status = gRT->SetVariable (
376 L"BootOrder",
377 &gEfiGlobalVariableGuid,
378 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
379 BootOrderSize,
380 BootOrder
381 );
382
383 *BdsLoadOption = BootOption;
384 return Status;
385 }
386
387 EFI_STATUS
388 BootOptionUpdate (
389 IN BDS_LOAD_OPTION* BdsLoadOption,
390 IN UINT32 Attributes,
391 IN CHAR16* BootDescription,
392 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
393 IN ARM_BDS_LOADER_TYPE BootType,
394 IN ARM_BDS_LOADER_ARGUMENTS* BootArguments
395 )
396 {
397 EFI_STATUS Status;
398 CHAR16 BootVariableName[9];
399
400 // Update the BDS Load Option structure
401 BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
402
403 // Update the related environment variables
404 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
405
406 Status = gRT->SetVariable (
407 BootVariableName,
408 &gEfiGlobalVariableGuid,
409 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
410 BdsLoadOption->LoadOptionSize,
411 BdsLoadOption->LoadOption
412 );
413
414 return Status;
415 }
416
417 EFI_STATUS
418 BootOptionDelete (
419 IN BDS_LOAD_OPTION *BootOption
420 )
421 {
422 UINTN Index;
423 UINTN BootOrderSize;
424 UINT16* BootOrder;
425 UINTN BootOrderCount;
426 EFI_STATUS Status;
427
428 // If the Boot Optiono was attached to a list remove it
429 if (!IsListEmpty (&BootOption->Link)) {
430 // Remove the entry from the list
431 RemoveEntryList (&BootOption->Link);
432 }
433
434 // Remove the entry from the BootOrder environment variable
435 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
436 if (!EFI_ERROR(Status)) {
437 BootOrderCount = BootOrderSize / sizeof(UINT16);
438
439 // Find the index of the removed entry
440 for (Index = 0; Index < BootOrderCount; Index++) {
441 if (BootOrder[Index] == BootOption->LoadOptionIndex) {
442 // If it the last entry we do not need to rearrange the BootOrder list
443 if (Index + 1 != BootOrderCount) {
444 CopyMem (&BootOrder[Index],&BootOrder[Index+1], BootOrderCount - (Index + 1));
445 }
446 break;
447 }
448 }
449
450 // Update the BootOrder environment variable
451 Status = gRT->SetVariable (
452 L"BootOrder",
453 &gEfiGlobalVariableGuid,
454 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
455 BootOrderSize - sizeof(UINT16),
456 BootOrder
457 );
458 }
459
460 return EFI_SUCCESS;
461 }