]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
OvmfPkg/PlatformBootManagerLib: remove module-local ARRAY_SIZE macro
[mirror_edk2.git] / OvmfPkg / Library / PlatformBootManagerLib / BdsPlatform.c
1 /** @file
2 Platform BDS customizations.
3
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "BdsPlatform.h"
16 #include <Guid/XenInfo.h>
17 #include <Guid/RootBridgesConnectedEventGroup.h>
18 #include <Protocol/FirmwareVolume2.h>
19
20
21 //
22 // Global data
23 //
24
25 VOID *mEfiDevPathNotifyReg;
26 EFI_EVENT mEfiDevPathEvent;
27 VOID *mEmuVariableEventReg;
28 EFI_EVENT mEmuVariableEvent;
29 BOOLEAN mDetectVgaOnly;
30 UINT16 mHostBridgeDevId;
31
32 //
33 // Table of host IRQs matching PCI IRQs A-D
34 // (for configuring PCI Interrupt Line register)
35 //
36 CONST UINT8 PciHostIrqs[] = {
37 0x0a, 0x0a, 0x0b, 0x0b
38 };
39
40 //
41 // Type definitions
42 //
43
44 typedef
45 EFI_STATUS
46 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
47 IN EFI_HANDLE Handle,
48 IN VOID *Instance,
49 IN VOID *Context
50 );
51
52 /**
53 @param[in] Handle - Handle of PCI device instance
54 @param[in] PciIo - PCI IO protocol instance
55 @param[in] Pci - PCI Header register block
56 **/
57 typedef
58 EFI_STATUS
59 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
60 IN EFI_HANDLE Handle,
61 IN EFI_PCI_IO_PROTOCOL *PciIo,
62 IN PCI_TYPE00 *Pci
63 );
64
65
66 //
67 // Function prototypes
68 //
69
70 EFI_STATUS
71 VisitAllInstancesOfProtocol (
72 IN EFI_GUID *Id,
73 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
74 IN VOID *Context
75 );
76
77 EFI_STATUS
78 VisitAllPciInstancesOfProtocol (
79 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
80 );
81
82 VOID
83 InstallDevicePathCallback (
84 VOID
85 );
86
87 VOID
88 PlatformRegisterFvBootOption (
89 EFI_GUID *FileGuid,
90 CHAR16 *Description,
91 UINT32 Attributes
92 )
93 {
94 EFI_STATUS Status;
95 INTN OptionIndex;
96 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
97 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
98 UINTN BootOptionCount;
99 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
100 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
101 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
102
103 Status = gBS->HandleProtocol (
104 gImageHandle,
105 &gEfiLoadedImageProtocolGuid,
106 (VOID **) &LoadedImage
107 );
108 ASSERT_EFI_ERROR (Status);
109
110 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
111 DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
112 ASSERT (DevicePath != NULL);
113 DevicePath = AppendDevicePathNode (
114 DevicePath,
115 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
116 );
117 ASSERT (DevicePath != NULL);
118
119 Status = EfiBootManagerInitializeLoadOption (
120 &NewOption,
121 LoadOptionNumberUnassigned,
122 LoadOptionTypeBoot,
123 Attributes,
124 Description,
125 DevicePath,
126 NULL,
127 0
128 );
129 ASSERT_EFI_ERROR (Status);
130 FreePool (DevicePath);
131
132 BootOptions = EfiBootManagerGetLoadOptions (
133 &BootOptionCount, LoadOptionTypeBoot
134 );
135
136 OptionIndex = EfiBootManagerFindLoadOption (
137 &NewOption, BootOptions, BootOptionCount
138 );
139
140 if (OptionIndex == -1) {
141 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
142 ASSERT_EFI_ERROR (Status);
143 }
144 EfiBootManagerFreeLoadOption (&NewOption);
145 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
146 }
147
148 /**
149 Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
150 whose device paths do not resolve exactly to an FvFile in the system.
151
152 This removes any boot options that point to binaries built into the firmware
153 and have become stale due to any of the following:
154 - DXEFV's base address or size changed (historical),
155 - DXEFV's FvNameGuid changed,
156 - the FILE_GUID of the pointed-to binary changed,
157 - the referenced binary is no longer built into the firmware.
158
159 EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
160 avoids exact duplicates.
161 **/
162 VOID
163 RemoveStaleFvFileOptions (
164 VOID
165 )
166 {
167 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
168 UINTN BootOptionCount;
169 UINTN Index;
170
171 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
172 LoadOptionTypeBoot);
173
174 for (Index = 0; Index < BootOptionCount; ++Index) {
175 EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
176 EFI_STATUS Status;
177 EFI_HANDLE FvHandle;
178
179 //
180 // If the device path starts with neither MemoryMapped(...) nor Fv(...),
181 // then keep the boot option.
182 //
183 Node1 = BootOptions[Index].FilePath;
184 if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
185 DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
186 !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
187 DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
188 continue;
189 }
190
191 //
192 // If the second device path node is not FvFile(...), then keep the boot
193 // option.
194 //
195 Node2 = NextDevicePathNode (Node1);
196 if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
197 DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
198 continue;
199 }
200
201 //
202 // Locate the Firmware Volume2 protocol instance that is denoted by the
203 // boot option. If this lookup fails (i.e., the boot option references a
204 // firmware volume that doesn't exist), then we'll proceed to delete the
205 // boot option.
206 //
207 SearchNode = Node1;
208 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
209 &SearchNode, &FvHandle);
210
211 if (!EFI_ERROR (Status)) {
212 //
213 // The firmware volume was found; now let's see if it contains the FvFile
214 // identified by GUID.
215 //
216 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
217 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
218 UINTN BufferSize;
219 EFI_FV_FILETYPE FoundType;
220 EFI_FV_FILE_ATTRIBUTES FileAttributes;
221 UINT32 AuthenticationStatus;
222
223 Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
224 (VOID **)&FvProtocol);
225 ASSERT_EFI_ERROR (Status);
226
227 FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
228 //
229 // Buffer==NULL means we request metadata only: BufferSize, FoundType,
230 // FileAttributes.
231 //
232 Status = FvProtocol->ReadFile (
233 FvProtocol,
234 &FvFileNode->FvFileName, // NameGuid
235 NULL, // Buffer
236 &BufferSize,
237 &FoundType,
238 &FileAttributes,
239 &AuthenticationStatus
240 );
241 if (!EFI_ERROR (Status)) {
242 //
243 // The FvFile was found. Keep the boot option.
244 //
245 continue;
246 }
247 }
248
249 //
250 // Delete the boot option.
251 //
252 Status = EfiBootManagerDeleteLoadOptionVariable (
253 BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
254 DEBUG_CODE (
255 CHAR16 *DevicePathString;
256
257 DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
258 FALSE, FALSE);
259 DEBUG ((
260 EFI_ERROR (Status) ? EFI_D_WARN : EFI_D_VERBOSE,
261 "%a: removing stale Boot#%04x %s: %r\n",
262 __FUNCTION__,
263 (UINT32)BootOptions[Index].OptionNumber,
264 DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
265 Status
266 ));
267 if (DevicePathString != NULL) {
268 FreePool (DevicePathString);
269 }
270 );
271 }
272
273 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
274 }
275
276 VOID
277 PlatformRegisterOptionsAndKeys (
278 VOID
279 )
280 {
281 EFI_STATUS Status;
282 EFI_INPUT_KEY Enter;
283 EFI_INPUT_KEY F2;
284 EFI_INPUT_KEY Esc;
285 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
286
287 //
288 // Register ENTER as CONTINUE key
289 //
290 Enter.ScanCode = SCAN_NULL;
291 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
292 Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
293 ASSERT_EFI_ERROR (Status);
294
295 //
296 // Map F2 to Boot Manager Menu
297 //
298 F2.ScanCode = SCAN_F2;
299 F2.UnicodeChar = CHAR_NULL;
300 Esc.ScanCode = SCAN_ESC;
301 Esc.UnicodeChar = CHAR_NULL;
302 Status = EfiBootManagerGetBootManagerMenu (&BootOption);
303 ASSERT_EFI_ERROR (Status);
304 Status = EfiBootManagerAddKeyOptionVariable (
305 NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
306 );
307 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
308 Status = EfiBootManagerAddKeyOptionVariable (
309 NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
310 );
311 ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
312 }
313
314 EFI_STATUS
315 EFIAPI
316 ConnectRootBridge (
317 IN EFI_HANDLE RootBridgeHandle,
318 IN VOID *Instance,
319 IN VOID *Context
320 );
321
322 STATIC
323 VOID
324 SaveS3BootScript (
325 VOID
326 );
327
328 //
329 // BDS Platform Functions
330 //
331 VOID
332 EFIAPI
333 PlatformBootManagerBeforeConsole (
334 VOID
335 )
336 /*++
337
338 Routine Description:
339
340 Platform Bds init. Include the platform firmware vendor, revision
341 and so crc check.
342
343 Arguments:
344
345 Returns:
346
347 None.
348
349 --*/
350 {
351 EFI_HANDLE Handle;
352 EFI_STATUS Status;
353 RETURN_STATUS PcdStatus;
354
355 DEBUG ((EFI_D_INFO, "PlatformBootManagerBeforeConsole\n"));
356 InstallDevicePathCallback ();
357
358 VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
359 ConnectRootBridge, NULL);
360
361 //
362 // Signal the ACPI platform driver that it can download QEMU ACPI tables.
363 //
364 EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
365
366 //
367 // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
368 // the preparation of S3 system information. That logic has a hard dependency
369 // on the presence of the FACS ACPI table. Since our ACPI tables are only
370 // installed after PCI enumeration completes, we must not trigger the S3 save
371 // earlier, hence we can't signal End-of-Dxe earlier.
372 //
373 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
374
375 if (QemuFwCfgS3Enabled ()) {
376 //
377 // Save the boot script too. Note that this will require us to emit the
378 // DxeSmmReadyToLock event just below, which in turn locks down SMM.
379 //
380 SaveS3BootScript ();
381 }
382
383 //
384 // Prevent further changes to LockBoxes or SMRAM.
385 //
386 Handle = NULL;
387 Status = gBS->InstallProtocolInterface (&Handle,
388 &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
389 NULL);
390 ASSERT_EFI_ERROR (Status);
391
392 PlatformInitializeConsole (gPlatformConsole);
393 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,
394 GetFrontPageTimeoutFromQemu ());
395 ASSERT_RETURN_ERROR (PcdStatus);
396
397 PlatformRegisterOptionsAndKeys ();
398 }
399
400
401 EFI_STATUS
402 EFIAPI
403 ConnectRootBridge (
404 IN EFI_HANDLE RootBridgeHandle,
405 IN VOID *Instance,
406 IN VOID *Context
407 )
408 {
409 EFI_STATUS Status;
410
411 //
412 // Make the PCI bus driver connect the root bridge, non-recursively. This
413 // will produce a number of child handles with PciIo on them.
414 //
415 Status = gBS->ConnectController (
416 RootBridgeHandle, // ControllerHandle
417 NULL, // DriverImageHandle
418 NULL, // RemainingDevicePath -- produce all
419 // children
420 FALSE // Recursive
421 );
422 return Status;
423 }
424
425
426 EFI_STATUS
427 PrepareLpcBridgeDevicePath (
428 IN EFI_HANDLE DeviceHandle
429 )
430 /*++
431
432 Routine Description:
433
434 Add IsaKeyboard to ConIn,
435 add IsaSerial to ConOut, ConIn, ErrOut.
436 LPC Bridge: 06 01 00
437
438 Arguments:
439
440 DeviceHandle - Handle of PCIIO protocol.
441
442 Returns:
443
444 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
445 EFI_STATUS - No LPC bridge is added.
446
447 --*/
448 {
449 EFI_STATUS Status;
450 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
451 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
452 CHAR16 *DevPathStr;
453
454 DevicePath = NULL;
455 Status = gBS->HandleProtocol (
456 DeviceHandle,
457 &gEfiDevicePathProtocolGuid,
458 (VOID*)&DevicePath
459 );
460 if (EFI_ERROR (Status)) {
461 return Status;
462 }
463 TempDevicePath = DevicePath;
464
465 //
466 // Register Keyboard
467 //
468 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
469
470 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
471
472 //
473 // Register COM1
474 //
475 DevicePath = TempDevicePath;
476 gPnp16550ComPortDeviceNode.UID = 0;
477
478 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
479 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
480 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
481
482 //
483 // Print Device Path
484 //
485 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
486 if (DevPathStr != NULL) {
487 DEBUG((
488 EFI_D_INFO,
489 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
490 __LINE__,
491 gPnp16550ComPortDeviceNode.UID + 1,
492 DevPathStr
493 ));
494 FreePool(DevPathStr);
495 }
496
497 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
498 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
499 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
500
501 //
502 // Register COM2
503 //
504 DevicePath = TempDevicePath;
505 gPnp16550ComPortDeviceNode.UID = 1;
506
507 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
508 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
509 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
510
511 //
512 // Print Device Path
513 //
514 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
515 if (DevPathStr != NULL) {
516 DEBUG((
517 EFI_D_INFO,
518 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
519 __LINE__,
520 gPnp16550ComPortDeviceNode.UID + 1,
521 DevPathStr
522 ));
523 FreePool(DevPathStr);
524 }
525
526 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
527 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
528 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
529
530 return EFI_SUCCESS;
531 }
532
533 EFI_STATUS
534 GetGopDevicePath (
535 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
536 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
537 )
538 {
539 UINTN Index;
540 EFI_STATUS Status;
541 EFI_HANDLE PciDeviceHandle;
542 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
543 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
544 UINTN GopHandleCount;
545 EFI_HANDLE *GopHandleBuffer;
546
547 if (PciDevicePath == NULL || GopDevicePath == NULL) {
548 return EFI_INVALID_PARAMETER;
549 }
550
551 //
552 // Initialize the GopDevicePath to be PciDevicePath
553 //
554 *GopDevicePath = PciDevicePath;
555 TempPciDevicePath = PciDevicePath;
556
557 Status = gBS->LocateDevicePath (
558 &gEfiDevicePathProtocolGuid,
559 &TempPciDevicePath,
560 &PciDeviceHandle
561 );
562 if (EFI_ERROR (Status)) {
563 return Status;
564 }
565
566 //
567 // Try to connect this handle, so that GOP driver could start on this
568 // device and create child handles with GraphicsOutput Protocol installed
569 // on them, then we get device paths of these child handles and select
570 // them as possible console device.
571 //
572 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
573
574 Status = gBS->LocateHandleBuffer (
575 ByProtocol,
576 &gEfiGraphicsOutputProtocolGuid,
577 NULL,
578 &GopHandleCount,
579 &GopHandleBuffer
580 );
581 if (!EFI_ERROR (Status)) {
582 //
583 // Add all the child handles as possible Console Device
584 //
585 for (Index = 0; Index < GopHandleCount; Index++) {
586 Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
587 if (EFI_ERROR (Status)) {
588 continue;
589 }
590 if (CompareMem (
591 PciDevicePath,
592 TempDevicePath,
593 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
594 ) == 0) {
595 //
596 // In current implementation, we only enable one of the child handles
597 // as console device, i.e. sotre one of the child handle's device
598 // path to variable "ConOut"
599 // In future, we could select all child handles to be console device
600 //
601
602 *GopDevicePath = TempDevicePath;
603
604 //
605 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
606 // Add the integrity GOP device path.
607 //
608 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
609 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
610 }
611 }
612 gBS->FreePool (GopHandleBuffer);
613 }
614
615 return EFI_SUCCESS;
616 }
617
618 EFI_STATUS
619 PreparePciDisplayDevicePath (
620 IN EFI_HANDLE DeviceHandle
621 )
622 /*++
623
624 Routine Description:
625
626 Add PCI VGA to ConOut.
627 PCI VGA: 03 00 00
628
629 Arguments:
630
631 DeviceHandle - Handle of PCIIO protocol.
632
633 Returns:
634
635 EFI_SUCCESS - PCI VGA is added to ConOut.
636 EFI_STATUS - No PCI VGA device is added.
637
638 --*/
639 {
640 EFI_STATUS Status;
641 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
642 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
643
644 DevicePath = NULL;
645 GopDevicePath = NULL;
646 Status = gBS->HandleProtocol (
647 DeviceHandle,
648 &gEfiDevicePathProtocolGuid,
649 (VOID*)&DevicePath
650 );
651 if (EFI_ERROR (Status)) {
652 return Status;
653 }
654
655 GetGopDevicePath (DevicePath, &GopDevicePath);
656 DevicePath = GopDevicePath;
657
658 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
659
660 return EFI_SUCCESS;
661 }
662
663 EFI_STATUS
664 PreparePciSerialDevicePath (
665 IN EFI_HANDLE DeviceHandle
666 )
667 /*++
668
669 Routine Description:
670
671 Add PCI Serial to ConOut, ConIn, ErrOut.
672 PCI Serial: 07 00 02
673
674 Arguments:
675
676 DeviceHandle - Handle of PCIIO protocol.
677
678 Returns:
679
680 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
681 EFI_STATUS - No PCI Serial device is added.
682
683 --*/
684 {
685 EFI_STATUS Status;
686 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
687
688 DevicePath = NULL;
689 Status = gBS->HandleProtocol (
690 DeviceHandle,
691 &gEfiDevicePathProtocolGuid,
692 (VOID*)&DevicePath
693 );
694 if (EFI_ERROR (Status)) {
695 return Status;
696 }
697
698 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
699 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
700
701 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
702 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
703 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
704
705 return EFI_SUCCESS;
706 }
707
708 EFI_STATUS
709 VisitAllInstancesOfProtocol (
710 IN EFI_GUID *Id,
711 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
712 IN VOID *Context
713 )
714 {
715 EFI_STATUS Status;
716 UINTN HandleCount;
717 EFI_HANDLE *HandleBuffer;
718 UINTN Index;
719 VOID *Instance;
720
721 //
722 // Start to check all the PciIo to find all possible device
723 //
724 HandleCount = 0;
725 HandleBuffer = NULL;
726 Status = gBS->LocateHandleBuffer (
727 ByProtocol,
728 Id,
729 NULL,
730 &HandleCount,
731 &HandleBuffer
732 );
733 if (EFI_ERROR (Status)) {
734 return Status;
735 }
736
737 for (Index = 0; Index < HandleCount; Index++) {
738 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
739 if (EFI_ERROR (Status)) {
740 continue;
741 }
742
743 Status = (*CallBackFunction) (
744 HandleBuffer[Index],
745 Instance,
746 Context
747 );
748 }
749
750 gBS->FreePool (HandleBuffer);
751
752 return EFI_SUCCESS;
753 }
754
755
756 EFI_STATUS
757 EFIAPI
758 VisitingAPciInstance (
759 IN EFI_HANDLE Handle,
760 IN VOID *Instance,
761 IN VOID *Context
762 )
763 {
764 EFI_STATUS Status;
765 EFI_PCI_IO_PROTOCOL *PciIo;
766 PCI_TYPE00 Pci;
767
768 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
769
770 //
771 // Check for all PCI device
772 //
773 Status = PciIo->Pci.Read (
774 PciIo,
775 EfiPciIoWidthUint32,
776 0,
777 sizeof (Pci) / sizeof (UINT32),
778 &Pci
779 );
780 if (EFI_ERROR (Status)) {
781 return Status;
782 }
783
784 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
785 Handle,
786 PciIo,
787 &Pci
788 );
789
790 }
791
792
793
794 EFI_STATUS
795 VisitAllPciInstances (
796 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
797 )
798 {
799 return VisitAllInstancesOfProtocol (
800 &gEfiPciIoProtocolGuid,
801 VisitingAPciInstance,
802 (VOID*)(UINTN) CallBackFunction
803 );
804 }
805
806
807 /**
808 Do platform specific PCI Device check and add them to
809 ConOut, ConIn, ErrOut.
810
811 @param[in] Handle - Handle of PCI device instance
812 @param[in] PciIo - PCI IO protocol instance
813 @param[in] Pci - PCI Header register block
814
815 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
816 @retval EFI_STATUS - PCI Device check or Console variable update fail.
817
818 **/
819 EFI_STATUS
820 EFIAPI
821 DetectAndPreparePlatformPciDevicePath (
822 IN EFI_HANDLE Handle,
823 IN EFI_PCI_IO_PROTOCOL *PciIo,
824 IN PCI_TYPE00 *Pci
825 )
826 {
827 EFI_STATUS Status;
828
829 Status = PciIo->Attributes (
830 PciIo,
831 EfiPciIoAttributeOperationEnable,
832 EFI_PCI_DEVICE_ENABLE,
833 NULL
834 );
835 ASSERT_EFI_ERROR (Status);
836
837 if (!mDetectVgaOnly) {
838 //
839 // Here we decide whether it is LPC Bridge
840 //
841 if ((IS_PCI_LPC (Pci)) ||
842 ((IS_PCI_ISA_PDECODE (Pci)) &&
843 (Pci->Hdr.VendorId == 0x8086) &&
844 (Pci->Hdr.DeviceId == 0x7000)
845 )
846 ) {
847 //
848 // Add IsaKeyboard to ConIn,
849 // add IsaSerial to ConOut, ConIn, ErrOut
850 //
851 DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
852 PrepareLpcBridgeDevicePath (Handle);
853 return EFI_SUCCESS;
854 }
855 //
856 // Here we decide which Serial device to enable in PCI bus
857 //
858 if (IS_PCI_16550SERIAL (Pci)) {
859 //
860 // Add them to ConOut, ConIn, ErrOut.
861 //
862 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
863 PreparePciSerialDevicePath (Handle);
864 return EFI_SUCCESS;
865 }
866 }
867
868 //
869 // Here we decide which display device to enable in PCI bus
870 //
871 if (IS_PCI_DISPLAY (Pci)) {
872 //
873 // Add them to ConOut.
874 //
875 DEBUG ((EFI_D_INFO, "Found PCI display device\n"));
876 PreparePciDisplayDevicePath (Handle);
877 return EFI_SUCCESS;
878 }
879
880 return Status;
881 }
882
883
884 /**
885 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
886
887 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
888
889 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
890 @retval EFI_STATUS - PCI Device check or Console variable update fail.
891
892 **/
893 EFI_STATUS
894 DetectAndPreparePlatformPciDevicePaths (
895 BOOLEAN DetectVgaOnly
896 )
897 {
898 mDetectVgaOnly = DetectVgaOnly;
899 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
900 }
901
902
903 VOID
904 PlatformInitializeConsole (
905 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
906 )
907 /*++
908
909 Routine Description:
910
911 Connect the predefined platform default console device. Always try to find
912 and enable the vga device if have.
913
914 Arguments:
915
916 PlatformConsole - Predefined platform default console device array.
917 --*/
918 {
919 UINTN Index;
920 EFI_DEVICE_PATH_PROTOCOL *VarConout;
921 EFI_DEVICE_PATH_PROTOCOL *VarConin;
922
923 //
924 // Connect RootBridge
925 //
926 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout, NULL);
927 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);
928
929 if (VarConout == NULL || VarConin == NULL) {
930 //
931 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
932 //
933 DetectAndPreparePlatformPciDevicePaths (FALSE);
934
935 //
936 // Have chance to connect the platform default console,
937 // the platform default console is the minimum device group
938 // the platform should support
939 //
940 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
941 //
942 // Update the console variable with the connect type
943 //
944 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
945 EfiBootManagerUpdateConsoleVariable (ConIn, PlatformConsole[Index].DevicePath, NULL);
946 }
947 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
948 EfiBootManagerUpdateConsoleVariable (ConOut, PlatformConsole[Index].DevicePath, NULL);
949 }
950 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
951 EfiBootManagerUpdateConsoleVariable (ErrOut, PlatformConsole[Index].DevicePath, NULL);
952 }
953 }
954 } else {
955 //
956 // Only detect VGA device and add them to ConOut
957 //
958 DetectAndPreparePlatformPciDevicePaths (TRUE);
959 }
960 }
961
962
963 /**
964 Configure PCI Interrupt Line register for applicable devices
965 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
966
967 @param[in] Handle - Handle of PCI device instance
968 @param[in] PciIo - PCI IO protocol instance
969 @param[in] PciHdr - PCI Header register block
970
971 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
972
973 **/
974 EFI_STATUS
975 EFIAPI
976 SetPciIntLine (
977 IN EFI_HANDLE Handle,
978 IN EFI_PCI_IO_PROTOCOL *PciIo,
979 IN PCI_TYPE00 *PciHdr
980 )
981 {
982 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
983 EFI_DEVICE_PATH_PROTOCOL *DevPath;
984 UINTN RootSlot;
985 UINTN Idx;
986 UINT8 IrqLine;
987 EFI_STATUS Status;
988 UINT32 RootBusNumber;
989
990 Status = EFI_SUCCESS;
991
992 if (PciHdr->Device.InterruptPin != 0) {
993
994 DevPathNode = DevicePathFromHandle (Handle);
995 ASSERT (DevPathNode != NULL);
996 DevPath = DevPathNode;
997
998 RootBusNumber = 0;
999 if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
1000 DevicePathSubType (DevPathNode) == ACPI_DP &&
1001 ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
1002 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
1003 }
1004
1005 //
1006 // Compute index into PciHostIrqs[] table by walking
1007 // the device path and adding up all device numbers
1008 //
1009 Status = EFI_NOT_FOUND;
1010 RootSlot = 0;
1011 Idx = PciHdr->Device.InterruptPin - 1;
1012 while (!IsDevicePathEnd (DevPathNode)) {
1013 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
1014 DevicePathSubType (DevPathNode) == HW_PCI_DP) {
1015
1016 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1017
1018 //
1019 // Unlike SeaBIOS, which starts climbing from the leaf device
1020 // up toward the root, we traverse the device path starting at
1021 // the root moving toward the leaf node.
1022 // The slot number of the top-level parent bridge is needed for
1023 // Q35 cases with more than 24 slots on the root bus.
1024 //
1025 if (Status != EFI_SUCCESS) {
1026 Status = EFI_SUCCESS;
1027 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1028 }
1029 }
1030
1031 DevPathNode = NextDevicePathNode (DevPathNode);
1032 }
1033 if (EFI_ERROR (Status)) {
1034 return Status;
1035 }
1036 if (RootBusNumber == 0 && RootSlot == 0) {
1037 DEBUG((
1038 EFI_D_ERROR,
1039 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1040 __FUNCTION__
1041 ));
1042 ASSERT (FALSE);
1043 }
1044
1045 //
1046 // Final PciHostIrqs[] index calculation depends on the platform
1047 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1048 //
1049 switch (mHostBridgeDevId) {
1050 case INTEL_82441_DEVICE_ID:
1051 Idx -= 1;
1052 break;
1053 case INTEL_Q35_MCH_DEVICE_ID:
1054 //
1055 // SeaBIOS contains the following comment:
1056 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1057 // with a different starting index - see q35-acpi-dsdt.dsl.
1058 //
1059 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1060 //
1061 if (RootSlot > 24) {
1062 //
1063 // in this case, subtract back out RootSlot from Idx
1064 // (SeaBIOS never adds it to begin with, but that would make our
1065 // device path traversal loop above too awkward)
1066 //
1067 Idx -= RootSlot;
1068 }
1069 break;
1070 default:
1071 ASSERT (FALSE); // should never get here
1072 }
1073 Idx %= ARRAY_SIZE (PciHostIrqs);
1074 IrqLine = PciHostIrqs[Idx];
1075
1076 DEBUG_CODE_BEGIN ();
1077 {
1078 CHAR16 *DevPathString;
1079 STATIC CHAR16 Fallback[] = L"<failed to convert>";
1080 UINTN Segment, Bus, Device, Function;
1081
1082 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
1083 if (DevPathString == NULL) {
1084 DevPathString = Fallback;
1085 }
1086 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
1087 ASSERT_EFI_ERROR (Status);
1088
1089 DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
1090 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
1091 IrqLine));
1092
1093 if (DevPathString != Fallback) {
1094 FreePool (DevPathString);
1095 }
1096 }
1097 DEBUG_CODE_END ();
1098
1099 //
1100 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1101 //
1102 Status = PciIo->Pci.Write (
1103 PciIo,
1104 EfiPciIoWidthUint8,
1105 PCI_INT_LINE_OFFSET,
1106 1,
1107 &IrqLine
1108 );
1109 }
1110
1111 return Status;
1112 }
1113
1114
1115 VOID
1116 PciAcpiInitialization (
1117 )
1118 {
1119 UINTN Pmba;
1120
1121 //
1122 // Query Host Bridge DID to determine platform type
1123 //
1124 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
1125 switch (mHostBridgeDevId) {
1126 case INTEL_82441_DEVICE_ID:
1127 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1128 //
1129 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1130 //
1131 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1132 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1133 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1134 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1135 break;
1136 case INTEL_Q35_MCH_DEVICE_ID:
1137 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1138 //
1139 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1140 //
1141 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1142 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1143 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1144 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1145 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1146 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1147 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1148 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1149 break;
1150 default:
1151 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1152 __FUNCTION__, mHostBridgeDevId));
1153 ASSERT (FALSE);
1154 return;
1155 }
1156
1157 //
1158 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1159 //
1160 VisitAllPciInstances (SetPciIntLine);
1161
1162 //
1163 // Set ACPI SCI_EN bit in PMCNTRL
1164 //
1165 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1166 }
1167
1168 /**
1169 This function detects if OVMF is running on Xen.
1170
1171 **/
1172 STATIC
1173 BOOLEAN
1174 XenDetected (
1175 VOID
1176 )
1177 {
1178 EFI_HOB_GUID_TYPE *GuidHob;
1179 STATIC INTN FoundHob = -1;
1180
1181 if (FoundHob == 0) {
1182 return FALSE;
1183 } else if (FoundHob == 1) {
1184 return TRUE;
1185 }
1186
1187 //
1188 // See if a XenInfo HOB is available
1189 //
1190 GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid);
1191 if (GuidHob == NULL) {
1192 FoundHob = 0;
1193 return FALSE;
1194 }
1195
1196 FoundHob = 1;
1197 return TRUE;
1198 }
1199
1200 EFI_STATUS
1201 EFIAPI
1202 ConnectRecursivelyIfPciMassStorage (
1203 IN EFI_HANDLE Handle,
1204 IN EFI_PCI_IO_PROTOCOL *Instance,
1205 IN PCI_TYPE00 *PciHeader
1206 )
1207 {
1208 EFI_STATUS Status;
1209 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1210 CHAR16 *DevPathStr;
1211
1212 //
1213 // Recognize PCI Mass Storage, and Xen PCI devices
1214 //
1215 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||
1216 (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) {
1217 DevicePath = NULL;
1218 Status = gBS->HandleProtocol (
1219 Handle,
1220 &gEfiDevicePathProtocolGuid,
1221 (VOID*)&DevicePath
1222 );
1223 if (EFI_ERROR (Status)) {
1224 return Status;
1225 }
1226
1227 //
1228 // Print Device Path
1229 //
1230 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1231 if (DevPathStr != NULL) {
1232 DEBUG((
1233 EFI_D_INFO,
1234 "Found %s device: %s\n",
1235 IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ? L"Mass Storage" : L"Xen",
1236 DevPathStr
1237 ));
1238 FreePool(DevPathStr);
1239 }
1240
1241 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
1242 if (EFI_ERROR (Status)) {
1243 return Status;
1244 }
1245
1246 }
1247
1248 return EFI_SUCCESS;
1249 }
1250
1251
1252 /**
1253 This notification function is invoked when the
1254 EMU Variable FVB has been changed.
1255
1256 @param Event The event that occurred
1257 @param Context For EFI compatibility. Not used.
1258
1259 **/
1260 VOID
1261 EFIAPI
1262 EmuVariablesUpdatedCallback (
1263 IN EFI_EVENT Event,
1264 IN VOID *Context
1265 )
1266 {
1267 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
1268 UpdateNvVarsOnFileSystem ();
1269 }
1270
1271
1272 EFI_STATUS
1273 EFIAPI
1274 VisitingFileSystemInstance (
1275 IN EFI_HANDLE Handle,
1276 IN VOID *Instance,
1277 IN VOID *Context
1278 )
1279 {
1280 EFI_STATUS Status;
1281 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
1282 RETURN_STATUS PcdStatus;
1283
1284 if (ConnectedToFileSystem) {
1285 return EFI_ALREADY_STARTED;
1286 }
1287
1288 Status = ConnectNvVarsToFileSystem (Handle);
1289 if (EFI_ERROR (Status)) {
1290 return Status;
1291 }
1292
1293 ConnectedToFileSystem = TRUE;
1294 mEmuVariableEvent =
1295 EfiCreateProtocolNotifyEvent (
1296 &gEfiDevicePathProtocolGuid,
1297 TPL_CALLBACK,
1298 EmuVariablesUpdatedCallback,
1299 NULL,
1300 &mEmuVariableEventReg
1301 );
1302 PcdStatus = PcdSet64S (PcdEmuVariableEvent,
1303 (UINT64)(UINTN) mEmuVariableEvent);
1304 ASSERT_RETURN_ERROR (PcdStatus);
1305
1306 return EFI_SUCCESS;
1307 }
1308
1309
1310 VOID
1311 PlatformBdsRestoreNvVarsFromHardDisk (
1312 )
1313 {
1314 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1315 VisitAllInstancesOfProtocol (
1316 &gEfiSimpleFileSystemProtocolGuid,
1317 VisitingFileSystemInstance,
1318 NULL
1319 );
1320
1321 }
1322
1323 VOID
1324 PlatformBdsConnectSequence (
1325 VOID
1326 )
1327 /*++
1328
1329 Routine Description:
1330
1331 Connect with predefined platform connect sequence,
1332 the OEM/IBV can customize with their own connect sequence.
1333
1334 Arguments:
1335
1336 None.
1337
1338 Returns:
1339
1340 None.
1341
1342 --*/
1343 {
1344 UINTN Index;
1345
1346 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
1347
1348 Index = 0;
1349
1350 //
1351 // Here we can get the customized platform connect sequence
1352 // Notes: we can connect with new variable which record the
1353 // last time boots connect device path sequence
1354 //
1355 while (gPlatformConnectSequence[Index] != NULL) {
1356 //
1357 // Build the platform boot option
1358 //
1359 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1360 Index++;
1361 }
1362
1363 //
1364 // Just use the simple policy to connect all devices
1365 //
1366 DEBUG ((EFI_D_INFO, "EfiBootManagerConnectAll\n"));
1367 EfiBootManagerConnectAll ();
1368
1369 PciAcpiInitialization ();
1370 }
1371
1372 /**
1373 Save the S3 boot script.
1374
1375 Note that DxeSmmReadyToLock must be signaled after this function returns;
1376 otherwise the script wouldn't be saved actually.
1377 **/
1378 STATIC
1379 VOID
1380 SaveS3BootScript (
1381 VOID
1382 )
1383 {
1384 EFI_STATUS Status;
1385 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1386 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1387
1388 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
1389 (VOID **) &BootScript);
1390 ASSERT_EFI_ERROR (Status);
1391
1392 //
1393 // Despite the opcode documentation in the PI spec, the protocol
1394 // implementation embeds a deep copy of the info in the boot script, rather
1395 // than storing just a pointer to runtime or NVS storage.
1396 //
1397 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1398 (UINT32) sizeof Info,
1399 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
1400 ASSERT_EFI_ERROR (Status);
1401 }
1402
1403
1404 VOID
1405 EFIAPI
1406 PlatformBootManagerAfterConsole (
1407 VOID
1408 )
1409 /*++
1410
1411 Routine Description:
1412
1413 The function will execute with as the platform policy, current policy
1414 is driven by boot mode. IBV/OEM can customize this code for their specific
1415 policy action.
1416
1417 --*/
1418 {
1419 EFI_BOOT_MODE BootMode;
1420
1421 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
1422
1423 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1424 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1425 "from disk since flash variables appear to be supported.\n"));
1426 } else {
1427 //
1428 // Try to restore variables from the hard disk early so
1429 // they can be used for the other BDS connect operations.
1430 //
1431 PlatformBdsRestoreNvVarsFromHardDisk ();
1432 }
1433
1434 //
1435 // Get current Boot Mode
1436 //
1437 BootMode = GetBootModeHob ();
1438 DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
1439
1440 //
1441 // Go the different platform policy with different boot mode
1442 // Notes: this part code can be change with the table policy
1443 //
1444 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1445
1446 //
1447 // Logo show
1448 //
1449 BootLogoEnableLogo ();
1450
1451 //
1452 // Perform some platform specific connect sequence
1453 //
1454 PlatformBdsConnectSequence ();
1455
1456 //
1457 // Process QEMU's -kernel command line option
1458 //
1459 TryRunningQemuKernel ();
1460
1461 EfiBootManagerRefreshAllBootOption ();
1462
1463 //
1464 // Register UEFI Shell
1465 //
1466 PlatformRegisterFvBootOption (
1467 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
1468 );
1469
1470 RemoveStaleFvFileOptions ();
1471 SetBootOrderFromQemu ();
1472 }
1473
1474 /**
1475 This notification function is invoked when an instance of the
1476 EFI_DEVICE_PATH_PROTOCOL is produced.
1477
1478 @param Event The event that occurred
1479 @param Context For EFI compatibility. Not used.
1480
1481 **/
1482 VOID
1483 EFIAPI
1484 NotifyDevPath (
1485 IN EFI_EVENT Event,
1486 IN VOID *Context
1487 )
1488 {
1489 EFI_HANDLE Handle;
1490 EFI_STATUS Status;
1491 UINTN BufferSize;
1492 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1493 ATAPI_DEVICE_PATH *Atapi;
1494
1495 //
1496 // Examine all new handles
1497 //
1498 for (;;) {
1499 //
1500 // Get the next handle
1501 //
1502 BufferSize = sizeof (Handle);
1503 Status = gBS->LocateHandle (
1504 ByRegisterNotify,
1505 NULL,
1506 mEfiDevPathNotifyReg,
1507 &BufferSize,
1508 &Handle
1509 );
1510
1511 //
1512 // If not found, we're done
1513 //
1514 if (EFI_NOT_FOUND == Status) {
1515 break;
1516 }
1517
1518 if (EFI_ERROR (Status)) {
1519 continue;
1520 }
1521
1522 //
1523 // Get the DevicePath protocol on that handle
1524 //
1525 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1526 ASSERT_EFI_ERROR (Status);
1527
1528 while (!IsDevicePathEnd (DevPathNode)) {
1529 //
1530 // Find the handler to dump this device path node
1531 //
1532 if (
1533 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1534 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1535 ) {
1536 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1537 PciOr16 (
1538 PCI_LIB_ADDRESS (
1539 0,
1540 1,
1541 1,
1542 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1543 ),
1544 BIT15
1545 );
1546 }
1547
1548 //
1549 // Next device path node
1550 //
1551 DevPathNode = NextDevicePathNode (DevPathNode);
1552 }
1553 }
1554
1555 return;
1556 }
1557
1558
1559 VOID
1560 InstallDevicePathCallback (
1561 VOID
1562 )
1563 {
1564 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1565 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1566 &gEfiDevicePathProtocolGuid,
1567 TPL_CALLBACK,
1568 NotifyDevPath,
1569 NULL,
1570 &mEfiDevPathNotifyReg
1571 );
1572 }
1573
1574 /**
1575 This function is called each second during the boot manager waits the timeout.
1576
1577 @param TimeoutRemain The remaining timeout.
1578 **/
1579 VOID
1580 EFIAPI
1581 PlatformBootManagerWaitCallback (
1582 UINT16 TimeoutRemain
1583 )
1584 {
1585 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
1586 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
1587 UINT16 Timeout;
1588
1589 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1590
1591 Black.Raw = 0x00000000;
1592 White.Raw = 0x00FFFFFF;
1593
1594 BootLogoUpdateProgress (
1595 White.Pixel,
1596 Black.Pixel,
1597 L"Start boot option",
1598 White.Pixel,
1599 (Timeout - TimeoutRemain) * 100 / Timeout,
1600 0
1601 );
1602 }
1603