]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/BdsLib/BdsLoadOption.c
ArmPkg: Introduce GetGlobalEnvironmentVariable() function.
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsLoadOption.c
1 /** @file
2 *
3 * Copyright (c) 2011-2013, ARM Limited. All rights reserved.
4 *
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
9 *
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.
12 *
13 **/
14
15 #include "BdsInternal.h"
16
17 EFI_STATUS
18 BootOptionParseLoadOption (
19 IN EFI_LOAD_OPTION EfiLoadOption,
20 IN UINTN EfiLoadOptionSize,
21 IN OUT BDS_LOAD_OPTION **BdsLoadOption
22 )
23 {
24 BDS_LOAD_OPTION *LoadOption;
25 UINTN DescriptionLength;
26
27 if (EfiLoadOption == NULL) {
28 return EFI_INVALID_PARAMETER;
29 }
30
31 if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
32 return EFI_BAD_BUFFER_SIZE;
33 }
34
35 if (*BdsLoadOption == NULL) {
36 LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
37 if (LoadOption == NULL) {
38 return EFI_OUT_OF_RESOURCES;
39 }
40 } else {
41 LoadOption = *BdsLoadOption;
42 }
43
44 LoadOption->LoadOption = EfiLoadOption;
45 LoadOption->LoadOptionSize = EfiLoadOptionSize;
46
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);
52
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;
57 } else {
58 LoadOption->OptionalData = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength);
59 LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - (UINTN)EfiLoadOption);
60 }
61
62 if (*BdsLoadOption == NULL) {
63 *BdsLoadOption = LoadOption;
64 }
65
66 return EFI_SUCCESS;
67 }
68
69 EFI_STATUS
70 BootOptionFromLoadOptionVariable (
71 IN CHAR16* BootVariableName,
72 OUT BDS_LOAD_OPTION** BdsLoadOption
73 )
74 {
75 EFI_STATUS Status;
76 EFI_LOAD_OPTION EfiLoadOption;
77 UINTN EfiLoadOptionSize;
78
79 Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
80 if (!EFI_ERROR(Status)) {
81 *BdsLoadOption = NULL;
82 Status = BootOptionParseLoadOption (EfiLoadOption, EfiLoadOptionSize, BdsLoadOption);
83 }
84
85 return Status;
86 }
87
88 EFI_STATUS
89 BootOptionFromLoadOptionIndex (
90 IN UINT16 LoadOptionIndex,
91 OUT BDS_LOAD_OPTION **BdsLoadOption
92 )
93 {
94 CHAR16 BootVariableName[9];
95 EFI_STATUS Status;
96
97 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);
98
99 Status = BootOptionFromLoadOptionVariable (BootVariableName, BdsLoadOption);
100 if (!EFI_ERROR(Status)) {
101 (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;
102 }
103
104 return Status;
105 }
106
107 EFI_STATUS
108 BootOptionToLoadOptionVariable (
109 IN BDS_LOAD_OPTION* BdsLoadOption
110 )
111 {
112 EFI_STATUS Status;
113 UINTN DescriptionSize;
114 //UINT16 FilePathListLength;
115 EFI_DEVICE_PATH_PROTOCOL* DevicePathNode;
116 UINTN NodeLength;
117 UINT8* EfiLoadOptionPtr;
118 VOID* OldLoadOption;
119 CHAR16 BootVariableName[9];
120 UINTN BootOrderSize;
121 UINT16* BootOrder;
122
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;
126 } else {
127 OldLoadOption = NULL;
128
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 ();
132
133 //TODO: Add to the the Boot Entry List
134 }
135
136 DescriptionSize = StrSize(BdsLoadOption->Description);
137
138 // Ensure the FilePathListLength information is correct
139 ASSERT (GetDevicePathSize (BdsLoadOption->FilePathList) == BdsLoadOption->FilePathListLength);
140
141 // Allocate the memory for the EFI Load Option
142 BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize;
143
144 BdsLoadOption->LoadOption = (EFI_LOAD_OPTION)AllocateZeroPool (BdsLoadOption->LoadOptionSize);
145 if (BdsLoadOption->LoadOption == NULL) {
146 return EFI_OUT_OF_RESOURCES;
147 }
148
149 EfiLoadOptionPtr = BdsLoadOption->LoadOption;
150
151 //
152 // Populate the EFI Load Option and BDS Boot Option structures
153 //
154
155 // Attributes fields
156 *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes;
157 EfiLoadOptionPtr += sizeof(UINT32);
158
159 // FilePath List fields
160 *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength;
161 EfiLoadOptionPtr += sizeof(UINT16);
162
163 // Boot description fields
164 CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize);
165 EfiLoadOptionPtr += DescriptionSize;
166
167 // File path fields
168 DevicePathNode = BdsLoadOption->FilePathList;
169 while (!IsDevicePathEndType (DevicePathNode)) {
170 NodeLength = DevicePathNodeLength(DevicePathNode);
171 CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
172 EfiLoadOptionPtr += NodeLength;
173 DevicePathNode = NextDevicePathNode (DevicePathNode);
174 }
175
176 // Set the End Device Path Type
177 SetDevicePathEndNode (EfiLoadOptionPtr);
178 EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH);
179
180 // Fill the Optional Data
181 if (BdsLoadOption->OptionalDataSize > 0) {
182 CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize);
183 }
184
185 // Case where the fields have been updated
186 if (OldLoadOption) {
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);
191 }
192
193 // Create/Update Boot#### environment variable
194 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
195 Status = gRT->SetVariable (
196 BootVariableName,
197 &gEfiGlobalVariableGuid,
198 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
199 BdsLoadOption->LoadOptionSize,
200 BdsLoadOption->LoadOption
201 );
202
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 = GetGlobalEnvironmentVariable (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);
212 } else {
213 // BootOrder does not exist. Create it
214 BootOrderSize = sizeof(UINT16);
215 BootOrder = &(BdsLoadOption->LoadOptionIndex);
216 }
217
218 // Update (or Create) the BootOrder environment variable
219 gRT->SetVariable (
220 L"BootOrder",
221 &gEfiGlobalVariableGuid,
222 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
223 BootOrderSize,
224 BootOrder
225 );
226 DEBUG((EFI_D_ERROR,"Create %s\n",BootVariableName));
227
228 // Free memory allocated by GetGlobalEnvironmentVariable
229 if (!EFI_ERROR(Status)) {
230 FreePool (BootOrder);
231 }
232 } else {
233 DEBUG((EFI_D_ERROR,"Update %s\n",BootVariableName));
234 }
235
236 return EFI_SUCCESS;
237 }
238
239 UINT16
240 BootOptionAllocateBootIndex (
241 VOID
242 )
243 {
244 EFI_STATUS Status;
245 UINTN Index;
246 UINT32 BootIndex;
247 UINT16 *BootOrder;
248 UINTN BootOrderSize;
249 BOOLEAN Found;
250
251 // Get the Boot Option Order from the environment variable
252 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
253 if (!EFI_ERROR(Status)) {
254 for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {
255 Found = FALSE;
256 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
257 if (BootOrder[Index] == BootIndex) {
258 Found = TRUE;
259 break;
260 }
261 }
262 if (!Found) {
263 return BootIndex;
264 }
265 }
266 FreePool (BootOrder);
267 }
268 // Return the first index
269 return 0;
270 }