• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
PlatformRegisterFvBootOption(EFI_GUID * FileGuid,CHAR16 * Description,UINT32 Attributes)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
RemoveStaleFvFileOptions(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
PlatformRegisterOptionsAndKeys(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
PlatformBootManagerBeforeConsole(VOID)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
ConnectRootBridge(IN EFI_HANDLE RootBridgeHandle,IN VOID * Instance,IN VOID * Context)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
PrepareLpcBridgeDevicePath(IN EFI_HANDLE DeviceHandle)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
GetGopDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * PciDevicePath,OUT EFI_DEVICE_PATH_PROTOCOL ** GopDevicePath)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
PreparePciDisplayDevicePath(IN EFI_HANDLE DeviceHandle)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
PreparePciSerialDevicePath(IN EFI_HANDLE DeviceHandle)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
VisitAllInstancesOfProtocol(IN EFI_GUID * Id,IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,IN VOID * Context)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
VisitingAPciInstance(IN EFI_HANDLE Handle,IN VOID * Instance,IN VOID * Context)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
VisitAllPciInstances(IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction)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
DetectAndPreparePlatformPciDevicePath(IN EFI_HANDLE Handle,IN EFI_PCI_IO_PROTOCOL * PciIo,IN PCI_TYPE00 * Pci)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
DetectAndPreparePlatformPciDevicePaths(BOOLEAN DetectVgaOnly)899 DetectAndPreparePlatformPciDevicePaths (
900   BOOLEAN DetectVgaOnly
901   )
902 {
903   mDetectVgaOnly = DetectVgaOnly;
904   return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
905 }
906 
907 
908 VOID
PlatformInitializeConsole(IN PLATFORM_CONSOLE_CONNECT_ENTRY * PlatformConsole)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
SetPciIntLine(IN EFI_HANDLE Handle,IN EFI_PCI_IO_PROTOCOL * PciIo,IN PCI_TYPE00 * PciHdr)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
PciAcpiInitialization()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
XenDetected(VOID)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
ConnectRecursivelyIfPciMassStorage(IN EFI_HANDLE Handle,IN EFI_PCI_IO_PROTOCOL * Instance,IN PCI_TYPE00 * PciHeader)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
EmuVariablesUpdatedCallback(IN EFI_EVENT Event,IN VOID * Context)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
VisitingFileSystemInstance(IN EFI_HANDLE Handle,IN VOID * Instance,IN VOID * Context)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
PlatformBdsRestoreNvVarsFromHardDisk()1316 PlatformBdsRestoreNvVarsFromHardDisk (
1317   )
1318 {
1319   VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1320   VisitAllInstancesOfProtocol (
1321     &gEfiSimpleFileSystemProtocolGuid,
1322     VisitingFileSystemInstance,
1323     NULL
1324     );
1325 
1326 }
1327 
1328 VOID
PlatformBdsConnectSequence(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 
1351   DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
1352 
1353   Index = 0;
1354 
1355   //
1356   // Here we can get the customized platform connect sequence
1357   // Notes: we can connect with new variable which record the
1358   // last time boots connect device path sequence
1359   //
1360   while (gPlatformConnectSequence[Index] != NULL) {
1361     //
1362     // Build the platform boot option
1363     //
1364     EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
1365     Index++;
1366   }
1367 
1368   //
1369   // Just use the simple policy to connect all devices
1370   //
1371   DEBUG ((EFI_D_INFO, "EfiBootManagerConnectAll\n"));
1372   EfiBootManagerConnectAll ();
1373 
1374   PciAcpiInitialization ();
1375 }
1376 
1377 /**
1378   Save the S3 boot script.
1379 
1380   Note that DxeSmmReadyToLock must be signaled after this function returns;
1381   otherwise the script wouldn't be saved actually.
1382 **/
1383 STATIC
1384 VOID
SaveS3BootScript(VOID)1385 SaveS3BootScript (
1386   VOID
1387   )
1388 {
1389   EFI_STATUS                 Status;
1390   EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
1391   STATIC CONST UINT8         Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1392 
1393   Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
1394                   (VOID **) &BootScript);
1395   ASSERT_EFI_ERROR (Status);
1396 
1397   //
1398   // Despite the opcode documentation in the PI spec, the protocol
1399   // implementation embeds a deep copy of the info in the boot script, rather
1400   // than storing just a pointer to runtime or NVS storage.
1401   //
1402   Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
1403                          (UINT32) sizeof Info,
1404                          (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
1405   ASSERT_EFI_ERROR (Status);
1406 }
1407 
1408 
1409 VOID
1410 EFIAPI
PlatformBootManagerAfterConsole(VOID)1411 PlatformBootManagerAfterConsole (
1412   VOID
1413   )
1414 /*++
1415 
1416 Routine Description:
1417 
1418   The function will execute with as the platform policy, current policy
1419   is driven by boot mode. IBV/OEM can customize this code for their specific
1420   policy action.
1421 
1422 --*/
1423 {
1424   EFI_BOOT_MODE                      BootMode;
1425 
1426   DEBUG ((EFI_D_INFO, "PlatformBootManagerAfterConsole\n"));
1427 
1428   if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1429     DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1430       "from disk since flash variables appear to be supported.\n"));
1431   } else {
1432     //
1433     // Try to restore variables from the hard disk early so
1434     // they can be used for the other BDS connect operations.
1435     //
1436     PlatformBdsRestoreNvVarsFromHardDisk ();
1437   }
1438 
1439   //
1440   // Get current Boot Mode
1441   //
1442   BootMode = GetBootModeHob ();
1443   DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
1444 
1445   //
1446   // Go the different platform policy with different boot mode
1447   // Notes: this part code can be change with the table policy
1448   //
1449   ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1450 
1451   //
1452   // Logo show
1453   //
1454   BootLogoEnableLogo ();
1455 
1456   //
1457   // Perform some platform specific connect sequence
1458   //
1459   PlatformBdsConnectSequence ();
1460 
1461   //
1462   // Process QEMU's -kernel command line option
1463   //
1464   TryRunningQemuKernel ();
1465 
1466   EfiBootManagerRefreshAllBootOption ();
1467 
1468   //
1469   // Register UEFI Shell
1470   //
1471   PlatformRegisterFvBootOption (
1472     PcdGetPtr (PcdShellFile), L"EFI Internal Shell", LOAD_OPTION_ACTIVE
1473     );
1474 
1475   RemoveStaleFvFileOptions ();
1476   SetBootOrderFromQemu ();
1477 }
1478 
1479 /**
1480   This notification function is invoked when an instance of the
1481   EFI_DEVICE_PATH_PROTOCOL is produced.
1482 
1483   @param  Event                 The event that occurred
1484   @param  Context               For EFI compatibility.  Not used.
1485 
1486 **/
1487 VOID
1488 EFIAPI
NotifyDevPath(IN EFI_EVENT Event,IN VOID * Context)1489 NotifyDevPath (
1490   IN  EFI_EVENT Event,
1491   IN  VOID      *Context
1492   )
1493 {
1494   EFI_HANDLE                            Handle;
1495   EFI_STATUS                            Status;
1496   UINTN                                 BufferSize;
1497   EFI_DEVICE_PATH_PROTOCOL             *DevPathNode;
1498   ATAPI_DEVICE_PATH                    *Atapi;
1499 
1500   //
1501   // Examine all new handles
1502   //
1503   for (;;) {
1504     //
1505     // Get the next handle
1506     //
1507     BufferSize = sizeof (Handle);
1508     Status = gBS->LocateHandle (
1509               ByRegisterNotify,
1510               NULL,
1511               mEfiDevPathNotifyReg,
1512               &BufferSize,
1513               &Handle
1514               );
1515 
1516     //
1517     // If not found, we're done
1518     //
1519     if (EFI_NOT_FOUND == Status) {
1520       break;
1521     }
1522 
1523     if (EFI_ERROR (Status)) {
1524       continue;
1525     }
1526 
1527     //
1528     // Get the DevicePath protocol on that handle
1529     //
1530     Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1531     ASSERT_EFI_ERROR (Status);
1532 
1533     while (!IsDevicePathEnd (DevPathNode)) {
1534       //
1535       // Find the handler to dump this device path node
1536       //
1537       if (
1538            (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1539            (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1540          ) {
1541         Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1542         PciOr16 (
1543           PCI_LIB_ADDRESS (
1544             0,
1545             1,
1546             1,
1547             (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1548             ),
1549           BIT15
1550           );
1551       }
1552 
1553       //
1554       // Next device path node
1555       //
1556       DevPathNode = NextDevicePathNode (DevPathNode);
1557     }
1558   }
1559 
1560   return;
1561 }
1562 
1563 
1564 VOID
InstallDevicePathCallback(VOID)1565 InstallDevicePathCallback (
1566   VOID
1567   )
1568 {
1569   DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1570   mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1571                           &gEfiDevicePathProtocolGuid,
1572                           TPL_CALLBACK,
1573                           NotifyDevPath,
1574                           NULL,
1575                           &mEfiDevPathNotifyReg
1576                           );
1577 }
1578 
1579 /**
1580   This function is called each second during the boot manager waits the timeout.
1581 
1582   @param TimeoutRemain  The remaining timeout.
1583 **/
1584 VOID
1585 EFIAPI
PlatformBootManagerWaitCallback(UINT16 TimeoutRemain)1586 PlatformBootManagerWaitCallback (
1587   UINT16          TimeoutRemain
1588   )
1589 {
1590   EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
1591   EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
1592   UINT16                              Timeout;
1593 
1594   Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1595 
1596   Black.Raw = 0x00000000;
1597   White.Raw = 0x00FFFFFF;
1598 
1599   BootLogoUpdateProgress (
1600     White.Pixel,
1601     Black.Pixel,
1602     L"Start boot option",
1603     White.Pixel,
1604     (Timeout - TimeoutRemain) * 100 / Timeout,
1605     0
1606     );
1607 }
1608 
1609