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
,
500 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
502 Address
= (UINTN
)Ring
->Desc
;
503 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
504 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueDesc
),
505 sizeof Address
, &Address
);
506 if (EFI_ERROR (Status
)) {
510 Address
= (UINTN
)Ring
->Avail
.Flags
;
511 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
512 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueAvail
),
513 sizeof Address
, &Address
);
514 if (EFI_ERROR (Status
)) {
518 Address
= (UINTN
)Ring
->Used
.Flags
;
519 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
520 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueUsed
),
521 sizeof Address
, &Address
);
522 if (EFI_ERROR (Status
)) {
527 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
528 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueEnable
),
529 sizeof Enable
, &Enable
);
537 Virtio10SetQueueSel (
538 IN VIRTIO_DEVICE_PROTOCOL
*This
,
545 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
547 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
548 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
549 sizeof Index
, &Index
);
557 Virtio10SetQueueNotify (
558 IN VIRTIO_DEVICE_PROTOCOL
*This
,
564 UINT16 SavedQueueSelect
;
567 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
570 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
571 // to stash & restore the current queue selector around it.
573 // So, start with saving the current queue selector.
575 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
576 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
577 sizeof SavedQueueSelect
, &SavedQueueSelect
);
578 if (EFI_ERROR (Status
)) {
583 // Select the requested queue.
585 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
586 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
587 sizeof Index
, &Index
);
588 if (EFI_ERROR (Status
)) {
593 // Read the QueueNotifyOff field.
595 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
596 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueNotifyOff
),
597 sizeof NotifyOffset
, &NotifyOffset
);
598 if (EFI_ERROR (Status
)) {
603 // Re-select the original queue.
605 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
606 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
607 sizeof SavedQueueSelect
, &SavedQueueSelect
);
608 if (EFI_ERROR (Status
)) {
613 // We can now kick the queue.
615 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->NotifyConfig
, TRUE
,
616 NotifyOffset
* Dev
->NotifyOffsetMultiplier
,
617 sizeof Index
, &Index
);
625 Virtio10SetQueueAlign (
626 IN VIRTIO_DEVICE_PROTOCOL
*This
,
630 return (Alignment
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
637 Virtio10SetPageSize (
638 IN VIRTIO_DEVICE_PROTOCOL
*This
,
642 return (PageSize
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
649 Virtio10GetQueueNumMax (
650 IN VIRTIO_DEVICE_PROTOCOL
*This
,
651 OUT UINT16
*QueueNumMax
657 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
659 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
660 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSize
),
661 sizeof *QueueNumMax
, QueueNumMax
);
669 Virtio10SetQueueNum (
670 IN VIRTIO_DEVICE_PROTOCOL
*This
,
678 // This member function is required for VirtIo MMIO, and a no-op in
679 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
680 // member to reduce memory consumption, but none of our drivers do. So
681 // just check that they set the size that is already in effect.
683 Status
= Virtio10GetQueueNumMax (This
, &CurrentSize
);
684 if (EFI_ERROR (Status
)) {
687 return (CurrentSize
== QueueSize
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
694 Virtio10GetDeviceStatus (
695 IN VIRTIO_DEVICE_PROTOCOL
*This
,
696 OUT UINT8
*DeviceStatus
702 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
704 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
705 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
706 sizeof *DeviceStatus
, DeviceStatus
);
714 Virtio10SetDeviceStatus (
715 IN VIRTIO_DEVICE_PROTOCOL
*This
,
716 IN UINT8 DeviceStatus
722 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
724 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
725 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
726 sizeof DeviceStatus
, &DeviceStatus
);
734 Virtio10WriteDevice (
735 IN VIRTIO_DEVICE_PROTOCOL
*This
,
736 IN UINTN FieldOffset
,
744 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
746 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, TRUE
,
747 FieldOffset
, FieldSize
, &Value
);
756 IN VIRTIO_DEVICE_PROTOCOL
*This
,
757 IN UINTN FieldOffset
,
766 if (FieldSize
!= BufferSize
) {
767 return EFI_INVALID_PARAMETER
;
770 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
772 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, FALSE
,
773 FieldOffset
, FieldSize
, Buffer
);
780 Virtio10AllocateSharedPages (
781 IN VIRTIO_DEVICE_PROTOCOL
*This
,
783 IN OUT VOID
**HostAddress
789 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
791 Status
= Dev
->PciIo
->AllocateBuffer (
797 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
805 Virtio10FreeSharedPages (
806 IN VIRTIO_DEVICE_PROTOCOL
*This
,
813 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
815 Dev
->PciIo
->FreeBuffer (
825 Virtio10MapSharedBuffer (
826 IN VIRTIO_DEVICE_PROTOCOL
*This
,
827 IN VIRTIO_MAP_OPERATION Operation
,
828 IN VOID
*HostAddress
,
829 IN OUT UINTN
*NumberOfBytes
,
830 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
836 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation
;
838 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
841 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
844 case VirtioOperationBusMasterRead
:
845 PciIoOperation
= EfiPciIoOperationBusMasterRead
;
847 case VirtioOperationBusMasterWrite
:
848 PciIoOperation
= EfiPciIoOperationBusMasterWrite
;
850 case VirtioOperationBusMasterCommonBuffer
:
851 PciIoOperation
= EfiPciIoOperationBusMasterCommonBuffer
;
854 return EFI_INVALID_PARAMETER
;
857 Status
= Dev
->PciIo
->Map (
871 Virtio10UnmapSharedBuffer (
872 IN VIRTIO_DEVICE_PROTOCOL
*This
,
879 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
881 Status
= Dev
->PciIo
->Unmap (
889 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate
= {
890 VIRTIO_SPEC_REVISION (1, 0, 0),
891 0, // SubSystemDeviceId, filled in dynamically
892 Virtio10GetDeviceFeatures
,
893 Virtio10SetGuestFeatures
,
894 Virtio10SetQueueAddress
,
896 Virtio10SetQueueNotify
,
897 Virtio10SetQueueAlign
,
899 Virtio10GetQueueNumMax
,
901 Virtio10GetDeviceStatus
,
902 Virtio10SetDeviceStatus
,
905 Virtio10AllocateSharedPages
,
906 Virtio10FreeSharedPages
,
907 Virtio10MapSharedBuffer
,
908 Virtio10UnmapSharedBuffer
913 // EFI_DRIVER_BINDING_PROTOCOL member functions
919 Virtio10BindingSupported (
920 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
921 IN EFI_HANDLE DeviceHandle
,
922 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
926 EFI_PCI_IO_PROTOCOL
*PciIo
;
929 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
930 (VOID
**)&PciIo
, This
->DriverBindingHandle
,
931 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
932 if (EFI_ERROR (Status
)) {
936 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0,
937 sizeof Pci
/ sizeof (UINT32
), &Pci
);
938 if (EFI_ERROR (Status
)) {
942 Status
= EFI_UNSUPPORTED
;
944 // Recognize non-transitional modern devices. Also, we'll have to parse the
945 // PCI capability list, so make sure the CapabilityPtr field will be valid.
947 if (Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
&&
948 Pci
.Hdr
.DeviceId
>= 0x1040 &&
949 Pci
.Hdr
.DeviceId
<= 0x107F &&
950 Pci
.Hdr
.RevisionID
>= 0x01 &&
951 Pci
.Device
.SubsystemID
>= 0x40 &&
952 (Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0) {
954 // The virtio-vga device is special. It can be driven both as a VGA device
955 // with a linear framebuffer, and through its underlying, modern,
956 // virtio-gpu-pci device, which has no linear framebuffer itself. For
957 // compatibility with guest OSes that insist on inheriting a linear
958 // framebuffer from the firmware, we should leave virtio-vga to
959 // QemuVideoDxe, and support only virtio-gpu-pci here.
961 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
962 // former has device class PCI_CLASS_DISPLAY_VGA.
964 if (Pci
.Hdr
.DeviceId
!= 0x1050 || !IS_PCI_VGA (&Pci
)) {
965 Status
= EFI_SUCCESS
;
970 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
971 This
->DriverBindingHandle
, DeviceHandle
);
980 Virtio10BindingStart (
981 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
982 IN EFI_HANDLE DeviceHandle
,
983 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
986 VIRTIO_1_0_DEV
*Device
;
989 UINT64 SetAttributes
;
991 Device
= AllocateZeroPool (sizeof *Device
);
992 if (Device
== NULL
) {
993 return EFI_OUT_OF_RESOURCES
;
996 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
997 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
999 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1000 (VOID
**)&Device
->PciIo
, This
->DriverBindingHandle
,
1001 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
1002 if (EFI_ERROR (Status
)) {
1006 Status
= Device
->PciIo
->Pci
.Read (Device
->PciIo
, EfiPciIoWidthUint32
, 0,
1007 sizeof Pci
/ sizeof (UINT32
), &Pci
);
1008 if (EFI_ERROR (Status
)) {
1012 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
1014 Status
= ParseCapabilities (Device
, Pci
.Device
.CapabilityPtr
);
1015 if (EFI_ERROR (Status
)) {
1019 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
1020 EfiPciIoAttributeOperationGet
, 0,
1021 &Device
->OriginalPciAttributes
);
1022 if (EFI_ERROR (Status
)) {
1026 SetAttributes
= (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
|
1027 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1028 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
1029 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
1030 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
1031 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
1032 EfiPciIoAttributeOperationEnable
, SetAttributes
,
1034 if (EFI_ERROR (Status
)) {
1038 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
1039 &gVirtioDeviceProtocolGuid
, EFI_NATIVE_INTERFACE
,
1041 if (EFI_ERROR (Status
)) {
1042 goto RestorePciAttributes
;
1047 RestorePciAttributes
:
1048 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1049 Device
->OriginalPciAttributes
, NULL
);
1052 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1053 This
->DriverBindingHandle
, DeviceHandle
);
1065 Virtio10BindingStop (
1066 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1067 IN EFI_HANDLE DeviceHandle
,
1068 IN UINTN NumberOfChildren
,
1069 IN EFI_HANDLE
*ChildHandleBuffer
1073 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
1074 VIRTIO_1_0_DEV
*Device
;
1076 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
1077 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
1078 DeviceHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1079 if (EFI_ERROR (Status
)) {
1083 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
1085 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
1086 &gVirtioDeviceProtocolGuid
, &Device
->VirtIo
);
1087 if (EFI_ERROR (Status
)) {
1091 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1092 Device
->OriginalPciAttributes
, NULL
);
1093 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1094 This
->DriverBindingHandle
, DeviceHandle
);
1101 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
1102 &Virtio10BindingSupported
,
1103 &Virtio10BindingStart
,
1104 &Virtio10BindingStop
,
1106 NULL
, // ImageHandle, to be overwritten
1107 NULL
// DriverBindingHandle, to be overwritten
1112 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1117 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1118 { "eng;en", L
"Virtio 1.0 PCI Driver" },
1123 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1128 Virtio10GetDriverName (
1129 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1131 OUT CHAR16
**DriverName
1134 return LookupUnicodeString2 (
1136 This
->SupportedLanguages
,
1139 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1146 Virtio10GetDeviceName (
1147 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1148 IN EFI_HANDLE DeviceHandle
,
1149 IN EFI_HANDLE ChildHandle
,
1151 OUT CHAR16
**ControllerName
1154 return EFI_UNSUPPORTED
;
1158 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1159 &Virtio10GetDriverName
,
1160 &Virtio10GetDeviceName
,
1165 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1166 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &Virtio10GetDriverName
,
1167 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &Virtio10GetDeviceName
,
1173 // Entry point of this driver
1178 Virtio10EntryPoint (
1179 IN EFI_HANDLE ImageHandle
,
1180 IN EFI_SYSTEM_TABLE
*SystemTable
1183 return EfiLibInstallDriverBindingComponentName2 (