]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
OvmfPkg/PlatformBootManagerLib: minimize the set of connected devices
[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 //
393 // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
394 //
395 EfiBootManagerDispatchDeferredImages ();
396
397 PlatformInitializeConsole (gPlatformConsole);
398 PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,
399 GetFrontPageTimeoutFromQemu ());
400 ASSERT_RETURN_ERROR (PcdStatus);
401
402 PlatformRegisterOptionsAndKeys ();
403 }
404
405
406 EFI_STATUS
407 EFIAPI
408 ConnectRootBridge (
409 IN EFI_HANDLE RootBridgeHandle,
410 IN VOID *Instance,
411 IN VOID *Context
412 )
413 {
414 EFI_STATUS Status;
415
416 //
417 // Make the PCI bus driver connect the root bridge, non-recursively. This
418 // will produce a number of child handles with PciIo on them.
419 //
420 Status = gBS->ConnectController (
421 RootBridgeHandle, // ControllerHandle
422 NULL, // DriverImageHandle
423 NULL, // RemainingDevicePath -- produce all
424 // children
425 FALSE // Recursive
426 );
427 return Status;
428 }
429
430
431 EFI_STATUS
432 PrepareLpcBridgeDevicePath (
433 IN EFI_HANDLE DeviceHandle
434 )
435 /*++
436
437 Routine Description:
438
439 Add IsaKeyboard to ConIn,
440 add IsaSerial to ConOut, ConIn, ErrOut.
441 LPC Bridge: 06 01 00
442
443 Arguments:
444
445 DeviceHandle - Handle of PCIIO protocol.
446
447 Returns:
448
449 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
450 EFI_STATUS - No LPC bridge is added.
451
452 --*/
453 {
454 EFI_STATUS Status;
455 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
456 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
457 CHAR16 *DevPathStr;
458
459 DevicePath = NULL;
460 Status = gBS->HandleProtocol (
461 DeviceHandle,
462 &gEfiDevicePathProtocolGuid,
463 (VOID*)&DevicePath
464 );
465 if (EFI_ERROR (Status)) {
466 return Status;
467 }
468 TempDevicePath = DevicePath;
469
470 //
471 // Register Keyboard
472 //
473 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
474
475 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
476
477 //
478 // Register COM1
479 //
480 DevicePath = TempDevicePath;
481 gPnp16550ComPortDeviceNode.UID = 0;
482
483 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
484 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
485 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
486
487 //
488 // Print Device Path
489 //
490 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
491 if (DevPathStr != NULL) {
492 DEBUG((
493 EFI_D_INFO,
494 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
495 __LINE__,
496 gPnp16550ComPortDeviceNode.UID + 1,
497 DevPathStr
498 ));
499 FreePool(DevPathStr);
500 }
501
502 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
503 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
504 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
505
506 //
507 // Register COM2
508 //
509 DevicePath = TempDevicePath;
510 gPnp16550ComPortDeviceNode.UID = 1;
511
512 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
513 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
514 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
515
516 //
517 // Print Device Path
518 //
519 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
520 if (DevPathStr != NULL) {
521 DEBUG((
522 EFI_D_INFO,
523 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
524 __LINE__,
525 gPnp16550ComPortDeviceNode.UID + 1,
526 DevPathStr
527 ));
528 FreePool(DevPathStr);
529 }
530
531 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
532 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
533 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
534
535 return EFI_SUCCESS;
536 }
537
538 EFI_STATUS
539 GetGopDevicePath (
540 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
541 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
542 )
543 {
544 UINTN Index;
545 EFI_STATUS Status;
546 EFI_HANDLE PciDeviceHandle;
547 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
548 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
549 UINTN GopHandleCount;
550 EFI_HANDLE *GopHandleBuffer;
551
552 if (PciDevicePath == NULL || GopDevicePath == NULL) {
553 return EFI_INVALID_PARAMETER;
554 }
555
556 //
557 // Initialize the GopDevicePath to be PciDevicePath
558 //
559 *GopDevicePath = PciDevicePath;
560 TempPciDevicePath = PciDevicePath;
561
562 Status = gBS->LocateDevicePath (
563 &gEfiDevicePathProtocolGuid,
564 &TempPciDevicePath,
565 &PciDeviceHandle
566 );
567 if (EFI_ERROR (Status)) {
568 return Status;
569 }
570
571 //
572 // Try to connect this handle, so that GOP driver could start on this
573 // device and create child handles with GraphicsOutput Protocol installed
574 // on them, then we get device paths of these child handles and select
575 // them as possible console device.
576 //
577 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
578
579 Status = gBS->LocateHandleBuffer (
580 ByProtocol,
581 &gEfiGraphicsOutputProtocolGuid,
582 NULL,
583 &GopHandleCount,
584 &GopHandleBuffer
585 );
586 if (!EFI_ERROR (Status)) {
587 //
588 // Add all the child handles as possible Console Device
589 //
590 for (Index = 0; Index < GopHandleCount; Index++) {
591 Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
592 if (EFI_ERROR (Status)) {
593 continue;
594 }
595 if (CompareMem (
596 PciDevicePath,
597 TempDevicePath,
598 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
599 ) == 0) {
600 //
601 // In current implementation, we only enable one of the child handles
602 // as console device, i.e. sotre one of the child handle's device
603 // path to variable "ConOut"
604 // In future, we could select all child handles to be console device
605 //
606
607 *GopDevicePath = TempDevicePath;
608
609 //
610 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
611 // Add the integrity GOP device path.
612 //
613 EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
614 EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
615 }
616 }
617 gBS->FreePool (GopHandleBuffer);
618 }
619
620 return EFI_SUCCESS;
621 }
622
623 EFI_STATUS
624 PreparePciDisplayDevicePath (
625 IN EFI_HANDLE DeviceHandle
626 )
627 /*++
628
629 Routine Description:
630
631 Add PCI VGA to ConOut.
632 PCI VGA: 03 00 00
633
634 Arguments:
635
636 DeviceHandle - Handle of PCIIO protocol.
637
638 Returns:
639
640 EFI_SUCCESS - PCI VGA is added to ConOut.
641 EFI_STATUS - No PCI VGA device is added.
642
643 --*/
644 {
645 EFI_STATUS Status;
646 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
647 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
648
649 DevicePath = NULL;
650 GopDevicePath = NULL;
651 Status = gBS->HandleProtocol (
652 DeviceHandle,
653 &gEfiDevicePathProtocolGuid,
654 (VOID*)&DevicePath
655 );
656 if (EFI_ERROR (Status)) {
657 return Status;
658 }
659
660 GetGopDevicePath (DevicePath, &GopDevicePath);
661 DevicePath = GopDevicePath;
662
663 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
664
665 return EFI_SUCCESS;
666 }
667
668 EFI_STATUS
669 PreparePciSerialDevicePath (
670 IN EFI_HANDLE DeviceHandle
671 )
672 /*++
673
674 Routine Description:
675
676 Add PCI Serial to ConOut, ConIn, ErrOut.
677 PCI Serial: 07 00 02
678
679 Arguments:
680
681 DeviceHandle - Handle of PCIIO protocol.
682
683 Returns:
684
685 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
686 EFI_STATUS - No PCI Serial device is added.
687
688 --*/
689 {
690 EFI_STATUS Status;
691 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
692
693 DevicePath = NULL;
694 Status = gBS->HandleProtocol (
695 DeviceHandle,
696 &gEfiDevicePathProtocolGuid,
697 (VOID*)&DevicePath
698 );
699 if (EFI_ERROR (Status)) {
700 return Status;
701 }
702
703 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
704 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
705
706 EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
707 EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
708 EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
709
710 return EFI_SUCCESS;
711 }
712
713 EFI_STATUS
714 VisitAllInstancesOfProtocol (
715 IN EFI_GUID *Id,
716 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
717 IN VOID *Context
718 )
719 {
720 EFI_STATUS Status;
721 UINTN HandleCount;
722 EFI_HANDLE *HandleBuffer;
723 UINTN Index;
724 VOID *Instance;
725
726 //
727 // Start to check all the PciIo to find all possible device
728 //
729 HandleCount = 0;
730 HandleBuffer = NULL;
731 Status = gBS->LocateHandleBuffer (
732 ByProtocol,
733 Id,
734 NULL,
735 &HandleCount,
736 &HandleBuffer
737 );
738 if (EFI_ERROR (Status)) {
739 return Status;
740 }
741
742 for (Index = 0; Index < HandleCount; Index++) {
743 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
744 if (EFI_ERROR (Status)) {
745 continue;
746 }
747
748 Status = (*CallBackFunction) (
749 HandleBuffer[Index],
750 Instance,
751 Context
752 );
753 }
754
755 gBS->FreePool (HandleBuffer);
756
757 return EFI_SUCCESS;
758 }
759
760
761 EFI_STATUS
762 EFIAPI
763 VisitingAPciInstance (
764 IN EFI_HANDLE Handle,
765 IN VOID *Instance,
766 IN VOID *Context
767 )
768 {
769 EFI_STATUS Status;
770 EFI_PCI_IO_PROTOCOL *PciIo;
771 PCI_TYPE00 Pci;
772
773 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
774
775 //
776 // Check for all PCI device
777 //
778 Status = PciIo->Pci.Read (
779 PciIo,
780 EfiPciIoWidthUint32,
781 0,
782 sizeof (Pci) / sizeof (UINT32),
783 &Pci
784 );
785 if (EFI_ERROR (Status)) {
786 return Status;
787 }
788
789 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
790 Handle,
791 PciIo,
792 &Pci
793 );
794
795 }
796
797
798
799 EFI_STATUS
800 VisitAllPciInstances (
801 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
802 )
803 {
804 return VisitAllInstancesOfProtocol (
805 &gEfiPciIoProtocolGuid,
806 VisitingAPciInstance,
807 (VOID*)(UINTN) CallBackFunction
808 );
809 }
810
811
812 /**
813 Do platform specific PCI Device check and add them to
814 ConOut, ConIn, ErrOut.
815
816 @param[in] Handle - Handle of PCI device instance
817 @param[in] PciIo - PCI IO protocol instance
818 @param[in] Pci - PCI Header register block
819
820 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
821 @retval EFI_STATUS - PCI Device check or Console variable update fail.
822
823 **/
824 EFI_STATUS
825 EFIAPI
826 DetectAndPreparePlatformPciDevicePath (
827 IN EFI_HANDLE Handle,
828 IN EFI_PCI_IO_PROTOCOL *PciIo,
829 IN PCI_TYPE00 *Pci
830 )
831 {
832 EFI_STATUS Status;
833
834 Status = PciIo->Attributes (
835 PciIo,
836 EfiPciIoAttributeOperationEnable,
837 EFI_PCI_DEVICE_ENABLE,
838 NULL
839 );
840 ASSERT_EFI_ERROR (Status);
841
842 if (!mDetectVgaOnly) {
843 //
844 // Here we decide whether it is LPC Bridge
845 //
846 if ((IS_PCI_LPC (Pci)) ||
847 ((IS_PCI_ISA_PDECODE (Pci)) &&
848 (Pci->Hdr.VendorId == 0x8086) &&
849 (Pci->Hdr.DeviceId == 0x7000)
850 )
851 ) {
852 //
853 // Add IsaKeyboard to ConIn,
854 // add IsaSerial to ConOut, ConIn, ErrOut
855 //
856 DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
857 PrepareLpcBridgeDevicePath (Handle);
858 return EFI_SUCCESS;
859 }
860 //
861 // Here we decide which Serial device to enable in PCI bus
862 //
863 if (IS_PCI_16550SERIAL (Pci)) {
864 //
865 // Add them to ConOut, ConIn, ErrOut.
866 //
867 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
868 PreparePciSerialDevicePath (Handle);
869 return EFI_SUCCESS;
870 }
871 }
872
873 //
874 // Here we decide which display device to enable in PCI bus
875 //
876 if (IS_PCI_DISPLAY (Pci)) {
877 //
878 // Add them to ConOut.
879 //
880 DEBUG ((EFI_D_INFO, "Found PCI display device\n"));
881 PreparePciDisplayDevicePath (Handle);
882 return EFI_SUCCESS;
883 }
884
885 return Status;
886 }
887
888
889 /**
890 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
891
892 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
893
894 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
895 @retval EFI_STATUS - PCI Device check or Console variable update fail.
896
897 **/
898 EFI_STATUS
899 DetectAndPreparePlatformPciDevicePaths (
900 BOOLEAN DetectVgaOnly
901 )
902 {
903 mDetectVgaOnly = DetectVgaOnly;
904 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
905 }
906
907
908 VOID
909 PlatformInitializeConsole (
910 IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
911 )
912 /*++
913
914 Routine Description:
915
916 Connect the predefined platform default console device. Always try to find
917 and enable the vga device if have.
918
919 Arguments:
920
921 PlatformConsole - Predefined platform default console device array.
922 --*/
923 {
924 UINTN Index;
925 EFI_DEVICE_PATH_PROTOCOL *VarConout;
926 EFI_DEVICE_PATH_PROTOCOL *VarConin;
927
928 //
929 // Connect RootBridge
930 //
931 GetEfiGlobalVariable2 (EFI_CON_OUT_VARIABLE_NAME, (VOID **) &VarConout, NULL);
932 GetEfiGlobalVariable2 (EFI_CON_IN_VARIABLE_NAME, (VOID **) &VarConin, NULL);
933
934 if (VarConout == NULL || VarConin == NULL) {
935 //
936 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
937 //
938 DetectAndPreparePlatformPciDevicePaths (FALSE);
939
940 //
941 // Have chance to connect the platform default console,
942 // the platform default console is the minimum device group
943 // the platform should support
944 //
945 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
946 //
947 // Update the console variable with the connect type
948 //
949 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
950 EfiBootManagerUpdateConsoleVariable (ConIn, PlatformConsole[Index].DevicePath, NULL);
951 }
952 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
953 EfiBootManagerUpdateConsoleVariable (ConOut, PlatformConsole[Index].DevicePath, NULL);
954 }
955 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
956 EfiBootManagerUpdateConsoleVariable (ErrOut, PlatformConsole[Index].DevicePath, NULL);
957 }
958 }
959 } else {
960 //
961 // Only detect VGA device and add them to ConOut
962 //
963 DetectAndPreparePlatformPciDevicePaths (TRUE);
964 }
965 }
966
967
968 /**
969 Configure PCI Interrupt Line register for applicable devices
970 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
971
972 @param[in] Handle - Handle of PCI device instance
973 @param[in] PciIo - PCI IO protocol instance
974 @param[in] PciHdr - PCI Header register block
975
976 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
977
978 **/
979 EFI_STATUS
980 EFIAPI
981 SetPciIntLine (
982 IN EFI_HANDLE Handle,
983 IN EFI_PCI_IO_PROTOCOL *PciIo,
984 IN PCI_TYPE00 *PciHdr
985 )
986 {
987 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
988 EFI_DEVICE_PATH_PROTOCOL *DevPath;
989 UINTN RootSlot;
990 UINTN Idx;
991 UINT8 IrqLine;
992 EFI_STATUS Status;
993 UINT32 RootBusNumber;
994
995 Status = EFI_SUCCESS;
996
997 if (PciHdr->Device.InterruptPin != 0) {
998
999 DevPathNode = DevicePathFromHandle (Handle);
1000 ASSERT (DevPathNode != NULL);
1001 DevPath = DevPathNode;
1002
1003 RootBusNumber = 0;
1004 if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
1005 DevicePathSubType (DevPathNode) == ACPI_DP &&
1006 ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
1007 RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
1008 }
1009
1010 //
1011 // Compute index into PciHostIrqs[] table by walking
1012 // the device path and adding up all device numbers
1013 //
1014 Status = EFI_NOT_FOUND;
1015 RootSlot = 0;
1016 Idx = PciHdr->Device.InterruptPin - 1;
1017 while (!IsDevicePathEnd (DevPathNode)) {
1018 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
1019 DevicePathSubType (DevPathNode) == HW_PCI_DP) {
1020
1021 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1022
1023 //
1024 // Unlike SeaBIOS, which starts climbing from the leaf device
1025 // up toward the root, we traverse the device path starting at
1026 // the root moving toward the leaf node.
1027 // The slot number of the top-level parent bridge is needed for
1028 // Q35 cases with more than 24 slots on the root bus.
1029 //
1030 if (Status != EFI_SUCCESS) {
1031 Status = EFI_SUCCESS;
1032 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
1033 }
1034 }
1035
1036 DevPathNode = NextDevicePathNode (DevPathNode);
1037 }
1038 if (EFI_ERROR (Status)) {
1039 return Status;
1040 }
1041 if (RootBusNumber == 0 && RootSlot == 0) {
1042 DEBUG((
1043 EFI_D_ERROR,
1044 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
1045 __FUNCTION__
1046 ));
1047 ASSERT (FALSE);
1048 }
1049
1050 //
1051 // Final PciHostIrqs[] index calculation depends on the platform
1052 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
1053 //
1054 switch (mHostBridgeDevId) {
1055 case INTEL_82441_DEVICE_ID:
1056 Idx -= 1;
1057 break;
1058 case INTEL_Q35_MCH_DEVICE_ID:
1059 //
1060 // SeaBIOS contains the following comment:
1061 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
1062 // with a different starting index - see q35-acpi-dsdt.dsl.
1063 //
1064 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
1065 //
1066 if (RootSlot > 24) {
1067 //
1068 // in this case, subtract back out RootSlot from Idx
1069 // (SeaBIOS never adds it to begin with, but that would make our
1070 // device path traversal loop above too awkward)
1071 //
1072 Idx -= RootSlot;
1073 }
1074 break;
1075 default:
1076 ASSERT (FALSE); // should never get here
1077 }
1078 Idx %= ARRAY_SIZE (PciHostIrqs);
1079 IrqLine = PciHostIrqs[Idx];
1080
1081 DEBUG_CODE_BEGIN ();
1082 {
1083 CHAR16 *DevPathString;
1084 STATIC CHAR16 Fallback[] = L"<failed to convert>";
1085 UINTN Segment, Bus, Device, Function;
1086
1087 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
1088 if (DevPathString == NULL) {
1089 DevPathString = Fallback;
1090 }
1091 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
1092 ASSERT_EFI_ERROR (Status);
1093
1094 DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
1095 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
1096 IrqLine));
1097
1098 if (DevPathString != Fallback) {
1099 FreePool (DevPathString);
1100 }
1101 }
1102 DEBUG_CODE_END ();
1103
1104 //
1105 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
1106 //
1107 Status = PciIo->Pci.Write (
1108 PciIo,
1109 EfiPciIoWidthUint8,
1110 PCI_INT_LINE_OFFSET,
1111 1,
1112 &IrqLine
1113 );
1114 }
1115
1116 return Status;
1117 }
1118
1119
1120 VOID
1121 PciAcpiInitialization (
1122 )
1123 {
1124 UINTN Pmba;
1125
1126 //
1127 // Query Host Bridge DID to determine platform type
1128 //
1129 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
1130 switch (mHostBridgeDevId) {
1131 case INTEL_82441_DEVICE_ID:
1132 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
1133 //
1134 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
1135 //
1136 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
1137 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
1138 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
1139 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
1140 break;
1141 case INTEL_Q35_MCH_DEVICE_ID:
1142 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
1143 //
1144 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
1145 //
1146 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
1147 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
1148 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
1149 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
1150 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
1151 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
1152 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
1153 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
1154 break;
1155 default:
1156 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
1157 __FUNCTION__, mHostBridgeDevId));
1158 ASSERT (FALSE);
1159 return;
1160 }
1161
1162 //
1163 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
1164 //
1165 VisitAllPciInstances (SetPciIntLine);
1166
1167 //
1168 // Set ACPI SCI_EN bit in PMCNTRL
1169 //
1170 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
1171 }
1172
1173 /**
1174 This function detects if OVMF is running on Xen.
1175
1176 **/
1177 STATIC
1178 BOOLEAN
1179 XenDetected (
1180 VOID
1181 )
1182 {
1183 EFI_HOB_GUID_TYPE *GuidHob;
1184 STATIC INTN FoundHob = -1;
1185
1186 if (FoundHob == 0) {
1187 return FALSE;
1188 } else if (FoundHob == 1) {
1189 return TRUE;
1190 }
1191
1192 //
1193 // See if a XenInfo HOB is available
1194 //
1195 GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid);
1196 if (GuidHob == NULL) {
1197 FoundHob = 0;
1198 return FALSE;
1199 }
1200
1201 FoundHob = 1;
1202 return TRUE;
1203 }
1204
1205 EFI_STATUS
1206 EFIAPI
1207 ConnectRecursivelyIfPciMassStorage (
1208 IN EFI_HANDLE Handle,
1209 IN EFI_PCI_IO_PROTOCOL *Instance,
1210 IN PCI_TYPE00 *PciHeader
1211 )
1212 {
1213 EFI_STATUS Status;
1214 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1215 CHAR16 *DevPathStr;
1216
1217 //
1218 // Recognize PCI Mass Storage, and Xen PCI devices
1219 //
1220 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ||
1221 (XenDetected() && IS_CLASS2 (PciHeader, 0xFF, 0x80))) {
1222 DevicePath = NULL;
1223 Status = gBS->HandleProtocol (
1224 Handle,
1225 &gEfiDevicePathProtocolGuid,
1226 (VOID*)&DevicePath
1227 );
1228 if (EFI_ERROR (Status)) {
1229 return Status;
1230 }
1231
1232 //
1233 // Print Device Path
1234 //
1235 DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1236 if (DevPathStr != NULL) {
1237 DEBUG((
1238 EFI_D_INFO,
1239 "Found %s device: %s\n",
1240 IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE) ? L"Mass Storage" : L"Xen",
1241 DevPathStr
1242 ));
1243 FreePool(DevPathStr);
1244 }
1245
1246 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
1247 if (EFI_ERROR (Status)) {
1248 return Status;
1249 }
1250
1251 }
1252
1253 return EFI_SUCCESS;
1254 }
1255
1256
1257 /**
1258 This notification function is invoked when the
1259 EMU Variable FVB has been changed.
1260
1261 @param Event The event that occurred
1262 @param Context For EFI compatibility. Not used.
1263
1264 **/
1265 VOID
1266 EFIAPI
1267 EmuVariablesUpdatedCallback (
1268 IN EFI_EVENT Event,
1269 IN VOID *Context
1270 )
1271 {
1272 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
1273 UpdateNvVarsOnFileSystem ();
1274 }
1275
1276
1277 EFI_STATUS
1278 EFIAPI
1279 VisitingFileSystemInstance (
1280 IN EFI_HANDLE Handle,
1281 IN VOID *Instance,
1282 IN VOID *Context
1283 )
1284 {
1285 EFI_STATUS Status;
1286 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
1287 RETURN_STATUS PcdStatus;
1288
1289 if (ConnectedToFileSystem) {
1290 return EFI_ALREADY_STARTED;
1291 }
1292
1293 Status = ConnectNvVarsToFileSystem (Handle);
1294 if (EFI_ERROR (Status)) {
1295 return Status;
1296 }
1297
1298 ConnectedToFileSystem = TRUE;
1299 mEmuVariableEvent =
1300 EfiCreateProtocolNotifyEvent (
1301 &gEfiDevicePathProtocolGuid,
1302 TPL_CALLBACK,
1303 EmuVariablesUpdatedCallback,
1304 NULL,
1305 &mEmuVariableEventReg
1306 );
1307 PcdStatus = PcdSet64S (PcdEmuVariableEvent,
1308 (UINT64)(UINTN) mEmuVariableEvent);
1309 ASSERT_RETURN_ERROR (PcdStatus);
1310
1311 return EFI_SUCCESS;
1312 }
1313
1314
1315 VOID
1316 PlatformBdsRestoreNvVarsFromHardDisk (
1317 )
1318 {
1319 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1320 VisitAllInstancesOfProtocol (
1321 &gEfiSimpleFileSystemProtocolGuid,
1322 VisitingFileSystemInstance,
1323 NULL
1324 );
1325
1326 }
1327
1328 VOID
1329 PlatformBdsConnectSequence (
1330 VOID
1331 )
1332 /*++
1333
1334 Routine Description:
1335
1336 Connect with predefined platform connect sequence,
1337 the OEM/IBV can customize with their own connect sequence.
1338
1339 Arguments:
1340
1341 None.
1342
1343 Returns:
1344
1345 None.
1346
1347 --*/
1348 {
1349 UINTN Index;
1350 RETURN_STATUS Status;
1351
1352 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
1353
1354 Index = 0;
1355
1356 //
1357 // Here we can get the customized platform connect sequence
1358 // Notes: we can connect with new variable which record the
1359 // last time boots connect device path sequence
1360 //
1361 while (gPlatformConnectSequence[Index] != NULL) {
1362 //
1363 // Build the platform boot option
1364 //
1365 EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1366 Index++;
1367 }
1368
1369 Status = ConnectDevicesFromQemu ();
1370 if (RETURN_ERROR (Status)) {
1371 //
1372 // Just use the simple policy to connect all devices
1373 //
1374 DEBUG ((DEBUG_INFO, "EfiBootManagerConnectAll\n"));
1375 EfiBootManagerConnectAll ();
1376 }
1377
1378 PciAcpiInitialization ();
1379 }
1380
1381 /**
1382 Save the S3 boot script.
1383
1384 Note that DxeSmmReadyToLock must be signaled after this function returns;
1385 otherwise the script wouldn't be saved actually.
1386 **/
1387 STATIC
1388 VOID
1389 SaveS3BootScript (
1390 VOID
1391 )
1392 {
1393 EFI_STATUS Status;
1394 EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1395 STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1396
1397 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
1398 (VOID **) &BootScript);
1399 ASSERT_EFI_ERROR (Status);
1400
1401 //
1402 // Despite the opcode documentation in the PI spec, the protocol
1403 // implementation embeds a deep copy of the info in the boot script, rather
1404 // than storing just a pointer to runtime or NVS storage.
1405 //
1406 Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1407 (UINT32) sizeof Info,
1408 (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
1409 ASSERT_EFI_ERROR (Status);
1410 }
1411
1412
1413 VOID
1414 EFIAPI
1415 PlatformBootManagerAfterConsole (
1416 VOID
1417 )
1418 /*++
1419
1420 Routine Description:
1421
1422 The function will execute with as the platform policy, current policy
1423 is driven by boot mode. IBV/OEM can customize this code for their specific
1424 policy action.
1425
1426 --*/
1427 {
1428 EFI_BOOT_MODE BootMode;
1429
1430 DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
1431
1432 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1433 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1434 "from disk since flash variables appear to be supported.\n"));
1435 } else {
1436 //
1437 // Try to restore variables from the hard disk early so
1438 // they can be used for the other BDS connect operations.
1439 //
1440 PlatformBdsRestoreNvVarsFromHardDisk ();
1441 }
1442
1443 //
1444 // Get current Boot Mode
1445 //
1446 BootMode = GetBootModeHob ();
1447 DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));
1448
1449 //
1450 // Go the different platform policy with different boot mode
1451 // Notes: this part code can be change with the table policy
1452 //
1453 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1454
1455 //
1456 // Logo show
1457 //
1458 BootLogoEnableLogo ();
1459
1460 //
1461 // Perform some platform specific connect sequence
1462 //
1463 PlatformBdsConnectSequence ();
1464
1465 //
1466 // Process QEMU's -kernel command line option
1467 //
1468 TryRunningQemuKernel ();
1469
1470 EfiBootManagerRefreshAllBootOption ();
1471
1472 //
1473 // Register UEFI Shell
1474 //
1475 PlatformRegisterFvBootOption (
1476 PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
1477 );
1478
1479 RemoveStaleFvFileOptions ();
1480 SetBootOrderFromQemu ();
1481 }
1482
1483 /**
1484 This notification function is invoked when an instance of the
1485 EFI_DEVICE_PATH_PROTOCOL is produced.
1486
1487 @param Event The event that occurred
1488 @param Context For EFI compatibility. Not used.
1489
1490 **/
1491 VOID
1492 EFIAPI
1493 NotifyDevPath (
1494 IN EFI_EVENT Event,
1495 IN VOID *Context
1496 )
1497 {
1498 EFI_HANDLE Handle;
1499 EFI_STATUS Status;
1500 UINTN BufferSize;
1501 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1502 ATAPI_DEVICE_PATH *Atapi;
1503
1504 //
1505 // Examine all new handles
1506 //
1507 for (;;) {
1508 //
1509 // Get the next handle
1510 //
1511 BufferSize = sizeof (Handle);
1512 Status = gBS->LocateHandle (
1513 ByRegisterNotify,
1514 NULL,
1515 mEfiDevPathNotifyReg,
1516 &BufferSize,
1517 &Handle
1518 );
1519
1520 //
1521 // If not found, we're done
1522 //
1523 if (EFI_NOT_FOUND == Status) {
1524 break;
1525 }
1526
1527 if (EFI_ERROR (Status)) {
1528 continue;
1529 }
1530
1531 //
1532 // Get the DevicePath protocol on that handle
1533 //
1534 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1535 ASSERT_EFI_ERROR (Status);
1536
1537 while (!IsDevicePathEnd (DevPathNode)) {
1538 //
1539 // Find the handler to dump this device path node
1540 //
1541 if (
1542 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1543 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1544 ) {
1545 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1546 PciOr16 (
1547 PCI_LIB_ADDRESS (
1548 0,
1549 1,
1550 1,
1551 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1552 ),
1553 BIT15
1554 );
1555 }
1556
1557 //
1558 // Next device path node
1559 //
1560 DevPathNode = NextDevicePathNode (DevPathNode);
1561 }
1562 }
1563
1564 return;
1565 }
1566
1567
1568 VOID
1569 InstallDevicePathCallback (
1570 VOID
1571 )
1572 {
1573 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1574 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1575 &gEfiDevicePathProtocolGuid,
1576 TPL_CALLBACK,
1577 NotifyDevPath,
1578 NULL,
1579 &mEfiDevPathNotifyReg
1580 );
1581 }
1582
1583 /**
1584 This function is called each second during the boot manager waits the timeout.
1585
1586 @param TimeoutRemain The remaining timeout.
1587 **/
1588 VOID
1589 EFIAPI
1590 PlatformBootManagerWaitCallback (
1591 UINT16 TimeoutRemain
1592 )
1593 {
1594 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
1595 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
1596 UINT16 Timeout;
1597
1598 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1599
1600 Black.Raw = 0x00000000;
1601 White.Raw = 0x00FFFFFF;
1602
1603 BootLogoUpdateProgress (
1604 White.Pixel,
1605 Black.Pixel,
1606 L"Start boot option",
1607 White.Pixel,
1608 (Timeout - TimeoutRemain) * 100 / Timeout,
1609 0
1610 );
1611 }
1612