]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BdsEntry.c
MdeModulePkg BdsDxe: Change file format which the existed folder has mixed file format.
[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
311 // supports boot manager menu, and if firmware is configured to boot in an
312 // interactive mode, the boot manager will stop processing the BootOrder variable and
313 // present a boot manager menu to the user.
314 //
315 if (BootOptions[Index].Status == EFI_SUCCESS) {
316 EfiBootManagerBoot (BootManagerMenu);
317 break;
318 }
319 }
320
321 return (BOOLEAN) (Index < BootOptionCount);
322 }
323
324 /**
325 The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.
326
327 @param LoadOptions Load option array.
328 @param LoadOptionCount Load option count.
329 **/
330 VOID
331 ProcessLoadOptions (
332 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,
333 IN UINTN LoadOptionCount
334 )
335 {
336 EFI_STATUS Status;
337 UINTN Index;
338 BOOLEAN ReconnectAll;
339 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
340
341 ReconnectAll = FALSE;
342 LoadOptionType = LoadOptionTypeMax;
343
344 //
345 // Process the driver option
346 //
347 for (Index = 0; Index < LoadOptionCount; Index++) {
348 //
349 // All the load options in the array should be of the same type.
350 //
351 if (Index == 0) {
352 LoadOptionType = LoadOptions[Index].OptionType;
353 }
354 ASSERT (LoadOptionType == LoadOptions[Index].OptionType);
355
356 Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);
357
358 if (!EFI_ERROR (Status)) {
359 if (LoadOptionType == LoadOptionTypePlatformRecovery) {
360 //
361 // Stop processing if any entry is successful
362 //
363 break;
364 }
365 if ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {
366 ReconnectAll = TRUE;
367 }
368 }
369 }
370
371 //
372 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
373 // then all of the EFI drivers in the system will be disconnected and
374 // reconnected after the last driver load option is processed.
375 //
376 if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {
377 EfiBootManagerDisconnectAll ();
378 EfiBootManagerConnectAll ();
379 }
380 }
381
382 /**
383
384 Validate input console variable data.
385
386 If found the device path is not a valid device path, remove the variable.
387
388 @param VariableName Input console variable name.
389
390 **/
391 VOID
392 BdsFormalizeConsoleVariable (
393 IN CHAR16 *VariableName
394 )
395 {
396 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
397 UINTN VariableSize;
398 EFI_STATUS Status;
399
400 GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);
401 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {
402 Status = gRT->SetVariable (
403 VariableName,
404 &gEfiGlobalVariableGuid,
405 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
406 0,
407 NULL
408 );
409 //
410 // Deleting variable with current variable implementation shouldn't fail.
411 //
412 ASSERT_EFI_ERROR (Status);
413 }
414
415 if (DevicePath != NULL) {
416 FreePool (DevicePath);
417 }
418 }
419
420 /**
421 Formalize OsIndication related variables.
422
423 For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
424 Delete OsIndications variable if it is not NV/BS/RT UINT64.
425
426 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
427
428 **/
429 VOID
430 BdsFormalizeOSIndicationVariable (
431 VOID
432 )
433 {
434 EFI_STATUS Status;
435 UINT64 OsIndicationSupport;
436 UINT64 OsIndication;
437 UINTN DataSize;
438 UINT32 Attributes;
439
440 //
441 // OS indicater support variable
442 //
443 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;
444 Status = gRT->SetVariable (
445 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
446 &gEfiGlobalVariableGuid,
447 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
448 sizeof(UINT64),
449 &OsIndicationSupport
450 );
451 //
452 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
453 //
454 ASSERT_EFI_ERROR (Status);
455
456 //
457 // If OsIndications is invalid, remove it.
458 // Invalid case
459 // 1. Data size != UINT64
460 // 2. OsIndication value inconsistence
461 // 3. OsIndication attribute inconsistence
462 //
463 OsIndication = 0;
464 Attributes = 0;
465 DataSize = sizeof(UINT64);
466 Status = gRT->GetVariable (
467 EFI_OS_INDICATIONS_VARIABLE_NAME,
468 &gEfiGlobalVariableGuid,
469 &Attributes,
470 &DataSize,
471 &OsIndication
472 );
473 if (Status == EFI_NOT_FOUND) {
474 return;
475 }
476
477 if ((DataSize != sizeof (OsIndication)) ||
478 ((OsIndication & ~OsIndicationSupport) != 0) ||
479 (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))
480 ){
481
482 DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));
483 Status = gRT->SetVariable (
484 EFI_OS_INDICATIONS_VARIABLE_NAME,
485 &gEfiGlobalVariableGuid,
486 0,
487 0,
488 NULL
489 );
490 //
491 // Deleting variable with current variable implementation shouldn't fail.
492 //
493 ASSERT_EFI_ERROR(Status);
494 }
495 }
496
497 /**
498
499 Validate variables.
500
501 **/
502 VOID
503 BdsFormalizeEfiGlobalVariable (
504 VOID
505 )
506 {
507 //
508 // Validate Console variable.
509 //
510 BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);
511 BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);
512 BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);
513
514 //
515 // Validate OSIndication related variable.
516 //
517 BdsFormalizeOSIndicationVariable ();
518 }
519
520 /**
521
522 Allocate a block of memory that will contain performance data to OS.
523
524 **/
525 VOID
526 BdsAllocateMemoryForPerformanceData (
527 VOID
528 )
529 {
530 EFI_STATUS Status;
531 EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;
532 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
533
534 AcpiLowMemoryBase = 0x0FFFFFFFFULL;
535
536 //
537 // Allocate a block of memory that will contain performance data to OS.
538 //
539 Status = gBS->AllocatePages (
540 AllocateMaxAddress,
541 EfiReservedMemoryType,
542 EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),
543 &AcpiLowMemoryBase
544 );
545 if (!EFI_ERROR (Status)) {
546 //
547 // Save the pointer to variable for use in S3 resume.
548 //
549 Status = BdsDxeSetVariableAndReportStatusCodeOnError (
550 L"PerfDataMemAddr",
551 &gPerformanceProtocolGuid,
552 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
553 sizeof (EFI_PHYSICAL_ADDRESS),
554 &AcpiLowMemoryBase
555 );
556 if (EFI_ERROR (Status)) {
557 DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));
558 }
559 //
560 // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists
561 // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.
562 //
563 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
564 if (!EFI_ERROR (Status)) {
565 Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);
566 ASSERT_EFI_ERROR (Status);
567 }
568 }
569 }
570
571 /**
572
573 Service routine for BdsInstance->Entry(). Devices are connected, the
574 consoles are initialized, and the boot options are tried.
575
576 @param This Protocol Instance structure.
577
578 **/
579 VOID
580 EFIAPI
581 BdsEntry (
582 IN EFI_BDS_ARCH_PROTOCOL *This
583 )
584 {
585 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;
586 UINTN LoadOptionCount;
587 CHAR16 *FirmwareVendor;
588 EFI_EVENT HotkeyTriggered;
589 UINT64 OsIndication;
590 UINTN DataSize;
591 EFI_STATUS Status;
592 UINT32 BootOptionSupport;
593 UINT16 BootTimeOut;
594 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
595 UINTN Index;
596 EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;
597 UINT16 *BootNext;
598 CHAR16 BootNextVariableName[sizeof ("Boot####")];
599 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
600 BOOLEAN BootFwUi;
601 BOOLEAN PlatformRecovery;
602 BOOLEAN BootSuccess;
603 EFI_DEVICE_PATH_PROTOCOL *FilePath;
604
605 HotkeyTriggered = NULL;
606 Status = EFI_SUCCESS;
607 BootSuccess = FALSE;
608
609 //
610 // Insert the performance probe
611 //
612 PERF_END (NULL, "DXE", NULL, 0);
613 PERF_START (NULL, "BDS", NULL, 0);
614 DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));
615
616 PERF_CODE (
617 BdsAllocateMemoryForPerformanceData ();
618 );
619
620 //
621 // Fill in FirmwareVendor and FirmwareRevision from PCDs
622 //
623 FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);
624 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);
625 ASSERT (gST->FirmwareVendor != NULL);
626 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);
627
628 //
629 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
630 //
631 gST->Hdr.CRC32 = 0;
632 gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);
633
634 //
635 // Validate Variable.
636 //
637 BdsFormalizeEfiGlobalVariable ();
638
639 //
640 // Mark the read-only variables if the Variable Lock protocol exists
641 //
642 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
643 DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));
644 if (!EFI_ERROR (Status)) {
645 for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {
646 Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);
647 ASSERT_EFI_ERROR (Status);
648 }
649 }
650
651 InitializeHwErrRecSupport ();
652
653 //
654 // Initialize L"Timeout" EFI global variable.
655 //
656 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
657 if (BootTimeOut != 0xFFFF) {
658 //
659 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
660 // define same behavior between no value or 0xFFFF value for L"Timeout".
661 //
662 BdsDxeSetVariableAndReportStatusCodeOnError (
663 EFI_TIME_OUT_VARIABLE_NAME,
664 &gEfiGlobalVariableGuid,
665 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
666 sizeof (UINT16),
667 &BootTimeOut
668 );
669 }
670
671 //
672 // Initialize L"BootOptionSupport" EFI global variable.
673 // Lazy-ConIn implictly disables BDS hotkey.
674 //
675 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;
676 if (!PcdGetBool (PcdConInConnectOnDemand)) {
677 BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
678 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
679 }
680 Status = gRT->SetVariable (
681 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
682 &gEfiGlobalVariableGuid,
683 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
684 sizeof (BootOptionSupport),
685 &BootOptionSupport
686 );
687 //
688 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
689 //
690 ASSERT_EFI_ERROR (Status);
691
692 //
693 // Cache and remove the "BootNext" NV variable.
694 //
695 GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);
696 if (DataSize != sizeof (UINT16)) {
697 if (BootNext != NULL) {
698 FreePool (BootNext);
699 }
700 BootNext = NULL;
701 }
702 Status = gRT->SetVariable (
703 EFI_BOOT_NEXT_VARIABLE_NAME,
704 &gEfiGlobalVariableGuid,
705 0,
706 0,
707 NULL
708 );
709 //
710 // Deleting NV variable shouldn't fail unless it doesn't exist.
711 //
712 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
713
714 //
715 // Initialize the platform language variables
716 //
717 InitializeLanguage (TRUE);
718
719 //
720 // System firmware must include a PlatformRecovery#### variable specifying
721 // a short-form File Path Media Device Path containing the platform default
722 // file path for removable media
723 //
724 FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);
725 Status = EfiBootManagerInitializeLoadOption (
726 &LoadOption,
727 0,
728 LoadOptionTypePlatformRecovery,
729 LOAD_OPTION_ACTIVE,
730 L"Default PlatformRecovery",
731 FilePath,
732 NULL,
733 0
734 );
735 ASSERT_EFI_ERROR (Status);
736 EfiBootManagerLoadOptionToVariable (&LoadOption);
737 EfiBootManagerFreeLoadOption (&LoadOption);
738 FreePool (FilePath);
739
740 //
741 // Report Status Code to indicate connecting drivers will happen
742 //
743 REPORT_STATUS_CODE (
744 EFI_PROGRESS_CODE,
745 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)
746 );
747
748 //
749 // Do the platform init, can be customized by OEM/IBV
750 // Possible things that can be done in PlatformBootManagerBeforeConsole:
751 // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT
752 // > Register new Driver#### or Boot####
753 // > Register new Key####: e.g.: F12
754 // > Signal ReadyToLock event
755 // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.
756 //
757 PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);
758 PlatformBootManagerBeforeConsole ();
759 PERF_END (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);
760
761 //
762 // Initialize hotkey service
763 //
764 EfiBootManagerStartHotkeyService (&HotkeyTriggered);
765
766 //
767 // Execute Driver Options
768 //
769 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);
770 ProcessLoadOptions (LoadOptions, LoadOptionCount);
771 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
772
773 //
774 // Connect consoles
775 //
776 PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);
777 if (PcdGetBool (PcdConInConnectOnDemand)) {
778 EfiBootManagerConnectConsoleVariable (ConOut);
779 EfiBootManagerConnectConsoleVariable (ErrOut);
780
781 //
782 // Initialize ConnectConIn event
783 //
784 Status = gBS->CreateEventEx (
785 EVT_NOTIFY_SIGNAL,
786 TPL_CALLBACK,
787 BdsDxeOnConnectConInCallBack,
788 NULL,
789 &gConnectConInEventGuid,
790 &gConnectConInEvent
791 );
792 if (EFI_ERROR (Status)) {
793 gConnectConInEvent = NULL;
794 }
795 } else {
796 EfiBootManagerConnectAllDefaultConsoles ();
797 }
798 PERF_END (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);
799
800 //
801 // Do the platform specific action after the console is ready
802 // Possible things that can be done in PlatformBootManagerAfterConsole:
803 // > Console post action:
804 // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
805 // > Signal console ready platform customized event
806 // > Run diagnostics like memory testing
807 // > Connect certain devices
808 // > Dispatch aditional option roms
809 // > Special boot: e.g.: USB boot, enter UI
810 //
811 PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);
812 PlatformBootManagerAfterConsole ();
813 PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);
814 //
815 // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
816 //
817 DataSize = sizeof (UINT64);
818 Status = gRT->GetVariable (
819 EFI_OS_INDICATIONS_VARIABLE_NAME,
820 &gEfiGlobalVariableGuid,
821 NULL,
822 &DataSize,
823 &OsIndication
824 );
825 if (EFI_ERROR (Status)) {
826 OsIndication = 0;
827 }
828
829 DEBUG_CODE (
830 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
831 DEBUG ((EFI_D_INFO, "[Bds]OsIndication: %016x\n", OsIndication));
832 DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));
833 for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {
834 DEBUG ((
835 EFI_D_INFO, " %s Options:\n",
836 mBdsLoadOptionName[LoadOptionType]
837 ));
838 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);
839 for (Index = 0; Index < LoadOptionCount; Index++) {
840 DEBUG ((
841 EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",
842 mBdsLoadOptionName[LoadOptionType],
843 LoadOptions[Index].OptionNumber,
844 LoadOptions[Index].Description,
845 LoadOptions[Index].Attributes
846 ));
847 }
848 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
849 }
850 DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));
851 );
852
853 //
854 // BootManagerMenu always contains the correct information even call fails.
855 //
856 EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
857
858 BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);
859 PlatformRecovery = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);
860 //
861 // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
862 //
863 if (BootFwUi || PlatformRecovery) {
864 OsIndication &= ~((UINT64) (EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));
865 Status = gRT->SetVariable (
866 EFI_OS_INDICATIONS_VARIABLE_NAME,
867 &gEfiGlobalVariableGuid,
868 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
869 sizeof(UINT64),
870 &OsIndication
871 );
872 //
873 // Changing the content without increasing its size with current variable implementation shouldn't fail.
874 //
875 ASSERT_EFI_ERROR (Status);
876 }
877
878 //
879 // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
880 //
881 if (BootFwUi) {
882 //
883 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
884 //
885 if (PcdGetBool (PcdConInConnectOnDemand)) {
886 BdsDxeOnConnectConInCallBack (NULL, NULL);
887 }
888
889 //
890 // Directly enter the setup page.
891 //
892 EfiBootManagerBoot (&BootManagerMenu);
893 }
894
895 if (!PlatformRecovery) {
896 //
897 // Execute SysPrep####
898 //
899 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);
900 ProcessLoadOptions (LoadOptions, LoadOptionCount);
901 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
902
903 //
904 // Execute Key####
905 //
906 PERF_START (NULL, "BdsWait", "BDS", 0);
907 BdsWait (HotkeyTriggered);
908 PERF_END (NULL, "BdsWait", "BDS", 0);
909
910 //
911 // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.
912 //
913 BdsReadKeys ();
914
915 EfiBootManagerHotkeyBoot ();
916
917 //
918 // Boot to "BootNext"
919 //
920 if (BootNext != NULL) {
921 UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);
922 Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);
923 if (!EFI_ERROR (Status)) {
924 EfiBootManagerBoot (&LoadOption);
925 EfiBootManagerFreeLoadOption (&LoadOption);
926 if (LoadOption.Status == EFI_SUCCESS) {
927 //
928 // Boot to Boot Manager Menu upon EFI_SUCCESS
929 //
930 EfiBootManagerBoot (&BootManagerMenu);
931 }
932 }
933 }
934
935 do {
936 //
937 // Retry to boot if any of the boot succeeds
938 //
939 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);
940 BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, &BootManagerMenu);
941 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
942 } while (BootSuccess);
943 }
944
945 EfiBootManagerFreeLoadOption (&BootManagerMenu);
946
947 if (!BootSuccess) {
948 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);
949 ProcessLoadOptions (LoadOptions, LoadOptionCount);
950 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
951 }
952
953 DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));
954 CpuDeadLoop ();
955 }
956
957 /**
958 Set the variable and report the error through status code upon failure.
959
960 @param VariableName A Null-terminated string that is the name of the vendor's variable.
961 Each VariableName is unique for each VendorGuid. VariableName must
962 contain 1 or more characters. If VariableName is an empty string,
963 then EFI_INVALID_PARAMETER is returned.
964 @param VendorGuid A unique identifier for the vendor.
965 @param Attributes Attributes bitmask to set for the variable.
966 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
967 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
968 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
969 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
970 set, then a SetVariable() call with a DataSize of zero will not cause any change to
971 the variable value (the timestamp associated with the variable may be updated however
972 even if no new data value is provided,see the description of the
973 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
974 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
975 @param Data The contents for the variable.
976
977 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
978 defined by the Attributes.
979 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
980 DataSize exceeds the maximum allowed.
981 @retval EFI_INVALID_PARAMETER VariableName is an empty string.
982 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
983 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
984 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
985 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
986 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
987 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
988 does NOT pass the validation check carried out by the firmware.
989
990 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
991 **/
992 EFI_STATUS
993 BdsDxeSetVariableAndReportStatusCodeOnError (
994 IN CHAR16 *VariableName,
995 IN EFI_GUID *VendorGuid,
996 IN UINT32 Attributes,
997 IN UINTN DataSize,
998 IN VOID *Data
999 )
1000 {
1001 EFI_STATUS Status;
1002 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
1003 UINTN NameSize;
1004
1005 Status = gRT->SetVariable (
1006 VariableName,
1007 VendorGuid,
1008 Attributes,
1009 DataSize,
1010 Data
1011 );
1012 if (EFI_ERROR (Status)) {
1013 NameSize = StrSize (VariableName);
1014 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
1015 if (SetVariableStatus != NULL) {
1016 CopyGuid (&SetVariableStatus->Guid, VendorGuid);
1017 SetVariableStatus->NameSize = NameSize;
1018 SetVariableStatus->DataSize = DataSize;
1019 SetVariableStatus->SetStatus = Status;
1020 SetVariableStatus->Attributes = Attributes;
1021 CopyMem (SetVariableStatus + 1, VariableName, NameSize);
1022 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);
1023
1024 REPORT_STATUS_CODE_EX (
1025 EFI_ERROR_CODE,
1026 PcdGet32 (PcdErrorCodeSetVariable),
1027 0,
1028 NULL,
1029 &gEdkiiStatusCodeDataTypeVariableGuid,
1030 SetVariableStatus,
1031 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
1032 );
1033
1034 FreePool (SetVariableStatus);
1035 }
1036 }
1037
1038 return Status;
1039 }