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 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <IndustryStandard/Pci.h>
11 #include <IndustryStandard/Virtio.h>
12 #include <Protocol/PciIo.h>
13 #include <Protocol/PciRootBridgeIo.h>
14 #include <Protocol/VirtioDevice.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PciCapLib.h>
19 #include <Library/PciCapPciIoLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiLib.h>
31 Transfer data between the caller and a register in a virtio-1.0 register
34 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents
37 @param[in] Config The "fat pointer" structure that identifies the
38 register block to access.
40 @param[in] Write TRUE if the register should be written, FALSE if
41 the register should be read.
43 @param[in] FieldOffset The offset of the register within the register
46 @param[in] FieldSize The size of the register within the register
47 block. Can be one of 1, 2, 4 and 8. Accesses to
48 8-byte registers are broken up into two 4-byte
51 @param[in,out] Buffer When Write is TRUE, the register is written with
52 data from Buffer. When Write is FALSE, the caller
53 receives the register value into Buffer.
55 @retval EFI_SUCCESS Register access successful.
57 @retval EFI_INVALID_PARAMETER The register block pointed-to by Config
58 doesn't exist; or FieldOffset and FieldSize
59 would overflow the register block; or
62 @return Error codes from
63 EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)
69 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
70 IN VIRTIO_1_0_CONFIG
*Config
,
78 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
79 EFI_PCI_IO_PROTOCOL_ACCESS
*BarType
;
80 EFI_PCI_IO_PROTOCOL_IO_MEM Access
;
82 if (!Config
->Exists
||
83 FieldSize
> Config
->Length
||
84 FieldOffset
> Config
->Length
- FieldSize
) {
85 return EFI_INVALID_PARAMETER
;
91 Width
= EfiPciIoWidthUint8
;
95 Width
= EfiPciIoWidthUint16
;
105 Width
= EfiPciIoWidthUint32
;
109 return EFI_INVALID_PARAMETER
;
112 BarType
= (Config
->BarType
== Virtio10BarTypeMem
) ? &PciIo
->Mem
: &PciIo
->Io
;
113 Access
= Write
? BarType
->Write
: BarType
->Read
;
115 return Access (PciIo
, Width
, Config
->Bar
, Config
->Offset
+ FieldOffset
,
121 Determine if a PCI BAR is IO or MMIO.
123 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
126 @param[in] BarIndex The number of the BAR whose type the caller is
129 @param[out] BarType On output, a VIRTIO_1_0_BAR_TYPE value that gives the
132 @retval EFI_SUCCESS The BAR type has been recognized and stored in
135 @retval EFI_UNSUPPORTED The BAR type couldn't be identified.
137 @return Error codes from
138 EFI_PCI_IO_PROTOCOL.GetBarAttributes().
143 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
145 OUT VIRTIO_1_0_BAR_TYPE
*BarType
151 Status
= PciIo
->GetBarAttributes (PciIo
, BarIndex
, NULL
, &Resources
);
152 if (EFI_ERROR (Status
)) {
156 Status
= EFI_UNSUPPORTED
;
158 if (*(UINT8
*)Resources
== ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
) {
159 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
161 Descriptor
= Resources
;
162 switch (Descriptor
->ResType
) {
163 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
164 *BarType
= Virtio10BarTypeMem
;
165 Status
= EFI_SUCCESS
;
168 case ACPI_ADDRESS_SPACE_TYPE_IO
:
169 *BarType
= Virtio10BarTypeIo
;
170 Status
= EFI_SUCCESS
;
178 FreePool (Resources
);
184 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
185 locations of the interesting virtio-1.0 register blocks.
187 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies
188 the device. On input, the caller is responsible
189 that the Device->PciIo member be live, and that
190 the CommonConfig, NotifyConfig,
191 NotifyOffsetMultiplier and SpecificConfig
192 members be zeroed. On output, said members
193 will have been updated from the PCI
196 @retval EFI_SUCCESS Traversal successful.
198 @return Error codes from PciCapPciIoLib, PciCapLib, and the
199 GetBarType() helper function.
204 IN OUT VIRTIO_1_0_DEV
*Device
208 PCI_CAP_DEV
*PciDevice
;
209 PCI_CAP_LIST
*CapList
;
210 UINT16 VendorInstance
;
213 Status
= PciCapPciIoDeviceInit (Device
->PciIo
, &PciDevice
);
214 if (EFI_ERROR (Status
)) {
217 Status
= PciCapListInit (PciDevice
, &CapList
);
218 if (EFI_ERROR (Status
)) {
219 goto UninitPciDevice
;
222 for (VendorInstance
= 0;
223 !EFI_ERROR (PciCapListFindCap (CapList
, PciCapNormal
,
224 EFI_PCI_CAPABILITY_ID_VENDOR
, VendorInstance
,
228 VIRTIO_PCI_CAP VirtIoCap
;
229 VIRTIO_1_0_CONFIG
*ParsedConfig
;
232 // Big enough to accommodate a VIRTIO_PCI_CAP structure?
234 Status
= PciCapRead (PciDevice
, VendorCap
,
235 OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR
, Length
), &CapLen
,
237 if (EFI_ERROR (Status
)) {
240 if (CapLen
< sizeof VirtIoCap
) {
242 // Too small, move to next.
248 // Read interesting part of capability.
250 Status
= PciCapRead (PciDevice
, VendorCap
, 0, &VirtIoCap
, sizeof VirtIoCap
);
251 if (EFI_ERROR (Status
)) {
255 switch (VirtIoCap
.ConfigType
) {
256 case VIRTIO_PCI_CAP_COMMON_CFG
:
257 ParsedConfig
= &Device
->CommonConfig
;
259 case VIRTIO_PCI_CAP_NOTIFY_CFG
:
260 ParsedConfig
= &Device
->NotifyConfig
;
262 case VIRTIO_PCI_CAP_DEVICE_CFG
:
263 ParsedConfig
= &Device
->SpecificConfig
;
267 // Capability is not interesting.
273 // Save the location of the register block into ParsedConfig.
275 Status
= GetBarType (Device
->PciIo
, VirtIoCap
.Bar
, &ParsedConfig
->BarType
);
276 if (EFI_ERROR (Status
)) {
279 ParsedConfig
->Bar
= VirtIoCap
.Bar
;
280 ParsedConfig
->Offset
= VirtIoCap
.Offset
;
281 ParsedConfig
->Length
= VirtIoCap
.Length
;
283 if (VirtIoCap
.ConfigType
== VIRTIO_PCI_CAP_NOTIFY_CFG
) {
285 // This capability has an additional field called NotifyOffsetMultiplier;
288 if (CapLen
< sizeof VirtIoCap
+ sizeof Device
->NotifyOffsetMultiplier
) {
290 // Too small, move to next.
295 Status
= PciCapRead (PciDevice
, VendorCap
, sizeof VirtIoCap
,
296 &Device
->NotifyOffsetMultiplier
,
297 sizeof Device
->NotifyOffsetMultiplier
);
298 if (EFI_ERROR (Status
)) {
304 // Capability parsed successfully.
306 ParsedConfig
->Exists
= TRUE
;
309 ASSERT_EFI_ERROR (Status
);
312 PciCapListUninit (CapList
);
315 PciCapPciIoDeviceUninit (PciDevice
);
322 Accumulate the BAR type of a virtio-1.0 register block into a UINT64
323 attribute map, such that the latter is suitable for enabling IO / MMIO
324 decoding with EFI_PCI_IO_PROTOCOL.Attributes().
326 @param[in] Config The "fat pointer" structure that identifies the
327 register block. It is allowed for the register
330 @param[in,out] Attributes On output, if the register block exists,
331 EFI_PCI_IO_ATTRIBUTE_MEMORY or
332 EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,
333 according to the register block's BAR type.
338 IN VIRTIO_1_0_CONFIG
*Config
,
339 IN OUT UINT64
*Attributes
342 if (Config
->Exists
) {
343 *Attributes
|= (Config
->BarType
== Virtio10BarTypeMem
) ?
344 EFI_PCI_IO_ATTRIBUTE_MEMORY
:
345 EFI_PCI_IO_ATTRIBUTE_IO
;
351 // VIRTIO_DEVICE_PROTOCOL member functions
357 Virtio10GetDeviceFeatures (
358 IN VIRTIO_DEVICE_PROTOCOL
*This
,
359 OUT UINT64
*DeviceFeatures
364 UINT32 Features32
[2];
366 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
368 for (Selector
= 0; Selector
< 2; ++Selector
) {
372 // Select the low or high half of the features.
374 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
375 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeatureSelect
),
376 sizeof Selector
, &Selector
);
377 if (EFI_ERROR (Status
)) {
384 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
385 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeature
),
386 sizeof Features32
[Selector
], &Features32
[Selector
]);
387 if (EFI_ERROR (Status
)) {
392 *DeviceFeatures
= LShiftU64 (Features32
[1], 32) | Features32
[0];
400 Virtio10SetGuestFeatures (
401 IN VIRTIO_DEVICE_PROTOCOL
*This
,
407 UINT32 Features32
[2];
409 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
411 Features32
[0] = (UINT32
)Features
;
412 Features32
[1] = (UINT32
)RShiftU64 (Features
, 32);
414 for (Selector
= 0; Selector
< 2; ++Selector
) {
418 // Select the low or high half of the features.
420 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
421 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeatureSelect
),
422 sizeof Selector
, &Selector
);
423 if (EFI_ERROR (Status
)) {
430 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
431 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeature
),
432 sizeof Features32
[Selector
], &Features32
[Selector
]);
433 if (EFI_ERROR (Status
)) {
445 Virtio10SetQueueAddress (
446 IN VIRTIO_DEVICE_PROTOCOL
*This
,
448 IN UINT64 RingBaseShift
456 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
458 Address
= (UINTN
)Ring
->Desc
;
459 Address
+= RingBaseShift
;
460 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
461 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueDesc
),
462 sizeof Address
, &Address
);
463 if (EFI_ERROR (Status
)) {
467 Address
= (UINTN
)Ring
->Avail
.Flags
;
468 Address
+= RingBaseShift
;
469 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
470 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueAvail
),
471 sizeof Address
, &Address
);
472 if (EFI_ERROR (Status
)) {
476 Address
= (UINTN
)Ring
->Used
.Flags
;
477 Address
+= RingBaseShift
;
478 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
479 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueUsed
),
480 sizeof Address
, &Address
);
481 if (EFI_ERROR (Status
)) {
486 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
487 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueEnable
),
488 sizeof Enable
, &Enable
);
496 Virtio10SetQueueSel (
497 IN VIRTIO_DEVICE_PROTOCOL
*This
,
504 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
506 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
507 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
508 sizeof Index
, &Index
);
516 Virtio10SetQueueNotify (
517 IN VIRTIO_DEVICE_PROTOCOL
*This
,
523 UINT16 SavedQueueSelect
;
526 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
529 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
530 // to stash & restore the current queue selector around it.
532 // So, start with saving the current queue selector.
534 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
535 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
536 sizeof SavedQueueSelect
, &SavedQueueSelect
);
537 if (EFI_ERROR (Status
)) {
542 // Select the requested queue.
544 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
545 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
546 sizeof Index
, &Index
);
547 if (EFI_ERROR (Status
)) {
552 // Read the QueueNotifyOff field.
554 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
555 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueNotifyOff
),
556 sizeof NotifyOffset
, &NotifyOffset
);
557 if (EFI_ERROR (Status
)) {
562 // Re-select the original queue.
564 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
565 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
566 sizeof SavedQueueSelect
, &SavedQueueSelect
);
567 if (EFI_ERROR (Status
)) {
572 // We can now kick the queue.
574 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->NotifyConfig
, TRUE
,
575 NotifyOffset
* Dev
->NotifyOffsetMultiplier
,
576 sizeof Index
, &Index
);
584 Virtio10SetQueueAlign (
585 IN VIRTIO_DEVICE_PROTOCOL
*This
,
589 return (Alignment
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
596 Virtio10SetPageSize (
597 IN VIRTIO_DEVICE_PROTOCOL
*This
,
601 return (PageSize
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
608 Virtio10GetQueueNumMax (
609 IN VIRTIO_DEVICE_PROTOCOL
*This
,
610 OUT UINT16
*QueueNumMax
616 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
618 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
619 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSize
),
620 sizeof *QueueNumMax
, QueueNumMax
);
628 Virtio10SetQueueNum (
629 IN VIRTIO_DEVICE_PROTOCOL
*This
,
637 // This member function is required for VirtIo MMIO, and a no-op in
638 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
639 // member to reduce memory consumption, but none of our drivers do. So
640 // just check that they set the size that is already in effect.
642 Status
= Virtio10GetQueueNumMax (This
, &CurrentSize
);
643 if (EFI_ERROR (Status
)) {
646 return (CurrentSize
== QueueSize
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
653 Virtio10GetDeviceStatus (
654 IN VIRTIO_DEVICE_PROTOCOL
*This
,
655 OUT UINT8
*DeviceStatus
661 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
663 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
664 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
665 sizeof *DeviceStatus
, DeviceStatus
);
673 Virtio10SetDeviceStatus (
674 IN VIRTIO_DEVICE_PROTOCOL
*This
,
675 IN UINT8 DeviceStatus
681 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
683 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
684 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
685 sizeof DeviceStatus
, &DeviceStatus
);
693 Virtio10WriteDevice (
694 IN VIRTIO_DEVICE_PROTOCOL
*This
,
695 IN UINTN FieldOffset
,
703 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
705 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, TRUE
,
706 FieldOffset
, FieldSize
, &Value
);
715 IN VIRTIO_DEVICE_PROTOCOL
*This
,
716 IN UINTN FieldOffset
,
725 if (FieldSize
!= BufferSize
) {
726 return EFI_INVALID_PARAMETER
;
729 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
731 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, FALSE
,
732 FieldOffset
, FieldSize
, Buffer
);
739 Virtio10AllocateSharedPages (
740 IN VIRTIO_DEVICE_PROTOCOL
*This
,
742 IN OUT VOID
**HostAddress
748 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
750 Status
= Dev
->PciIo
->AllocateBuffer (
756 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
764 Virtio10FreeSharedPages (
765 IN VIRTIO_DEVICE_PROTOCOL
*This
,
772 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
774 Dev
->PciIo
->FreeBuffer (
784 Virtio10MapSharedBuffer (
785 IN VIRTIO_DEVICE_PROTOCOL
*This
,
786 IN VIRTIO_MAP_OPERATION Operation
,
787 IN VOID
*HostAddress
,
788 IN OUT UINTN
*NumberOfBytes
,
789 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
795 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation
;
797 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
800 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
803 case VirtioOperationBusMasterRead
:
804 PciIoOperation
= EfiPciIoOperationBusMasterRead
;
806 case VirtioOperationBusMasterWrite
:
807 PciIoOperation
= EfiPciIoOperationBusMasterWrite
;
809 case VirtioOperationBusMasterCommonBuffer
:
810 PciIoOperation
= EfiPciIoOperationBusMasterCommonBuffer
;
813 return EFI_INVALID_PARAMETER
;
816 Status
= Dev
->PciIo
->Map (
830 Virtio10UnmapSharedBuffer (
831 IN VIRTIO_DEVICE_PROTOCOL
*This
,
838 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
840 Status
= Dev
->PciIo
->Unmap (
848 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate
= {
849 VIRTIO_SPEC_REVISION (1, 0, 0),
850 0, // SubSystemDeviceId, filled in dynamically
851 Virtio10GetDeviceFeatures
,
852 Virtio10SetGuestFeatures
,
853 Virtio10SetQueueAddress
,
855 Virtio10SetQueueNotify
,
856 Virtio10SetQueueAlign
,
858 Virtio10GetQueueNumMax
,
860 Virtio10GetDeviceStatus
,
861 Virtio10SetDeviceStatus
,
864 Virtio10AllocateSharedPages
,
865 Virtio10FreeSharedPages
,
866 Virtio10MapSharedBuffer
,
867 Virtio10UnmapSharedBuffer
872 // EFI_DRIVER_BINDING_PROTOCOL member functions
878 Virtio10BindingSupported (
879 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
880 IN EFI_HANDLE DeviceHandle
,
881 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
885 EFI_PCI_IO_PROTOCOL
*PciIo
;
888 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
889 (VOID
**)&PciIo
, This
->DriverBindingHandle
,
890 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
891 if (EFI_ERROR (Status
)) {
895 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0,
896 sizeof Pci
/ sizeof (UINT32
), &Pci
);
897 if (EFI_ERROR (Status
)) {
901 Status
= EFI_UNSUPPORTED
;
903 // Recognize non-transitional modern devices. Also, we'll have to parse the
904 // PCI capability list, so make sure the CapabilityPtr field will be valid.
906 if (Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
&&
907 Pci
.Hdr
.DeviceId
>= 0x1040 &&
908 Pci
.Hdr
.DeviceId
<= 0x107F &&
909 Pci
.Hdr
.RevisionID
>= 0x01 &&
910 Pci
.Device
.SubsystemID
>= 0x40 &&
911 (Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0) {
913 // The virtio-vga device is special. It can be driven both as a VGA device
914 // with a linear framebuffer, and through its underlying, modern,
915 // virtio-gpu-pci device, which has no linear framebuffer itself. For
916 // compatibility with guest OSes that insist on inheriting a linear
917 // framebuffer from the firmware, we should leave virtio-vga to
918 // QemuVideoDxe, and support only virtio-gpu-pci here.
920 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
921 // former has device class PCI_CLASS_DISPLAY_VGA.
923 if (Pci
.Hdr
.DeviceId
!= 0x1050 || !IS_PCI_VGA (&Pci
)) {
924 Status
= EFI_SUCCESS
;
929 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
930 This
->DriverBindingHandle
, DeviceHandle
);
939 Virtio10BindingStart (
940 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
941 IN EFI_HANDLE DeviceHandle
,
942 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
945 VIRTIO_1_0_DEV
*Device
;
948 UINT64 SetAttributes
;
950 Device
= AllocateZeroPool (sizeof *Device
);
951 if (Device
== NULL
) {
952 return EFI_OUT_OF_RESOURCES
;
955 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
956 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
958 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
959 (VOID
**)&Device
->PciIo
, This
->DriverBindingHandle
,
960 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
961 if (EFI_ERROR (Status
)) {
965 Status
= Device
->PciIo
->Pci
.Read (Device
->PciIo
, EfiPciIoWidthUint32
, 0,
966 sizeof Pci
/ sizeof (UINT32
), &Pci
);
967 if (EFI_ERROR (Status
)) {
971 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
973 Status
= ParseCapabilities (Device
);
974 if (EFI_ERROR (Status
)) {
978 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
979 EfiPciIoAttributeOperationGet
, 0,
980 &Device
->OriginalPciAttributes
);
981 if (EFI_ERROR (Status
)) {
985 SetAttributes
= (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
|
986 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
987 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
988 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
989 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
990 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
991 EfiPciIoAttributeOperationEnable
, SetAttributes
,
993 if (EFI_ERROR (Status
)) {
997 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
998 &gVirtioDeviceProtocolGuid
, EFI_NATIVE_INTERFACE
,
1000 if (EFI_ERROR (Status
)) {
1001 goto RestorePciAttributes
;
1006 RestorePciAttributes
:
1007 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1008 Device
->OriginalPciAttributes
, NULL
);
1011 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1012 This
->DriverBindingHandle
, DeviceHandle
);
1024 Virtio10BindingStop (
1025 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1026 IN EFI_HANDLE DeviceHandle
,
1027 IN UINTN NumberOfChildren
,
1028 IN EFI_HANDLE
*ChildHandleBuffer
1032 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
1033 VIRTIO_1_0_DEV
*Device
;
1035 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
1036 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
1037 DeviceHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1038 if (EFI_ERROR (Status
)) {
1042 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
1044 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
1045 &gVirtioDeviceProtocolGuid
, &Device
->VirtIo
);
1046 if (EFI_ERROR (Status
)) {
1050 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
1051 Device
->OriginalPciAttributes
, NULL
);
1052 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1053 This
->DriverBindingHandle
, DeviceHandle
);
1060 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
1061 &Virtio10BindingSupported
,
1062 &Virtio10BindingStart
,
1063 &Virtio10BindingStop
,
1065 NULL
, // ImageHandle, to be overwritten
1066 NULL
// DriverBindingHandle, to be overwritten
1071 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1076 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1077 { "eng;en", L
"Virtio 1.0 PCI Driver" },
1082 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1087 Virtio10GetDriverName (
1088 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1090 OUT CHAR16
**DriverName
1093 return LookupUnicodeString2 (
1095 This
->SupportedLanguages
,
1098 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1105 Virtio10GetDeviceName (
1106 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1107 IN EFI_HANDLE DeviceHandle
,
1108 IN EFI_HANDLE ChildHandle
,
1110 OUT CHAR16
**ControllerName
1113 return EFI_UNSUPPORTED
;
1117 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1118 &Virtio10GetDriverName
,
1119 &Virtio10GetDeviceName
,
1124 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1125 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &Virtio10GetDriverName
,
1126 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &Virtio10GetDeviceName
,
1132 // Entry point of this driver
1137 Virtio10EntryPoint (
1138 IN EFI_HANDLE ImageHandle
,
1139 IN EFI_SYSTEM_TABLE
*SystemTable
1142 return EfiLibInstallDriverBindingComponentName2 (