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