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 // Fill the EFI Load option fields
262 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex();
263 BootOption
->LoadOption
= EfiLoadOption
;
264 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
271 IN UINT32 Attributes
,
272 IN CHAR16
* BootDescription
,
273 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
274 IN BDS_LOADER_TYPE BootType
,
275 IN CHAR8
* BootArguments
,
276 OUT BDS_LOAD_OPTION
**BdsLoadOption
280 BDS_LOAD_OPTION
*BootOption
;
281 CHAR16 BootVariableName
[9];
286 // Allocate and fill the memory for the BDS Load Option structure
288 BootOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION
));
290 InitializeListHead (&BootOption
->Link
);
291 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
294 // Set the related environment variables
297 // Create Boot#### environment variable
298 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
299 Status
= gRT
->SetVariable (
301 &gEfiGlobalVariableGuid
,
302 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
303 BootOption
->LoadOptionSize
,
304 BootOption
->LoadOption
307 // Add the new Boot Index to the list
308 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
309 if (!EFI_ERROR(Status
)) {
310 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
311 // Add the new index at the end
312 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
313 BootOrderSize
+= sizeof(UINT16
);
315 // BootOrder does not exist. Create it
316 BootOrderSize
= sizeof(UINT16
);
317 BootOrder
= &(BootOption
->LoadOptionIndex
);
320 // Update (or Create) the BootOrder environment variable
321 Status
= gRT
->SetVariable (
323 &gEfiGlobalVariableGuid
,
324 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
329 *BdsLoadOption
= BootOption
;
335 IN BDS_LOAD_OPTION
*BdsLoadOption
,
336 IN UINT32 Attributes
,
337 IN CHAR16
* BootDescription
,
338 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
339 IN BDS_LOADER_TYPE BootType
,
340 IN CHAR8
* BootArguments
344 BDS_LOAD_OPTION
*BootOption
;
345 CHAR16 BootVariableName
[9];
347 // Update the BDS Load Option structure
348 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
350 // Update the related environment variables
351 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
352 Status
= gRT
->SetVariable (
354 &gEfiGlobalVariableGuid
,
355 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
356 BootOption
->LoadOptionSize
,
357 BootOption
->LoadOption
365 IN BDS_LOAD_OPTION
*BootOption
371 UINTN BootOrderCount
;
374 // If the Boot Optiono was attached to a list remove it
375 if (!IsListEmpty (&BootOption
->Link
)) {
376 // Remove the entry from the list
377 RemoveEntryList (&BootOption
->Link
);
380 // Remove the entry from the BootOrder environment variable
381 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
382 if (!EFI_ERROR(Status
)) {
383 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
385 // Find the index of the removed entry
386 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
387 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
388 // If it the last entry we do not need to rearrange the BootOrder list
389 if (Index
+ 1 != BootOrderCount
) {
390 CopyMem (&BootOrder
[Index
],&BootOrder
[Index
+1], BootOrderCount
- (Index
+ 1));
396 // Update the BootOrder environment variable
397 Status
= gRT
->SetVariable (
399 &gEfiGlobalVariableGuid
,
400 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
401 BootOrderSize
- sizeof(UINT16
),