3 * Copyright (c) 2011-2013, 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_FROM_TEXT_PROTOCOL
* EfiDevicePathFromTextProtocol
;
27 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
28 ARM_BDS_LINUX_ARGUMENTS
* LinuxArguments
;
29 EFI_DEVICE_PATH_PROTOCOL
* FdtDevicePath
;
30 EFI_DEVICE_PATH_PROTOCOL
* DefaultFdtDevicePath
;
31 UINTN FdtDevicePathSize
;
34 EFI_DEVICE_PATH
* Initrd
;
35 UINT16 LoadOptionIndexSize
;
37 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
38 Status
= EFI_UNSUPPORTED
;
39 OptionalData
= BootOption
->OptionalData
;
40 LoaderType
= ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
42 if (LoaderType
== BDS_LOADER_EFI_APPLICATION
) {
43 // Need to connect every drivers to ensure no dependencies are missing for the application
44 BdsConnectAllDrivers();
46 Status
= BdsStartEfiApplication (mImageHandle
, BootOption
->FilePathList
, 0, NULL
);
47 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
48 LinuxArguments
= &(OptionalData
->Arguments
.LinuxArguments
);
49 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
50 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
53 Initrd
= GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
));
58 Status
= BdsBootLinuxAtag (BootOption
->FilePathList
,
60 (CHAR8
*)(LinuxArguments
+ 1)); // CmdLine
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
);
67 Initrd
= GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
));
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
));
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
);
82 Status
= BdsBootLinuxFdt (BootOption
->FilePathList
,
84 (CHAR8
*)(LinuxArguments
+ 1),
87 FreePool (FdtDevicePath
);
90 // Set BootCurrent variable
91 LoadOptionIndexSize
= sizeof(UINT16
);
92 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
93 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
94 LoadOptionIndexSize
, &(BootOption
->LoadOptionIndex
));
96 Status
= BdsStartEfiApplication (mImageHandle
, BootOption
->FilePathList
, BootOption
->OptionalDataSize
, BootOption
->OptionalData
);
98 // Clear BootCurrent variable
99 LoadOptionIndexSize
= sizeof(UINT16
);
100 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
101 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
110 IN OUT LIST_ENTRY
*BootOptionList
117 BDS_LOAD_OPTION
* BdsLoadOption
;
118 BDS_LOAD_OPTION_ENTRY
* BdsLoadOptionEntry
;
120 InitializeListHead (BootOptionList
);
122 // Get the Boot Option Order from the environment variable
123 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
124 if (EFI_ERROR(Status
)) {
128 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
129 Status
= BootOptionFromLoadOptionIndex (BootOrder
[Index
], &BdsLoadOption
);
130 if (!EFI_ERROR(Status
)) {
131 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY
));
132 BdsLoadOptionEntry
->BdsLoadOption
= BdsLoadOption
;
133 InsertTailList (BootOptionList
,&BdsLoadOptionEntry
->Link
);
137 FreePool (BootOrder
);
144 BootOptionSetFields (
145 IN BDS_LOAD_OPTION
* BootOption
,
146 IN UINT32 Attributes
,
147 IN CHAR16
* BootDescription
,
148 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
149 IN ARM_BDS_LOADER_TYPE BootType
,
150 IN ARM_BDS_LOADER_ARGUMENTS
* BootArguments
153 EFI_LOAD_OPTION EfiLoadOption
;
154 UINTN EfiLoadOptionSize
;
155 UINTN BootDescriptionSize
;
156 UINTN BootOptionalDataSize
;
157 UINT16 FilePathListLength
;
158 UINT8
* EfiLoadOptionPtr
;
159 UINT8
* InitrdPathListPtr
;
160 UINTN OptionalDataSize
;
161 ARM_BDS_LINUX_ARGUMENTS
* DestLinuxArguments
;
162 ARM_BDS_LINUX_ARGUMENTS
* SrcLinuxArguments
;
164 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
165 if (BootOption
->LoadOption
) {
166 FreePool(BootOption
->LoadOption
);
169 BootDescriptionSize
= StrSize (BootDescription
);
170 BootOptionalDataSize
= sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER
);
171 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
172 BootOptionalDataSize
+= sizeof(ARM_BDS_LINUX_ARGUMENTS
) + BootArguments
->LinuxArguments
.CmdLineSize
+ BootArguments
->LinuxArguments
.InitrdSize
;
175 // Compute the size of the FilePath list
176 FilePathListLength
= GetUnalignedDevicePathSize (DevicePath
);
178 // Allocate the memory for the EFI Load Option
179 EfiLoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + BootDescriptionSize
+ FilePathListLength
+ BootOptionalDataSize
;
180 EfiLoadOption
= (EFI_LOAD_OPTION
)AllocatePool(EfiLoadOptionSize
);
181 EfiLoadOptionPtr
= EfiLoadOption
;
184 // Populate the EFI Load Option and BDS Boot Option structures
188 BootOption
->Attributes
= Attributes
;
189 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
190 EfiLoadOptionPtr
+= sizeof(UINT32
);
192 // FilePath List fields
193 BootOption
->FilePathListLength
= FilePathListLength
;
194 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
195 EfiLoadOptionPtr
+= sizeof(UINT16
);
197 // Boot description fields
198 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
199 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
200 EfiLoadOptionPtr
+= BootDescriptionSize
;
203 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
204 CopyMem (EfiLoadOptionPtr
, DevicePath
, FilePathListLength
);
205 EfiLoadOptionPtr
+= FilePathListLength
;
207 // Optional Data fields, Do unaligned writes
208 BootOption
->OptionalData
= EfiLoadOptionPtr
;
209 WriteUnaligned32 ((UINT32
*)EfiLoadOptionPtr
, ARM_BDS_OPTIONAL_DATA_SIGNATURE
);
210 WriteUnaligned32 ((UINT32
*)(EfiLoadOptionPtr
+ 4), BootType
);
212 OptionalDataSize
= sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER
);
214 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
215 SrcLinuxArguments
= &(BootArguments
->LinuxArguments
);
216 DestLinuxArguments
= &((ARM_BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
)->Arguments
.LinuxArguments
;
218 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->CmdLineSize
);
219 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->InitrdSize
), SrcLinuxArguments
->InitrdSize
);
220 OptionalDataSize
+= sizeof (ARM_BDS_LINUX_ARGUMENTS
);
222 if (SrcLinuxArguments
->CmdLineSize
> 0) {
223 CopyMem ((VOID
*)(DestLinuxArguments
+ 1), (VOID
*)(SrcLinuxArguments
+ 1), SrcLinuxArguments
->CmdLineSize
);
224 OptionalDataSize
+= SrcLinuxArguments
->CmdLineSize
;
227 if (SrcLinuxArguments
->InitrdSize
> 0) {
228 InitrdPathListPtr
= (UINT8
*)((UINTN
)(DestLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
);
229 CopyMem (InitrdPathListPtr
, (VOID
*)((UINTN
)(SrcLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->InitrdSize
);
232 BootOption
->OptionalDataSize
= OptionalDataSize
;
234 // If this function is called at the creation of the Boot Device entry (not at the update) the
235 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
236 if (BootOption
->LoadOptionSize
== 0) {
237 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex ();
240 // Fill the EFI Load option fields
241 BootOption
->LoadOption
= EfiLoadOption
;
242 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
249 IN UINT32 Attributes
,
250 IN CHAR16
* BootDescription
,
251 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
252 IN ARM_BDS_LOADER_TYPE BootType
,
253 IN ARM_BDS_LOADER_ARGUMENTS
* BootArguments
,
254 OUT BDS_LOAD_OPTION
** BdsLoadOption
258 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
259 BDS_LOAD_OPTION
* BootOption
;
260 CHAR16 BootVariableName
[9];
265 // Allocate and fill the memory for the BDS Load Option structure
267 BootOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY
));
268 InitializeListHead (&BootOptionEntry
->Link
);
269 BootOptionEntry
->BdsLoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
271 BootOption
= BootOptionEntry
->BdsLoadOption
;
272 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
275 // Set the related environment variables
278 // Create Boot#### environment variable
279 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
280 Status
= gRT
->SetVariable (
282 &gEfiGlobalVariableGuid
,
283 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
284 BootOption
->LoadOptionSize
,
285 BootOption
->LoadOption
288 // Add the new Boot Index to the list
289 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
290 if (!EFI_ERROR(Status
)) {
291 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
292 // Add the new index at the end
293 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
294 BootOrderSize
+= sizeof(UINT16
);
296 // BootOrder does not exist. Create it
297 BootOrderSize
= sizeof(UINT16
);
298 BootOrder
= &(BootOption
->LoadOptionIndex
);
301 // Update (or Create) the BootOrder environment variable
302 Status
= gRT
->SetVariable (
304 &gEfiGlobalVariableGuid
,
305 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
310 // We only free it if the UEFI Variable 'BootOrder' was already existing
311 if (BootOrderSize
> sizeof(UINT16
)) {
312 FreePool (BootOrder
);
315 *BdsLoadOption
= BootOption
;
321 IN BDS_LOAD_OPTION
* BdsLoadOption
,
322 IN UINT32 Attributes
,
323 IN CHAR16
* BootDescription
,
324 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
325 IN ARM_BDS_LOADER_TYPE BootType
,
326 IN ARM_BDS_LOADER_ARGUMENTS
* BootArguments
330 CHAR16 BootVariableName
[9];
332 // Update the BDS Load Option structure
333 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, BootArguments
);
335 // Update the related environment variables
336 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
338 Status
= gRT
->SetVariable (
340 &gEfiGlobalVariableGuid
,
341 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
342 BdsLoadOption
->LoadOptionSize
,
343 BdsLoadOption
->LoadOption
351 IN BDS_LOAD_OPTION
*BootOption
357 UINTN BootOrderCount
;
360 // Remove the entry from the BootOrder environment variable
361 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
362 if (!EFI_ERROR(Status
)) {
363 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
365 // Find the index of the removed entry
366 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
367 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
368 // If it the last entry we do not need to rearrange the BootOrder list
369 if (Index
+ 1 != BootOrderCount
) {
372 &BootOrder
[Index
+ 1],
373 (BootOrderCount
- (Index
+ 1)) * sizeof(UINT16
)
380 // Update the BootOrder environment variable
381 Status
= gRT
->SetVariable (
383 &gEfiGlobalVariableGuid
,
384 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
385 BootOrderSize
- sizeof(UINT16
),
390 FreePool (BootOrder
);