3 * Copyright (c) 2011-2012, 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"
18 BootOptionParseLoadOption (
19 IN EFI_LOAD_OPTION EfiLoadOption
,
20 IN UINTN EfiLoadOptionSize
,
21 IN OUT BDS_LOAD_OPTION
**BdsLoadOption
24 BDS_LOAD_OPTION
*LoadOption
;
25 UINTN DescriptionLength
;
27 if (EfiLoadOption
== NULL
) {
28 return EFI_INVALID_PARAMETER
;
31 if (EfiLoadOptionSize
< sizeof(UINT32
) + sizeof(UINT16
) + sizeof(CHAR16
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
)) {
32 return EFI_BAD_BUFFER_SIZE
;
35 if (*BdsLoadOption
== NULL
) {
36 LoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
37 if (LoadOption
== NULL
) {
38 return EFI_OUT_OF_RESOURCES
;
41 LoadOption
= *BdsLoadOption
;
44 LoadOption
->LoadOption
= EfiLoadOption
;
45 LoadOption
->LoadOptionSize
= EfiLoadOptionSize
;
47 LoadOption
->Attributes
= *(UINT32
*)EfiLoadOption
;
48 LoadOption
->FilePathListLength
= *(UINT16
*)(EfiLoadOption
+ sizeof(UINT32
));
49 LoadOption
->Description
= (CHAR16
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
));
50 DescriptionLength
= StrSize (LoadOption
->Description
);
51 LoadOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)(EfiLoadOption
+ sizeof(UINT32
) + sizeof(UINT16
) + DescriptionLength
);
53 // If ((End of EfiLoadOptiony - Start of EfiLoadOption) == EfiLoadOptionSize) then No Optional Data
54 if ((UINTN
)((UINTN
)LoadOption
->FilePathList
+ LoadOption
->FilePathListLength
- (UINTN
)EfiLoadOption
) == EfiLoadOptionSize
) {
55 LoadOption
->OptionalData
= NULL
;
56 LoadOption
->OptionalDataSize
= 0;
58 LoadOption
->OptionalData
= (VOID
*)((UINTN
)(LoadOption
->FilePathList
) + LoadOption
->FilePathListLength
);
59 LoadOption
->OptionalDataSize
= EfiLoadOptionSize
- ((UINTN
)LoadOption
->OptionalData
- (UINTN
)EfiLoadOption
);
62 if (*BdsLoadOption
== NULL
) {
63 *BdsLoadOption
= LoadOption
;
70 BootOptionFromLoadOptionVariable (
71 IN CHAR16
* BootVariableName
,
72 OUT BDS_LOAD_OPTION
** BdsLoadOption
76 EFI_LOAD_OPTION EfiLoadOption
;
77 UINTN EfiLoadOptionSize
;
79 Status
= GetEnvironmentVariable (BootVariableName
, NULL
, &EfiLoadOptionSize
, (VOID
**)&EfiLoadOption
);
80 if (!EFI_ERROR(Status
)) {
81 *BdsLoadOption
= NULL
;
82 Status
= BootOptionParseLoadOption (EfiLoadOption
, EfiLoadOptionSize
, BdsLoadOption
);
89 BootOptionFromLoadOptionIndex (
90 IN UINT16 LoadOptionIndex
,
91 OUT BDS_LOAD_OPTION
**BdsLoadOption
94 CHAR16 BootVariableName
[9];
97 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", LoadOptionIndex
);
99 Status
= BootOptionFromLoadOptionVariable (BootVariableName
, BdsLoadOption
);
100 if (!EFI_ERROR(Status
)) {
101 (*BdsLoadOption
)->LoadOptionIndex
= LoadOptionIndex
;
108 BootOptionToLoadOptionVariable (
109 IN BDS_LOAD_OPTION
* BdsLoadOption
113 UINTN DescriptionSize
;
114 //UINT16 FilePathListLength;
115 EFI_DEVICE_PATH_PROTOCOL
* DevicePathNode
;
117 UINT8
* EfiLoadOptionPtr
;
119 CHAR16 BootVariableName
[9];
123 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
124 if (BdsLoadOption
->LoadOptionSize
> 0) {
125 OldLoadOption
= BdsLoadOption
->LoadOption
;
127 OldLoadOption
= NULL
;
129 // If this function is called at the creation of the Boot Device entry (not at the update) the
130 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
131 BdsLoadOption
->LoadOptionIndex
= BootOptionAllocateBootIndex ();
133 //TODO: Add to the the Boot Entry List
136 DescriptionSize
= StrSize(BdsLoadOption
->Description
);
138 // Ensure the FilePathListLength information is correct
139 ASSERT (GetDevicePathSize (BdsLoadOption
->FilePathList
) == BdsLoadOption
->FilePathListLength
);
141 // Allocate the memory for the EFI Load Option
142 BdsLoadOption
->LoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + DescriptionSize
+ BdsLoadOption
->FilePathListLength
+ BdsLoadOption
->OptionalDataSize
;
144 BdsLoadOption
->LoadOption
= (EFI_LOAD_OPTION
)AllocateZeroPool (BdsLoadOption
->LoadOptionSize
);
145 if (BdsLoadOption
->LoadOption
== NULL
) {
146 return EFI_OUT_OF_RESOURCES
;
149 EfiLoadOptionPtr
= BdsLoadOption
->LoadOption
;
152 // Populate the EFI Load Option and BDS Boot Option structures
156 *(UINT32
*)EfiLoadOptionPtr
= BdsLoadOption
->Attributes
;
157 EfiLoadOptionPtr
+= sizeof(UINT32
);
159 // FilePath List fields
160 *(UINT16
*)EfiLoadOptionPtr
= BdsLoadOption
->FilePathListLength
;
161 EfiLoadOptionPtr
+= sizeof(UINT16
);
163 // Boot description fields
164 CopyMem (EfiLoadOptionPtr
, BdsLoadOption
->Description
, DescriptionSize
);
165 EfiLoadOptionPtr
+= DescriptionSize
;
168 DevicePathNode
= BdsLoadOption
->FilePathList
;
169 while (!IsDevicePathEndType (DevicePathNode
)) {
170 NodeLength
= DevicePathNodeLength(DevicePathNode
);
171 CopyMem (EfiLoadOptionPtr
, DevicePathNode
, NodeLength
);
172 EfiLoadOptionPtr
+= NodeLength
;
173 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
176 // Set the End Device Path Type
177 SetDevicePathEndNode (EfiLoadOptionPtr
);
178 EfiLoadOptionPtr
+= sizeof(EFI_DEVICE_PATH
);
180 // Fill the Optional Data
181 if (BdsLoadOption
->OptionalDataSize
> 0) {
182 CopyMem (EfiLoadOptionPtr
, BdsLoadOption
->OptionalData
, BdsLoadOption
->OptionalDataSize
);
185 // Case where the fields have been updated
187 // Now, the old data has been copied to the new allocated packed structure, we need to update the pointers of BdsLoadOption
188 BootOptionParseLoadOption (BdsLoadOption
->LoadOption
, BdsLoadOption
->LoadOptionSize
, &BdsLoadOption
);
189 // Free the old packed structure
190 FreePool (OldLoadOption
);
193 // Create/Update Boot#### environment variable
194 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
195 Status
= gRT
->SetVariable (
197 &gEfiGlobalVariableGuid
,
198 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
199 BdsLoadOption
->LoadOptionSize
,
200 BdsLoadOption
->LoadOption
203 // When it is a new entry we must add the entry to the BootOrder
204 if (OldLoadOption
== NULL
) {
205 // Add the new Boot Index to the list
206 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
207 if (!EFI_ERROR(Status
)) {
208 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
209 // Add the new index at the end
210 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BdsLoadOption
->LoadOptionIndex
;
211 BootOrderSize
+= sizeof(UINT16
);
213 // BootOrder does not exist. Create it
214 BootOrderSize
= sizeof(UINT16
);
215 BootOrder
= &(BdsLoadOption
->LoadOptionIndex
);
218 // Update (or Create) the BootOrder environment variable
221 &gEfiGlobalVariableGuid
,
222 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
226 DEBUG((EFI_D_ERROR
,"Create %s\n",BootVariableName
));
228 // Free memory allocated by GetEnvironmentVariable
229 if (!EFI_ERROR(Status
)) {
230 FreePool (BootOrder
);
233 DEBUG((EFI_D_ERROR
,"Update %s\n",BootVariableName
));
240 BootOptionAllocateBootIndex (
251 // Get the Boot Option Order from the environment variable
252 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
253 if (!EFI_ERROR(Status
)) {
254 for (BootIndex
= 0; BootIndex
<= 0xFFFF; BootIndex
++) {
256 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
257 if (BootOrder
[Index
] == BootIndex
) {
266 FreePool (BootOrder
);
268 // Return the first index