• 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 (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
BdsDxeOnConnectConInCallBack(IN EFI_EVENT Event,IN VOID * Context)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
BdsInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
BdsWaitForSingleEvent(IN EFI_EVENT Event,IN UINT64 Timeout OPTIONAL)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
BdsReadKeys(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
BdsWait(IN EFI_EVENT HotkeyTriggered)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
BootBootOptions(IN EFI_BOOT_MANAGER_LOAD_OPTION * BootOptions,IN UINTN BootOptionCount,IN EFI_BOOT_MANAGER_LOAD_OPTION * BootManagerMenu)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
ProcessLoadOptions(IN EFI_BOOT_MANAGER_LOAD_OPTION * LoadOptions,IN UINTN LoadOptionCount)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
BdsFormalizeConsoleVariable(IN CHAR16 * VariableName)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
BdsFormalizeOSIndicationVariable(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
BdsFormalizeEfiGlobalVariable(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
BdsAllocateMemoryForPerformanceData(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
BdsEntry(IN EFI_BDS_ARCH_PROTOCOL * This)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
BdsDxeSetVariableAndReportStatusCodeOnError(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)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 }
1040