3 * Copyright (c) 2011-2015, 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 <Guid/ArmGlobalVariableHob.h>
16 #include "BdsInternal.h"
20 IN BDS_LOAD_OPTION
*BootOption
24 UINT16 LoadOptionIndexSize
;
26 // Connect all the drivers if the EFI Application is not a EFI OS Loader
27 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_APP
) {
28 BdsConnectAllDrivers ();
31 // Set BootCurrent variable
32 LoadOptionIndexSize
= sizeof (UINT16
);
33 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
34 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
35 LoadOptionIndexSize
, &(BootOption
->LoadOptionIndex
));
37 Status
= BdsStartEfiApplication (gImageHandle
, BootOption
->FilePathList
, BootOption
->OptionalDataSize
, BootOption
->OptionalData
);
39 // Clear BootCurrent variable
40 LoadOptionIndexSize
= sizeof (UINT16
);
41 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
42 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
50 IN OUT LIST_ENTRY
*BootOptionList
57 BDS_LOAD_OPTION
* BdsLoadOption
;
58 BDS_LOAD_OPTION_ENTRY
* BdsLoadOptionEntry
;
60 InitializeListHead (BootOptionList
);
62 // Get the Boot Option Order from the environment variable
63 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
64 if (EFI_ERROR(Status
)) {
68 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
69 Status
= BootOptionFromLoadOptionIndex (BootOrder
[Index
], &BdsLoadOption
);
70 if (!EFI_ERROR(Status
)) {
71 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY
));
72 BdsLoadOptionEntry
->BdsLoadOption
= BdsLoadOption
;
73 InsertTailList (BootOptionList
,&BdsLoadOptionEntry
->Link
);
85 IN BDS_LOAD_OPTION
* BootOption
,
87 IN CHAR16
* BootDescription
,
88 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
89 IN UINT8
* OptionalData
,
90 IN UINTN OptionalDataSize
93 EFI_LOAD_OPTION
*EfiLoadOption
;
94 UINTN EfiLoadOptionSize
;
95 UINTN BootDescriptionSize
;
96 UINT16 FilePathListLength
;
97 UINT8
* EfiLoadOptionPtr
;
99 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
100 if (BootOption
->LoadOption
) {
101 FreePool (BootOption
->LoadOption
);
104 BootDescriptionSize
= StrSize (BootDescription
);
106 // Compute the size of the FilePath list
107 FilePathListLength
= GetUnalignedDevicePathSize (DevicePath
);
109 // Allocate the memory for the EFI Load Option
110 EfiLoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + BootDescriptionSize
+ FilePathListLength
+ OptionalDataSize
;
111 EfiLoadOption
= (EFI_LOAD_OPTION
*)AllocatePool(EfiLoadOptionSize
);
112 EfiLoadOptionPtr
= (UINT8
*)EfiLoadOption
;
115 // Populate the EFI Load Option and BDS Boot Option structures
119 BootOption
->Attributes
= Attributes
;
120 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
121 EfiLoadOptionPtr
+= sizeof(UINT32
);
123 // FilePath List fields
124 BootOption
->FilePathListLength
= FilePathListLength
;
125 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
126 EfiLoadOptionPtr
+= sizeof(UINT16
);
128 // Boot description fields
129 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
130 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
131 EfiLoadOptionPtr
+= BootDescriptionSize
;
134 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
135 CopyMem (EfiLoadOptionPtr
, DevicePath
, FilePathListLength
);
136 EfiLoadOptionPtr
+= FilePathListLength
;
138 // Optional Data fields, Do unaligned writes
139 BootOption
->OptionalData
= EfiLoadOptionPtr
;
141 if (OptionalData
!= NULL
) {
142 CopyMem (BootOption
->OptionalData
, OptionalData
, OptionalDataSize
);
145 BootOption
->OptionalDataSize
= OptionalDataSize
;
147 // If this function is called at the creation of the Boot Device entry (not at the update) the
148 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
149 if (BootOption
->LoadOptionSize
== 0) {
150 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex ();
153 // Fill the EFI Load option fields
154 BootOption
->LoadOption
= EfiLoadOption
;
155 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
162 IN UINT32 Attributes
,
163 IN CHAR16
* BootDescription
,
164 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
165 IN UINT8
* OptionalData
,
166 IN UINTN OptionalDataSize
,
167 OUT BDS_LOAD_OPTION
** BdsLoadOption
171 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
172 BDS_LOAD_OPTION
* BootOption
;
173 CHAR16 BootVariableName
[9];
178 // Allocate and fill the memory for the BDS Load Option structure
180 BootOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY
));
181 InitializeListHead (&BootOptionEntry
->Link
);
182 BootOptionEntry
->BdsLoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
184 BootOption
= BootOptionEntry
->BdsLoadOption
;
185 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
);
188 // Set the related environment variables
191 // Create Boot#### environment variable
192 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
193 Status
= gRT
->SetVariable (
195 &gEfiGlobalVariableGuid
,
196 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
197 BootOption
->LoadOptionSize
,
198 BootOption
->LoadOption
201 // Add the new Boot Index to the list
202 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
203 if (!EFI_ERROR(Status
)) {
204 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
205 // Add the new index at the end
206 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
207 BootOrderSize
+= sizeof(UINT16
);
209 // BootOrder does not exist. Create it
210 BootOrderSize
= sizeof(UINT16
);
211 BootOrder
= &(BootOption
->LoadOptionIndex
);
214 // Update (or Create) the BootOrder environment variable
215 Status
= gRT
->SetVariable (
217 &gEfiGlobalVariableGuid
,
218 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
223 // We only free it if the UEFI Variable 'BootOrder' was already existing
224 if (BootOrderSize
> sizeof(UINT16
)) {
225 FreePool (BootOrder
);
228 *BdsLoadOption
= BootOption
;
234 IN BDS_LOAD_OPTION
* BdsLoadOption
,
235 IN UINT32 Attributes
,
236 IN CHAR16
* BootDescription
,
237 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
238 IN UINT8
* OptionalData
,
239 IN UINTN OptionalDataSize
243 CHAR16 BootVariableName
[9];
245 // Update the BDS Load Option structure
246 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, OptionalData
, OptionalDataSize
);
248 // Update the related environment variables
249 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
251 Status
= gRT
->SetVariable (
253 &gEfiGlobalVariableGuid
,
254 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
255 BdsLoadOption
->LoadOptionSize
,
256 BdsLoadOption
->LoadOption
264 IN BDS_LOAD_OPTION
*BootOption
270 UINTN BootOrderCount
;
271 CHAR16 BootVariableName
[9];
274 // Remove the entry from the BootOrder environment variable
275 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
276 if (!EFI_ERROR(Status
)) {
277 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
279 // Find the index of the removed entry
280 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
281 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
282 // If it the last entry we do not need to rearrange the BootOrder list
283 if (Index
+ 1 != BootOrderCount
) {
286 &BootOrder
[Index
+ 1],
287 (BootOrderCount
- (Index
+ 1)) * sizeof(UINT16
)
294 // Update the BootOrder environment variable
295 Status
= gRT
->SetVariable (
297 &gEfiGlobalVariableGuid
,
298 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
299 BootOrderSize
- sizeof(UINT16
),
304 // Delete 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
,
314 FreePool (BootOrder
);