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>
30 Transfer data between the caller and a register in a virtio-1.0 register
33 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents
36 @param[in] Config The "fat pointer" structure that identifies the
37 register block to access.
39 @param[in] Write TRUE if the register should be written, FALSE if
40 the register should be read.
42 @param[in] FieldOffset The offset of the register within the register
45 @param[in] FieldSize The size of the register within the register
46 block. Can be one of 1, 2, 4 and 8. Accesses to
47 8-byte registers are broken up into two 4-byte
50 @param[in,out] Buffer When Write is TRUE, the register is written with
51 data from Buffer. When Write is FALSE, the caller
52 receives the register value into Buffer.
54 @retval EFI_SUCCESS Register access successful.
56 @retval EFI_INVALID_PARAMETER The register block pointed-to by Config
57 doesn't exist; or FieldOffset and FieldSize
58 would overflow the register block; or
61 @return Error codes from
62 EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)
68 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
69 IN VIRTIO_1_0_CONFIG
*Config
,
77 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
78 EFI_PCI_IO_PROTOCOL_ACCESS
*BarType
;
79 EFI_PCI_IO_PROTOCOL_IO_MEM Access
;
81 if (!Config
->Exists
||
82 (FieldSize
> Config
->Length
) ||
83 (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
;
119 Config
->Offset
+ FieldOffset
,
126 Determine if a PCI BAR is IO or MMIO.
128 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
131 @param[in] BarIndex The number of the BAR whose type the caller is
134 @param[out] BarType On output, a VIRTIO_1_0_BAR_TYPE value that gives the
137 @retval EFI_SUCCESS The BAR type has been recognized and stored in
140 @retval EFI_UNSUPPORTED The BAR type couldn't be identified.
142 @return Error codes from
143 EFI_PCI_IO_PROTOCOL.GetBarAttributes().
148 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
150 OUT VIRTIO_1_0_BAR_TYPE
*BarType
156 Status
= PciIo
->GetBarAttributes (PciIo
, BarIndex
, NULL
, &Resources
);
157 if (EFI_ERROR (Status
)) {
161 Status
= EFI_UNSUPPORTED
;
163 if (*(UINT8
*)Resources
== ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
) {
164 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
166 Descriptor
= Resources
;
167 switch (Descriptor
->ResType
) {
168 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
169 *BarType
= Virtio10BarTypeMem
;
170 Status
= EFI_SUCCESS
;
173 case ACPI_ADDRESS_SPACE_TYPE_IO
:
174 *BarType
= Virtio10BarTypeIo
;
175 Status
= EFI_SUCCESS
;
183 FreePool (Resources
);
188 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
189 locations of the interesting virtio-1.0 register blocks.
191 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies
192 the device. On input, the caller is responsible
193 that the Device->PciIo member be live, and that
194 the CommonConfig, NotifyConfig,
195 NotifyOffsetMultiplier and SpecificConfig
196 members be zeroed. On output, said members
197 will have been updated from the PCI
200 @retval EFI_SUCCESS Traversal successful.
202 @return Error codes from PciCapPciIoLib, PciCapLib, and the
203 GetBarType() helper function.
208 IN OUT VIRTIO_1_0_DEV
*Device
212 PCI_CAP_DEV
*PciDevice
;
213 PCI_CAP_LIST
*CapList
;
214 UINT16 VendorInstance
;
217 Status
= PciCapPciIoDeviceInit (Device
->PciIo
, &PciDevice
);
218 if (EFI_ERROR (Status
)) {
222 Status
= PciCapListInit (PciDevice
, &CapList
);
223 if (EFI_ERROR (Status
)) {
224 goto UninitPciDevice
;
227 for (VendorInstance
= 0;
232 EFI_PCI_CAPABILITY_ID_VENDOR
,
240 VIRTIO_PCI_CAP VirtIoCap
;
241 VIRTIO_1_0_CONFIG
*ParsedConfig
;
244 // Big enough to accommodate a VIRTIO_PCI_CAP structure?
246 Status
= PciCapRead (
249 OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR
, Length
),
253 if (EFI_ERROR (Status
)) {
257 if (CapLen
< sizeof VirtIoCap
) {
259 // Too small, move to next.
265 // Read interesting part of capability.
267 Status
= PciCapRead (PciDevice
, VendorCap
, 0, &VirtIoCap
, sizeof VirtIoCap
);
268 if (EFI_ERROR (Status
)) {
272 switch (VirtIoCap
.ConfigType
) {
273 case VIRTIO_PCI_CAP_COMMON_CFG
:
274 ParsedConfig
= &Device
->CommonConfig
;
276 case VIRTIO_PCI_CAP_NOTIFY_CFG
:
277 ParsedConfig
= &Device
->NotifyConfig
;
279 case VIRTIO_PCI_CAP_DEVICE_CFG
:
280 ParsedConfig
= &Device
->SpecificConfig
;
284 // Capability is not interesting.
290 // Save the location of the register block into ParsedConfig.
292 Status
= GetBarType (Device
->PciIo
, VirtIoCap
.Bar
, &ParsedConfig
->BarType
);
293 if (EFI_ERROR (Status
)) {
297 ParsedConfig
->Bar
= VirtIoCap
.Bar
;
298 ParsedConfig
->Offset
= VirtIoCap
.Offset
;
299 ParsedConfig
->Length
= VirtIoCap
.Length
;
301 if (VirtIoCap
.ConfigType
== VIRTIO_PCI_CAP_NOTIFY_CFG
) {
303 // This capability has an additional field called NotifyOffsetMultiplier;
306 if (CapLen
< sizeof VirtIoCap
+ sizeof Device
->NotifyOffsetMultiplier
) {
308 // Too small, move to next.
313 Status
= PciCapRead (
317 &Device
->NotifyOffsetMultiplier
,
318 sizeof Device
->NotifyOffsetMultiplier
320 if (EFI_ERROR (Status
)) {
326 // Capability parsed successfully.
328 ParsedConfig
->Exists
= TRUE
;
331 ASSERT_EFI_ERROR (Status
);
334 PciCapListUninit (CapList
);
337 PciCapPciIoDeviceUninit (PciDevice
);
343 Accumulate the BAR type of a virtio-1.0 register block into a UINT64
344 attribute map, such that the latter is suitable for enabling IO / MMIO
345 decoding with EFI_PCI_IO_PROTOCOL.Attributes().
347 @param[in] Config The "fat pointer" structure that identifies the
348 register block. It is allowed for the register
351 @param[in,out] Attributes On output, if the register block exists,
352 EFI_PCI_IO_ATTRIBUTE_MEMORY or
353 EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,
354 according to the register block's BAR type.
359 IN VIRTIO_1_0_CONFIG
*Config
,
360 IN OUT UINT64
*Attributes
363 if (Config
->Exists
) {
364 *Attributes
|= (Config
->BarType
== Virtio10BarTypeMem
) ?
365 EFI_PCI_IO_ATTRIBUTE_MEMORY
:
366 EFI_PCI_IO_ATTRIBUTE_IO
;
371 // VIRTIO_DEVICE_PROTOCOL member functions
377 Virtio10GetDeviceFeatures (
378 IN VIRTIO_DEVICE_PROTOCOL
*This
,
379 OUT UINT64
*DeviceFeatures
384 UINT32 Features32
[2];
386 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
388 for (Selector
= 0; Selector
< 2; ++Selector
) {
392 // Select the low or high half of the features.
394 Status
= Virtio10Transfer (
398 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeatureSelect
),
402 if (EFI_ERROR (Status
)) {
409 Status
= Virtio10Transfer (
413 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeature
),
414 sizeof Features32
[Selector
],
415 &Features32
[Selector
]
417 if (EFI_ERROR (Status
)) {
422 *DeviceFeatures
= LShiftU64 (Features32
[1], 32) | Features32
[0];
429 Virtio10SetGuestFeatures (
430 IN VIRTIO_DEVICE_PROTOCOL
*This
,
436 UINT32 Features32
[2];
438 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
440 Features32
[0] = (UINT32
)Features
;
441 Features32
[1] = (UINT32
)RShiftU64 (Features
, 32);
443 for (Selector
= 0; Selector
< 2; ++Selector
) {
447 // Select the low or high half of the features.
449 Status
= Virtio10Transfer (
453 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeatureSelect
),
457 if (EFI_ERROR (Status
)) {
464 Status
= Virtio10Transfer (
468 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeature
),
469 sizeof Features32
[Selector
],
470 &Features32
[Selector
]
472 if (EFI_ERROR (Status
)) {
483 Virtio10SetQueueAddress (
484 IN VIRTIO_DEVICE_PROTOCOL
*This
,
486 IN UINT64 RingBaseShift
494 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
496 Address
= (UINTN
)Ring
->Desc
;
497 Address
+= RingBaseShift
;
498 Status
= Virtio10Transfer (
502 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueDesc
),
506 if (EFI_ERROR (Status
)) {
510 Address
= (UINTN
)Ring
->Avail
.Flags
;
511 Address
+= RingBaseShift
;
512 Status
= Virtio10Transfer (
516 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueAvail
),
520 if (EFI_ERROR (Status
)) {
524 Address
= (UINTN
)Ring
->Used
.Flags
;
525 Address
+= RingBaseShift
;
526 Status
= Virtio10Transfer (
530 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueUsed
),
534 if (EFI_ERROR (Status
)) {
539 Status
= Virtio10Transfer (
543 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueEnable
),
553 Virtio10SetQueueSel (
554 IN VIRTIO_DEVICE_PROTOCOL
*This
,
561 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
563 Status
= Virtio10Transfer (
567 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
577 Virtio10SetQueueNotify (
578 IN VIRTIO_DEVICE_PROTOCOL
*This
,
584 UINT16 SavedQueueSelect
;
587 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
590 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
591 // to stash & restore the current queue selector around it.
593 // So, start with saving the current queue selector.
595 Status
= Virtio10Transfer (
599 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
600 sizeof SavedQueueSelect
,
603 if (EFI_ERROR (Status
)) {
608 // Select the requested queue.
610 Status
= Virtio10Transfer (
614 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
618 if (EFI_ERROR (Status
)) {
623 // Read the QueueNotifyOff field.
625 Status
= Virtio10Transfer (
629 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueNotifyOff
),
633 if (EFI_ERROR (Status
)) {
638 // Re-select the original queue.
640 Status
= Virtio10Transfer (
644 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
645 sizeof SavedQueueSelect
,
648 if (EFI_ERROR (Status
)) {
653 // We can now kick the queue.
655 Status
= Virtio10Transfer (
659 NotifyOffset
* Dev
->NotifyOffsetMultiplier
,
669 Virtio10SetQueueAlign (
670 IN VIRTIO_DEVICE_PROTOCOL
*This
,
674 return (Alignment
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
680 Virtio10SetPageSize (
681 IN VIRTIO_DEVICE_PROTOCOL
*This
,
685 return (PageSize
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
691 Virtio10GetQueueNumMax (
692 IN VIRTIO_DEVICE_PROTOCOL
*This
,
693 OUT UINT16
*QueueNumMax
699 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
701 Status
= Virtio10Transfer (
705 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSize
),
715 Virtio10SetQueueNum (
716 IN VIRTIO_DEVICE_PROTOCOL
*This
,
724 // This member function is required for VirtIo MMIO, and a no-op in
725 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
726 // member to reduce memory consumption, but none of our drivers do. So
727 // just check that they set the size that is already in effect.
729 Status
= Virtio10GetQueueNumMax (This
, &CurrentSize
);
730 if (EFI_ERROR (Status
)) {
734 return (CurrentSize
== QueueSize
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
740 Virtio10GetDeviceStatus (
741 IN VIRTIO_DEVICE_PROTOCOL
*This
,
742 OUT UINT8
*DeviceStatus
748 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
750 Status
= Virtio10Transfer (
754 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
755 sizeof *DeviceStatus
,
764 Virtio10SetDeviceStatus (
765 IN VIRTIO_DEVICE_PROTOCOL
*This
,
766 IN UINT8 DeviceStatus
772 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
774 Status
= Virtio10Transfer (
778 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
788 Virtio10WriteDevice (
789 IN VIRTIO_DEVICE_PROTOCOL
*This
,
790 IN UINTN FieldOffset
,
798 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
800 Status
= Virtio10Transfer (
802 &Dev
->SpecificConfig
,
815 IN VIRTIO_DEVICE_PROTOCOL
*This
,
816 IN UINTN FieldOffset
,
825 if (FieldSize
!= BufferSize
) {
826 return EFI_INVALID_PARAMETER
;
829 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
831 Status
= Virtio10Transfer (
833 &Dev
->SpecificConfig
,
845 Virtio10AllocateSharedPages (
846 IN VIRTIO_DEVICE_PROTOCOL
*This
,
848 IN OUT VOID
**HostAddress
854 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
856 Status
= Dev
->PciIo
->AllocateBuffer (
862 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
870 Virtio10FreeSharedPages (
871 IN VIRTIO_DEVICE_PROTOCOL
*This
,
878 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
880 Dev
->PciIo
->FreeBuffer (
890 Virtio10MapSharedBuffer (
891 IN VIRTIO_DEVICE_PROTOCOL
*This
,
892 IN VIRTIO_MAP_OPERATION Operation
,
893 IN VOID
*HostAddress
,
894 IN OUT UINTN
*NumberOfBytes
,
895 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
901 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation
;
903 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
906 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
909 case VirtioOperationBusMasterRead
:
910 PciIoOperation
= EfiPciIoOperationBusMasterRead
;
912 case VirtioOperationBusMasterWrite
:
913 PciIoOperation
= EfiPciIoOperationBusMasterWrite
;
915 case VirtioOperationBusMasterCommonBuffer
:
916 PciIoOperation
= EfiPciIoOperationBusMasterCommonBuffer
;
919 return EFI_INVALID_PARAMETER
;
922 Status
= Dev
->PciIo
->Map (
936 Virtio10UnmapSharedBuffer (
937 IN VIRTIO_DEVICE_PROTOCOL
*This
,
944 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
946 Status
= Dev
->PciIo
->Unmap (
954 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate
= {
955 VIRTIO_SPEC_REVISION (1, 0, 0),
956 0, // SubSystemDeviceId, filled in dynamically
957 Virtio10GetDeviceFeatures
,
958 Virtio10SetGuestFeatures
,
959 Virtio10SetQueueAddress
,
961 Virtio10SetQueueNotify
,
962 Virtio10SetQueueAlign
,
964 Virtio10GetQueueNumMax
,
966 Virtio10GetDeviceStatus
,
967 Virtio10SetDeviceStatus
,
970 Virtio10AllocateSharedPages
,
971 Virtio10FreeSharedPages
,
972 Virtio10MapSharedBuffer
,
973 Virtio10UnmapSharedBuffer
977 // EFI_DRIVER_BINDING_PROTOCOL member functions
983 Virtio10BindingSupported (
984 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
985 IN EFI_HANDLE DeviceHandle
,
986 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
990 EFI_PCI_IO_PROTOCOL
*PciIo
;
993 Status
= gBS
->OpenProtocol (
995 &gEfiPciIoProtocolGuid
,
997 This
->DriverBindingHandle
,
999 EFI_OPEN_PROTOCOL_BY_DRIVER
1001 if (EFI_ERROR (Status
)) {
1005 Status
= PciIo
->Pci
.Read (
1007 EfiPciIoWidthUint32
,
1009 sizeof Pci
/ sizeof (UINT32
),
1012 if (EFI_ERROR (Status
)) {
1016 Status
= EFI_UNSUPPORTED
;
1018 // Recognize non-transitional modern devices. Also, we'll have to parse the
1019 // PCI capability list, so make sure the CapabilityPtr field will be valid.
1021 if ((Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
) &&
1022 (Pci
.Hdr
.DeviceId
>= 0x1040) &&
1023 (Pci
.Hdr
.DeviceId
<= 0x107F) &&
1024 (Pci
.Hdr
.RevisionID
>= 0x01) &&
1025 (Pci
.Device
.SubsystemID
>= 0x40) &&
1026 ((Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0))
1029 // The virtio-vga device is special. It can be driven both as a VGA device
1030 // with a linear framebuffer, and through its underlying, modern,
1031 // virtio-gpu-pci device, which has no linear framebuffer itself. For
1032 // compatibility with guest OSes that insist on inheriting a linear
1033 // framebuffer from the firmware, we should leave virtio-vga to
1034 // QemuVideoDxe, and support only virtio-gpu-pci here.
1036 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
1037 // former has device class PCI_CLASS_DISPLAY_VGA.
1039 if ((Pci
.Hdr
.DeviceId
!= 0x1050) || !IS_PCI_VGA (&Pci
)) {
1040 Status
= EFI_SUCCESS
;
1045 gBS
->CloseProtocol (
1047 &gEfiPciIoProtocolGuid
,
1048 This
->DriverBindingHandle
,
1058 Virtio10BindingStart (
1059 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1060 IN EFI_HANDLE DeviceHandle
,
1061 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1064 VIRTIO_1_0_DEV
*Device
;
1067 UINT64 SetAttributes
;
1069 Device
= AllocateZeroPool (sizeof *Device
);
1070 if (Device
== NULL
) {
1071 return EFI_OUT_OF_RESOURCES
;
1074 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
1075 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
1077 Status
= gBS
->OpenProtocol (
1079 &gEfiPciIoProtocolGuid
,
1080 (VOID
**)&Device
->PciIo
,
1081 This
->DriverBindingHandle
,
1083 EFI_OPEN_PROTOCOL_BY_DRIVER
1085 if (EFI_ERROR (Status
)) {
1089 Status
= Device
->PciIo
->Pci
.Read (
1091 EfiPciIoWidthUint32
,
1093 sizeof Pci
/ sizeof (UINT32
),
1096 if (EFI_ERROR (Status
)) {
1100 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
1102 Status
= ParseCapabilities (Device
);
1103 if (EFI_ERROR (Status
)) {
1107 Status
= Device
->PciIo
->Attributes (
1109 EfiPciIoAttributeOperationGet
,
1111 &Device
->OriginalPciAttributes
1113 if (EFI_ERROR (Status
)) {
1117 SetAttributes
= (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
|
1118 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
);
1119 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
1120 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
1121 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
1122 Status
= Device
->PciIo
->Attributes (
1124 EfiPciIoAttributeOperationEnable
,
1128 if (EFI_ERROR (Status
)) {
1132 Status
= gBS
->InstallProtocolInterface (
1134 &gVirtioDeviceProtocolGuid
,
1135 EFI_NATIVE_INTERFACE
,
1138 if (EFI_ERROR (Status
)) {
1139 goto RestorePciAttributes
;
1144 RestorePciAttributes
:
1145 Device
->PciIo
->Attributes (
1147 EfiPciIoAttributeOperationSet
,
1148 Device
->OriginalPciAttributes
,
1153 gBS
->CloseProtocol (
1155 &gEfiPciIoProtocolGuid
,
1156 This
->DriverBindingHandle
,
1169 Virtio10BindingStop (
1170 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1171 IN EFI_HANDLE DeviceHandle
,
1172 IN UINTN NumberOfChildren
,
1173 IN EFI_HANDLE
*ChildHandleBuffer
1177 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
1178 VIRTIO_1_0_DEV
*Device
;
1180 Status
= gBS
->OpenProtocol (
1182 &gVirtioDeviceProtocolGuid
,
1184 This
->DriverBindingHandle
,
1186 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1188 if (EFI_ERROR (Status
)) {
1192 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
1194 Status
= gBS
->UninstallProtocolInterface (
1196 &gVirtioDeviceProtocolGuid
,
1199 if (EFI_ERROR (Status
)) {
1203 Device
->PciIo
->Attributes (
1205 EfiPciIoAttributeOperationSet
,
1206 Device
->OriginalPciAttributes
,
1209 gBS
->CloseProtocol (
1211 &gEfiPciIoProtocolGuid
,
1212 This
->DriverBindingHandle
,
1220 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
1221 &Virtio10BindingSupported
,
1222 &Virtio10BindingStart
,
1223 &Virtio10BindingStop
,
1225 NULL
, // ImageHandle, to be overwritten
1226 NULL
// DriverBindingHandle, to be overwritten
1230 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1235 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1236 { "eng;en", L
"Virtio 1.0 PCI Driver" },
1241 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1246 Virtio10GetDriverName (
1247 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1249 OUT CHAR16
**DriverName
1252 return LookupUnicodeString2 (
1254 This
->SupportedLanguages
,
1257 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1264 Virtio10GetDeviceName (
1265 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1266 IN EFI_HANDLE DeviceHandle
,
1267 IN EFI_HANDLE ChildHandle
,
1269 OUT CHAR16
**ControllerName
1272 return EFI_UNSUPPORTED
;
1276 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1277 &Virtio10GetDriverName
,
1278 &Virtio10GetDeviceName
,
1283 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1284 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
)&Virtio10GetDriverName
,
1285 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
)&Virtio10GetDeviceName
,
1290 // Entry point of this driver
1295 Virtio10EntryPoint (
1296 IN EFI_HANDLE ImageHandle
,
1297 IN EFI_SYSTEM_TABLE
*SystemTable
1300 return EfiLibInstallDriverBindingComponentName2 (