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
;
28 Status
= EFI_UNSUPPORTED
;
30 if (BootOption
->OptionalData
->LoaderType
== BDS_LOADER_EFI_APPLICATION
) {
31 // Need to connect every drivers to ensure no dependencies are missing for the application
32 BdsConnectAllDrivers();
34 Status
= BdsStartEfiApplication (mImageHandle
, BootOption
->FilePathList
);
35 } else if (BootOption
->OptionalData
->LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
36 Status
= BdsBootLinux (BootOption
->FilePathList
, BootOption
->OptionalData
->Arguments
, NULL
);
37 } else if (BootOption
->OptionalData
->LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
) {
38 // Convert the FDT path into a Device Path
39 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
40 ASSERT_EFI_ERROR(Status
);
41 FdtDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath ((CHAR16
*)PcdGetPtr(PcdFdtDevicePath
));
43 Status
= BdsBootLinux (BootOption
->FilePathList
, BootOption
->OptionalData
->Arguments
, FdtDevicePath
);
44 FreePool(FdtDevicePath
);
51 BootOptionParseLoadOption (
52 IN EFI_LOAD_OPTION EfiLoadOption
,
53 IN UINTN EfiLoadOptionSize
,
54 OUT BDS_LOAD_OPTION
**BdsLoadOption
57 BDS_LOAD_OPTION
*LoadOption
;
58 UINTN FilePathListLength
;
59 UINTN DescriptionLength
;
61 if (EfiLoadOption
== NULL
) {
62 return EFI_INVALID_PARAMETER
;
65 if (EfiLoadOptionSize
< sizeof(UINT32
) + sizeof(UINT16
) + sizeof(CHAR16
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
)) {
66 return EFI_BAD_BUFFER_SIZE
;
69 LoadOption
= (BDS_LOAD_OPTION
*)AllocatePool(sizeof(BDS_LOAD_OPTION
));
70 if (LoadOption
== NULL
) {
71 return EFI_OUT_OF_RESOURCES
;
74 LoadOption
->LoadOption
= EfiLoadOption
;
75 LoadOption
->LoadOptionSize
= EfiLoadOptionSize
;
77 LoadOption
->Attributes
= *(UINT32
*)EfiLoadOption
;
78 FilePathListLength
= *(UINT16
*)(EfiLoadOption
+ sizeof(UINT32
));
79 LoadOption
->Description
= (CHAR16
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
));
80 DescriptionLength
= StrSize (LoadOption
->Description
);
81 LoadOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
) + DescriptionLength
);
83 if ((UINTN
)((UINT8
*)LoadOption
->FilePathList
+ FilePathListLength
- EfiLoadOption
) == EfiLoadOptionSize
) {
84 LoadOption
->OptionalData
= NULL
;
86 LoadOption
->OptionalData
= (BDS_LOADER_OPTIONAL_DATA
*)((UINT8
*)LoadOption
->FilePathList
+ FilePathListLength
);
89 *BdsLoadOption
= LoadOption
;
94 BootOptionFromLoadOptionVariable (
95 IN UINT16 LoadOptionIndex
,
96 OUT BDS_LOAD_OPTION
**BdsLoadOption
100 CHAR16 BootVariableName
[9];
101 EFI_LOAD_OPTION EfiLoadOption
;
102 UINTN EfiLoadOptionSize
;
104 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", LoadOptionIndex
);
106 Status
= GetEnvironmentVariable (BootVariableName
, NULL
, &EfiLoadOptionSize
, (VOID
**)&EfiLoadOption
);
107 if (!EFI_ERROR(Status
)) {
108 Status
= BootOptionParseLoadOption (EfiLoadOption
,EfiLoadOptionSize
,BdsLoadOption
);
109 if (!EFI_ERROR(Status
)) {
110 (*BdsLoadOption
)->LoadOptionIndex
= LoadOptionIndex
;
119 IN OUT LIST_ENTRY
*BootOptionList
126 BDS_LOAD_OPTION
*BdsLoadOption
;
128 InitializeListHead (BootOptionList
);
130 // Get the Boot Option Order from the environment variable
131 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
132 if (EFI_ERROR(Status
)) {
136 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
137 Status
= BootOptionFromLoadOptionVariable (BootOrder
[Index
],&BdsLoadOption
);
138 if (!EFI_ERROR(Status
)) {
139 InsertTailList (BootOptionList
,&BdsLoadOption
->Link
);
147 BootOptionAllocateBootIndex (
158 // Get the Boot Option Order from the environment variable
159 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
160 if (!EFI_ERROR(Status
)) {
161 for (BootIndex
= 0; BootIndex
<= 0xFFFF; BootIndex
++) {
163 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
164 if (BootOrder
[Index
] == BootIndex
) {
174 // Return the first index
180 BootOptionSetFields (
181 IN BDS_LOAD_OPTION
*BootOption
,
182 IN UINT32 Attributes
,
183 IN CHAR16
* BootDescription
,
184 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
185 IN BDS_LOADER_TYPE BootType
,
186 IN CHAR8
* BootArguments
189 EFI_LOAD_OPTION EfiLoadOption
;
190 UINTN EfiLoadOptionSize
;
191 UINTN BootDescriptionSize
;
192 UINTN BootOptionalDataSize
;
193 UINT16 FilePathListLength
;
194 EFI_DEVICE_PATH_PROTOCOL
* DevicePathNode
;
196 UINT8
* EfiLoadOptionPtr
;
198 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
199 if (BootOption
->LoadOption
) {
200 FreePool(BootOption
->LoadOption
);
203 BootDescriptionSize
= StrSize(BootDescription
);
204 BootOptionalDataSize
= sizeof(BDS_LOADER_OPTIONAL_DATA
) +
205 (BootArguments
== NULL
? 0 : AsciiStrSize(BootArguments
));
207 // Compute the size of the FilePath list
208 FilePathListLength
= 0;
209 DevicePathNode
= DevicePath
;
210 while (!IsDevicePathEndType (DevicePathNode
)) {
211 FilePathListLength
+= DevicePathNodeLength (DevicePathNode
);
212 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
214 // Add the length of the DevicePath EndType
215 FilePathListLength
+= DevicePathNodeLength (DevicePathNode
);
217 // Allocate the memory for the EFI Load Option
218 EfiLoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + BootDescriptionSize
+ FilePathListLength
+ BootOptionalDataSize
;
219 EfiLoadOption
= (EFI_LOAD_OPTION
)AllocatePool(EfiLoadOptionSize
);
220 EfiLoadOptionPtr
= EfiLoadOption
;
223 // Populate the EFI Load Option and BDS Boot Option structures
227 BootOption
->Attributes
= Attributes
;
228 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
229 EfiLoadOptionPtr
+= sizeof(UINT32
);
231 // FilePath List fields
232 BootOption
->FilePathListLength
= FilePathListLength
;
233 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
234 EfiLoadOptionPtr
+= sizeof(UINT16
);
236 // Boot description fields
237 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
238 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
239 EfiLoadOptionPtr
+= BootDescriptionSize
;
242 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
243 DevicePathNode
= DevicePath
;
244 while (!IsDevicePathEndType (DevicePathNode
)) {
245 NodeLength
= DevicePathNodeLength(DevicePathNode
);
246 CopyMem (EfiLoadOptionPtr
, DevicePathNode
, NodeLength
);
247 EfiLoadOptionPtr
+= NodeLength
;
248 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
251 // Set the End Device Path Type
252 SetDevicePathEndNode (EfiLoadOptionPtr
);
253 EfiLoadOptionPtr
= (UINT8
*)EfiLoadOptionPtr
+ sizeof(EFI_DEVICE_PATH
);
255 // Optional Data fields, Do unaligned writes
256 WriteUnaligned32 ((UINT32
*)EfiLoadOptionPtr
, BootType
);
258 CopyMem (&((BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
)->Arguments
, BootArguments
, AsciiStrSize(BootArguments
));
259 BootOption
->OptionalData
= (BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
;
261 // If this function is called at the creation of the Boot Device entry (not at the update) the
262 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
263 if (BootOption
->LoadOptionSize
== 0) {
264 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex();
267 // Fill the EFI Load option fields
268 BootOption
->LoadOption
= EfiLoadOption
;
269 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
276 IN UINT32 Attributes
,
277 IN CHAR16
* BootDescription
,
278 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
279 IN BDS_LOADER_TYPE BootType
,
280 IN CHAR8
* BootArguments
,
281 OUT BDS_LOAD_OPTION
**BdsLoadOption
285 BDS_LOAD_OPTION
*BootOption
;
286 CHAR16 BootVariableName
[9];
291 // Allocate and fill the memory for the BDS Load Option structure
293 BootOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION
));
295 InitializeListHead (&BootOption
->Link
);
296 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
299 // Set the related environment variables
302 // Create Boot#### environment variable
303 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
304 Status
= gRT
->SetVariable (
306 &gEfiGlobalVariableGuid
,
307 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
308 BootOption
->LoadOptionSize
,
309 BootOption
->LoadOption
312 // Add the new Boot Index to the list
313 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
314 if (!EFI_ERROR(Status
)) {
315 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
316 // Add the new index at the end
317 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
318 BootOrderSize
+= sizeof(UINT16
);
320 // BootOrder does not exist. Create it
321 BootOrderSize
= sizeof(UINT16
);
322 BootOrder
= &(BootOption
->LoadOptionIndex
);
325 // Update (or Create) the BootOrder environment variable
326 Status
= gRT
->SetVariable (
328 &gEfiGlobalVariableGuid
,
329 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
334 *BdsLoadOption
= BootOption
;
340 IN BDS_LOAD_OPTION
*BdsLoadOption
,
341 IN UINT32 Attributes
,
342 IN CHAR16
* BootDescription
,
343 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
344 IN BDS_LOADER_TYPE BootType
,
345 IN CHAR8
* BootArguments
349 CHAR16 BootVariableName
[9];
351 // Update the BDS Load Option structure
352 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
354 // Update the related environment variables
355 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
357 Status
= gRT
->SetVariable (
359 &gEfiGlobalVariableGuid
,
360 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
361 BdsLoadOption
->LoadOptionSize
,
362 BdsLoadOption
->LoadOption
370 IN BDS_LOAD_OPTION
*BootOption
376 UINTN BootOrderCount
;
379 // If the Boot Optiono was attached to a list remove it
380 if (!IsListEmpty (&BootOption
->Link
)) {
381 // Remove the entry from the list
382 RemoveEntryList (&BootOption
->Link
);
385 // Remove the entry from the BootOrder environment variable
386 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
387 if (!EFI_ERROR(Status
)) {
388 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
390 // Find the index of the removed entry
391 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
392 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
393 // If it the last entry we do not need to rearrange the BootOrder list
394 if (Index
+ 1 != BootOrderCount
) {
395 CopyMem (&BootOrder
[Index
],&BootOrder
[Index
+1], BootOrderCount
- (Index
+ 1));
401 // Update the BootOrder environment variable
402 Status
= gRT
->SetVariable (
404 &gEfiGlobalVariableGuid
,
405 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
406 BootOrderSize
- sizeof(UINT16
),