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
)) {
826 // Recognize non-transitional modern devices. Also, we'll have to parse the
827 // PCI capability list, so make sure the CapabilityPtr field will be valid.
829 if (Pci
.Hdr
.VendorId
== VIRTIO_VENDOR_ID
&&
830 Pci
.Hdr
.DeviceId
>= 0x1040 &&
831 Pci
.Hdr
.DeviceId
<= 0x107F &&
832 Pci
.Hdr
.RevisionID
>= 0x01 &&
833 Pci
.Device
.SubsystemID
>= 0x40 &&
834 (Pci
.Hdr
.Status
& EFI_PCI_STATUS_CAPABILITY
) != 0) {
835 Status
= EFI_SUCCESS
;
837 Status
= EFI_UNSUPPORTED
;
841 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
842 This
->DriverBindingHandle
, DeviceHandle
);
851 Virtio10BindingStart (
852 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
853 IN EFI_HANDLE DeviceHandle
,
854 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
857 VIRTIO_1_0_DEV
*Device
;
860 UINT64 SetAttributes
;
862 Device
= AllocateZeroPool (sizeof *Device
);
863 if (Device
== NULL
) {
864 return EFI_OUT_OF_RESOURCES
;
867 Device
->Signature
= VIRTIO_1_0_SIGNATURE
;
868 CopyMem (&Device
->VirtIo
, &mVirtIoTemplate
, sizeof mVirtIoTemplate
);
870 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
871 (VOID
**)&Device
->PciIo
, This
->DriverBindingHandle
,
872 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
873 if (EFI_ERROR (Status
)) {
877 Status
= Device
->PciIo
->Pci
.Read (Device
->PciIo
, EfiPciIoWidthUint32
, 0,
878 sizeof Pci
/ sizeof (UINT32
), &Pci
);
879 if (EFI_ERROR (Status
)) {
883 Device
->VirtIo
.SubSystemDeviceId
= Pci
.Hdr
.DeviceId
- 0x1040;
885 Status
= ParseCapabilities (Device
, Pci
.Device
.CapabilityPtr
);
886 if (EFI_ERROR (Status
)) {
890 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
891 EfiPciIoAttributeOperationGet
, 0,
892 &Device
->OriginalPciAttributes
);
893 if (EFI_ERROR (Status
)) {
898 UpdateAttributes (&Device
->CommonConfig
, &SetAttributes
);
899 UpdateAttributes (&Device
->NotifyConfig
, &SetAttributes
);
900 UpdateAttributes (&Device
->SpecificConfig
, &SetAttributes
);
901 Status
= Device
->PciIo
->Attributes (Device
->PciIo
,
902 EfiPciIoAttributeOperationEnable
, SetAttributes
,
904 if (EFI_ERROR (Status
)) {
908 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
909 &gVirtioDeviceProtocolGuid
, EFI_NATIVE_INTERFACE
,
911 if (EFI_ERROR (Status
)) {
912 goto RestorePciAttributes
;
917 RestorePciAttributes
:
918 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
919 Device
->OriginalPciAttributes
, NULL
);
922 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
923 This
->DriverBindingHandle
, DeviceHandle
);
935 Virtio10BindingStop (
936 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
937 IN EFI_HANDLE DeviceHandle
,
938 IN UINTN NumberOfChildren
,
939 IN EFI_HANDLE
*ChildHandleBuffer
943 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
944 VIRTIO_1_0_DEV
*Device
;
946 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
947 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
948 DeviceHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
949 if (EFI_ERROR (Status
)) {
953 Device
= VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo
);
955 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
956 &gVirtioDeviceProtocolGuid
, &Device
->VirtIo
);
957 if (EFI_ERROR (Status
)) {
961 Device
->PciIo
->Attributes (Device
->PciIo
, EfiPciIoAttributeOperationSet
,
962 Device
->OriginalPciAttributes
, NULL
);
963 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
964 This
->DriverBindingHandle
, DeviceHandle
);
971 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
972 &Virtio10BindingSupported
,
973 &Virtio10BindingStart
,
974 &Virtio10BindingStop
,
976 NULL
, // ImageHandle, to be overwritten
977 NULL
// DriverBindingHandle, to be overwritten
982 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
987 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
988 { "eng;en", L
"Virtio 1.0 PCI Driver" },
993 EFI_COMPONENT_NAME_PROTOCOL mComponentName
;
998 Virtio10GetDriverName (
999 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1001 OUT CHAR16
**DriverName
1004 return LookupUnicodeString2 (
1006 This
->SupportedLanguages
,
1009 (BOOLEAN
)(This
== &mComponentName
) // Iso639Language
1016 Virtio10GetDeviceName (
1017 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1018 IN EFI_HANDLE DeviceHandle
,
1019 IN EFI_HANDLE ChildHandle
,
1021 OUT CHAR16
**ControllerName
1024 return EFI_UNSUPPORTED
;
1028 EFI_COMPONENT_NAME_PROTOCOL mComponentName
= {
1029 &Virtio10GetDriverName
,
1030 &Virtio10GetDeviceName
,
1035 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
1036 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &Virtio10GetDriverName
,
1037 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &Virtio10GetDeviceName
,
1043 // Entry point of this driver
1048 Virtio10EntryPoint (
1049 IN EFI_HANDLE ImageHandle
,
1050 IN EFI_SYSTEM_TABLE
*SystemTable
1053 return EfiLibInstallDriverBindingComponentName2 (