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