2 A non-transitional driver for VirtIo 1.0 PCI devices.
4 Copyright (C) 2016, Red Hat, Inc.
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <IndustryStandard/Pci.h>
16 #include <IndustryStandard/Virtio.h>
17 #include <Protocol/PciIo.h>
18 #include <Protocol/VirtioDevice.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiLib.h>
33 Transfer data between the caller and a register in a virtio-1.0 register
36 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents
39 @param[in] Config The "fat pointer" structure that identifies the
40 register block to access.
42 @param[in] Write TRUE if the register should be written, FALSE if
43 the register should be read.
45 @param[in] FieldOffset The offset of the register within the register
48 @param[in] FieldSize The size of the register within the register
49 block. Can be one of 1, 2, 4 and 8. Accesses to
50 8-byte registers are broken up into two 4-byte
53 @param[in,out] Buffer When Write is TRUE, the register is written with
54 data from Buffer. When Write is FALSE, the caller
55 receives the register value into Buffer.
57 @retval EFI_SUCCESS Register access successful.
59 @retval EFI_INVALID_PARAMETER The register block pointed-to by Config
60 doesn't exist; or FieldOffset and FieldSize
61 would overflow the register block; or
64 @return Error codes from
65 EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)
71 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
72 IN VIRTIO_1_0_CONFIG
*Config
,
80 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
81 EFI_PCI_IO_PROTOCOL_ACCESS
*BarType
;
82 EFI_PCI_IO_PROTOCOL_IO_MEM Access
;
84 if (!Config
->Exists
||
85 FieldSize
> Config
->Length
||
86 FieldOffset
> Config
->Length
- FieldSize
) {
87 return EFI_INVALID_PARAMETER
;
93 Width
= EfiPciIoWidthUint8
;
97 Width
= EfiPciIoWidthUint16
;
107 Width
= EfiPciIoWidthUint32
;
111 return EFI_INVALID_PARAMETER
;
114 BarType
= (Config
->BarType
== Virtio10BarTypeMem
) ? &PciIo
->Mem
: &PciIo
->Io
;
115 Access
= Write
? BarType
->Write
: BarType
->Read
;
117 return Access (PciIo
, Width
, Config
->Bar
, Config
->Offset
+ FieldOffset
,
123 Determine if a PCI BAR is IO or MMIO.
125 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
128 @param[in] BarIndex The number of the BAR whose type the caller is
131 @param[out] BarType On output, a VIRTIO_1_0_BAR_TYPE value that gives the
134 @retval EFI_SUCCESS The BAR type has been recognized and stored in
137 @retval EFI_UNSUPPORTED The BAR type couldn't be identified.
139 @return Error codes from
140 EFI_PCI_IO_PROTOCOL.GetBarAttributes().
145 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
147 OUT VIRTIO_1_0_BAR_TYPE
*BarType
153 Status
= PciIo
->GetBarAttributes (PciIo
, BarIndex
, NULL
, &Resources
);
154 if (EFI_ERROR (Status
)) {
158 Status
= EFI_UNSUPPORTED
;
160 if (*(UINT8
*)Resources
== ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
) {
161 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
163 Descriptor
= Resources
;
164 switch (Descriptor
->ResType
) {
165 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
166 *BarType
= Virtio10BarTypeMem
;
167 Status
= EFI_SUCCESS
;
170 case ACPI_ADDRESS_SPACE_TYPE_IO
:
171 *BarType
= Virtio10BarTypeIo
;
172 Status
= EFI_SUCCESS
;
180 FreePool (Resources
);
186 Read a slice from PCI config space at the given offset, then advance the
189 @param [in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
192 @param [in,out] Offset On input, the offset in PCI config space to start
193 reading from. On output, the offset of the first byte
194 that was not read. On error, Offset is not modified.
196 @param [in] Size The number of bytes to read.
198 @param [out] Buffer On output, the bytes read from PCI config space are
199 stored in this object.
201 @retval EFI_SUCCESS Size bytes have been transferred from PCI config space
202 (from Offset) to Buffer, and Offset has been incremented
205 @return Error codes from PciIo->Pci.Read().
210 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
211 IN OUT UINT32
*Offset
,
218 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint8
, *Offset
, Size
, Buffer
);
219 if (EFI_ERROR (Status
)) {
222 *Offset
+= (UINT32
)Size
;
228 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
229 locations of the interesting virtio-1.0 register blocks.
231 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies
232 the device. On input, the caller is responsible
233 that the Device->PciIo member be live, and that
234 the CommonConfig, NotifyConfig,
235 NotifyOffsetMultiplier and SpecificConfig
236 members be zeroed. On output, said members
237 will have been updated from the PCI
240 @param[in] CapabilityPtr The offset of the first capability in PCI
241 config space, taken from the standard PCI
244 @retval EFI_SUCCESS Traversal successful.
246 @return Error codes from the ReadConfigSpace() and GetBarType()
252 IN OUT VIRTIO_1_0_DEV
*Device
,
253 IN UINT8 CapabilityPtr
257 VIRTIO_PCI_CAP_LINK CapLink
;
259 for (Offset
= CapabilityPtr
& 0xFC;
261 Offset
= CapLink
.CapNext
& 0xFC
265 VIRTIO_PCI_CAP VirtIoCap
;
266 VIRTIO_1_0_CONFIG
*ParsedConfig
;
269 // Read capability identifier and link to next capability.
271 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
, sizeof CapLink
,
273 if (EFI_ERROR (Status
)) {
276 if (CapLink
.CapId
!= 0x09) {
278 // Not a vendor-specific capability, move to the next one.
284 // Big enough to accommodate a VIRTIO_PCI_CAP structure?
286 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
, sizeof CapLen
, &CapLen
);
287 if (EFI_ERROR (Status
)) {
290 if (CapLen
< sizeof CapLink
+ sizeof CapLen
+ sizeof VirtIoCap
) {
292 // Too small, move to next.
298 // Read interesting part of capability.
300 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
, sizeof VirtIoCap
,
302 if (EFI_ERROR (Status
)) {
305 switch (VirtIoCap
.ConfigType
) {
306 case VIRTIO_PCI_CAP_COMMON_CFG
:
307 ParsedConfig
= &Device
->CommonConfig
;
309 case VIRTIO_PCI_CAP_NOTIFY_CFG
:
310 ParsedConfig
= &Device
->NotifyConfig
;
312 case VIRTIO_PCI_CAP_DEVICE_CFG
:
313 ParsedConfig
= &Device
->SpecificConfig
;
317 // Capability is not interesting.
323 // Save the location of the register block into ParsedConfig.
325 Status
= GetBarType (Device
->PciIo
, VirtIoCap
.Bar
, &ParsedConfig
->BarType
);
326 if (EFI_ERROR (Status
)) {
329 ParsedConfig
->Bar
= VirtIoCap
.Bar
;
330 ParsedConfig
->Offset
= VirtIoCap
.Offset
;
331 ParsedConfig
->Length
= VirtIoCap
.Length
;
333 if (VirtIoCap
.ConfigType
== VIRTIO_PCI_CAP_NOTIFY_CFG
) {
335 // This capability has an additional field called NotifyOffsetMultiplier;
338 if (CapLen
< sizeof CapLink
+ sizeof CapLen
+ sizeof VirtIoCap
+
339 sizeof Device
->NotifyOffsetMultiplier
) {
341 // Too small, move to next.
346 Status
= ReadConfigSpace (Device
->PciIo
, &Offset
,
347 sizeof Device
->NotifyOffsetMultiplier
,
348 &Device
->NotifyOffsetMultiplier
);
349 if (EFI_ERROR (Status
)) {
355 // Capability parsed successfully.
357 ParsedConfig
->Exists
= TRUE
;
365 Accumulate the BAR type of a virtio-1.0 register block into a UINT64
366 attribute map, such that the latter is suitable for enabling IO / MMIO
367 decoding with EFI_PCI_IO_PROTOCOL.Attributes().
369 @param[in] Config The "fat pointer" structure that identifies the
370 register block. It is allowed for the register
373 @param[in,out] Attributes On output, if the register block exists,
374 EFI_PCI_IO_ATTRIBUTE_MEMORY or
375 EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,
376 according to the register block's BAR type.
381 IN VIRTIO_1_0_CONFIG
*Config
,
382 IN OUT UINT64
*Attributes
385 if (Config
->Exists
) {
386 *Attributes
|= (Config
->BarType
== Virtio10BarTypeMem
) ?
387 EFI_PCI_IO_ATTRIBUTE_MEMORY
:
388 EFI_PCI_IO_ATTRIBUTE_IO
;
394 // VIRTIO_DEVICE_PROTOCOL member functions
400 Virtio10GetDeviceFeatures (
401 IN VIRTIO_DEVICE_PROTOCOL
*This
,
402 OUT UINT64
*DeviceFeatures
407 UINT32 Features32
[2];
409 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
411 for (Selector
= 0; Selector
< 2; ++Selector
) {
415 // Select the low or high half of the features.
417 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
418 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeatureSelect
),
419 sizeof Selector
, &Selector
);
420 if (EFI_ERROR (Status
)) {
427 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
428 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceFeature
),
429 sizeof Features32
[Selector
], &Features32
[Selector
]);
430 if (EFI_ERROR (Status
)) {
435 *DeviceFeatures
= LShiftU64 (Features32
[1], 32) | Features32
[0];
443 Virtio10SetGuestFeatures (
444 IN VIRTIO_DEVICE_PROTOCOL
*This
,
450 UINT32 Features32
[2];
452 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
454 Features32
[0] = (UINT32
)Features
;
455 Features32
[1] = (UINT32
)RShiftU64 (Features
, 32);
457 for (Selector
= 0; Selector
< 2; ++Selector
) {
461 // Select the low or high half of the features.
463 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
464 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeatureSelect
),
465 sizeof Selector
, &Selector
);
466 if (EFI_ERROR (Status
)) {
473 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
474 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DriverFeature
),
475 sizeof Features32
[Selector
], &Features32
[Selector
]);
476 if (EFI_ERROR (Status
)) {
488 Virtio10SetQueueAddress (
489 IN VIRTIO_DEVICE_PROTOCOL
*This
,
498 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
500 Address
= (UINTN
)Ring
->Desc
;
501 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
502 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueDesc
),
503 sizeof Address
, &Address
);
504 if (EFI_ERROR (Status
)) {
508 Address
= (UINTN
)Ring
->Avail
.Flags
;
509 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
510 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueAvail
),
511 sizeof Address
, &Address
);
512 if (EFI_ERROR (Status
)) {
516 Address
= (UINTN
)Ring
->Used
.Flags
;
517 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
518 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueUsed
),
519 sizeof Address
, &Address
);
520 if (EFI_ERROR (Status
)) {
525 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
526 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueEnable
),
527 sizeof Enable
, &Enable
);
535 Virtio10SetQueueSel (
536 IN VIRTIO_DEVICE_PROTOCOL
*This
,
543 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
545 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
546 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
547 sizeof Index
, &Index
);
555 Virtio10SetQueueNotify (
556 IN VIRTIO_DEVICE_PROTOCOL
*This
,
562 UINT16 SavedQueueSelect
;
565 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
568 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
569 // to stash & restore the current queue selector around it.
571 // So, start with saving the current queue selector.
573 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
574 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
575 sizeof SavedQueueSelect
, &SavedQueueSelect
);
576 if (EFI_ERROR (Status
)) {
581 // Select the requested queue.
583 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
584 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
585 sizeof Index
, &Index
);
586 if (EFI_ERROR (Status
)) {
591 // Read the QueueNotifyOff field.
593 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
594 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueNotifyOff
),
595 sizeof NotifyOffset
, &NotifyOffset
);
596 if (EFI_ERROR (Status
)) {
601 // Re-select the original queue.
603 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
604 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSelect
),
605 sizeof SavedQueueSelect
, &SavedQueueSelect
);
606 if (EFI_ERROR (Status
)) {
611 // We can now kick the queue.
613 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->NotifyConfig
, TRUE
,
614 NotifyOffset
* Dev
->NotifyOffsetMultiplier
,
615 sizeof Index
, &Index
);
623 Virtio10SetQueueAlign (
624 IN VIRTIO_DEVICE_PROTOCOL
*This
,
628 return (Alignment
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
635 Virtio10SetPageSize (
636 IN VIRTIO_DEVICE_PROTOCOL
*This
,
640 return (PageSize
== EFI_PAGE_SIZE
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
647 Virtio10GetQueueNumMax (
648 IN VIRTIO_DEVICE_PROTOCOL
*This
,
649 OUT UINT16
*QueueNumMax
655 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
657 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
658 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, QueueSize
),
659 sizeof *QueueNumMax
, QueueNumMax
);
667 Virtio10SetQueueNum (
668 IN VIRTIO_DEVICE_PROTOCOL
*This
,
676 // This member function is required for VirtIo MMIO, and a no-op in
677 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
678 // member to reduce memory consumption, but none of our drivers do. So
679 // just check that they set the size that is already in effect.
681 Status
= Virtio10GetQueueNumMax (This
, &CurrentSize
);
682 if (EFI_ERROR (Status
)) {
685 return (CurrentSize
== QueueSize
) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
692 Virtio10GetDeviceStatus (
693 IN VIRTIO_DEVICE_PROTOCOL
*This
,
694 OUT UINT8
*DeviceStatus
700 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
702 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, FALSE
,
703 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
704 sizeof *DeviceStatus
, DeviceStatus
);
712 Virtio10SetDeviceStatus (
713 IN VIRTIO_DEVICE_PROTOCOL
*This
,
714 IN UINT8 DeviceStatus
720 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
722 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->CommonConfig
, TRUE
,
723 OFFSET_OF (VIRTIO_PCI_COMMON_CFG
, DeviceStatus
),
724 sizeof DeviceStatus
, &DeviceStatus
);
732 Virtio10WriteDevice (
733 IN VIRTIO_DEVICE_PROTOCOL
*This
,
734 IN UINTN FieldOffset
,
742 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
744 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, TRUE
,
745 FieldOffset
, FieldSize
, &Value
);
754 IN VIRTIO_DEVICE_PROTOCOL
*This
,
755 IN UINTN FieldOffset
,
764 if (FieldSize
!= BufferSize
) {
765 return EFI_INVALID_PARAMETER
;
768 Dev
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (This
);
770 Status
= Virtio10Transfer (Dev
->PciIo
, &Dev
->SpecificConfig
, FALSE
,
771 FieldOffset
, FieldSize
, Buffer
);
776 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate
= {
777 VIRTIO_SPEC_REVISION (1, 0, 0),
778 0, // SubSystemDeviceId, filled in dynamically
779 Virtio10GetDeviceFeatures
,
780 Virtio10SetGuestFeatures
,
781 Virtio10SetQueueAddress
,
783 Virtio10SetQueueNotify
,
784 Virtio10SetQueueAlign
,
786 Virtio10GetQueueNumMax
,
788 Virtio10GetDeviceStatus
,
789 Virtio10SetDeviceStatus
,
796 // EFI_DRIVER_BINDING_PROTOCOL member functions
802 Virtio10BindingSupported (
803 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
804 IN EFI_HANDLE DeviceHandle
,
805 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
809 EFI_PCI_IO_PROTOCOL
*PciIo
;
812 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
813 (VOID
**)&PciIo
, This
->DriverBindingHandle
,
814 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
815 if (EFI_ERROR (Status
)) {
819 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0,
820 sizeof Pci
/ sizeof (UINT32
), &Pci
);
821 if (EFI_ERROR (Status
)) {
825 Status
= EFI_UNSUPPORTED
;
827 // Recognize non-transitional modern devices. Also, we'll have to parse the
828 // PCI capability list, so make sure the CapabilityPtr field will be valid.
830 if (Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
&&
831 Pci
.Hdr
.DeviceId
>= 0x1040 &&
832 Pci
.Hdr
.DeviceId
<= 0x107F &&
833 Pci
.Hdr
.RevisionID
>= 0x01 &&
834 Pci
.Device
.SubsystemID
>= 0x40 &&
835 (Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0) {
837 // The virtio-vga device is special. It can be driven both as a VGA device
838 // with a linear framebuffer, and through its underlying, modern,
839 // virtio-gpu-pci device, which has no linear framebuffer itself. For
840 // compatibility with guest OSes that insist on inheriting a linear
841 // framebuffer from the firmware, we should leave virtio-vga to
842 // QemuVideoDxe, and support only virtio-gpu-pci here.
844 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
845 // former has device class PCI_CLASS_DISPLAY_VGA.
847 if (Pci
.Hdr
.DeviceId
!= 0x1050 || !IS_PCI_VGA (&Pci
)) {
848 Status
= EFI_SUCCESS
;
853 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
854 This
->DriverBindingHandle
, DeviceHandle
);
863 Virtio10BindingStart (
864 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
865 IN EFI_HANDLE DeviceHandle
,
866 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
869 VIRTIO_1_0_DEV
*Device
;
872 UINT64 SetAttributes
;
874 Device
= AllocateZeroPool (sizeof *Device
);
875 if (Device
== NULL
) {
876 return EFI_OUT_OF_RESOURCES
;
879 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
880 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
882 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
883 (VOID
**)&Device
->PciIo
, This
->DriverBindingHandle
,
884 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
885 if (EFI_ERROR (Status
)) {
889 Status
= Device
->PciIo
->Pci
.Read (Device
->PciIo
, EfiPciIoWidthUint32
, 0,
890 sizeof Pci
/ sizeof (UINT32
), &Pci
);
891 if (EFI_ERROR (Status
)) {
895 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
897 Status
= ParseCapabilities (Device
, Pci
.Device
.CapabilityPtr
);
898 if (EFI_ERROR (Status
)) {
902 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
903 EfiPciIoAttributeOperationGet
, 0,
904 &Device
->OriginalPciAttributes
);
905 if (EFI_ERROR (Status
)) {
910 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
911 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
912 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
913 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
914 EfiPciIoAttributeOperationEnable
, SetAttributes
,
916 if (EFI_ERROR (Status
)) {
920 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
921 &gVirtioDeviceProtocolGuid
, EFI_NATIVE_INTERFACE
,
923 if (EFI_ERROR (Status
)) {
924 goto RestorePciAttributes
;
929 RestorePciAttributes
:
930 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
931 Device
->OriginalPciAttributes
, NULL
);
934 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
935 This
->DriverBindingHandle
, DeviceHandle
);
947 Virtio10BindingStop (
948 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
949 IN EFI_HANDLE DeviceHandle
,
950 IN UINTN NumberOfChildren
,
951 IN EFI_HANDLE
*ChildHandleBuffer
955 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
956 VIRTIO_1_0_DEV
*Device
;
958 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
959 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
960 DeviceHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
961 if (EFI_ERROR (Status
)) {
965 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
967 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
968 &gVirtioDeviceProtocolGuid
, &Device
->VirtIo
);
969 if (EFI_ERROR (Status
)) {
973 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
974 Device
->OriginalPciAttributes
, NULL
);
975 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
976 This
->DriverBindingHandle
, DeviceHandle
);
983 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
984 &Virtio10BindingSupported
,
985 &Virtio10BindingStart
,
986 &Virtio10BindingStop
,
988 NULL
, // ImageHandle, to be overwritten
989 NULL
// DriverBindingHandle, to be overwritten
994 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
999 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1000 { "eng;en", L
"Virtio 1.0 PCI Driver" },
1005 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
1010 Virtio10GetDriverName (
1011 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1013 OUT CHAR16
**DriverName
1016 return LookupUnicodeString2 (
1018 This
->SupportedLanguages
,
1021 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1028 Virtio10GetDeviceName (
1029 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1030 IN EFI_HANDLE DeviceHandle
,
1031 IN EFI_HANDLE ChildHandle
,
1033 OUT CHAR16
**ControllerName
1036 return EFI_UNSUPPORTED
;
1040 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1041 &Virtio10GetDriverName
,
1042 &Virtio10GetDeviceName
,
1047 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1048 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &Virtio10GetDriverName
,
1049 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &Virtio10GetDeviceName
,
1055 // Entry point of this driver
1060 Virtio10EntryPoint (
1061 IN EFI_HANDLE ImageHandle
,
1062 IN EFI_SYSTEM_TABLE
*SystemTable
1065 return EfiLibInstallDriverBindingComponentName2 (