2 A non-transitional driver for VirtIo 1.0 PCI devices.
4 Copyright (C) 2016, Red Hat, Inc.
5 Copyright (C) 2017, AMD Inc, All rights reserved.<BR>
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <IndustryStandard/Pci.h>
17 #include <IndustryStandard/Virtio.h>
18 #include <Protocol/PciIo.h>
19 #include <Protocol/PciRootBridgeIo.h>
20 #include <Protocol/VirtioDevice.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/DebugLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/UefiLib.h>
35 Transfer data between the caller and a register in a virtio-1.0 register
38 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents
41 @param[in] Config The "fat pointer" structure that identifies the
42 register block to access.
44 @param[in] Write TRUE if the register should be written, FALSE if
45 the register should be read.
47 @param[in] FieldOffset The offset of the register within the register
50 @param[in] FieldSize The size of the register within the register
51 block. Can be one of 1, 2, 4 and 8. Accesses to
52 8-byte registers are broken up into two 4-byte
55 @param[in,out] Buffer When Write is TRUE, the register is written with
56 data from Buffer. When Write is FALSE, the caller
57 receives the register value into Buffer.
59 @retval EFI_SUCCESS Register access successful.
61 @retval EFI_INVALID_PARAMETER The register block pointed-to by Config
62 doesn't exist; or FieldOffset and FieldSize
63 would overflow the register block; or
66 @return Error codes from
67 EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)
73 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
74 IN VIRTIO_1_0_CONFIG
*Config
,
82 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
83 EFI_PCI_IO_PROTOCOL_ACCESS
*BarType
;
84 EFI_PCI_IO_PROTOCOL_IO_MEM Access
;
86 if (!Config
->Exists
||
87 FieldSize
> Config
->Length
||
88 FieldOffset
> Config
->Length
- FieldSize
) {
89 return EFI_INVALID_PARAMETER
;
95 Width
= EfiPciIoWidthUint8
;
99 Width
= EfiPciIoWidthUint16
;
109 Width
= EfiPciIoWidthUint32
;
113 return EFI_INVALID_PARAMETER
;
116 BarType
= (Config
->BarType
== Virtio10BarTypeMem
) ? &PciIo
->Mem
: &PciIo
->Io
;
117 Access
= Write
? BarType
->Write
: BarType
->Read
;
119 return Access (PciIo
, Width
, Config
->Bar
, Config
->Offset
+ FieldOffset
,
125 Determine if a PCI BAR is IO or MMIO.
127 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
130 @param[in] BarIndex The number of the BAR whose type the caller is
133 @param[out] BarType On output, a VIRTIO_1_0_BAR_TYPE value that gives the
136 @retval EFI_SUCCESS The BAR type has been recognized and stored in
139 @retval EFI_UNSUPPORTED The BAR type couldn't be identified.
141 @return Error codes from
142 EFI_PCI_IO_PROTOCOL.GetBarAttributes().
147 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
149 OUT VIRTIO_1_0_BAR_TYPE
*BarType
155 Status
= PciIo
->GetBarAttributes (PciIo
, BarIndex
, NULL
, &Resources
);
156 if (EFI_ERROR (Status
)) {
160 Status
= EFI_UNSUPPORTED
;
162 if (*(UINT8
*)Resources
== ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
) {
163 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
165 Descriptor
= Resources
;
166 switch (Descriptor
->ResType
) {
167 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
168 *BarType
= Virtio10BarTypeMem
;
169 Status
= EFI_SUCCESS
;
172 case ACPI_ADDRESS_SPACE_TYPE_IO
:
173 *BarType
= Virtio10BarTypeIo
;
174 Status
= EFI_SUCCESS
;
182 FreePool (Resources
);
188 Read a slice from PCI config space at the given offset, then advance the
191 @param [in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
194 @param [in,out] Offset On input, the offset in PCI config space to start
195 reading from. On output, the offset of the first byte
196 that was not read. On error, Offset is not modified.
198 @param [in] Size The number of bytes to read.
200 @param [out] Buffer On output, the bytes read from PCI config space are
201 stored in this object.
203 @retval EFI_SUCCESS Size bytes have been transferred from PCI config space
204 (from Offset) to Buffer, and Offset has been incremented
207 @return Error codes from PciIo->Pci.Read().
212 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
213 IN OUT UINT32
*Offset
,
220 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, *Offset
, Size
, Buffer
);
221 if (EFI_ERROR (Status
)) {
224 *Offset
+= (UINT32
)Size
;
230 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
231 locations of the interesting virtio-1.0 register blocks.
233 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies
234 the device. On input, the caller is responsible
235 that the Device->PciIo member be live, and that
236 the CommonConfig, NotifyConfig,
237 NotifyOffsetMultiplier and SpecificConfig
238 members be zeroed. On output, said members
239 will have been updated from the PCI
242 @param[in] CapabilityPtr The offset of the first capability in PCI
243 config space, taken from the standard PCI
246 @retval EFI_SUCCESS Traversal successful.
248 @return Error codes from the ReadConfigSpace() and GetBarType()
254 IN OUT VIRTIO_1_0_DEV
*Device
,
255 IN UINT8 CapabilityPtr
259 VIRTIO_PCI_CAP_LINK CapLink
;
261 for (Offset
= CapabilityPtr
& 0xFC;
263 Offset
= CapLink
.CapNext
& 0xFC
267 VIRTIO_PCI_CAP VirtIoCap
;
268 VIRTIO_1_0_CONFIG
*ParsedConfig
;
271 // Read capability identifier and link to next capability.
273 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
, sizeof CapLink
,
275 if (EFI_ERROR (Status
)) {
278 if (CapLink
.CapId
!= 0x09) {
280 // Not a vendor-specific capability, move to the next one.
286 // Big enough to accommodate a VIRTIO_PCI_CAP structure?
288 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
, sizeof CapLen
, &CapLen
);
289 if (EFI_ERROR (Status
)) {
292 if (CapLen
< sizeof CapLink
+ sizeof CapLen
+ sizeof VirtIoCap
) {
294 // Too small, move to next.
300 // Read interesting part of capability.
302 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
, sizeof VirtIoCap
,
304 if (EFI_ERROR (Status
)) {
307 switch (VirtIoCap
.ConfigType
) {
308 case VIRTIO_PCI_CAP_COMMON_CFG
:
309 ParsedConfig
= &Device
->CommonConfig
;
311 case VIRTIO_PCI_CAP_NOTIFY_CFG
:
312 ParsedConfig
= &Device
->NotifyConfig
;
314 case VIRTIO_PCI_CAP_DEVICE_CFG
:
315 ParsedConfig
= &Device
->SpecificConfig
;
319 // Capability is not interesting.
325 // Save the location of the register block into ParsedConfig.
327 Status
= GetBarType (Device
->PciIo
, VirtIoCap
.Bar
, &ParsedConfig
->BarType
);
328 if (EFI_ERROR (Status
)) {
331 ParsedConfig
->Bar
= VirtIoCap
.Bar
;
332 ParsedConfig
->Offset
= VirtIoCap
.Offset
;
333 ParsedConfig
->Length
= VirtIoCap
.Length
;
335 if (VirtIoCap
.ConfigType
== VIRTIO_PCI_CAP_NOTIFY_CFG
) {
337 // This capability has an additional field called NotifyOffsetMultiplier;
340 if (CapLen
< sizeof CapLink
+ sizeof CapLen
+ sizeof VirtIoCap
+
341 sizeof Device
->NotifyOffsetMultiplier
) {
343 // Too small, move to next.
348 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
,
349 sizeof Device
->NotifyOffsetMultiplier
,
350 &Device
->NotifyOffsetMultiplier
);
351 if (EFI_ERROR (Status
)) {
357 // Capability parsed successfully.
359 ParsedConfig
->Exists
= TRUE
;
367 Accumulate the BAR type of a virtio-1.0 register block into a UINT64
368 attribute map, such that the latter is suitable for enabling IO / MMIO
369 decoding with EFI_PCI_IO_PROTOCOL.Attributes().
371 @param[in] Config The "fat pointer" structure that identifies the
372 register block. It is allowed for the register
375 @param[in,out] Attributes On output, if the register block exists,
376 EFI_PCI_IO_ATTRIBUTE_MEMORY or
377 EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,
378 according to the register block's BAR type.
383 IN VIRTIO_1_0_CONFIG
*Config
,
384 IN OUT UINT64
*Attributes
387 if (Config
->Exists
) {
388 *Attributes
|= (Config
->BarType
== Virtio10BarTypeMem
) ?
389 EFI_PCI_IO_ATTRIBUTE_MEMORY
:
390 EFI_PCI_IO_ATTRIBUTE_IO
;
396 // VIRTIO_DEVICE_PROTOCOL member functions
402 Virtio10GetDeviceFeatures (
403 IN VIRTIO_DEVICE_PROTOCOL
*This
,
404 OUT UINT64
*DeviceFeatures
409 UINT32 Features32
[2];
411 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
413 for (Selector
= 0; Selector
< 2; ++Selector
) {
417 // Select the low or high half of the features.
419 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
420 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeatureSelect
),
421 sizeof Selector
, &Selector
);
422 if (EFI_ERROR (Status
)) {
429 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
430 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeature
),
431 sizeof Features32
[Selector
], &Features32
[Selector
]);
432 if (EFI_ERROR (Status
)) {
437 *DeviceFeatures
= LShiftU64 (Features32
[1], 32) | Features32
[0];
445 Virtio10SetGuestFeatures (
446 IN VIRTIO_DEVICE_PROTOCOL
*This
,
452 UINT32 Features32
[2];
454 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
456 Features32
[0] = (UINT32
)Features
;
457 Features32
[1] = (UINT32
)RShiftU64 (Features
, 32);
459 for (Selector
= 0; Selector
< 2; ++Selector
) {
463 // Select the low or high half of the features.
465 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
466 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeatureSelect
),
467 sizeof Selector
, &Selector
);
468 if (EFI_ERROR (Status
)) {
475 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
476 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeature
),
477 sizeof Features32
[Selector
], &Features32
[Selector
]);
478 if (EFI_ERROR (Status
)) {
490 Virtio10SetQueueAddress (
491 IN VIRTIO_DEVICE_PROTOCOL
*This
,
493 IN UINT64 RingBaseShift
501 ASSERT (RingBaseShift
== 0);
503 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
505 Address
= (UINTN
)Ring
->Desc
;
506 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
507 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueDesc
),
508 sizeof Address
, &Address
);
509 if (EFI_ERROR (Status
)) {
513 Address
= (UINTN
)Ring
->Avail
.Flags
;
514 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
515 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueAvail
),
516 sizeof Address
, &Address
);
517 if (EFI_ERROR (Status
)) {
521 Address
= (UINTN
)Ring
->Used
.Flags
;
522 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
523 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueUsed
),
524 sizeof Address
, &Address
);
525 if (EFI_ERROR (Status
)) {
530 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
531 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueEnable
),
532 sizeof Enable
, &Enable
);
540 Virtio10SetQueueSel (
541 IN VIRTIO_DEVICE_PROTOCOL
*This
,
548 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
550 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
551 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
552 sizeof Index
, &Index
);
560 Virtio10SetQueueNotify (
561 IN VIRTIO_DEVICE_PROTOCOL
*This
,
567 UINT16 SavedQueueSelect
;
570 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
573 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
574 // to stash & restore the current queue selector around it.
576 // So, start with saving the current queue selector.
578 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
579 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
580 sizeof SavedQueueSelect
, &SavedQueueSelect
);
581 if (EFI_ERROR (Status
)) {
586 // Select the requested queue.
588 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
589 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
590 sizeof Index
, &Index
);
591 if (EFI_ERROR (Status
)) {
596 // Read the QueueNotifyOff field.
598 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
599 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueNotifyOff
),
600 sizeof NotifyOffset
, &NotifyOffset
);
601 if (EFI_ERROR (Status
)) {
606 // Re-select the original queue.
608 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
609 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
610 sizeof SavedQueueSelect
, &SavedQueueSelect
);
611 if (EFI_ERROR (Status
)) {
616 // We can now kick the queue.
618 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->NotifyConfig
, TRUE
,
619 NotifyOffset
* Dev
->NotifyOffsetMultiplier
,
620 sizeof Index
, &Index
);
628 Virtio10SetQueueAlign (
629 IN VIRTIO_DEVICE_PROTOCOL
*This
,
633 return (Alignment
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
640 Virtio10SetPageSize (
641 IN VIRTIO_DEVICE_PROTOCOL
*This
,
645 return (PageSize
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
652 Virtio10GetQueueNumMax (
653 IN VIRTIO_DEVICE_PROTOCOL
*This
,
654 OUT UINT16
*QueueNumMax
660 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
662 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
663 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSize
),
664 sizeof *QueueNumMax
, QueueNumMax
);
672 Virtio10SetQueueNum (
673 IN VIRTIO_DEVICE_PROTOCOL
*This
,
681 // This member function is required for VirtIo MMIO, and a no-op in
682 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
683 // member to reduce memory consumption, but none of our drivers do. So
684 // just check that they set the size that is already in effect.
686 Status
= Virtio10GetQueueNumMax (This
, &CurrentSize
);
687 if (EFI_ERROR (Status
)) {
690 return (CurrentSize
== QueueSize
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
697 Virtio10GetDeviceStatus (
698 IN VIRTIO_DEVICE_PROTOCOL
*This
,
699 OUT UINT8
*DeviceStatus
705 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
707 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
708 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
709 sizeof *DeviceStatus
, DeviceStatus
);
717 Virtio10SetDeviceStatus (
718 IN VIRTIO_DEVICE_PROTOCOL
*This
,
719 IN UINT8 DeviceStatus
725 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
727 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
728 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
729 sizeof DeviceStatus
, &DeviceStatus
);
737 Virtio10WriteDevice (
738 IN VIRTIO_DEVICE_PROTOCOL
*This
,
739 IN UINTN FieldOffset
,
747 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
749 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, TRUE
,
750 FieldOffset
, FieldSize
, &Value
);
759 IN VIRTIO_DEVICE_PROTOCOL
*This
,
760 IN UINTN FieldOffset
,
769 if (FieldSize
!= BufferSize
) {
770 return EFI_INVALID_PARAMETER
;
773 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
775 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, FALSE
,
776 FieldOffset
, FieldSize
, Buffer
);
783 Virtio10AllocateSharedPages (
784 IN VIRTIO_DEVICE_PROTOCOL
*This
,
786 IN OUT VOID
**HostAddress
792 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
794 Status
= Dev
->PciIo
->AllocateBuffer (
800 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
808 Virtio10FreeSharedPages (
809 IN VIRTIO_DEVICE_PROTOCOL
*This
,
816 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
818 Dev
->PciIo
->FreeBuffer (
828 Virtio10MapSharedBuffer (
829 IN VIRTIO_DEVICE_PROTOCOL
*This
,
830 IN VIRTIO_MAP_OPERATION Operation
,
831 IN VOID
*HostAddress
,
832 IN OUT UINTN
*NumberOfBytes
,
833 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
839 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation
;
841 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
844 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
847 case VirtioOperationBusMasterRead
:
848 PciIoOperation
= EfiPciIoOperationBusMasterRead
;
850 case VirtioOperationBusMasterWrite
:
851 PciIoOperation
= EfiPciIoOperationBusMasterWrite
;
853 case VirtioOperationBusMasterCommonBuffer
:
854 PciIoOperation
= EfiPciIoOperationBusMasterCommonBuffer
;
857 return EFI_INVALID_PARAMETER
;
860 Status
= Dev
->PciIo
->Map (
874 Virtio10UnmapSharedBuffer (
875 IN VIRTIO_DEVICE_PROTOCOL
*This
,
882 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
884 Status
= Dev
->PciIo
->Unmap (
892 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate
= {
893 VIRTIO_SPEC_REVISION (1, 0, 0),
894 0, // SubSystemDeviceId, filled in dynamically
895 Virtio10GetDeviceFeatures
,
896 Virtio10SetGuestFeatures
,
897 Virtio10SetQueueAddress
,
899 Virtio10SetQueueNotify
,
900 Virtio10SetQueueAlign
,
902 Virtio10GetQueueNumMax
,
904 Virtio10GetDeviceStatus
,
905 Virtio10SetDeviceStatus
,
908 Virtio10AllocateSharedPages
,
909 Virtio10FreeSharedPages
,
910 Virtio10MapSharedBuffer
,
911 Virtio10UnmapSharedBuffer
916 // EFI_DRIVER_BINDING_PROTOCOL member functions
922 Virtio10BindingSupported (
923 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
924 IN EFI_HANDLE DeviceHandle
,
925 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
929 EFI_PCI_IO_PROTOCOL
*PciIo
;
932 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
933 (VOID
**)&PciIo
, This
->DriverBindingHandle
,
934 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
935 if (EFI_ERROR (Status
)) {
939 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0,
940 sizeof Pci
/ sizeof (UINT32
), &Pci
);
941 if (EFI_ERROR (Status
)) {
945 Status
= EFI_UNSUPPORTED
;
947 // Recognize non-transitional modern devices. Also, we'll have to parse the
948 // PCI capability list, so make sure the CapabilityPtr field will be valid.
950 if (Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
&&
951 Pci
.Hdr
.DeviceId
>= 0x1040 &&
952 Pci
.Hdr
.DeviceId
<= 0x107F &&
953 Pci
.Hdr
.RevisionID
>= 0x01 &&
954 Pci
.Device
.SubsystemID
>= 0x40 &&
955 (Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0) {
957 // The virtio-vga device is special. It can be driven both as a VGA device
958 // with a linear framebuffer, and through its underlying, modern,
959 // virtio-gpu-pci device, which has no linear framebuffer itself. For
960 // compatibility with guest OSes that insist on inheriting a linear
961 // framebuffer from the firmware, we should leave virtio-vga to
962 // QemuVideoDxe, and support only virtio-gpu-pci here.
964 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
965 // former has device class PCI_CLASS_DISPLAY_VGA.
967 if (Pci
.Hdr
.DeviceId
!= 0x1050 || !IS_PCI_VGA (&Pci
)) {
968 Status
= EFI_SUCCESS
;
973 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
974 This
->DriverBindingHandle
, DeviceHandle
);
983 Virtio10BindingStart (
984 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
985 IN EFI_HANDLE DeviceHandle
,
986 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
989 VIRTIO_1_0_DEV
*Device
;
992 UINT64 SetAttributes
;
994 Device
= AllocateZeroPool (sizeof *Device
);
995 if (Device
== NULL
) {
996 return EFI_OUT_OF_RESOURCES
;
999 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
1000 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
1002 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1003 (VOID
**)&Device
->PciIo
, This
->DriverBindingHandle
,
1004 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
1005 if (EFI_ERROR (Status
)) {
1009 Status
= Device
->PciIo
->Pci
.Read (Device
->PciIo
, EfiPciIoWidthUint32
, 0,
1010 sizeof Pci
/ sizeof (UINT32
), &Pci
);
1011 if (EFI_ERROR (Status
)) {
1015 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
1017 Status
= ParseCapabilities (Device
, Pci
.Device
.CapabilityPtr
);
1018 if (EFI_ERROR (Status
)) {
1022 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
1023 EfiPciIoAttributeOperationGet
, 0,
1024 &Device
->OriginalPciAttributes
);
1025 if (EFI_ERROR (Status
)) {
1029 SetAttributes
= (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
|
1030 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1031 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
1032 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
1033 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
1034 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
1035 EfiPciIoAttributeOperationEnable
, SetAttributes
,
1037 if (EFI_ERROR (Status
)) {
1041 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
1042 &gVirtioDeviceProtocolGuid
, EFI_NATIVE_INTERFACE
,
1044 if (EFI_ERROR (Status
)) {
1045 goto RestorePciAttributes
;
1050 RestorePciAttributes
:
1051 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1052 Device
->OriginalPciAttributes
, NULL
);
1055 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1056 This
->DriverBindingHandle
, DeviceHandle
);
1068 Virtio10BindingStop (
1069 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1070 IN EFI_HANDLE DeviceHandle
,
1071 IN UINTN NumberOfChildren
,
1072 IN EFI_HANDLE
*ChildHandleBuffer
1076 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
1077 VIRTIO_1_0_DEV
*Device
;
1079 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
1080 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
1081 DeviceHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1082 if (EFI_ERROR (Status
)) {
1086 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
1088 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
1089 &gVirtioDeviceProtocolGuid
, &Device
->VirtIo
);
1090 if (EFI_ERROR (Status
)) {
1094 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1095 Device
->OriginalPciAttributes
, NULL
);
1096 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1097 This
->DriverBindingHandle
, DeviceHandle
);
1104 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
1105 &Virtio10BindingSupported
,
1106 &Virtio10BindingStart
,
1107 &Virtio10BindingStop
,
1109 NULL
, // ImageHandle, to be overwritten
1110 NULL
// DriverBindingHandle, to be overwritten
1115 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1120 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1121 { "eng;en", L
"Virtio 1.0 PCI Driver" },
1126 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1131 Virtio10GetDriverName (
1132 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1134 OUT CHAR16
**DriverName
1137 return LookupUnicodeString2 (
1139 This
->SupportedLanguages
,
1142 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1149 Virtio10GetDeviceName (
1150 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1151 IN EFI_HANDLE DeviceHandle
,
1152 IN EFI_HANDLE ChildHandle
,
1154 OUT CHAR16
**ControllerName
1157 return EFI_UNSUPPORTED
;
1161 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1162 &Virtio10GetDriverName
,
1163 &Virtio10GetDeviceName
,
1168 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1169 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &Virtio10GetDriverName
,
1170 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &Virtio10GetDeviceName
,
1176 // Entry point of this driver
1181 Virtio10EntryPoint (
1182 IN EFI_HANDLE ImageHandle
,
1183 IN EFI_SYSTEM_TABLE
*SystemTable
1186 return EfiLibInstallDriverBindingComponentName2 (