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