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