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/PciCapLib.h>
25 #include <Library/PciCapPciIoLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Library/UefiLib.h>
37 Transfer data between the caller and a register in a virtio-1.0 register
40 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents
43 @param[in] Config The "fat pointer" structure that identifies the
44 register block to access.
46 @param[in] Write TRUE if the register should be written, FALSE if
47 the register should be read.
49 @param[in] FieldOffset The offset of the register within the register
52 @param[in] FieldSize The size of the register within the register
53 block. Can be one of 1, 2, 4 and 8. Accesses to
54 8-byte registers are broken up into two 4-byte
57 @param[in,out] Buffer When Write is TRUE, the register is written with
58 data from Buffer. When Write is FALSE, the caller
59 receives the register value into Buffer.
61 @retval EFI_SUCCESS Register access successful.
63 @retval EFI_INVALID_PARAMETER The register block pointed-to by Config
64 doesn't exist; or FieldOffset and FieldSize
65 would overflow the register block; or
68 @return Error codes from
69 EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)
75 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
76 IN VIRTIO_1_0_CONFIG
*Config
,
84 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
85 EFI_PCI_IO_PROTOCOL_ACCESS
*BarType
;
86 EFI_PCI_IO_PROTOCOL_IO_MEM Access
;
88 if (!Config
->Exists
||
89 FieldSize
> Config
->Length
||
90 FieldOffset
> Config
->Length
- FieldSize
) {
91 return EFI_INVALID_PARAMETER
;
97 Width
= EfiPciIoWidthUint8
;
101 Width
= EfiPciIoWidthUint16
;
111 Width
= EfiPciIoWidthUint32
;
115 return EFI_INVALID_PARAMETER
;
118 BarType
= (Config
->BarType
== Virtio10BarTypeMem
) ? &PciIo
->Mem
: &PciIo
->Io
;
119 Access
= Write
? BarType
->Write
: BarType
->Read
;
121 return Access (PciIo
, Width
, Config
->Bar
, Config
->Offset
+ FieldOffset
,
127 Determine if a PCI BAR is IO or MMIO.
129 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
132 @param[in] BarIndex The number of the BAR whose type the caller is
135 @param[out] BarType On output, a VIRTIO_1_0_BAR_TYPE value that gives the
138 @retval EFI_SUCCESS The BAR type has been recognized and stored in
141 @retval EFI_UNSUPPORTED The BAR type couldn't be identified.
143 @return Error codes from
144 EFI_PCI_IO_PROTOCOL.GetBarAttributes().
149 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
151 OUT VIRTIO_1_0_BAR_TYPE
*BarType
157 Status
= PciIo
->GetBarAttributes (PciIo
, BarIndex
, NULL
, &Resources
);
158 if (EFI_ERROR (Status
)) {
162 Status
= EFI_UNSUPPORTED
;
164 if (*(UINT8
*)Resources
== ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
) {
165 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
167 Descriptor
= Resources
;
168 switch (Descriptor
->ResType
) {
169 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
170 *BarType
= Virtio10BarTypeMem
;
171 Status
= EFI_SUCCESS
;
174 case ACPI_ADDRESS_SPACE_TYPE_IO
:
175 *BarType
= Virtio10BarTypeIo
;
176 Status
= EFI_SUCCESS
;
184 FreePool (Resources
);
190 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
191 locations of the interesting virtio-1.0 register blocks.
193 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies
194 the device. On input, the caller is responsible
195 that the Device->PciIo member be live, and that
196 the CommonConfig, NotifyConfig,
197 NotifyOffsetMultiplier and SpecificConfig
198 members be zeroed. On output, said members
199 will have been updated from the PCI
202 @retval EFI_SUCCESS Traversal successful.
204 @return Error codes from PciCapPciIoLib, PciCapLib, and the
205 GetBarType() helper function.
210 IN OUT VIRTIO_1_0_DEV
*Device
214 PCI_CAP_DEV
*PciDevice
;
215 PCI_CAP_LIST
*CapList
;
216 UINT16 VendorInstance
;
219 Status
= PciCapPciIoDeviceInit (Device
->PciIo
, &PciDevice
);
220 if (EFI_ERROR (Status
)) {
223 Status
= PciCapListInit (PciDevice
, &CapList
);
224 if (EFI_ERROR (Status
)) {
225 goto UninitPciDevice
;
228 for (VendorInstance
= 0;
229 !EFI_ERROR (PciCapListFindCap (CapList
, PciCapNormal
,
230 EFI_PCI_CAPABILITY_ID_VENDOR
, VendorInstance
,
234 VIRTIO_PCI_CAP VirtIoCap
;
235 VIRTIO_1_0_CONFIG
*ParsedConfig
;
238 // Big enough to accommodate a VIRTIO_PCI_CAP structure?
240 Status
= PciCapRead (PciDevice
, VendorCap
,
241 OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR
, Length
), &CapLen
,
243 if (EFI_ERROR (Status
)) {
246 if (CapLen
< sizeof VirtIoCap
) {
248 // Too small, move to next.
254 // Read interesting part of capability.
256 Status
= PciCapRead (PciDevice
, VendorCap
, 0, &VirtIoCap
, sizeof VirtIoCap
);
257 if (EFI_ERROR (Status
)) {
261 switch (VirtIoCap
.ConfigType
) {
262 case VIRTIO_PCI_CAP_COMMON_CFG
:
263 ParsedConfig
= &Device
->CommonConfig
;
265 case VIRTIO_PCI_CAP_NOTIFY_CFG
:
266 ParsedConfig
= &Device
->NotifyConfig
;
268 case VIRTIO_PCI_CAP_DEVICE_CFG
:
269 ParsedConfig
= &Device
->SpecificConfig
;
273 // Capability is not interesting.
279 // Save the location of the register block into ParsedConfig.
281 Status
= GetBarType (Device
->PciIo
, VirtIoCap
.Bar
, &ParsedConfig
->BarType
);
282 if (EFI_ERROR (Status
)) {
285 ParsedConfig
->Bar
= VirtIoCap
.Bar
;
286 ParsedConfig
->Offset
= VirtIoCap
.Offset
;
287 ParsedConfig
->Length
= VirtIoCap
.Length
;
289 if (VirtIoCap
.ConfigType
== VIRTIO_PCI_CAP_NOTIFY_CFG
) {
291 // This capability has an additional field called NotifyOffsetMultiplier;
294 if (CapLen
< sizeof VirtIoCap
+ sizeof Device
->NotifyOffsetMultiplier
) {
296 // Too small, move to next.
301 Status
= PciCapRead (PciDevice
, VendorCap
, sizeof VirtIoCap
,
302 &Device
->NotifyOffsetMultiplier
,
303 sizeof Device
->NotifyOffsetMultiplier
);
304 if (EFI_ERROR (Status
)) {
310 // Capability parsed successfully.
312 ParsedConfig
->Exists
= TRUE
;
315 ASSERT_EFI_ERROR (Status
);
318 PciCapListUninit (CapList
);
321 PciCapPciIoDeviceUninit (PciDevice
);
328 Accumulate the BAR type of a virtio-1.0 register block into a UINT64
329 attribute map, such that the latter is suitable for enabling IO / MMIO
330 decoding with EFI_PCI_IO_PROTOCOL.Attributes().
332 @param[in] Config The "fat pointer" structure that identifies the
333 register block. It is allowed for the register
336 @param[in,out] Attributes On output, if the register block exists,
337 EFI_PCI_IO_ATTRIBUTE_MEMORY or
338 EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,
339 according to the register block's BAR type.
344 IN VIRTIO_1_0_CONFIG
*Config
,
345 IN OUT UINT64
*Attributes
348 if (Config
->Exists
) {
349 *Attributes
|= (Config
->BarType
== Virtio10BarTypeMem
) ?
350 EFI_PCI_IO_ATTRIBUTE_MEMORY
:
351 EFI_PCI_IO_ATTRIBUTE_IO
;
357 // VIRTIO_DEVICE_PROTOCOL member functions
363 Virtio10GetDeviceFeatures (
364 IN VIRTIO_DEVICE_PROTOCOL
*This
,
365 OUT UINT64
*DeviceFeatures
370 UINT32 Features32
[2];
372 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
374 for (Selector
= 0; Selector
< 2; ++Selector
) {
378 // Select the low or high half of the features.
380 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
381 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeatureSelect
),
382 sizeof Selector
, &Selector
);
383 if (EFI_ERROR (Status
)) {
390 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
391 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeature
),
392 sizeof Features32
[Selector
], &Features32
[Selector
]);
393 if (EFI_ERROR (Status
)) {
398 *DeviceFeatures
= LShiftU64 (Features32
[1], 32) | Features32
[0];
406 Virtio10SetGuestFeatures (
407 IN VIRTIO_DEVICE_PROTOCOL
*This
,
413 UINT32 Features32
[2];
415 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
417 Features32
[0] = (UINT32
)Features
;
418 Features32
[1] = (UINT32
)RShiftU64 (Features
, 32);
420 for (Selector
= 0; Selector
< 2; ++Selector
) {
424 // Select the low or high half of the features.
426 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
427 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeatureSelect
),
428 sizeof Selector
, &Selector
);
429 if (EFI_ERROR (Status
)) {
436 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
437 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeature
),
438 sizeof Features32
[Selector
], &Features32
[Selector
]);
439 if (EFI_ERROR (Status
)) {
451 Virtio10SetQueueAddress (
452 IN VIRTIO_DEVICE_PROTOCOL
*This
,
454 IN UINT64 RingBaseShift
462 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
464 Address
= (UINTN
)Ring
->Desc
;
465 Address
+= RingBaseShift
;
466 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
467 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueDesc
),
468 sizeof Address
, &Address
);
469 if (EFI_ERROR (Status
)) {
473 Address
= (UINTN
)Ring
->Avail
.Flags
;
474 Address
+= RingBaseShift
;
475 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
476 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueAvail
),
477 sizeof Address
, &Address
);
478 if (EFI_ERROR (Status
)) {
482 Address
= (UINTN
)Ring
->Used
.Flags
;
483 Address
+= RingBaseShift
;
484 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
485 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueUsed
),
486 sizeof Address
, &Address
);
487 if (EFI_ERROR (Status
)) {
492 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
493 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueEnable
),
494 sizeof Enable
, &Enable
);
502 Virtio10SetQueueSel (
503 IN VIRTIO_DEVICE_PROTOCOL
*This
,
510 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
512 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
513 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
514 sizeof Index
, &Index
);
522 Virtio10SetQueueNotify (
523 IN VIRTIO_DEVICE_PROTOCOL
*This
,
529 UINT16 SavedQueueSelect
;
532 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
535 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
536 // to stash & restore the current queue selector around it.
538 // So, start with saving the current queue selector.
540 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
541 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
542 sizeof SavedQueueSelect
, &SavedQueueSelect
);
543 if (EFI_ERROR (Status
)) {
548 // Select the requested queue.
550 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
551 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
552 sizeof Index
, &Index
);
553 if (EFI_ERROR (Status
)) {
558 // Read the QueueNotifyOff field.
560 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
561 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueNotifyOff
),
562 sizeof NotifyOffset
, &NotifyOffset
);
563 if (EFI_ERROR (Status
)) {
568 // Re-select the original queue.
570 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
571 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
572 sizeof SavedQueueSelect
, &SavedQueueSelect
);
573 if (EFI_ERROR (Status
)) {
578 // We can now kick the queue.
580 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->NotifyConfig
, TRUE
,
581 NotifyOffset
* Dev
->NotifyOffsetMultiplier
,
582 sizeof Index
, &Index
);
590 Virtio10SetQueueAlign (
591 IN VIRTIO_DEVICE_PROTOCOL
*This
,
595 return (Alignment
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
602 Virtio10SetPageSize (
603 IN VIRTIO_DEVICE_PROTOCOL
*This
,
607 return (PageSize
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
614 Virtio10GetQueueNumMax (
615 IN VIRTIO_DEVICE_PROTOCOL
*This
,
616 OUT UINT16
*QueueNumMax
622 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
624 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
625 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSize
),
626 sizeof *QueueNumMax
, QueueNumMax
);
634 Virtio10SetQueueNum (
635 IN VIRTIO_DEVICE_PROTOCOL
*This
,
643 // This member function is required for VirtIo MMIO, and a no-op in
644 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
645 // member to reduce memory consumption, but none of our drivers do. So
646 // just check that they set the size that is already in effect.
648 Status
= Virtio10GetQueueNumMax (This
, &CurrentSize
);
649 if (EFI_ERROR (Status
)) {
652 return (CurrentSize
== QueueSize
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
659 Virtio10GetDeviceStatus (
660 IN VIRTIO_DEVICE_PROTOCOL
*This
,
661 OUT UINT8
*DeviceStatus
667 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
669 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
670 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
671 sizeof *DeviceStatus
, DeviceStatus
);
679 Virtio10SetDeviceStatus (
680 IN VIRTIO_DEVICE_PROTOCOL
*This
,
681 IN UINT8 DeviceStatus
687 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
689 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
690 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
691 sizeof DeviceStatus
, &DeviceStatus
);
699 Virtio10WriteDevice (
700 IN VIRTIO_DEVICE_PROTOCOL
*This
,
701 IN UINTN FieldOffset
,
709 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
711 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, TRUE
,
712 FieldOffset
, FieldSize
, &Value
);
721 IN VIRTIO_DEVICE_PROTOCOL
*This
,
722 IN UINTN FieldOffset
,
731 if (FieldSize
!= BufferSize
) {
732 return EFI_INVALID_PARAMETER
;
735 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
737 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, FALSE
,
738 FieldOffset
, FieldSize
, Buffer
);
745 Virtio10AllocateSharedPages (
746 IN VIRTIO_DEVICE_PROTOCOL
*This
,
748 IN OUT VOID
**HostAddress
754 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
756 Status
= Dev
->PciIo
->AllocateBuffer (
762 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
770 Virtio10FreeSharedPages (
771 IN VIRTIO_DEVICE_PROTOCOL
*This
,
778 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
780 Dev
->PciIo
->FreeBuffer (
790 Virtio10MapSharedBuffer (
791 IN VIRTIO_DEVICE_PROTOCOL
*This
,
792 IN VIRTIO_MAP_OPERATION Operation
,
793 IN VOID
*HostAddress
,
794 IN OUT UINTN
*NumberOfBytes
,
795 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
801 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation
;
803 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
806 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
809 case VirtioOperationBusMasterRead
:
810 PciIoOperation
= EfiPciIoOperationBusMasterRead
;
812 case VirtioOperationBusMasterWrite
:
813 PciIoOperation
= EfiPciIoOperationBusMasterWrite
;
815 case VirtioOperationBusMasterCommonBuffer
:
816 PciIoOperation
= EfiPciIoOperationBusMasterCommonBuffer
;
819 return EFI_INVALID_PARAMETER
;
822 Status
= Dev
->PciIo
->Map (
836 Virtio10UnmapSharedBuffer (
837 IN VIRTIO_DEVICE_PROTOCOL
*This
,
844 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
846 Status
= Dev
->PciIo
->Unmap (
854 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate
= {
855 VIRTIO_SPEC_REVISION (1, 0, 0),
856 0, // SubSystemDeviceId, filled in dynamically
857 Virtio10GetDeviceFeatures
,
858 Virtio10SetGuestFeatures
,
859 Virtio10SetQueueAddress
,
861 Virtio10SetQueueNotify
,
862 Virtio10SetQueueAlign
,
864 Virtio10GetQueueNumMax
,
866 Virtio10GetDeviceStatus
,
867 Virtio10SetDeviceStatus
,
870 Virtio10AllocateSharedPages
,
871 Virtio10FreeSharedPages
,
872 Virtio10MapSharedBuffer
,
873 Virtio10UnmapSharedBuffer
878 // EFI_DRIVER_BINDING_PROTOCOL member functions
884 Virtio10BindingSupported (
885 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
886 IN EFI_HANDLE DeviceHandle
,
887 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
891 EFI_PCI_IO_PROTOCOL
*PciIo
;
894 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
895 (VOID
**)&PciIo
, This
->DriverBindingHandle
,
896 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
897 if (EFI_ERROR (Status
)) {
901 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0,
902 sizeof Pci
/ sizeof (UINT32
), &Pci
);
903 if (EFI_ERROR (Status
)) {
907 Status
= EFI_UNSUPPORTED
;
909 // Recognize non-transitional modern devices. Also, we'll have to parse the
910 // PCI capability list, so make sure the CapabilityPtr field will be valid.
912 if (Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
&&
913 Pci
.Hdr
.DeviceId
>= 0x1040 &&
914 Pci
.Hdr
.DeviceId
<= 0x107F &&
915 Pci
.Hdr
.RevisionID
>= 0x01 &&
916 Pci
.Device
.SubsystemID
>= 0x40 &&
917 (Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0) {
919 // The virtio-vga device is special. It can be driven both as a VGA device
920 // with a linear framebuffer, and through its underlying, modern,
921 // virtio-gpu-pci device, which has no linear framebuffer itself. For
922 // compatibility with guest OSes that insist on inheriting a linear
923 // framebuffer from the firmware, we should leave virtio-vga to
924 // QemuVideoDxe, and support only virtio-gpu-pci here.
926 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
927 // former has device class PCI_CLASS_DISPLAY_VGA.
929 if (Pci
.Hdr
.DeviceId
!= 0x1050 || !IS_PCI_VGA (&Pci
)) {
930 Status
= EFI_SUCCESS
;
935 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
936 This
->DriverBindingHandle
, DeviceHandle
);
945 Virtio10BindingStart (
946 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
947 IN EFI_HANDLE DeviceHandle
,
948 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
951 VIRTIO_1_0_DEV
*Device
;
954 UINT64 SetAttributes
;
956 Device
= AllocateZeroPool (sizeof *Device
);
957 if (Device
== NULL
) {
958 return EFI_OUT_OF_RESOURCES
;
961 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
962 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
964 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
965 (VOID
**)&Device
->PciIo
, This
->DriverBindingHandle
,
966 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
967 if (EFI_ERROR (Status
)) {
971 Status
= Device
->PciIo
->Pci
.Read (Device
->PciIo
, EfiPciIoWidthUint32
, 0,
972 sizeof Pci
/ sizeof (UINT32
), &Pci
);
973 if (EFI_ERROR (Status
)) {
977 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
979 Status
= ParseCapabilities (Device
);
980 if (EFI_ERROR (Status
)) {
984 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
985 EfiPciIoAttributeOperationGet
, 0,
986 &Device
->OriginalPciAttributes
);
987 if (EFI_ERROR (Status
)) {
991 SetAttributes
= (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
|
992 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
993 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
994 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
995 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
996 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
997 EfiPciIoAttributeOperationEnable
, SetAttributes
,
999 if (EFI_ERROR (Status
)) {
1003 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
1004 &gVirtioDeviceProtocolGuid
, EFI_NATIVE_INTERFACE
,
1006 if (EFI_ERROR (Status
)) {
1007 goto RestorePciAttributes
;
1012 RestorePciAttributes
:
1013 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1014 Device
->OriginalPciAttributes
, NULL
);
1017 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1018 This
->DriverBindingHandle
, DeviceHandle
);
1030 Virtio10BindingStop (
1031 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1032 IN EFI_HANDLE DeviceHandle
,
1033 IN UINTN NumberOfChildren
,
1034 IN EFI_HANDLE
*ChildHandleBuffer
1038 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
1039 VIRTIO_1_0_DEV
*Device
;
1041 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
1042 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
1043 DeviceHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1044 if (EFI_ERROR (Status
)) {
1048 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
1050 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
1051 &gVirtioDeviceProtocolGuid
, &Device
->VirtIo
);
1052 if (EFI_ERROR (Status
)) {
1056 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1057 Device
->OriginalPciAttributes
, NULL
);
1058 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1059 This
->DriverBindingHandle
, DeviceHandle
);
1066 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
1067 &Virtio10BindingSupported
,
1068 &Virtio10BindingStart
,
1069 &Virtio10BindingStop
,
1071 NULL
, // ImageHandle, to be overwritten
1072 NULL
// DriverBindingHandle, to be overwritten
1077 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1082 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1083 { "eng;en", L
"Virtio 1.0 PCI Driver" },
1088 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1093 Virtio10GetDriverName (
1094 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1096 OUT CHAR16
**DriverName
1099 return LookupUnicodeString2 (
1101 This
->SupportedLanguages
,
1104 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1111 Virtio10GetDeviceName (
1112 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1113 IN EFI_HANDLE DeviceHandle
,
1114 IN EFI_HANDLE ChildHandle
,
1116 OUT CHAR16
**ControllerName
1119 return EFI_UNSUPPORTED
;
1123 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1124 &Virtio10GetDriverName
,
1125 &Virtio10GetDeviceName
,
1130 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1131 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &Virtio10GetDriverName
,
1132 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &Virtio10GetDeviceName
,
1138 // Entry point of this driver
1143 Virtio10EntryPoint (
1144 IN EFI_HANDLE ImageHandle
,
1145 IN EFI_SYSTEM_TABLE
*SystemTable
1148 return EfiLibInstallDriverBindingComponentName2 (