**/\r
\r
#include <IndustryStandard/Pci22.h>\r
+#include <IndustryStandard/Virtio095.h>\r
#include <Library/BootLogoLib.h>\r
#include <Library/DevicePathLib.h>\r
#include <Library/PcdLib.h>\r
#include <Protocol/LoadedImage.h>\r
#include <Protocol/PciIo.h>\r
#include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/VirtioDevice.h>\r
#include <Guid/EventGroup.h>\r
#include <Guid/RootBridgesConnectedEventGroup.h>\r
\r
}\r
\r
\r
+/**\r
+ This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
+ the VIRTIO_DEVICE_PROTOCOL level.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsVirtioRng (\r
+ IN EFI_HANDLE Handle,\r
+ IN CONST CHAR16 *ReportText\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VIRTIO_DEVICE_PROTOCOL *VirtIo;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gVirtioDeviceProtocolGuid,\r
+ (VOID**)&VirtIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ return (BOOLEAN)(VirtIo->SubSystemDeviceId ==\r
+ VIRTIO_SUBSYSTEM_ENTROPY_SOURCE);\r
+}\r
+\r
+\r
+/**\r
+ This FILTER_FUNCTION checks if a handle corresponds to a Virtio RNG device at\r
+ the EFI_PCI_IO_PROTOCOL level.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsVirtioPciRng (\r
+ IN EFI_HANDLE Handle,\r
+ IN CONST CHAR16 *ReportText\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT16 VendorId;\r
+ UINT16 DeviceId;\r
+ UINT8 RevisionId;\r
+ BOOLEAN Virtio10;\r
+ UINT16 SubsystemId;\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,\r
+ (VOID**)&PciIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Read and check VendorId.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,\r
+ 1, &VendorId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+ if (VendorId != VIRTIO_VENDOR_ID) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Read DeviceId and RevisionId.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,\r
+ 1, &DeviceId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,\r
+ 1, &RevisionId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+\r
+ //\r
+ // From DeviceId and RevisionId, determine whether the device is a\r
+ // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
+ // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
+ // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
+ // only be sanity-checked, and SubsystemId will decide.\r
+ //\r
+ if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&\r
+ RevisionId >= 0x01) {\r
+ Virtio10 = TRUE;\r
+ } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {\r
+ Virtio10 = FALSE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Read and check SubsystemId as dictated by Virtio10.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,\r
+ PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto PciError;\r
+ }\r
+ if (Virtio10 && SubsystemId >= 0x40) {\r
+ return TRUE;\r
+ }\r
+ if (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) {\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+\r
+PciError:\r
+ DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));\r
+ return FALSE;\r
+}\r
+\r
+\r
/**\r
This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
the matching driver to produce all first-level child handles.\r
// Register platform-specific boot options and keyboard shortcuts.\r
//\r
PlatformRegisterOptionsAndKeys ();\r
+\r
+ //\r
+ // At this point, VIRTIO_DEVICE_PROTOCOL instances exist only for Virtio MMIO\r
+ // transports. Install EFI_RNG_PROTOCOL instances on Virtio MMIO RNG devices.\r
+ //\r
+ FilterAndProcess (&gVirtioDeviceProtocolGuid, IsVirtioRng, Connect);\r
+\r
+ //\r
+ // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
+ // instances on Virtio PCI RNG devices.\r
+ //\r
+ FilterAndProcess (&gEfiPciIoProtocolGuid, IsVirtioPciRng, Connect);\r
}\r
\r
/**\r