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
, BootOption
->OptionalData
->Arguments
, NULL
);
39 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
) {
40 // Convert the FDT path into a Device Path
41 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
42 ASSERT_EFI_ERROR(Status
);
43 FdtDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath ((CHAR16
*)PcdGetPtr(PcdFdtDevicePath
));
45 Status
= BdsBootLinux (BootOption
->FilePathList
, BootOption
->OptionalData
->Arguments
, FdtDevicePath
);
46 FreePool(FdtDevicePath
);
53 BootOptionParseLoadOption (
54 IN EFI_LOAD_OPTION EfiLoadOption
,
55 IN UINTN EfiLoadOptionSize
,
56 OUT BDS_LOAD_OPTION
**BdsLoadOption
59 BDS_LOAD_OPTION
*LoadOption
;
60 UINTN FilePathListLength
;
61 UINTN DescriptionLength
;
63 if (EfiLoadOption
== NULL
) {
64 return EFI_INVALID_PARAMETER
;
67 if (EfiLoadOptionSize
< sizeof(UINT32
) + sizeof(UINT16
) + sizeof(CHAR16
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
)) {
68 return EFI_BAD_BUFFER_SIZE
;
71 LoadOption
= (BDS_LOAD_OPTION
*)AllocatePool(sizeof(BDS_LOAD_OPTION
));
72 if (LoadOption
== NULL
) {
73 return EFI_OUT_OF_RESOURCES
;
76 LoadOption
->LoadOption
= EfiLoadOption
;
77 LoadOption
->LoadOptionSize
= EfiLoadOptionSize
;
79 LoadOption
->Attributes
= *(UINT32
*)EfiLoadOption
;
80 FilePathListLength
= *(UINT16
*)(EfiLoadOption
+ sizeof(UINT32
));
81 LoadOption
->Description
= (CHAR16
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
));
82 DescriptionLength
= StrSize (LoadOption
->Description
);
83 LoadOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
) + DescriptionLength
);
85 if ((UINTN
)((UINT8
*)LoadOption
->FilePathList
+ FilePathListLength
- EfiLoadOption
) == EfiLoadOptionSize
) {
86 LoadOption
->OptionalData
= NULL
;
88 LoadOption
->OptionalData
= (BDS_LOADER_OPTIONAL_DATA
*)((UINT8
*)LoadOption
->FilePathList
+ FilePathListLength
);
91 *BdsLoadOption
= LoadOption
;
96 BootOptionFromLoadOptionVariable (
97 IN UINT16 LoadOptionIndex
,
98 OUT BDS_LOAD_OPTION
**BdsLoadOption
102 CHAR16 BootVariableName
[9];
103 EFI_LOAD_OPTION EfiLoadOption
;
104 UINTN EfiLoadOptionSize
;
106 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", LoadOptionIndex
);
108 Status
= GetEnvironmentVariable (BootVariableName
, NULL
, &EfiLoadOptionSize
, (VOID
**)&EfiLoadOption
);
109 if (!EFI_ERROR(Status
)) {
110 Status
= BootOptionParseLoadOption (EfiLoadOption
,EfiLoadOptionSize
,BdsLoadOption
);
111 if (!EFI_ERROR(Status
)) {
112 (*BdsLoadOption
)->LoadOptionIndex
= LoadOptionIndex
;
121 IN OUT LIST_ENTRY
*BootOptionList
128 BDS_LOAD_OPTION
*BdsLoadOption
;
130 InitializeListHead (BootOptionList
);
132 // Get the Boot Option Order from the environment variable
133 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
134 if (EFI_ERROR(Status
)) {
138 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
139 Status
= BootOptionFromLoadOptionVariable (BootOrder
[Index
],&BdsLoadOption
);
140 if (!EFI_ERROR(Status
)) {
141 InsertTailList (BootOptionList
,&BdsLoadOption
->Link
);
149 BootOptionAllocateBootIndex (
160 // Get the Boot Option Order from the environment variable
161 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
162 if (!EFI_ERROR(Status
)) {
163 for (BootIndex
= 0; BootIndex
<= 0xFFFF; BootIndex
++) {
165 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
166 if (BootOrder
[Index
] == BootIndex
) {
176 // Return the first index
182 BootOptionSetFields (
183 IN BDS_LOAD_OPTION
* BootOption
,
184 IN UINT32 Attributes
,
185 IN CHAR16
* BootDescription
,
186 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
187 IN BDS_LOADER_TYPE BootType
,
188 IN CHAR8
* BootArguments
191 EFI_LOAD_OPTION EfiLoadOption
;
192 UINTN EfiLoadOptionSize
;
193 UINTN BootDescriptionSize
;
194 UINTN BootOptionalDataSize
;
195 UINT16 FilePathListLength
;
196 EFI_DEVICE_PATH_PROTOCOL
* DevicePathNode
;
198 UINT8
* EfiLoadOptionPtr
;
200 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
201 if (BootOption
->LoadOption
) {
202 FreePool(BootOption
->LoadOption
);
205 BootDescriptionSize
= StrSize(BootDescription
);
206 BootOptionalDataSize
= sizeof(BDS_LOADER_OPTIONAL_DATA
) +
207 (BootArguments
== NULL
? 0 : AsciiStrSize(BootArguments
));
209 // Compute the size of the FilePath list
210 FilePathListLength
= 0;
211 DevicePathNode
= DevicePath
;
212 while (!IsDevicePathEndType (DevicePathNode
)) {
213 FilePathListLength
+= DevicePathNodeLength (DevicePathNode
);
214 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
216 // Add the length of the DevicePath EndType
217 FilePathListLength
+= DevicePathNodeLength (DevicePathNode
);
219 // Allocate the memory for the EFI Load Option
220 EfiLoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + BootDescriptionSize
+ FilePathListLength
+ BootOptionalDataSize
;
221 EfiLoadOption
= (EFI_LOAD_OPTION
)AllocatePool(EfiLoadOptionSize
);
222 EfiLoadOptionPtr
= EfiLoadOption
;
225 // Populate the EFI Load Option and BDS Boot Option structures
229 BootOption
->Attributes
= Attributes
;
230 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
231 EfiLoadOptionPtr
+= sizeof(UINT32
);
233 // FilePath List fields
234 BootOption
->FilePathListLength
= FilePathListLength
;
235 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
236 EfiLoadOptionPtr
+= sizeof(UINT16
);
238 // Boot description fields
239 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
240 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
241 EfiLoadOptionPtr
+= BootDescriptionSize
;
244 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
245 DevicePathNode
= DevicePath
;
246 while (!IsDevicePathEndType (DevicePathNode
)) {
247 NodeLength
= DevicePathNodeLength(DevicePathNode
);
248 CopyMem (EfiLoadOptionPtr
, DevicePathNode
, NodeLength
);
249 EfiLoadOptionPtr
+= NodeLength
;
250 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
253 // Set the End Device Path Type
254 SetDevicePathEndNode (EfiLoadOptionPtr
);
255 EfiLoadOptionPtr
= (UINT8
*)EfiLoadOptionPtr
+ sizeof(EFI_DEVICE_PATH
);
257 // Optional Data fields, Do unaligned writes
258 WriteUnaligned32 ((UINT32
*)EfiLoadOptionPtr
, BootType
);
260 CopyMem (&((BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
)->Arguments
, BootArguments
, AsciiStrSize(BootArguments
));
261 BootOption
->OptionalData
= (BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
;
263 // If this function is called at the creation of the Boot Device entry (not at the update) the
264 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
265 if (BootOption
->LoadOptionSize
== 0) {
266 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex();
269 // Fill the EFI Load option fields
270 BootOption
->LoadOption
= EfiLoadOption
;
271 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
278 IN UINT32 Attributes
,
279 IN CHAR16
* BootDescription
,
280 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
281 IN BDS_LOADER_TYPE BootType
,
282 IN CHAR8
* BootArguments
,
283 OUT BDS_LOAD_OPTION
**BdsLoadOption
287 BDS_LOAD_OPTION
*BootOption
;
288 CHAR16 BootVariableName
[9];
293 // Allocate and fill the memory for the BDS Load Option structure
295 BootOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION
));
297 InitializeListHead (&BootOption
->Link
);
298 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
301 // Set the related environment variables
304 // Create Boot#### environment variable
305 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
306 Status
= gRT
->SetVariable (
308 &gEfiGlobalVariableGuid
,
309 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
310 BootOption
->LoadOptionSize
,
311 BootOption
->LoadOption
314 // Add the new Boot Index to the list
315 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
316 if (!EFI_ERROR(Status
)) {
317 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
318 // Add the new index at the end
319 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
320 BootOrderSize
+= sizeof(UINT16
);
322 // BootOrder does not exist. Create it
323 BootOrderSize
= sizeof(UINT16
);
324 BootOrder
= &(BootOption
->LoadOptionIndex
);
327 // Update (or Create) the BootOrder environment variable
328 Status
= gRT
->SetVariable (
330 &gEfiGlobalVariableGuid
,
331 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
336 *BdsLoadOption
= BootOption
;
342 IN BDS_LOAD_OPTION
*BdsLoadOption
,
343 IN UINT32 Attributes
,
344 IN CHAR16
* BootDescription
,
345 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
346 IN BDS_LOADER_TYPE BootType
,
347 IN CHAR8
* BootArguments
351 CHAR16 BootVariableName
[9];
353 // Update the BDS Load Option structure
354 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
356 // Update the related environment variables
357 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
359 Status
= gRT
->SetVariable (
361 &gEfiGlobalVariableGuid
,
362 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
363 BdsLoadOption
->LoadOptionSize
,
364 BdsLoadOption
->LoadOption
372 IN BDS_LOAD_OPTION
*BootOption
378 UINTN BootOrderCount
;
381 // If the Boot Optiono was attached to a list remove it
382 if (!IsListEmpty (&BootOption
->Link
)) {
383 // Remove the entry from the list
384 RemoveEntryList (&BootOption
->Link
);
387 // Remove the entry from the BootOrder environment variable
388 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
389 if (!EFI_ERROR(Status
)) {
390 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
392 // Find the index of the removed entry
393 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
394 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
395 // If it the last entry we do not need to rearrange the BootOrder list
396 if (Index
+ 1 != BootOrderCount
) {
397 CopyMem (&BootOrder
[Index
],&BootOrder
[Index
+1], BootOrderCount
- (Index
+ 1));
403 // Update the BootOrder environment variable
404 Status
= gRT
->SetVariable (
406 &gEfiGlobalVariableGuid
,
407 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
408 BootOrderSize
- sizeof(UINT16
),