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