]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Bds/BootOption.c
ArmPlatformPkg/Bds: Upgrade the BDS to be more conformed to the UEFI Specification
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootOption.c
CommitLineData
ea46ebbe 1/** @file\r
2*\r
3* Copyright (c) 2011, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
17extern EFI_HANDLE mImageHandle;\r
18\r
19EFI_STATUS\r
20BootOptionStart (\r
21 IN BDS_LOAD_OPTION *BootOption\r
22 )\r
23{\r
24 EFI_STATUS Status;\r
25 EFI_DEVICE_PATH* FdtDevicePath;\r
26 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
27\r
28 Status = EFI_UNSUPPORTED;\r
29\r
30 if (BootOption->OptionalData->LoaderType == BDS_LOADER_EFI_APPLICATION) {\r
31 // Need to connect every drivers to ensure no dependencies are missing for the application\r
32 BdsConnectAllDrivers();\r
33\r
34 Status = BdsStartEfiApplication (mImageHandle, BootOption->FilePathList);\r
35 } else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {\r
36 Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, NULL);\r
37 } else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {\r
38 // Convert the FDT path into a Device Path\r
39 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
40 ASSERT_EFI_ERROR(Status);\r
41 FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath));\r
42\r
43 Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, FdtDevicePath);\r
44 FreePool(FdtDevicePath);\r
45 }\r
46\r
47 return Status;\r
48}\r
49\r
50EFI_STATUS\r
51BootOptionParseLoadOption (\r
52 IN EFI_LOAD_OPTION EfiLoadOption,\r
53 IN UINTN EfiLoadOptionSize,\r
54 OUT BDS_LOAD_OPTION **BdsLoadOption\r
55 )\r
56{\r
57 BDS_LOAD_OPTION *LoadOption;\r
58 UINTN FilePathListLength;\r
59 UINTN DescriptionLength;\r
60\r
61 if (EfiLoadOption == NULL) {\r
62 return EFI_INVALID_PARAMETER;\r
63 }\r
64\r
65 if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {\r
66 return EFI_BAD_BUFFER_SIZE;\r
67 }\r
68\r
69 LoadOption = (BDS_LOAD_OPTION*)AllocatePool(sizeof(BDS_LOAD_OPTION));\r
70 if (LoadOption == NULL) {\r
71 return EFI_OUT_OF_RESOURCES;\r
72 }\r
73\r
74 LoadOption->LoadOption = EfiLoadOption;\r
75 LoadOption->LoadOptionSize = EfiLoadOptionSize;\r
76\r
77 LoadOption->Attributes = *(UINT32*)EfiLoadOption;\r
78 FilePathListLength = *(UINT16*)(EfiLoadOption + sizeof(UINT32));\r
79 LoadOption->Description = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16));\r
80 DescriptionLength = StrSize (LoadOption->Description);\r
81 LoadOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);\r
82\r
83 if ((UINTN)((UINT8*)LoadOption->FilePathList + FilePathListLength - EfiLoadOption) == EfiLoadOptionSize) {\r
84 LoadOption->OptionalData = NULL;\r
85 } else {\r
86 LoadOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)((UINT8*)LoadOption->FilePathList + FilePathListLength);\r
87 }\r
88\r
89 *BdsLoadOption = LoadOption;\r
90 return EFI_SUCCESS;\r
91}\r
92\r
93EFI_STATUS\r
94BootOptionFromLoadOptionVariable (\r
95 IN UINT16 LoadOptionIndex,\r
96 OUT BDS_LOAD_OPTION **BdsLoadOption\r
97 )\r
98{\r
99 EFI_STATUS Status;\r
100 CHAR16 BootVariableName[9];\r
101 EFI_LOAD_OPTION EfiLoadOption;\r
102 UINTN EfiLoadOptionSize;\r
103\r
104 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);\r
105\r
106 Status = GetEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);\r
107 if (!EFI_ERROR(Status)) {\r
108 Status = BootOptionParseLoadOption (EfiLoadOption,EfiLoadOptionSize,BdsLoadOption);\r
109 if (!EFI_ERROR(Status)) {\r
110 (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;\r
111 }\r
112 }\r
113\r
114 return Status;\r
115}\r
116\r
117EFI_STATUS\r
118BootOptionList (\r
119 IN OUT LIST_ENTRY *BootOptionList\r
120 )\r
121{\r
122 EFI_STATUS Status;\r
123 UINTN Index;\r
124 UINT16 *BootOrder;\r
125 UINTN BootOrderSize;\r
126 BDS_LOAD_OPTION *BdsLoadOption;\r
127\r
128 InitializeListHead (BootOptionList);\r
129\r
130 // Get the Boot Option Order from the environment variable\r
131 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
132 if (EFI_ERROR(Status)) {\r
133 return Status;\r
134 }\r
135\r
136 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
137 Status = BootOptionFromLoadOptionVariable (BootOrder[Index],&BdsLoadOption);\r
138 if (!EFI_ERROR(Status)) {\r
139 InsertTailList (BootOptionList,&BdsLoadOption->Link);\r
140 }\r
141 }\r
142\r
143 return EFI_SUCCESS;\r
144}\r
145\r
146UINT16\r
147BootOptionAllocateBootIndex (\r
148 VOID\r
149 )\r
150{\r
151 EFI_STATUS Status;\r
152 UINTN Index;\r
153 UINT32 BootIndex;\r
154 UINT16 *BootOrder;\r
155 UINTN BootOrderSize;\r
156 BOOLEAN Found;\r
157\r
158 // Get the Boot Option Order from the environment variable\r
159 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
160 if (!EFI_ERROR(Status)) {\r
161 for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {\r
162 Found = FALSE;\r
163 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
164 if (BootOrder[Index] == BootIndex) {\r
165 Found = TRUE;\r
166 break;\r
167 }\r
168 }\r
169 if (!Found) {\r
170 return BootIndex;\r
171 }\r
172 }\r
173 }\r
174 // Return the first index\r
175 return 0;\r
176}\r
177\r
178STATIC\r
179EFI_STATUS\r
180BootOptionSetFields (\r
181 IN BDS_LOAD_OPTION *BootOption,\r
182 IN UINT32 Attributes,\r
183 IN CHAR16* BootDescription,\r
184 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
185 IN BDS_LOADER_TYPE BootType,\r
186 IN CHAR8* BootArguments\r
187 )\r
188{\r
189 EFI_LOAD_OPTION EfiLoadOption;\r
190 UINTN EfiLoadOptionSize;\r
191 UINTN BootDescriptionSize;\r
192 UINTN BootOptionalDataSize;\r
193 UINT16 FilePathListLength;\r
194 EFI_DEVICE_PATH_PROTOCOL* DevicePathNode;\r
195 UINTN NodeLength;\r
196 UINT8* EfiLoadOptionPtr;\r
197\r
198 // If we are overwriting an existent Boot Option then we have to free previously allocated memory\r
199 if (BootOption->LoadOption) {\r
200 FreePool(BootOption->LoadOption);\r
201 }\r
202\r
203 BootDescriptionSize = StrSize(BootDescription);\r
204 BootOptionalDataSize = sizeof(BDS_LOADER_OPTIONAL_DATA) +\r
205 (BootArguments == NULL ? 0 : AsciiStrSize(BootArguments));\r
206\r
207 // Compute the size of the FilePath list\r
208 FilePathListLength = 0;\r
209 DevicePathNode = DevicePath;\r
210 while (!IsDevicePathEndType (DevicePathNode)) {\r
211 FilePathListLength += DevicePathNodeLength (DevicePathNode);\r
212 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
213 }\r
214 // Add the length of the DevicePath EndType\r
215 FilePathListLength += DevicePathNodeLength (DevicePathNode);\r
216\r
217 // Allocate the memory for the EFI Load Option\r
218 EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + BootOptionalDataSize;\r
219 EfiLoadOption = (EFI_LOAD_OPTION)AllocatePool(EfiLoadOptionSize);\r
220 EfiLoadOptionPtr = EfiLoadOption;\r
221\r
222 //\r
223 // Populate the EFI Load Option and BDS Boot Option structures\r
224 //\r
225\r
226 // Attributes fields\r
227 BootOption->Attributes = Attributes;\r
228 *(UINT32*)EfiLoadOptionPtr = Attributes;\r
229 EfiLoadOptionPtr += sizeof(UINT32);\r
230\r
231 // FilePath List fields\r
232 BootOption->FilePathListLength = FilePathListLength;\r
233 *(UINT16*)EfiLoadOptionPtr = FilePathListLength;\r
234 EfiLoadOptionPtr += sizeof(UINT16);\r
235\r
236 // Boot description fields\r
237 BootOption->Description = (CHAR16*)EfiLoadOptionPtr;\r
238 CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);\r
239 EfiLoadOptionPtr += BootDescriptionSize;\r
240\r
241 // File path fields\r
242 BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;\r
243 DevicePathNode = DevicePath;\r
244 while (!IsDevicePathEndType (DevicePathNode)) {\r
245 NodeLength = DevicePathNodeLength(DevicePathNode);\r
246 CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);\r
247 EfiLoadOptionPtr += NodeLength;\r
248 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
249 }\r
250\r
251 // Set the End Device Path Type\r
252 SetDevicePathEndNode (EfiLoadOptionPtr);\r
253 EfiLoadOptionPtr = (UINT8 *)EfiLoadOptionPtr + sizeof(EFI_DEVICE_PATH);\r
254\r
255 // Optional Data fields, Do unaligned writes\r
256 WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, BootType);\r
257\r
258 CopyMem (&((BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments, BootArguments, AsciiStrSize(BootArguments));\r
259 BootOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)EfiLoadOptionPtr;\r
260\r
261 // Fill the EFI Load option fields\r
262 BootOption->LoadOptionIndex = BootOptionAllocateBootIndex();\r
263 BootOption->LoadOption = EfiLoadOption;\r
264 BootOption->LoadOptionSize = EfiLoadOptionSize;\r
265\r
266 return EFI_SUCCESS;\r
267}\r
268\r
269EFI_STATUS\r
270BootOptionCreate (\r
271 IN UINT32 Attributes,\r
272 IN CHAR16* BootDescription,\r
273 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
274 IN BDS_LOADER_TYPE BootType,\r
275 IN CHAR8* BootArguments,\r
276 OUT BDS_LOAD_OPTION **BdsLoadOption\r
277 )\r
278{\r
279 EFI_STATUS Status;\r
280 BDS_LOAD_OPTION *BootOption;\r
281 CHAR16 BootVariableName[9];\r
282 UINT16 *BootOrder;\r
283 UINTN BootOrderSize;\r
284\r
285 //\r
286 // Allocate and fill the memory for the BDS Load Option structure\r
287 //\r
288 BootOption = (BDS_LOAD_OPTION*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION));\r
289\r
290 InitializeListHead (&BootOption->Link);\r
291 BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);\r
292\r
293 //\r
294 // Set the related environment variables\r
295 //\r
296\r
297 // Create Boot#### environment variable\r
298 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);\r
299 Status = gRT->SetVariable (\r
300 BootVariableName,\r
301 &gEfiGlobalVariableGuid,\r
302 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
303 BootOption->LoadOptionSize,\r
304 BootOption->LoadOption\r
305 );\r
306\r
307 // Add the new Boot Index to the list\r
308 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
309 if (!EFI_ERROR(Status)) {\r
310 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);\r
311 // Add the new index at the end\r
312 BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;\r
313 BootOrderSize += sizeof(UINT16);\r
314 } else {\r
315 // BootOrder does not exist. Create it\r
316 BootOrderSize = sizeof(UINT16);\r
317 BootOrder = &(BootOption->LoadOptionIndex);\r
318 }\r
319\r
320 // Update (or Create) the BootOrder environment variable\r
321 Status = gRT->SetVariable (\r
322 L"BootOrder",\r
323 &gEfiGlobalVariableGuid,\r
324 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
325 BootOrderSize,\r
326 BootOrder\r
327 );\r
328\r
329 *BdsLoadOption = BootOption;\r
330 return Status;\r
331}\r
332\r
333EFI_STATUS\r
334BootOptionUpdate (\r
335 IN BDS_LOAD_OPTION *BdsLoadOption,\r
336 IN UINT32 Attributes,\r
337 IN CHAR16* BootDescription,\r
338 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
339 IN BDS_LOADER_TYPE BootType,\r
340 IN CHAR8* BootArguments\r
341 )\r
342{\r
343 EFI_STATUS Status;\r
344 BDS_LOAD_OPTION *BootOption;\r
345 CHAR16 BootVariableName[9];\r
346\r
347 // Update the BDS Load Option structure\r
348 BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);\r
349\r
350 // Update the related environment variables\r
351 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);\r
352 Status = gRT->SetVariable (\r
353 BootVariableName,\r
354 &gEfiGlobalVariableGuid,\r
355 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
356 BootOption->LoadOptionSize,\r
357 BootOption->LoadOption\r
358 );\r
359\r
360 return Status;\r
361}\r
362\r
363EFI_STATUS\r
364BootOptionDelete (\r
365 IN BDS_LOAD_OPTION *BootOption\r
366 )\r
367{\r
368 UINTN Index;\r
369 UINTN BootOrderSize;\r
370 UINT16* BootOrder;\r
371 UINTN BootOrderCount;\r
372 EFI_STATUS Status;\r
373\r
374 // If the Boot Optiono was attached to a list remove it\r
375 if (!IsListEmpty (&BootOption->Link)) {\r
376 // Remove the entry from the list\r
377 RemoveEntryList (&BootOption->Link);\r
378 }\r
379\r
380 // Remove the entry from the BootOrder environment variable\r
381 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
382 if (!EFI_ERROR(Status)) {\r
383 BootOrderCount = BootOrderSize / sizeof(UINT16);\r
384\r
385 // Find the index of the removed entry\r
386 for (Index = 0; Index < BootOrderCount; Index++) {\r
387 if (BootOrder[Index] == BootOption->LoadOptionIndex) {\r
388 // If it the last entry we do not need to rearrange the BootOrder list\r
389 if (Index + 1 != BootOrderCount) {\r
390 CopyMem (&BootOrder[Index],&BootOrder[Index+1], BootOrderCount - (Index + 1));\r
391 }\r
392 break;\r
393 }\r
394 }\r
395\r
396 // Update the BootOrder environment variable\r
397 Status = gRT->SetVariable (\r
398 L"BootOrder",\r
399 &gEfiGlobalVariableGuid,\r
400 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
401 BootOrderSize - sizeof(UINT16),\r
402 BootOrder\r
403 );\r
404 }\r
405\r
406 return EFI_SUCCESS;\r
407}\r