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"
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
;
26 UINTN EfiLoadOptionPtr
;
28 if (EfiLoadOption
== NULL
) {
29 return EFI_INVALID_PARAMETER
;
32 if (EfiLoadOptionSize
< sizeof(UINT32
) + sizeof(UINT16
) + sizeof(CHAR16
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
)) {
33 return EFI_BAD_BUFFER_SIZE
;
36 if (*BdsLoadOption
== NULL
) {
37 LoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
38 if (LoadOption
== NULL
) {
39 return EFI_OUT_OF_RESOURCES
;
42 LoadOption
= *BdsLoadOption
;
45 EfiLoadOptionPtr
= (UINTN
)EfiLoadOption
;
46 LoadOption
->LoadOption
= EfiLoadOption
;
47 LoadOption
->LoadOptionSize
= EfiLoadOptionSize
;
49 LoadOption
->Attributes
= *(UINT32
*)EfiLoadOptionPtr
;
50 LoadOption
->FilePathListLength
= *(UINT16
*)(EfiLoadOptionPtr
+ sizeof(UINT32
));
51 LoadOption
->Description
= (CHAR16
*)(EfiLoadOptionPtr
+ sizeof(UINT32
) + sizeof(UINT16
));
52 DescriptionLength
= StrSize (LoadOption
->Description
);
53 LoadOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)(EfiLoadOptionPtr
+ sizeof(UINT32
) + sizeof(UINT16
) + DescriptionLength
);
55 // If ((End of EfiLoadOptiony - Start of EfiLoadOption) == EfiLoadOptionSize) then No Optional Data
56 if ((UINTN
)((UINTN
)LoadOption
->FilePathList
+ LoadOption
->FilePathListLength
- EfiLoadOptionPtr
) == EfiLoadOptionSize
) {
57 LoadOption
->OptionalData
= NULL
;
58 LoadOption
->OptionalDataSize
= 0;
60 LoadOption
->OptionalData
= (VOID
*)((UINTN
)(LoadOption
->FilePathList
) + LoadOption
->FilePathListLength
);
61 LoadOption
->OptionalDataSize
= EfiLoadOptionSize
- ((UINTN
)LoadOption
->OptionalData
- EfiLoadOptionPtr
);
64 if (*BdsLoadOption
== NULL
) {
65 *BdsLoadOption
= LoadOption
;
72 BootOptionFromLoadOptionVariable (
73 IN CHAR16
* BootVariableName
,
74 OUT BDS_LOAD_OPTION
** BdsLoadOption
78 EFI_LOAD_OPTION
*EfiLoadOption
;
79 UINTN EfiLoadOptionSize
;
81 Status
= GetGlobalEnvironmentVariable (BootVariableName
, NULL
, &EfiLoadOptionSize
, (VOID
**)&EfiLoadOption
);
82 if (!EFI_ERROR(Status
)) {
83 *BdsLoadOption
= NULL
;
84 Status
= BootOptionParseLoadOption (EfiLoadOption
, EfiLoadOptionSize
, BdsLoadOption
);
91 BootOptionFromLoadOptionIndex (
92 IN UINT16 LoadOptionIndex
,
93 OUT BDS_LOAD_OPTION
**BdsLoadOption
96 CHAR16 BootVariableName
[9];
99 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", LoadOptionIndex
);
101 Status
= BootOptionFromLoadOptionVariable (BootVariableName
, BdsLoadOption
);
102 if (!EFI_ERROR(Status
)) {
103 (*BdsLoadOption
)->LoadOptionIndex
= LoadOptionIndex
;
110 BootOptionToLoadOptionVariable (
111 IN BDS_LOAD_OPTION
* BdsLoadOption
115 UINTN DescriptionSize
;
116 //UINT16 FilePathListLength;
117 EFI_DEVICE_PATH_PROTOCOL
* DevicePathNode
;
119 UINT8
* EfiLoadOptionPtr
;
121 CHAR16 BootVariableName
[9];
125 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
126 if (BdsLoadOption
->LoadOptionSize
> 0) {
127 OldLoadOption
= BdsLoadOption
->LoadOption
;
129 OldLoadOption
= NULL
;
131 // If this function is called at the creation of the Boot Device entry (not at the update) the
132 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
133 BdsLoadOption
->LoadOptionIndex
= BootOptionAllocateBootIndex ();
135 //TODO: Add to the the Boot Entry List
138 DescriptionSize
= StrSize(BdsLoadOption
->Description
);
140 // Ensure the FilePathListLength information is correct
141 ASSERT (GetDevicePathSize (BdsLoadOption
->FilePathList
) == BdsLoadOption
->FilePathListLength
);
143 // Allocate the memory for the EFI Load Option
144 BdsLoadOption
->LoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + DescriptionSize
+ BdsLoadOption
->FilePathListLength
+ BdsLoadOption
->OptionalDataSize
;
146 BdsLoadOption
->LoadOption
= (EFI_LOAD_OPTION
*)AllocateZeroPool (BdsLoadOption
->LoadOptionSize
);
147 if (BdsLoadOption
->LoadOption
== NULL
) {
148 return EFI_OUT_OF_RESOURCES
;
151 EfiLoadOptionPtr
= (UINT8
*) BdsLoadOption
->LoadOption
;
154 // Populate the EFI Load Option and BDS Boot Option structures
158 *(UINT32
*)EfiLoadOptionPtr
= BdsLoadOption
->Attributes
;
159 EfiLoadOptionPtr
+= sizeof(UINT32
);
161 // FilePath List fields
162 *(UINT16
*)EfiLoadOptionPtr
= BdsLoadOption
->FilePathListLength
;
163 EfiLoadOptionPtr
+= sizeof(UINT16
);
165 // Boot description fields
166 CopyMem (EfiLoadOptionPtr
, BdsLoadOption
->Description
, DescriptionSize
);
167 EfiLoadOptionPtr
+= DescriptionSize
;
170 DevicePathNode
= BdsLoadOption
->FilePathList
;
171 while (!IsDevicePathEndType (DevicePathNode
)) {
172 NodeLength
= DevicePathNodeLength(DevicePathNode
);
173 CopyMem (EfiLoadOptionPtr
, DevicePathNode
, NodeLength
);
174 EfiLoadOptionPtr
+= NodeLength
;
175 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
178 // Set the End Device Path Type
179 SetDevicePathEndNode (EfiLoadOptionPtr
);
180 EfiLoadOptionPtr
+= sizeof(EFI_DEVICE_PATH
);
182 // Fill the Optional Data
183 if (BdsLoadOption
->OptionalDataSize
> 0) {
184 CopyMem (EfiLoadOptionPtr
, BdsLoadOption
->OptionalData
, BdsLoadOption
->OptionalDataSize
);
187 // Case where the fields have been updated
189 // Now, the old data has been copied to the new allocated packed structure, we need to update the pointers of BdsLoadOption
190 BootOptionParseLoadOption (BdsLoadOption
->LoadOption
, BdsLoadOption
->LoadOptionSize
, &BdsLoadOption
);
191 // Free the old packed structure
192 FreePool (OldLoadOption
);
195 // Create/Update Boot#### environment variable
196 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
197 Status
= gRT
->SetVariable (
199 &gEfiGlobalVariableGuid
,
200 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
201 BdsLoadOption
->LoadOptionSize
,
202 BdsLoadOption
->LoadOption
205 // When it is a new entry we must add the entry to the BootOrder
206 if (OldLoadOption
== NULL
) {
207 // Add the new Boot Index to the list
208 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
209 if (!EFI_ERROR(Status
)) {
210 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
211 // Add the new index at the end
212 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BdsLoadOption
->LoadOptionIndex
;
213 BootOrderSize
+= sizeof(UINT16
);
215 // BootOrder does not exist. Create it
216 BootOrderSize
= sizeof(UINT16
);
217 BootOrder
= &(BdsLoadOption
->LoadOptionIndex
);
220 // Update (or Create) the BootOrder environment variable
223 &gEfiGlobalVariableGuid
,
224 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
228 DEBUG((EFI_D_ERROR
,"Create %s\n",BootVariableName
));
230 // Free memory allocated by GetGlobalEnvironmentVariable
231 if (!EFI_ERROR(Status
)) {
232 FreePool (BootOrder
);
235 DEBUG((EFI_D_ERROR
,"Update %s\n",BootVariableName
));
242 BootOptionAllocateBootIndex (
253 // Get the Boot Option Order from the environment variable
254 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
255 if (!EFI_ERROR(Status
)) {
256 for (BootIndex
= 0; BootIndex
<= 0xFFFF; BootIndex
++) {
258 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
259 if (BootOrder
[Index
] == BootIndex
) {
268 FreePool (BootOrder
);
270 // Return the first index