]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/BdsDxe/BdsEntry.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BdsEntry.c
CommitLineData
f4cd24da
RN
1/** @file\r
2 This module produce main entry for BDS phase - BdsEntry.\r
3 When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed\r
4 which contains interface of BdsEntry.\r
5 After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked\r
6 to enter BDS phase.\r
7\r
43311062 8Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>\r
b1564648 9(C) Copyright 2016-2019 Hewlett Packard Enterprise Development LP<BR>\r
e58f1ae5 10(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
9d510e61 11SPDX-License-Identifier: BSD-2-Clause-Patent\r
f4cd24da
RN
12\r
13**/\r
14\r
15#include "Bds.h"\r
16#include "Language.h"\r
17#include "HwErrRecSupport.h"\r
d9a7612f 18#include <Library/VariablePolicyHelperLib.h>\r
f4cd24da 19\r
1436aea4 20#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \\r
f4cd24da
RN
21 (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \\r
22 }\r
23\r
24///\r
25/// BDS arch protocol instance initial value.\r
26///\r
27EFI_BDS_ARCH_PROTOCOL gBds = {\r
28 BdsEntry\r
29};\r
30\r
31//\r
32// gConnectConInEvent - Event which is signaled when ConIn connection is required\r
33//\r
1436aea4 34EFI_EVENT gConnectConInEvent = NULL;\r
f4cd24da
RN
35\r
36///\r
37/// The read-only variables defined in UEFI Spec.\r
38///\r
39CHAR16 *mReadOnlyVariables[] = {\r
40 EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,\r
41 EFI_LANG_CODES_VARIABLE_NAME,\r
42 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
43 EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,\r
44 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME\r
1436aea4 45};\r
f4cd24da 46\r
1436aea4 47CHAR16 *mBdsLoadOptionName[] = {\r
1634214d
RN
48 L"Driver",\r
49 L"SysPrep",\r
68456d8a
RN
50 L"Boot",\r
51 L"PlatformRecovery"\r
1634214d
RN
52};\r
53\r
f4cd24da
RN
54/**\r
55 Event to Connect ConIn.\r
56\r
57 @param Event Event whose notification function is being invoked.\r
58 @param Context Pointer to the notification function's context,\r
59 which is implementation-dependent.\r
60\r
61**/\r
62VOID\r
63EFIAPI\r
64BdsDxeOnConnectConInCallBack (\r
1436aea4
MK
65 IN EFI_EVENT Event,\r
66 IN VOID *Context\r
f4cd24da
RN
67 )\r
68{\r
1436aea4 69 EFI_STATUS Status;\r
f4cd24da
RN
70\r
71 //\r
72 // When Osloader call ReadKeyStroke to signal this event\r
73 // no driver dependency is assumed existing. So use a non-dispatch version\r
74 //\r
75 Status = EfiBootManagerConnectConsoleVariable (ConIn);\r
76 if (EFI_ERROR (Status)) {\r
77 //\r
78 // Should not enter this case, if enter, the keyboard will not work.\r
79 // May need platfrom policy to connect keyboard.\r
80 //\r
87000d77 81 DEBUG ((DEBUG_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));\r
f4cd24da
RN
82 }\r
83}\r
1436aea4 84\r
048bcba1
RN
85/**\r
86 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to\r
87 check whether there is remaining deferred load images.\r
88\r
89 @param[in] Event The Event that is being processed.\r
90 @param[in] Context The Event Context.\r
91\r
92**/\r
93VOID\r
94EFIAPI\r
95CheckDeferredLoadImageOnReadyToBoot (\r
1436aea4
MK
96 IN EFI_EVENT Event,\r
97 IN VOID *Context\r
048bcba1
RN
98 )\r
99{\r
1436aea4
MK
100 EFI_STATUS Status;\r
101 EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *DeferredImage;\r
102 UINTN HandleCount;\r
103 EFI_HANDLE *Handles;\r
104 UINTN Index;\r
105 UINTN ImageIndex;\r
106 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
107 VOID *Image;\r
108 UINTN ImageSize;\r
109 BOOLEAN BootOption;\r
110 CHAR16 *DevicePathStr;\r
048bcba1
RN
111\r
112 //\r
113 // Find all the deferred image load protocols.\r
114 //\r
115 HandleCount = 0;\r
1436aea4
MK
116 Handles = NULL;\r
117 Status = gBS->LocateHandleBuffer (\r
118 ByProtocol,\r
119 &gEfiDeferredImageLoadProtocolGuid,\r
120 NULL,\r
121 &HandleCount,\r
122 &Handles\r
123 );\r
048bcba1
RN
124 if (EFI_ERROR (Status)) {\r
125 return;\r
126 }\r
127\r
128 for (Index = 0; Index < HandleCount; Index++) {\r
1436aea4 129 Status = gBS->HandleProtocol (Handles[Index], &gEfiDeferredImageLoadProtocolGuid, (VOID **)&DeferredImage);\r
048bcba1
RN
130 if (EFI_ERROR (Status)) {\r
131 continue;\r
132 }\r
133\r
134 for (ImageIndex = 0; ; ImageIndex++) {\r
135 //\r
136 // Load all the deferred images in this protocol instance.\r
137 //\r
138 Status = DeferredImage->GetImageInfo (\r
1436aea4
MK
139 DeferredImage,\r
140 ImageIndex,\r
141 &ImageDevicePath,\r
142 (VOID **)&Image,\r
143 &ImageSize,\r
144 &BootOption\r
145 );\r
048bcba1
RN
146 if (EFI_ERROR (Status)) {\r
147 break;\r
148 }\r
1436aea4 149\r
048bcba1
RN
150 DevicePathStr = ConvertDevicePathToText (ImageDevicePath, FALSE, FALSE);\r
151 DEBUG ((DEBUG_LOAD, "[Bds] Image was deferred but not loaded: %s.\n", DevicePathStr));\r
152 if (DevicePathStr != NULL) {\r
153 FreePool (DevicePathStr);\r
154 }\r
155 }\r
156 }\r
1436aea4 157\r
048bcba1
RN
158 if (Handles != NULL) {\r
159 FreePool (Handles);\r
160 }\r
161}\r
f4cd24da
RN
162\r
163/**\r
164\r
165 Install Boot Device Selection Protocol\r
166\r
167 @param ImageHandle The image handle.\r
168 @param SystemTable The system table.\r
169\r
170 @retval EFI_SUCEESS BDS has finished initializing.\r
171 Return the dispatcher and recall BDS.Entry\r
172 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface\r
173\r
174**/\r
175EFI_STATUS\r
176EFIAPI\r
177BdsInitialize (\r
1436aea4
MK
178 IN EFI_HANDLE ImageHandle,\r
179 IN EFI_SYSTEM_TABLE *SystemTable\r
f4cd24da
RN
180 )\r
181{\r
182 EFI_STATUS Status;\r
183 EFI_HANDLE Handle;\r
1436aea4 184\r
f4cd24da
RN
185 //\r
186 // Install protocol interface\r
187 //\r
188 Handle = NULL;\r
189 Status = gBS->InstallMultipleProtocolInterfaces (\r
190 &Handle,\r
1436aea4
MK
191 &gEfiBdsArchProtocolGuid,\r
192 &gBds,\r
f4cd24da
RN
193 NULL\r
194 );\r
195 ASSERT_EFI_ERROR (Status);\r
196\r
048bcba1
RN
197 DEBUG_CODE (\r
198 EFI_EVENT Event;\r
199 //\r
200 // Register notify function to check deferred images on ReadyToBoot Event.\r
201 //\r
202 Status = gBS->CreateEventEx (\r
203 EVT_NOTIFY_SIGNAL,\r
204 TPL_CALLBACK,\r
205 CheckDeferredLoadImageOnReadyToBoot,\r
206 NULL,\r
207 &gEfiEventReadyToBootGuid,\r
208 &Event\r
209 );\r
210 ASSERT_EFI_ERROR (Status);\r
1436aea4 211 );\r
f4cd24da
RN
212 return Status;\r
213}\r
214\r
f4cd24da
RN
215/**\r
216 Function waits for a given event to fire, or for an optional timeout to expire.\r
217\r
218 @param Event The event to wait for\r
219 @param Timeout An optional timeout value in 100 ns units.\r
220\r
221 @retval EFI_SUCCESS Event fired before Timeout expired.\r
222 @retval EFI_TIME_OUT Timout expired before Event fired..\r
223\r
224**/\r
225EFI_STATUS\r
226BdsWaitForSingleEvent (\r
1436aea4
MK
227 IN EFI_EVENT Event,\r
228 IN UINT64 Timeout OPTIONAL\r
f4cd24da
RN
229 )\r
230{\r
231 UINTN Index;\r
232 EFI_STATUS Status;\r
233 EFI_EVENT TimerEvent;\r
234 EFI_EVENT WaitList[2];\r
235\r
236 if (Timeout != 0) {\r
237 //\r
238 // Create a timer event\r
239 //\r
240 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
241 if (!EFI_ERROR (Status)) {\r
242 //\r
243 // Set the timer event\r
244 //\r
245 gBS->SetTimer (\r
246 TimerEvent,\r
247 TimerRelative,\r
248 Timeout\r
249 );\r
250\r
251 //\r
252 // Wait for the original event or the timer\r
253 //\r
254 WaitList[0] = Event;\r
255 WaitList[1] = TimerEvent;\r
256 Status = gBS->WaitForEvent (2, WaitList, &Index);\r
257 ASSERT_EFI_ERROR (Status);\r
258 gBS->CloseEvent (TimerEvent);\r
259\r
260 //\r
261 // If the timer expired, change the return to timed out\r
262 //\r
263 if (Index == 1) {\r
264 Status = EFI_TIMEOUT;\r
265 }\r
266 }\r
267 } else {\r
268 //\r
269 // No timeout... just wait on the event\r
270 //\r
271 Status = gBS->WaitForEvent (1, &Event, &Index);\r
272 ASSERT (!EFI_ERROR (Status));\r
273 ASSERT (Index == 0);\r
274 }\r
275\r
276 return Status;\r
277}\r
278\r
279/**\r
280 The function reads user inputs.\r
281\r
282**/\r
283VOID\r
284BdsReadKeys (\r
285 VOID\r
286 )\r
287{\r
1436aea4
MK
288 EFI_STATUS Status;\r
289 EFI_INPUT_KEY Key;\r
f4cd24da
RN
290\r
291 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
292 return;\r
293 }\r
294\r
295 while (gST->ConIn != NULL) {\r
f4cd24da 296 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
d1102dba 297\r
f4cd24da
RN
298 if (EFI_ERROR (Status)) {\r
299 //\r
300 // No more keys.\r
301 //\r
302 break;\r
303 }\r
304 }\r
305}\r
306\r
307/**\r
308 The function waits for the boot manager timeout expires or hotkey is pressed.\r
309\r
310 It calls PlatformBootManagerWaitCallback each second.\r
311\r
312 @param HotkeyTriggered Input hotkey event.\r
313**/\r
314VOID\r
315BdsWait (\r
1436aea4 316 IN EFI_EVENT HotkeyTriggered\r
f4cd24da
RN
317 )\r
318{\r
1436aea4
MK
319 EFI_STATUS Status;\r
320 UINT16 TimeoutRemain;\r
f4cd24da 321\r
87000d77 322 DEBUG ((DEBUG_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));\r
f4cd24da
RN
323\r
324 TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);\r
325 while (TimeoutRemain != 0) {\r
1436aea4 326 DEBUG ((DEBUG_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN)TimeoutRemain));\r
f4cd24da
RN
327 PlatformBootManagerWaitCallback (TimeoutRemain);\r
328\r
329 BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered\r
330 // Can be removed after all keyboard drivers invoke callback in timer callback.\r
331\r
332 if (HotkeyTriggered != NULL) {\r
333 Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));\r
334 if (!EFI_ERROR (Status)) {\r
335 break;\r
336 }\r
337 } else {\r
338 gBS->Stall (1000000);\r
339 }\r
340\r
341 //\r
342 // 0xffff means waiting forever\r
343 // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop\r
344 //\r
345 if (TimeoutRemain != 0xffff) {\r
346 TimeoutRemain--;\r
347 }\r
348 }\r
4d05a4b7
LE
349\r
350 //\r
351 // If the platform configured a nonzero and finite time-out, and we have\r
352 // actually reached that, report 100% completion to the platform.\r
353 //\r
354 // Note that the (TimeoutRemain == 0) condition excludes\r
355 // PcdPlatformBootTimeOut=0xFFFF, and that's deliberate.\r
356 //\r
1436aea4 357 if ((PcdGet16 (PcdPlatformBootTimeOut) != 0) && (TimeoutRemain == 0)) {\r
4d05a4b7
LE
358 PlatformBootManagerWaitCallback (0);\r
359 }\r
1436aea4 360\r
87000d77 361 DEBUG ((DEBUG_INFO, "[Bds]Exit the waiting!\n"));\r
f4cd24da
RN
362}\r
363\r
364/**\r
365 Attempt to boot each boot option in the BootOptions array.\r
366\r
367 @param BootOptions Input boot option array.\r
368 @param BootOptionCount Input boot option count.\r
68456d8a 369 @param BootManagerMenu Input boot manager menu.\r
f4cd24da
RN
370\r
371 @retval TRUE Successfully boot one of the boot options.\r
372 @retval FALSE Failed boot any of the boot options.\r
373**/\r
374BOOLEAN\r
68456d8a 375BootBootOptions (\r
1436aea4
MK
376 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
377 IN UINTN BootOptionCount,\r
378 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootManagerMenu OPTIONAL\r
f4cd24da
RN
379 )\r
380{\r
1436aea4 381 UINTN Index;\r
f4cd24da 382\r
45b57c12
DB
383 //\r
384 // Report Status Code to indicate BDS starts attempting booting from the UEFI BootOrder list.\r
385 //\r
386 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_ATTEMPT_BOOT_ORDER_EVENT));\r
387\r
f4cd24da
RN
388 //\r
389 // Attempt boot each boot option\r
390 //\r
391 for (Index = 0; Index < BootOptionCount; Index++) {\r
392 //\r
393 // According to EFI Specification, if a load option is not marked\r
394 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
395 // load the option.\r
396 //\r
397 if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
398 continue;\r
399 }\r
400\r
401 //\r
402 // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not\r
403 // part of the normal boot processing. Boot options with reserved category values will be\r
404 // ignored by the boot manager.\r
405 //\r
406 if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {\r
407 continue;\r
408 }\r
409\r
410 //\r
411 // All the driver options should have been processed since\r
412 // now boot will be performed.\r
413 //\r
414 EfiBootManagerBoot (&BootOptions[Index]);\r
415\r
416 //\r
311b5a6f
ED
417 // If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware\r
418 // supports boot manager menu, and if firmware is configured to boot in an\r
419 // interactive mode, the boot manager will stop processing the BootOrder variable and\r
420 // present a boot manager menu to the user.\r
f4cd24da 421 //\r
e58f1ae5 422 if ((BootManagerMenu != NULL) && (BootOptions[Index].Status == EFI_SUCCESS)) {\r
68456d8a 423 EfiBootManagerBoot (BootManagerMenu);\r
f4cd24da
RN
424 break;\r
425 }\r
426 }\r
427\r
1436aea4 428 return (BOOLEAN)(Index < BootOptionCount);\r
f4cd24da
RN
429}\r
430\r
431/**\r
68456d8a 432 The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.\r
f4cd24da 433\r
1634214d
RN
434 @param LoadOptions Load option array.\r
435 @param LoadOptionCount Load option count.\r
f4cd24da
RN
436**/\r
437VOID\r
1634214d 438ProcessLoadOptions (\r
1436aea4
MK
439 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,\r
440 IN UINTN LoadOptionCount\r
f4cd24da
RN
441 )\r
442{\r
1436aea4
MK
443 EFI_STATUS Status;\r
444 UINTN Index;\r
445 BOOLEAN ReconnectAll;\r
446 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
f4cd24da 447\r
68456d8a 448 ReconnectAll = FALSE;\r
1634214d 449 LoadOptionType = LoadOptionTypeMax;\r
f4cd24da
RN
450\r
451 //\r
452 // Process the driver option\r
453 //\r
1634214d 454 for (Index = 0; Index < LoadOptionCount; Index++) {\r
f4cd24da 455 //\r
1634214d 456 // All the load options in the array should be of the same type.\r
f4cd24da 457 //\r
68456d8a 458 if (Index == 0) {\r
1634214d 459 LoadOptionType = LoadOptions[Index].OptionType;\r
f4cd24da 460 }\r
1436aea4 461\r
1634214d 462 ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
de67c35c 463 ASSERT (LoadOptionType != LoadOptionTypeBoot);\r
f4cd24da 464\r
1634214d 465 Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
f4cd24da 466\r
de67c35c
RN
467 //\r
468 // Status indicates whether the load option is loaded and executed\r
469 // LoadOptions[Index].Status is what the load option returns\r
470 //\r
68456d8a 471 if (!EFI_ERROR (Status)) {\r
de67c35c
RN
472 //\r
473 // Stop processing if any PlatformRecovery#### returns success.\r
474 //\r
475 if ((LoadOptions[Index].Status == EFI_SUCCESS) &&\r
1436aea4
MK
476 (LoadOptionType == LoadOptionTypePlatformRecovery))\r
477 {\r
68456d8a
RN
478 break;\r
479 }\r
de67c35c
RN
480\r
481 //\r
482 // Only set ReconnectAll flag when the load option executes successfully.\r
483 //\r
484 if (!EFI_ERROR (LoadOptions[Index].Status) &&\r
1436aea4
MK
485 ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0))\r
486 {\r
68456d8a
RN
487 ReconnectAll = TRUE;\r
488 }\r
f4cd24da
RN
489 }\r
490 }\r
1634214d 491\r
f4cd24da 492 //\r
1634214d
RN
493 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
494 // then all of the EFI drivers in the system will be disconnected and\r
495 // reconnected after the last driver load option is processed.\r
f4cd24da 496 //\r
1436aea4 497 if (ReconnectAll && (LoadOptionType == LoadOptionTypeDriver)) {\r
f4cd24da
RN
498 EfiBootManagerDisconnectAll ();\r
499 EfiBootManagerConnectAll ();\r
500 }\r
f4cd24da
RN
501}\r
502\r
503/**\r
504\r
d1102dba 505 Validate input console variable data.\r
f4cd24da
RN
506\r
507 If found the device path is not a valid device path, remove the variable.\r
d1102dba 508\r
f4cd24da
RN
509 @param VariableName Input console variable name.\r
510\r
511**/\r
512VOID\r
513BdsFormalizeConsoleVariable (\r
1436aea4 514 IN CHAR16 *VariableName\r
f4cd24da
RN
515 )\r
516{\r
517 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
518 UINTN VariableSize;\r
519 EFI_STATUS Status;\r
520\r
1436aea4 521 GetEfiGlobalVariable2 (VariableName, (VOID **)&DevicePath, &VariableSize);\r
d1102dba 522 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {\r
f4cd24da
RN
523 Status = gRT->SetVariable (\r
524 VariableName,\r
525 &gEfiGlobalVariableGuid,\r
526 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
527 0,\r
528 NULL\r
529 );\r
530 //\r
531 // Deleting variable with current variable implementation shouldn't fail.\r
532 //\r
533 ASSERT_EFI_ERROR (Status);\r
534 }\r
535\r
536 if (DevicePath != NULL) {\r
537 FreePool (DevicePath);\r
538 }\r
539}\r
540\r
541/**\r
d1102dba
LG
542 Formalize OsIndication related variables.\r
543\r
544 For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps\r
f4cd24da 545 Delete OsIndications variable if it is not NV/BS/RT UINT64.\r
d1102dba 546\r
f4cd24da
RN
547 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
548\r
e58f1ae5
SW
549 Create a boot option for BootManagerMenu if it hasn't been created yet\r
550\r
f4cd24da 551**/\r
d1102dba 552VOID\r
f4cd24da
RN
553BdsFormalizeOSIndicationVariable (\r
554 VOID\r
555 )\r
556{\r
1436aea4
MK
557 EFI_STATUS Status;\r
558 UINT64 OsIndicationSupport;\r
559 UINT64 OsIndication;\r
560 UINTN DataSize;\r
561 UINT32 Attributes;\r
562 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
f4cd24da
RN
563\r
564 //\r
565 // OS indicater support variable\r
566 //\r
e58f1ae5
SW
567 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
568 if (Status != EFI_NOT_FOUND) {\r
0889500c 569 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\r
e58f1ae5
SW
570 EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
571 } else {\r
0889500c
ZG
572 OsIndicationSupport = 0;\r
573 }\r
574\r
575 if (PcdGetBool (PcdPlatformRecoverySupport)) {\r
576 OsIndicationSupport |= EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;\r
e58f1ae5
SW
577 }\r
578\r
1436aea4 579 if (PcdGetBool (PcdCapsuleOnDiskSupport)) {\r
43311062
WX
580 OsIndicationSupport |= EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;\r
581 }\r
582\r
f4cd24da 583 Status = gRT->SetVariable (\r
cc4812f6 584 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,\r
f4cd24da
RN
585 &gEfiGlobalVariableGuid,\r
586 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1436aea4 587 sizeof (UINT64),\r
f4cd24da
RN
588 &OsIndicationSupport\r
589 );\r
590 //\r
591 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
592 //\r
593 ASSERT_EFI_ERROR (Status);\r
594\r
595 //\r
596 // If OsIndications is invalid, remove it.\r
597 // Invalid case\r
598 // 1. Data size != UINT64\r
599 // 2. OsIndication value inconsistence\r
600 // 3. OsIndication attribute inconsistence\r
601 //\r
602 OsIndication = 0;\r
1436aea4
MK
603 Attributes = 0;\r
604 DataSize = sizeof (UINT64);\r
605 Status = gRT->GetVariable (\r
606 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
607 &gEfiGlobalVariableGuid,\r
608 &Attributes,\r
609 &DataSize,\r
610 &OsIndication\r
611 );\r
f4cd24da
RN
612 if (Status == EFI_NOT_FOUND) {\r
613 return;\r
614 }\r
615\r
616 if ((DataSize != sizeof (OsIndication)) ||\r
617 ((OsIndication & ~OsIndicationSupport) != 0) ||\r
618 (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))\r
1436aea4
MK
619 )\r
620 {\r
87000d77 621 DEBUG ((DEBUG_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
f4cd24da 622 Status = gRT->SetVariable (\r
cc4812f6 623 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
f4cd24da
RN
624 &gEfiGlobalVariableGuid,\r
625 0,\r
626 0,\r
627 NULL\r
628 );\r
629 //\r
630 // Deleting variable with current variable implementation shouldn't fail.\r
631 //\r
1436aea4 632 ASSERT_EFI_ERROR (Status);\r
f4cd24da
RN
633 }\r
634}\r
635\r
636/**\r
637\r
d1102dba 638 Validate variables.\r
f4cd24da
RN
639\r
640**/\r
d1102dba 641VOID\r
f4cd24da
RN
642BdsFormalizeEfiGlobalVariable (\r
643 VOID\r
644 )\r
645{\r
646 //\r
647 // Validate Console variable.\r
648 //\r
cc4812f6
RN
649 BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);\r
650 BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);\r
651 BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);\r
f4cd24da
RN
652\r
653 //\r
654 // Validate OSIndication related variable.\r
655 //\r
656 BdsFormalizeOSIndicationVariable ();\r
657}\r
658\r
f4cd24da
RN
659/**\r
660\r
661 Service routine for BdsInstance->Entry(). Devices are connected, the\r
662 consoles are initialized, and the boot options are tried.\r
663\r
664 @param This Protocol Instance structure.\r
665\r
666**/\r
667VOID\r
668EFIAPI\r
669BdsEntry (\r
670 IN EFI_BDS_ARCH_PROTOCOL *This\r
671 )\r
672{\r
1634214d
RN
673 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;\r
674 UINTN LoadOptionCount;\r
f4cd24da
RN
675 CHAR16 *FirmwareVendor;\r
676 EFI_EVENT HotkeyTriggered;\r
677 UINT64 OsIndication;\r
678 UINTN DataSize;\r
679 EFI_STATUS Status;\r
680 UINT32 BootOptionSupport;\r
681 UINT16 BootTimeOut;\r
d9a7612f 682 EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy;\r
f4cd24da 683 UINTN Index;\r
d175f4e6 684 EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;\r
f4cd24da
RN
685 UINT16 *BootNext;\r
686 CHAR16 BootNextVariableName[sizeof ("Boot####")];\r
1634214d
RN
687 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
688 BOOLEAN BootFwUi;\r
68456d8a
RN
689 BOOLEAN PlatformRecovery;\r
690 BOOLEAN BootSuccess;\r
d175f4e6 691 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
e58f1ae5 692 EFI_STATUS BootManagerMenuStatus;\r
0889500c 693 EFI_BOOT_MANAGER_LOAD_OPTION PlatformDefaultBootOption;\r
f4cd24da
RN
694\r
695 HotkeyTriggered = NULL;\r
696 Status = EFI_SUCCESS;\r
68456d8a 697 BootSuccess = FALSE;\r
f4cd24da
RN
698\r
699 //\r
700 // Insert the performance probe\r
701 //\r
1436aea4
MK
702 PERF_CROSSMODULE_END ("DXE");\r
703 PERF_CROSSMODULE_BEGIN ("BDS");\r
87000d77 704 DEBUG ((DEBUG_INFO, "[Bds] Entry...\n"));\r
f4cd24da 705\r
f4cd24da
RN
706 //\r
707 // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
708 //\r
1436aea4 709 FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);\r
f4cd24da
RN
710 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
711 ASSERT (gST->FirmwareVendor != NULL);\r
712 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
713\r
714 //\r
715 // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
716 //\r
717 gST->Hdr.CRC32 = 0;\r
1436aea4 718 gBS->CalculateCrc32 ((VOID *)gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
f4cd24da
RN
719\r
720 //\r
721 // Validate Variable.\r
722 //\r
723 BdsFormalizeEfiGlobalVariable ();\r
724\r
725 //\r
726 // Mark the read-only variables if the Variable Lock protocol exists\r
727 //\r
1436aea4
MK
728 Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);\r
729 DEBUG ((DEBUG_INFO, "[BdsDxe] Locate Variable Policy protocol - %r\n", Status));\r
f4cd24da 730 if (!EFI_ERROR (Status)) {\r
1a5afd71 731 for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {\r
1436aea4 732 Status = RegisterBasicVariablePolicy (\r
d9a7612f
KL
733 VariablePolicy,\r
734 &gEfiGlobalVariableGuid,\r
735 mReadOnlyVariables[Index],\r
736 VARIABLE_POLICY_NO_MIN_SIZE,\r
737 VARIABLE_POLICY_NO_MAX_SIZE,\r
738 VARIABLE_POLICY_NO_MUST_ATTR,\r
739 VARIABLE_POLICY_NO_CANT_ATTR,\r
740 VARIABLE_POLICY_TYPE_LOCK_NOW\r
741 );\r
1436aea4 742 ASSERT_EFI_ERROR (Status);\r
f4cd24da
RN
743 }\r
744 }\r
745\r
746 InitializeHwErrRecSupport ();\r
747\r
748 //\r
749 // Initialize L"Timeout" EFI global variable.\r
750 //\r
751 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);\r
752 if (BootTimeOut != 0xFFFF) {\r
753 //\r
754 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification\r
755 // define same behavior between no value or 0xFFFF value for L"Timeout".\r
756 //\r
757 BdsDxeSetVariableAndReportStatusCodeOnError (\r
758 EFI_TIME_OUT_VARIABLE_NAME,\r
759 &gEfiGlobalVariableGuid,\r
760 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
761 sizeof (UINT16),\r
762 &BootTimeOut\r
763 );\r
764 }\r
765\r
766 //\r
767 // Initialize L"BootOptionSupport" EFI global variable.\r
768 // Lazy-ConIn implictly disables BDS hotkey.\r
769 //\r
1634214d 770 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;\r
f4cd24da
RN
771 if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
772 BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
773 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
774 }\r
1436aea4 775\r
f4cd24da
RN
776 Status = gRT->SetVariable (\r
777 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
778 &gEfiGlobalVariableGuid,\r
779 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
780 sizeof (BootOptionSupport),\r
781 &BootOptionSupport\r
782 );\r
783 //\r
784 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
785 //\r
786 ASSERT_EFI_ERROR (Status);\r
787\r
788 //\r
0e6584e3
RN
789 // Cache the "BootNext" NV variable before calling any PlatformBootManagerLib APIs\r
790 // This could avoid the "BootNext" set by PlatformBootManagerLib be consumed in this boot.\r
f4cd24da 791 //\r
1436aea4 792 GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **)&BootNext, &DataSize);\r
f4cd24da
RN
793 if (DataSize != sizeof (UINT16)) {\r
794 if (BootNext != NULL) {\r
795 FreePool (BootNext);\r
796 }\r
1436aea4 797\r
f4cd24da
RN
798 BootNext = NULL;\r
799 }\r
f4cd24da
RN
800\r
801 //\r
802 // Initialize the platform language variables\r
803 //\r
804 InitializeLanguage (TRUE);\r
805\r
d175f4e6 806 FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
0889500c 807 if (FilePath == NULL) {\r
92b96395 808 DEBUG ((DEBUG_ERROR, "Fail to allocate memory for default boot file path. Unable to boot.\n"));\r
0889500c
ZG
809 CpuDeadLoop ();\r
810 }\r
1436aea4 811\r
d175f4e6 812 Status = EfiBootManagerInitializeLoadOption (\r
0889500c 813 &PlatformDefaultBootOption,\r
0dc3fb06 814 LoadOptionNumberUnassigned,\r
d175f4e6
RN
815 LoadOptionTypePlatformRecovery,\r
816 LOAD_OPTION_ACTIVE,\r
817 L"Default PlatformRecovery",\r
818 FilePath,\r
819 NULL,\r
820 0\r
821 );\r
822 ASSERT_EFI_ERROR (Status);\r
0889500c
ZG
823\r
824 //\r
825 // System firmware must include a PlatformRecovery#### variable specifying\r
826 // a short-form File Path Media Device Path containing the platform default\r
827 // file path for removable media if the platform supports Platform Recovery.\r
828 //\r
829 if (PcdGetBool (PcdPlatformRecoverySupport)) {\r
830 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
831 if (EfiBootManagerFindLoadOption (&PlatformDefaultBootOption, LoadOptions, LoadOptionCount) == -1) {\r
832 for (Index = 0; Index < LoadOptionCount; Index++) {\r
833 //\r
834 // The PlatformRecovery#### options are sorted by OptionNumber.\r
835 // Find the the smallest unused number as the new OptionNumber.\r
836 //\r
837 if (LoadOptions[Index].OptionNumber != Index) {\r
838 break;\r
839 }\r
0dc3fb06 840 }\r
1436aea4 841\r
0889500c 842 PlatformDefaultBootOption.OptionNumber = Index;\r
1436aea4 843 Status = EfiBootManagerLoadOptionToVariable (&PlatformDefaultBootOption);\r
0889500c 844 ASSERT_EFI_ERROR (Status);\r
0dc3fb06 845 }\r
1436aea4 846\r
0889500c 847 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
0dc3fb06 848 }\r
1436aea4 849\r
d175f4e6
RN
850 FreePool (FilePath);\r
851\r
f4cd24da
RN
852 //\r
853 // Report Status Code to indicate connecting drivers will happen\r
854 //\r
855 REPORT_STATUS_CODE (\r
856 EFI_PROGRESS_CODE,\r
857 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
858 );\r
859\r
8537bd7e
RN
860 //\r
861 // Initialize ConnectConIn event before calling platform code.\r
862 //\r
863 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
864 Status = gBS->CreateEventEx (\r
865 EVT_NOTIFY_SIGNAL,\r
866 TPL_CALLBACK,\r
867 BdsDxeOnConnectConInCallBack,\r
868 NULL,\r
869 &gConnectConInEventGuid,\r
870 &gConnectConInEvent\r
871 );\r
872 if (EFI_ERROR (Status)) {\r
873 gConnectConInEvent = NULL;\r
874 }\r
875 }\r
876\r
f4cd24da
RN
877 //\r
878 // Do the platform init, can be customized by OEM/IBV\r
879 // Possible things that can be done in PlatformBootManagerBeforeConsole:\r
880 // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT\r
881 // > Register new Driver#### or Boot####\r
d1102dba 882 // > Register new Key####: e.g.: F12\r
f4cd24da
RN
883 // > Signal ReadyToLock event\r
884 // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.\r
885 //\r
1436aea4 886 PERF_INMODULE_BEGIN ("PlatformBootManagerBeforeConsole");\r
f4cd24da 887 PlatformBootManagerBeforeConsole ();\r
1436aea4 888 PERF_INMODULE_END ("PlatformBootManagerBeforeConsole");\r
f4cd24da
RN
889\r
890 //\r
891 // Initialize hotkey service\r
892 //\r
893 EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
894\r
895 //\r
1634214d 896 // Execute Driver Options\r
f4cd24da 897 //\r
1634214d
RN
898 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);\r
899 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
900 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
f4cd24da
RN
901\r
902 //\r
903 // Connect consoles\r
904 //\r
1436aea4 905 PERF_INMODULE_BEGIN ("EfiBootManagerConnectAllDefaultConsoles");\r
f4cd24da
RN
906 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
907 EfiBootManagerConnectConsoleVariable (ConOut);\r
908 EfiBootManagerConnectConsoleVariable (ErrOut);\r
f4cd24da 909 //\r
8537bd7e 910 // Do not connect ConIn devices when lazy ConIn feature is ON.\r
f4cd24da 911 //\r
f4cd24da
RN
912 } else {\r
913 EfiBootManagerConnectAllDefaultConsoles ();\r
914 }\r
1436aea4
MK
915\r
916 PERF_INMODULE_END ("EfiBootManagerConnectAllDefaultConsoles");\r
f4cd24da
RN
917\r
918 //\r
919 // Do the platform specific action after the console is ready\r
920 // Possible things that can be done in PlatformBootManagerAfterConsole:\r
921 // > Console post action:\r
922 // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
923 // > Signal console ready platform customized event\r
924 // > Run diagnostics like memory testing\r
925 // > Connect certain devices\r
926 // > Dispatch aditional option roms\r
927 // > Special boot: e.g.: USB boot, enter UI\r
d1102dba 928 //\r
1436aea4 929 PERF_INMODULE_BEGIN ("PlatformBootManagerAfterConsole");\r
f4cd24da 930 PlatformBootManagerAfterConsole ();\r
1436aea4 931 PERF_INMODULE_END ("PlatformBootManagerAfterConsole");\r
6fb8b96d
KM
932\r
933 //\r
934 // If any component set PcdTestKeyUsed to TRUE because use of a test key\r
935 // was detected, then display a warning message on the debug log and the console\r
936 //\r
937 if (PcdGetBool (PcdTestKeyUsed)) {\r
938 DEBUG ((DEBUG_ERROR, "**********************************\n"));\r
939 DEBUG ((DEBUG_ERROR, "** WARNING: Test Key is used. **\n"));\r
940 DEBUG ((DEBUG_ERROR, "**********************************\n"));\r
941 Print (L"** WARNING: Test Key is used. **\n");\r
942 }\r
943\r
68456d8a
RN
944 //\r
945 // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
946 //\r
947 DataSize = sizeof (UINT64);\r
1436aea4
MK
948 Status = gRT->GetVariable (\r
949 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
950 &gEfiGlobalVariableGuid,\r
951 NULL,\r
952 &DataSize,\r
953 &OsIndication\r
954 );\r
68456d8a
RN
955 if (EFI_ERROR (Status)) {\r
956 OsIndication = 0;\r
957 }\r
f4cd24da 958\r
db52c7f7 959 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
960 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
961\r
962 DEBUG ((DEBUG_INFO, "[Bds]OsIndication: %016x\n", OsIndication));\r
963 DEBUG ((DEBUG_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
964 for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
965 DEBUG ((\r
966 DEBUG_INFO,\r
967 " %s Options:\n",\r
968 mBdsLoadOptionName[LoadOptionType]\r
969 ));\r
970 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);\r
971 for (Index = 0; Index < LoadOptionCount; Index++) {\r
f4cd24da 972 DEBUG ((\r
1436aea4
MK
973 DEBUG_INFO,\r
974 " %s%04x: %s \t\t 0x%04x\n",\r
975 mBdsLoadOptionName[LoadOptionType],\r
976 LoadOptions[Index].OptionNumber,\r
977 LoadOptions[Index].Description,\r
978 LoadOptions[Index].Attributes\r
f4cd24da
RN
979 ));\r
980 }\r
1436aea4
MK
981\r
982 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
983 }\r
984\r
985 DEBUG ((DEBUG_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
db52c7f7 986 DEBUG_CODE_END ();\r
f4cd24da
RN
987\r
988 //\r
e58f1ae5 989 // BootManagerMenu doesn't contain the correct information when return status is EFI_NOT_FOUND.\r
f4cd24da 990 //\r
e58f1ae5 991 BootManagerMenuStatus = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
1634214d 992\r
1436aea4
MK
993 BootFwUi = (BOOLEAN)((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\r
994 PlatformRecovery = (BOOLEAN)((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);\r
1634214d
RN
995 //\r
996 // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
d1102dba 997 //\r
68456d8a 998 if (BootFwUi || PlatformRecovery) {\r
1436aea4
MK
999 OsIndication &= ~((UINT64)(EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));\r
1000 Status = gRT->SetVariable (\r
1001 EFI_OS_INDICATIONS_VARIABLE_NAME,\r
1002 &gEfiGlobalVariableGuid,\r
1003 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1004 sizeof (UINT64),\r
1005 &OsIndication\r
1006 );\r
f4cd24da
RN
1007 //\r
1008 // Changing the content without increasing its size with current variable implementation shouldn't fail.\r
1009 //\r
1010 ASSERT_EFI_ERROR (Status);\r
1634214d 1011 }\r
f4cd24da 1012\r
1634214d
RN
1013 //\r
1014 // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
1015 //\r
e58f1ae5 1016 if (BootFwUi && (BootManagerMenuStatus != EFI_NOT_FOUND)) {\r
f4cd24da
RN
1017 //\r
1018 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
1019 //\r
1020 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
1021 BdsDxeOnConnectConInCallBack (NULL, NULL);\r
1022 }\r
1023\r
1024 //\r
1634214d 1025 // Directly enter the setup page.\r
f4cd24da 1026 //\r
1634214d 1027 EfiBootManagerBoot (&BootManagerMenu);\r
f4cd24da
RN
1028 }\r
1029\r
68456d8a
RN
1030 if (!PlatformRecovery) {\r
1031 //\r
1032 // Execute SysPrep####\r
1033 //\r
1034 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
1035 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
1036 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
1634214d 1037\r
68456d8a
RN
1038 //\r
1039 // Execute Key####\r
1040 //\r
67e9ab84 1041 PERF_INMODULE_BEGIN ("BdsWait");\r
68456d8a 1042 BdsWait (HotkeyTriggered);\r
67e9ab84 1043 PERF_INMODULE_END ("BdsWait");\r
68456d8a
RN
1044 //\r
1045 // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.\r
1046 //\r
1047 BdsReadKeys ();\r
1634214d 1048\r
68456d8a 1049 EfiBootManagerHotkeyBoot ();\r
1634214d 1050\r
68456d8a 1051 if (BootNext != NULL) {\r
0e6584e3
RN
1052 //\r
1053 // Delete "BootNext" NV variable before transferring control to it to prevent loops.\r
1054 //\r
1055 Status = gRT->SetVariable (\r
1056 EFI_BOOT_NEXT_VARIABLE_NAME,\r
1057 &gEfiGlobalVariableGuid,\r
1058 0,\r
1059 0,\r
1060 NULL\r
1061 );\r
1062 //\r
1063 // Deleting NV variable shouldn't fail unless it doesn't exist.\r
1064 //\r
1065 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
1066\r
1067 //\r
1068 // Boot to "BootNext"\r
1069 //\r
68456d8a
RN
1070 UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);\r
1071 Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);\r
1072 if (!EFI_ERROR (Status)) {\r
d175f4e6
RN
1073 EfiBootManagerBoot (&LoadOption);\r
1074 EfiBootManagerFreeLoadOption (&LoadOption);\r
d1102dba 1075 if ((LoadOption.Status == EFI_SUCCESS) &&\r
e58f1ae5 1076 (BootManagerMenuStatus != EFI_NOT_FOUND) &&\r
1436aea4
MK
1077 (LoadOption.OptionNumber != BootManagerMenu.OptionNumber))\r
1078 {\r
68456d8a
RN
1079 //\r
1080 // Boot to Boot Manager Menu upon EFI_SUCCESS\r
f5cbc197 1081 // Exception: Do not boot again when the BootNext points to Boot Manager Menu.\r
68456d8a
RN
1082 //\r
1083 EfiBootManagerBoot (&BootManagerMenu);\r
1084 }\r
f4cd24da
RN
1085 }\r
1086 }\r
68456d8a
RN
1087\r
1088 do {\r
1089 //\r
1090 // Retry to boot if any of the boot succeeds\r
1091 //\r
1092 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);\r
e58f1ae5 1093 BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);\r
68456d8a
RN
1094 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
1095 } while (BootSuccess);\r
f4cd24da
RN
1096 }\r
1097\r
f50db933
RN
1098 if (BootManagerMenuStatus != EFI_NOT_FOUND) {\r
1099 EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
1100 }\r
1101\r
68456d8a 1102 if (!BootSuccess) {\r
b1564648 1103 if (PcdGetBool (PcdPlatformRecoverySupport)) {\r
0889500c
ZG
1104 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);\r
1105 ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
1106 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
1107 } else {\r
1108 //\r
1109 // When platform recovery is not enabled, still boot to platform default file path.\r
1110 //\r
1111 EfiBootManagerProcessLoadOption (&PlatformDefaultBootOption);\r
1112 }\r
f4cd24da 1113 }\r
1436aea4 1114\r
0889500c 1115 EfiBootManagerFreeLoadOption (&PlatformDefaultBootOption);\r
68456d8a 1116\r
87000d77 1117 DEBUG ((DEBUG_ERROR, "[Bds] Unable to boot!\n"));\r
1010873b 1118 PlatformBootManagerUnableToBoot ();\r
68456d8a 1119 CpuDeadLoop ();\r
f4cd24da
RN
1120}\r
1121\r
1122/**\r
1123 Set the variable and report the error through status code upon failure.\r
1124\r
1125 @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
1126 Each VariableName is unique for each VendorGuid. VariableName must\r
1127 contain 1 or more characters. If VariableName is an empty string,\r
1128 then EFI_INVALID_PARAMETER is returned.\r
1129 @param VendorGuid A unique identifier for the vendor.\r
1130 @param Attributes Attributes bitmask to set for the variable.\r
d1102dba 1131 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,\r
4073f85d 1132 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero\r
d1102dba
LG
1133 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is\r
1134 set, then a SetVariable() call with a DataSize of zero will not cause any change to\r
1135 the variable value (the timestamp associated with the variable may be updated however\r
1136 even if no new data value is provided,see the description of the\r
1137 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not\r
1138 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).\r
f4cd24da
RN
1139 @param Data The contents for the variable.\r
1140\r
1141 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
1142 defined by the Attributes.\r
1143 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
1144 DataSize exceeds the maximum allowed.\r
1145 @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
1146 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
1147 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
1148 @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
1149 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
4073f85d
ZC
1150 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS\r
1151 being set, but the AuthInfo does NOT pass the validation check carried out by the firmware.\r
f4cd24da
RN
1152\r
1153 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
1154**/\r
1155EFI_STATUS\r
1156BdsDxeSetVariableAndReportStatusCodeOnError (\r
1436aea4
MK
1157 IN CHAR16 *VariableName,\r
1158 IN EFI_GUID *VendorGuid,\r
1159 IN UINT32 Attributes,\r
1160 IN UINTN DataSize,\r
1161 IN VOID *Data\r
f4cd24da
RN
1162 )\r
1163{\r
1164 EFI_STATUS Status;\r
1165 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
1166 UINTN NameSize;\r
1167\r
1168 Status = gRT->SetVariable (\r
1169 VariableName,\r
1170 VendorGuid,\r
1171 Attributes,\r
1172 DataSize,\r
1173 Data\r
1174 );\r
1175 if (EFI_ERROR (Status)) {\r
1436aea4 1176 NameSize = StrSize (VariableName);\r
f4cd24da
RN
1177 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
1178 if (SetVariableStatus != NULL) {\r
1179 CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
1180 SetVariableStatus->NameSize = NameSize;\r
1181 SetVariableStatus->DataSize = DataSize;\r
1182 SetVariableStatus->SetStatus = Status;\r
1183 SetVariableStatus->Attributes = Attributes;\r
1436aea4
MK
1184 CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
1185 CopyMem (((UINT8 *)(SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
f4cd24da
RN
1186\r
1187 REPORT_STATUS_CODE_EX (\r
1188 EFI_ERROR_CODE,\r
1189 PcdGet32 (PcdErrorCodeSetVariable),\r
1190 0,\r
1191 NULL,\r
1192 &gEdkiiStatusCodeDataTypeVariableGuid,\r
1193 SetVariableStatus,\r
1194 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
1195 );\r
1196\r
1197 FreePool (SetVariableStatus);\r
1198 }\r
1199 }\r
1200\r
1201 return Status;\r
1202}\r