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