VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/BdsDxe/BdsEntry.c@ 101297

Last change on this file since 101297 was 101291, checked in by vboxsync, 17 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette