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