3 * Copyright (c) 2011, ARM Limited. All rights reserved.
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
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.
15 #include "BdsInternal.h"
17 extern EFI_HANDLE mImageHandle
;
21 IN BDS_LOAD_OPTION
*BootOption
25 EFI_DEVICE_PATH
* FdtDevicePath
;
26 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
* EfiDevicePathFromTextProtocol
;
29 Status
= EFI_UNSUPPORTED
;
30 LoaderType
= ReadUnaligned32 (&BootOption
->OptionalData
->LoaderType
);
32 if (LoaderType
== BDS_LOADER_EFI_APPLICATION
) {
33 // Need to connect every drivers to ensure no dependencies are missing for the application
34 BdsConnectAllDrivers();
36 Status
= BdsStartEfiApplication (mImageHandle
, BootOption
->FilePathList
);
37 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
38 Status
= BdsBootLinux (BootOption
->FilePathList
,
39 (EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)),
40 BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
,
42 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
) {
43 // Convert the FDT path into a Device Path
44 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
45 ASSERT_EFI_ERROR(Status
);
46 FdtDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath ((CHAR16
*)PcdGetPtr(PcdFdtDevicePath
));
48 Status
= BdsBootLinux (BootOption
->FilePathList
,
53 FreePool(FdtDevicePath
);
60 BootOptionParseLoadOption (
61 IN EFI_LOAD_OPTION EfiLoadOption
,
62 IN UINTN EfiLoadOptionSize
,
63 OUT BDS_LOAD_OPTION
**BdsLoadOption
66 BDS_LOAD_OPTION
*LoadOption
;
67 UINTN FilePathListLength
;
68 UINTN DescriptionLength
;
70 if (EfiLoadOption
== NULL
) {
71 return EFI_INVALID_PARAMETER
;
74 if (EfiLoadOptionSize
< sizeof(UINT32
) + sizeof(UINT16
) + sizeof(CHAR16
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
)) {
75 return EFI_BAD_BUFFER_SIZE
;
78 LoadOption
= (BDS_LOAD_OPTION
*)AllocatePool(sizeof(BDS_LOAD_OPTION
));
79 if (LoadOption
== NULL
) {
80 return EFI_OUT_OF_RESOURCES
;
83 LoadOption
->LoadOption
= EfiLoadOption
;
84 LoadOption
->LoadOptionSize
= EfiLoadOptionSize
;
86 LoadOption
->Attributes
= *(UINT32
*)EfiLoadOption
;
87 FilePathListLength
= *(UINT16
*)(EfiLoadOption
+ sizeof(UINT32
));
88 LoadOption
->Description
= (CHAR16
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
));
89 DescriptionLength
= StrSize (LoadOption
->Description
);
90 LoadOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
) + DescriptionLength
);
92 if ((UINTN
)((UINT8
*)LoadOption
->FilePathList
+ FilePathListLength
- EfiLoadOption
) == EfiLoadOptionSize
) {
93 LoadOption
->OptionalData
= NULL
;
95 LoadOption
->OptionalData
= (BDS_LOADER_OPTIONAL_DATA
*)((UINT8
*)LoadOption
->FilePathList
+ FilePathListLength
);
98 *BdsLoadOption
= LoadOption
;
103 BootOptionFromLoadOptionVariable (
104 IN UINT16 LoadOptionIndex
,
105 OUT BDS_LOAD_OPTION
**BdsLoadOption
109 CHAR16 BootVariableName
[9];
110 EFI_LOAD_OPTION EfiLoadOption
;
111 UINTN EfiLoadOptionSize
;
113 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", LoadOptionIndex
);
115 Status
= GetEnvironmentVariable (BootVariableName
, NULL
, &EfiLoadOptionSize
, (VOID
**)&EfiLoadOption
);
116 if (!EFI_ERROR(Status
)) {
117 Status
= BootOptionParseLoadOption (EfiLoadOption
,EfiLoadOptionSize
,BdsLoadOption
);
118 if (!EFI_ERROR(Status
)) {
119 (*BdsLoadOption
)->LoadOptionIndex
= LoadOptionIndex
;
128 IN OUT LIST_ENTRY
*BootOptionList
135 BDS_LOAD_OPTION
*BdsLoadOption
;
137 InitializeListHead (BootOptionList
);
139 // Get the Boot Option Order from the environment variable
140 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
141 if (EFI_ERROR(Status
)) {
145 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
146 Status
= BootOptionFromLoadOptionVariable (BootOrder
[Index
],&BdsLoadOption
);
147 if (!EFI_ERROR(Status
)) {
148 InsertTailList (BootOptionList
,&BdsLoadOption
->Link
);
156 BootOptionAllocateBootIndex (
167 // Get the Boot Option Order from the environment variable
168 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
169 if (!EFI_ERROR(Status
)) {
170 for (BootIndex
= 0; BootIndex
<= 0xFFFF; BootIndex
++) {
172 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
173 if (BootOrder
[Index
] == BootIndex
) {
183 // Return the first index
189 BootOptionSetFields (
190 IN BDS_LOAD_OPTION
* BootOption
,
191 IN UINT32 Attributes
,
192 IN CHAR16
* BootDescription
,
193 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
194 IN BDS_LOADER_TYPE BootType
,
195 IN BDS_LOADER_ARGUMENTS
* BootArguments
198 EFI_LOAD_OPTION EfiLoadOption
;
199 UINTN EfiLoadOptionSize
;
200 UINTN BootDescriptionSize
;
201 UINTN BootOptionalDataSize
;
202 UINT16 FilePathListLength
;
203 UINT16 InitrdPathListLength
;
204 EFI_DEVICE_PATH_PROTOCOL
* DevicePathNode
;
205 EFI_DEVICE_PATH_PROTOCOL
* InitrdPathNode
;
207 UINT8
* EfiLoadOptionPtr
;
208 UINT8
*InitrdPathListPtr
;
210 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
211 if (BootOption
->LoadOption
) {
212 FreePool(BootOption
->LoadOption
);
215 BootDescriptionSize
= StrSize(BootDescription
);
216 BootOptionalDataSize
= sizeof(BDS_LOADER_TYPE
) + (BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
?
217 (sizeof(UINT16
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
*) + BOOT_DEVICE_OPTION_MAX
+ 1)
220 // Compute the size of the FilePath list
221 FilePathListLength
= 0;
222 DevicePathNode
= DevicePath
;
223 while (!IsDevicePathEndType (DevicePathNode
)) {
224 FilePathListLength
+= DevicePathNodeLength (DevicePathNode
);
225 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
227 // Add the length of the DevicePath EndType
228 FilePathListLength
+= DevicePathNodeLength (DevicePathNode
);
230 InitrdPathListLength
= 0;
231 if (BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
&& BootArguments
->LinuxAtagArguments
.InitrdPathList
!= NULL
) {
232 // Compute the size of the InitrdPath list
233 InitrdPathNode
= BootArguments
->LinuxAtagArguments
.InitrdPathList
;
234 while (!IsDevicePathEndType (InitrdPathNode
)) {
235 InitrdPathListLength
+= DevicePathNodeLength (InitrdPathNode
);
236 InitrdPathNode
= NextDevicePathNode (InitrdPathNode
);
238 // Add the length of the DevicePath EndType
239 InitrdPathListLength
+= DevicePathNodeLength (InitrdPathNode
);
242 // Allocate the memory for the EFI Load Option
243 EfiLoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + BootDescriptionSize
+ FilePathListLength
+ BootOptionalDataSize
;
244 EfiLoadOption
= (EFI_LOAD_OPTION
)AllocatePool(EfiLoadOptionSize
);
245 EfiLoadOptionPtr
= EfiLoadOption
;
248 // Populate the EFI Load Option and BDS Boot Option structures
252 BootOption
->Attributes
= Attributes
;
253 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
254 EfiLoadOptionPtr
+= sizeof(UINT32
);
256 // FilePath List fields
257 BootOption
->FilePathListLength
= FilePathListLength
;
258 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
259 EfiLoadOptionPtr
+= sizeof(UINT16
);
261 // Boot description fields
262 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
263 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
264 EfiLoadOptionPtr
+= BootDescriptionSize
;
267 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
268 DevicePathNode
= DevicePath
;
269 while (!IsDevicePathEndType (DevicePathNode
)) {
270 NodeLength
= DevicePathNodeLength(DevicePathNode
);
271 CopyMem (EfiLoadOptionPtr
, DevicePathNode
, NodeLength
);
272 EfiLoadOptionPtr
+= NodeLength
;
273 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
276 // Set the End Device Path Type
277 SetDevicePathEndNode (EfiLoadOptionPtr
);
278 EfiLoadOptionPtr
= (UINT8
*)EfiLoadOptionPtr
+ sizeof(EFI_DEVICE_PATH
);
280 // Optional Data fields, Do unaligned writes
281 WriteUnaligned32 ((UINT32
*)EfiLoadOptionPtr
, BootType
);
283 BootOption
->OptionalData
= (BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
;
285 if (BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
286 CopyMem (&((BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
)->Arguments
.LinuxAtagArguments
.CmdLine
,
287 BootArguments
->LinuxAtagArguments
.CmdLine
,
288 AsciiStrSize(BootArguments
->LinuxAtagArguments
.CmdLine
));
290 WriteUnaligned32 ((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathListLength
), InitrdPathListLength
);
292 if ((EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
) != NULL
293 && BootArguments
->LinuxAtagArguments
.InitrdPathList
!= NULL
) {
294 InitrdPathListPtr
= AllocatePool(InitrdPathListLength
);
295 WriteUnaligned32 ((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
), (UINT32
)InitrdPathListPtr
);
296 InitrdPathNode
= BootArguments
->LinuxAtagArguments
.InitrdPathList
;
298 while (!IsDevicePathEndType (InitrdPathNode
)) {
299 NodeLength
= DevicePathNodeLength(InitrdPathNode
);
300 CopyMem (InitrdPathListPtr
, InitrdPathNode
, NodeLength
);
301 InitrdPathListPtr
+= NodeLength
;
302 InitrdPathNode
= NextDevicePathNode (InitrdPathNode
);
305 // Set the End Device Path Type
306 SetDevicePathEndNode (InitrdPathListPtr
);
308 WriteUnaligned32 ((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
), (UINT32
)NULL
);
311 // If this function is called at the creation of the Boot Device entry (not at the update) the
312 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
313 if (BootOption
->LoadOptionSize
== 0) {
314 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex();
317 // Fill the EFI Load option fields
318 BootOption
->LoadOption
= EfiLoadOption
;
319 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
326 IN UINT32 Attributes
,
327 IN CHAR16
* BootDescription
,
328 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
329 IN BDS_LOADER_TYPE BootType
,
330 IN BDS_LOADER_ARGUMENTS
* BootArguments
,
331 OUT BDS_LOAD_OPTION
**BdsLoadOption
335 BDS_LOAD_OPTION
*BootOption
;
336 CHAR16 BootVariableName
[9];
341 // Allocate and fill the memory for the BDS Load Option structure
343 BootOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION
));
345 InitializeListHead (&BootOption
->Link
);
346 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
349 // Set the related environment variables
352 // Create Boot#### environment variable
353 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
354 Status
= gRT
->SetVariable (
356 &gEfiGlobalVariableGuid
,
357 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
358 BootOption
->LoadOptionSize
,
359 BootOption
->LoadOption
362 // Add the new Boot Index to the list
363 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
364 if (!EFI_ERROR(Status
)) {
365 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
366 // Add the new index at the end
367 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
368 BootOrderSize
+= sizeof(UINT16
);
370 // BootOrder does not exist. Create it
371 BootOrderSize
= sizeof(UINT16
);
372 BootOrder
= &(BootOption
->LoadOptionIndex
);
375 // Update (or Create) the BootOrder environment variable
376 Status
= gRT
->SetVariable (
378 &gEfiGlobalVariableGuid
,
379 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
384 *BdsLoadOption
= BootOption
;
390 IN BDS_LOAD_OPTION
*BdsLoadOption
,
391 IN UINT32 Attributes
,
392 IN CHAR16
* BootDescription
,
393 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
394 IN BDS_LOADER_TYPE BootType
,
395 IN BDS_LOADER_ARGUMENTS
* BootArguments
399 CHAR16 BootVariableName
[9];
401 // Update the BDS Load Option structure
402 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
404 // Update the related environment variables
405 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
407 Status
= gRT
->SetVariable (
409 &gEfiGlobalVariableGuid
,
410 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
411 BdsLoadOption
->LoadOptionSize
,
412 BdsLoadOption
->LoadOption
420 IN BDS_LOAD_OPTION
*BootOption
426 UINTN BootOrderCount
;
429 // If the Boot Optiono was attached to a list remove it
430 if (!IsListEmpty (&BootOption
->Link
)) {
431 // Remove the entry from the list
432 RemoveEntryList (&BootOption
->Link
);
435 // Remove the entry from the BootOrder environment variable
436 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
437 if (!EFI_ERROR(Status
)) {
438 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
440 // Find the index of the removed entry
441 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
442 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
443 // If it the last entry we do not need to rearrange the BootOrder list
444 if (Index
+ 1 != BootOrderCount
) {
445 CopyMem (&BootOrder
[Index
],&BootOrder
[Index
+1], BootOrderCount
- (Index
+ 1));
451 // Update the BootOrder environment variable
452 Status
= gRT
->SetVariable (
454 &gEfiGlobalVariableGuid
,
455 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
456 BootOrderSize
- sizeof(UINT16
),