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 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
503 Address
= (UINTN
)Ring
->Desc
;
504 Address
+= RingBaseShift
;
505 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
506 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueDesc
),
507 sizeof Address
, &Address
);
508 if (EFI_ERROR (Status
)) {
512 Address
= (UINTN
)Ring
->Avail
.Flags
;
513 Address
+= RingBaseShift
;
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 Address
+= RingBaseShift
;
523 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
524 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueUsed
),
525 sizeof Address
, &Address
);
526 if (EFI_ERROR (Status
)) {
531 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
532 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueEnable
),
533 sizeof Enable
, &Enable
);
541 Virtio10SetQueueSel (
542 IN VIRTIO_DEVICE_PROTOCOL
*This
,
549 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
551 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
552 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
553 sizeof Index
, &Index
);
561 Virtio10SetQueueNotify (
562 IN VIRTIO_DEVICE_PROTOCOL
*This
,
568 UINT16 SavedQueueSelect
;
571 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
574 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
575 // to stash & restore the current queue selector around it.
577 // So, start with saving the current queue selector.
579 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
580 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
581 sizeof SavedQueueSelect
, &SavedQueueSelect
);
582 if (EFI_ERROR (Status
)) {
587 // Select the requested queue.
589 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
590 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
591 sizeof Index
, &Index
);
592 if (EFI_ERROR (Status
)) {
597 // Read the QueueNotifyOff field.
599 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
600 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueNotifyOff
),
601 sizeof NotifyOffset
, &NotifyOffset
);
602 if (EFI_ERROR (Status
)) {
607 // Re-select the original queue.
609 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
610 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
611 sizeof SavedQueueSelect
, &SavedQueueSelect
);
612 if (EFI_ERROR (Status
)) {
617 // We can now kick the queue.
619 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->NotifyConfig
, TRUE
,
620 NotifyOffset
* Dev
->NotifyOffsetMultiplier
,
621 sizeof Index
, &Index
);
629 Virtio10SetQueueAlign (
630 IN VIRTIO_DEVICE_PROTOCOL
*This
,
634 return (Alignment
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
641 Virtio10SetPageSize (
642 IN VIRTIO_DEVICE_PROTOCOL
*This
,
646 return (PageSize
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
653 Virtio10GetQueueNumMax (
654 IN VIRTIO_DEVICE_PROTOCOL
*This
,
655 OUT UINT16
*QueueNumMax
661 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
663 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
664 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSize
),
665 sizeof *QueueNumMax
, QueueNumMax
);
673 Virtio10SetQueueNum (
674 IN VIRTIO_DEVICE_PROTOCOL
*This
,
682 // This member function is required for VirtIo MMIO, and a no-op in
683 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
684 // member to reduce memory consumption, but none of our drivers do. So
685 // just check that they set the size that is already in effect.
687 Status
= Virtio10GetQueueNumMax (This
, &CurrentSize
);
688 if (EFI_ERROR (Status
)) {
691 return (CurrentSize
== QueueSize
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
698 Virtio10GetDeviceStatus (
699 IN VIRTIO_DEVICE_PROTOCOL
*This
,
700 OUT UINT8
*DeviceStatus
706 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
708 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
709 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
710 sizeof *DeviceStatus
, DeviceStatus
);
718 Virtio10SetDeviceStatus (
719 IN VIRTIO_DEVICE_PROTOCOL
*This
,
720 IN UINT8 DeviceStatus
726 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
728 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
729 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
730 sizeof DeviceStatus
, &DeviceStatus
);
738 Virtio10WriteDevice (
739 IN VIRTIO_DEVICE_PROTOCOL
*This
,
740 IN UINTN FieldOffset
,
748 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
750 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, TRUE
,
751 FieldOffset
, FieldSize
, &Value
);
760 IN VIRTIO_DEVICE_PROTOCOL
*This
,
761 IN UINTN FieldOffset
,
770 if (FieldSize
!= BufferSize
) {
771 return EFI_INVALID_PARAMETER
;
774 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
776 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, FALSE
,
777 FieldOffset
, FieldSize
, Buffer
);
784 Virtio10AllocateSharedPages (
785 IN VIRTIO_DEVICE_PROTOCOL
*This
,
787 IN OUT VOID
**HostAddress
793 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
795 Status
= Dev
->PciIo
->AllocateBuffer (
801 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
809 Virtio10FreeSharedPages (
810 IN VIRTIO_DEVICE_PROTOCOL
*This
,
817 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
819 Dev
->PciIo
->FreeBuffer (
829 Virtio10MapSharedBuffer (
830 IN VIRTIO_DEVICE_PROTOCOL
*This
,
831 IN VIRTIO_MAP_OPERATION Operation
,
832 IN VOID
*HostAddress
,
833 IN OUT UINTN
*NumberOfBytes
,
834 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
840 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation
;
842 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
845 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
848 case VirtioOperationBusMasterRead
:
849 PciIoOperation
= EfiPciIoOperationBusMasterRead
;
851 case VirtioOperationBusMasterWrite
:
852 PciIoOperation
= EfiPciIoOperationBusMasterWrite
;
854 case VirtioOperationBusMasterCommonBuffer
:
855 PciIoOperation
= EfiPciIoOperationBusMasterCommonBuffer
;
858 return EFI_INVALID_PARAMETER
;
861 Status
= Dev
->PciIo
->Map (
875 Virtio10UnmapSharedBuffer (
876 IN VIRTIO_DEVICE_PROTOCOL
*This
,
883 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
885 Status
= Dev
->PciIo
->Unmap (
893 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate
= {
894 VIRTIO_SPEC_REVISION (1, 0, 0),
895 0, // SubSystemDeviceId, filled in dynamically
896 Virtio10GetDeviceFeatures
,
897 Virtio10SetGuestFeatures
,
898 Virtio10SetQueueAddress
,
900 Virtio10SetQueueNotify
,
901 Virtio10SetQueueAlign
,
903 Virtio10GetQueueNumMax
,
905 Virtio10GetDeviceStatus
,
906 Virtio10SetDeviceStatus
,
909 Virtio10AllocateSharedPages
,
910 Virtio10FreeSharedPages
,
911 Virtio10MapSharedBuffer
,
912 Virtio10UnmapSharedBuffer
917 // EFI_DRIVER_BINDING_PROTOCOL member functions
923 Virtio10BindingSupported (
924 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
925 IN EFI_HANDLE DeviceHandle
,
926 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
930 EFI_PCI_IO_PROTOCOL
*PciIo
;
933 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
934 (VOID
**)&PciIo
, This
->DriverBindingHandle
,
935 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
936 if (EFI_ERROR (Status
)) {
940 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0,
941 sizeof Pci
/ sizeof (UINT32
), &Pci
);
942 if (EFI_ERROR (Status
)) {
946 Status
= EFI_UNSUPPORTED
;
948 // Recognize non-transitional modern devices. Also, we'll have to parse the
949 // PCI capability list, so make sure the CapabilityPtr field will be valid.
951 if (Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
&&
952 Pci
.Hdr
.DeviceId
>= 0x1040 &&
953 Pci
.Hdr
.DeviceId
<= 0x107F &&
954 Pci
.Hdr
.RevisionID
>= 0x01 &&
955 Pci
.Device
.SubsystemID
>= 0x40 &&
956 (Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0) {
958 // The virtio-vga device is special. It can be driven both as a VGA device
959 // with a linear framebuffer, and through its underlying, modern,
960 // virtio-gpu-pci device, which has no linear framebuffer itself. For
961 // compatibility with guest OSes that insist on inheriting a linear
962 // framebuffer from the firmware, we should leave virtio-vga to
963 // QemuVideoDxe, and support only virtio-gpu-pci here.
965 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
966 // former has device class PCI_CLASS_DISPLAY_VGA.
968 if (Pci
.Hdr
.DeviceId
!= 0x1050 || !IS_PCI_VGA (&Pci
)) {
969 Status
= EFI_SUCCESS
;
974 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
975 This
->DriverBindingHandle
, DeviceHandle
);
984 Virtio10BindingStart (
985 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
986 IN EFI_HANDLE DeviceHandle
,
987 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
990 VIRTIO_1_0_DEV
*Device
;
993 UINT64 SetAttributes
;
995 Device
= AllocateZeroPool (sizeof *Device
);
996 if (Device
== NULL
) {
997 return EFI_OUT_OF_RESOURCES
;
1000 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
1001 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
1003 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1004 (VOID
**)&Device
->PciIo
, This
->DriverBindingHandle
,
1005 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
1006 if (EFI_ERROR (Status
)) {
1010 Status
= Device
->PciIo
->Pci
.Read (Device
->PciIo
, EfiPciIoWidthUint32
, 0,
1011 sizeof Pci
/ sizeof (UINT32
), &Pci
);
1012 if (EFI_ERROR (Status
)) {
1016 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
1018 Status
= ParseCapabilities (Device
, Pci
.Device
.CapabilityPtr
);
1019 if (EFI_ERROR (Status
)) {
1023 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
1024 EfiPciIoAttributeOperationGet
, 0,
1025 &Device
->OriginalPciAttributes
);
1026 if (EFI_ERROR (Status
)) {
1030 SetAttributes
= (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
|
1031 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1032 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
1033 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
1034 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
1035 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
1036 EfiPciIoAttributeOperationEnable
, SetAttributes
,
1038 if (EFI_ERROR (Status
)) {
1042 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
1043 &gVirtioDeviceProtocolGuid
, EFI_NATIVE_INTERFACE
,
1045 if (EFI_ERROR (Status
)) {
1046 goto RestorePciAttributes
;
1051 RestorePciAttributes
:
1052 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1053 Device
->OriginalPciAttributes
, NULL
);
1056 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1057 This
->DriverBindingHandle
, DeviceHandle
);
1069 Virtio10BindingStop (
1070 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1071 IN EFI_HANDLE DeviceHandle
,
1072 IN UINTN NumberOfChildren
,
1073 IN EFI_HANDLE
*ChildHandleBuffer
1077 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
1078 VIRTIO_1_0_DEV
*Device
;
1080 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
1081 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
1082 DeviceHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1083 if (EFI_ERROR (Status
)) {
1087 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
1089 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
1090 &gVirtioDeviceProtocolGuid
, &Device
->VirtIo
);
1091 if (EFI_ERROR (Status
)) {
1095 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1096 Device
->OriginalPciAttributes
, NULL
);
1097 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1098 This
->DriverBindingHandle
, DeviceHandle
);
1105 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
1106 &Virtio10BindingSupported
,
1107 &Virtio10BindingStart
,
1108 &Virtio10BindingStop
,
1110 NULL
, // ImageHandle, to be overwritten
1111 NULL
// DriverBindingHandle, to be overwritten
1116 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1121 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1122 { "eng;en", L
"Virtio 1.0 PCI Driver" },
1127 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1132 Virtio10GetDriverName (
1133 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1135 OUT CHAR16
**DriverName
1138 return LookupUnicodeString2 (
1140 This
->SupportedLanguages
,
1143 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1150 Virtio10GetDeviceName (
1151 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1152 IN EFI_HANDLE DeviceHandle
,
1153 IN EFI_HANDLE ChildHandle
,
1155 OUT CHAR16
**ControllerName
1158 return EFI_UNSUPPORTED
;
1162 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1163 &Virtio10GetDriverName
,
1164 &Virtio10GetDeviceName
,
1169 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1170 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &Virtio10GetDriverName
,
1171 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &Virtio10GetDeviceName
,
1177 // Entry point of this driver
1182 Virtio10EntryPoint (
1183 IN EFI_HANDLE ImageHandle
,
1184 IN EFI_SYSTEM_TABLE
*SystemTable
1187 return EfiLibInstallDriverBindingComponentName2 (