3 This driver produces Block I/O Protocol instances for virtio-blk devices.
5 The implementation is basic:
7 - No attach/detach (ie. removable media).
9 - Although the non-blocking interfaces of EFI_BLOCK_IO2_PROTOCOL could be a
10 good match for multiple in-flight virtio-blk requests, we stick to
11 synchronous requests and EFI_BLOCK_IO_PROTOCOL for now.
13 Copyright (C) 2012, Red Hat, Inc.
15 This program and the accompanying materials are licensed and made available
16 under the terms and conditions of the BSD License which accompanies this
17 distribution. The full text of the license may be found at
18 http://opensource.org/licenses/bsd-license.php
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
21 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
25 #include <IndustryStandard/Pci.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/DebugLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/UefiLib.h>
32 #include "VirtioBlk.h"
36 Write a word into Region 0 of the device specified by PciIo.
38 Region 0 must be an iomem region. This is an internal function for the
39 VIRTIO_CFG_WRITE() macro below.
41 @param[in] PciIo Target PCI device.
43 @param[in] FieldOffset Destination offset.
45 @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.
47 @param[in] Value Little endian value to write, converted to UINT64.
48 The least significant FieldSize bytes will be used.
51 @return Status code returned by PciIo->Io.Write().
58 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
65 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
70 Width
= EfiPciIoWidthUint8
;
74 Width
= EfiPciIoWidthUint16
;
82 Width
= EfiPciIoWidthUint32
;
89 return PciIo
->Io
.Write (
102 Read a word from Region 0 of the device specified by PciIo.
104 Region 0 must be an iomem region. This is an internal function for the
105 VIRTIO_CFG_READ() macro below.
107 @param[in] PciIo Source PCI device.
109 @param[in] FieldOffset Source offset.
111 @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.
113 @param[in] BufferSize Number of bytes available in the target buffer. Must
116 @param[out] Buffer Target buffer.
119 @return Status code returned by PciIo->Io.Read().
126 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
127 IN UINTN FieldOffset
,
134 EFI_PCI_IO_PROTOCOL_WIDTH Width
;
136 ASSERT (FieldSize
== BufferSize
);
141 Width
= EfiPciIoWidthUint8
;
145 Width
= EfiPciIoWidthUint16
;
153 Width
= EfiPciIoWidthUint32
;
160 return PciIo
->Io
.Read (
173 Convenience macros to read and write region 0 IO space elements of the
174 virtio-blk PCI device, for configuration purposes.
176 The following macros make it possible to specify only the "core parameters"
177 for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
178 returns, the transaction will have been completed.
180 @param[in] Dev Pointer to the VBLK_DEV structure whose PCI IO space
181 we're accessing. Dev->PciIo must be valid.
183 @param[in] Field A field name from VBLK_HDR, identifying the virtio-blk
184 configuration item to access.
186 @param[in] Value (VIRTIO_CFG_WRITE() only.) The value to write to the
187 selected configuration item.
189 @param[out] Pointer (VIRTIO_CFG_READ() only.) The object to receive the
190 value read from the configuration item. Its type must be
191 one of UINT8, UINT16, UINT32, UINT64.
194 @return Status code returned by VirtioWrite() / VirtioRead().
198 #define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \
200 OFFSET_OF_VHDR (Field), \
201 SIZE_OF_VHDR (Field), \
205 #define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \
207 OFFSET_OF_VHDR (Field), \
208 SIZE_OF_VHDR (Field), \
215 // UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol
216 // Driver Writer's Guide for UEFI 2.3.1 v1.01,
217 // 24.2 Block I/O Protocol Implementations
222 IN EFI_BLOCK_IO_PROTOCOL
*This
,
223 IN BOOLEAN ExtendedVerification
227 // If we managed to initialize and install the driver, then the device is
228 // working correctly.
235 Verify correctness of the read/write (not flush) request submitted to the
236 EFI_BLOCK_IO_PROTOCOL instance.
238 This function provides most verification steps described in:
240 UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
242 - EFI_BLOCK_IO_PROTOCOL.ReadBlocks()
243 - EFI_BLOCK_IO_PROTOCOL.WriteBlocks()
245 Driver Writer's Guide for UEFI 2.3.1 v1.01,
246 - 24.2.2. ReadBlocks() and ReadBlocksEx() Implementation
247 - 24.2.3 WriteBlocks() and WriteBlockEx() Implementation
249 Request sizes are limited to 1 GB (checked). This is not a practical
250 limitation, just conformance to virtio-0.9.5, 2.3.2 Descriptor Table: "no
251 descriptor chain may be more than 2^32 bytes long in total".
253 Some Media characteristics are hardcoded in VirtioBlkInit() below (like
254 non-removable media, no restriction on buffer alignment etc); we rely on
255 those here without explicit mention.
257 @param[in] Media The EFI_BLOCK_IO_MEDIA characteristics for
258 this driver instance, extracted from the
259 underlying virtio-blk device at initialization
260 time. We validate the request against this set
264 @param[in] Lba Logical Block Address: number of logical
265 blocks to skip from the beginning of the
268 @param[in] PositiveBufferSize Size of buffer to transfer, in bytes. The
269 caller is responsible to ensure this parameter
272 @param[in] RequestIsWrite TRUE iff data transfer goes from guest to
276 @@return Validation result to be forwarded outwards by
277 ReadBlocks() and WriteBlocks, as required by
284 VerifyReadWriteRequest (
285 IN EFI_BLOCK_IO_MEDIA
*Media
,
287 IN UINTN PositiveBufferSize
,
288 IN BOOLEAN RequestIsWrite
293 ASSERT (PositiveBufferSize
> 0);
295 if (PositiveBufferSize
> SIZE_1GB
||
296 PositiveBufferSize
% Media
->BlockSize
> 0) {
297 return EFI_BAD_BUFFER_SIZE
;
299 BlockCount
= PositiveBufferSize
/ Media
->BlockSize
;
302 // Avoid unsigned wraparound on either side in the second comparison.
304 if (Lba
> Media
->LastBlock
|| BlockCount
- 1 > Media
->LastBlock
- Lba
) {
305 return EFI_INVALID_PARAMETER
;
308 if (RequestIsWrite
&& Media
->ReadOnly
) {
309 return EFI_WRITE_PROTECTED
;
318 Append a contiguous buffer for transmission / reception via the virtio ring.
320 This function implements the following sections from virtio-0.9.5:
321 - 2.4.1.1 Placing Buffers into the Descriptor Table
322 - 2.4.1.2 Updating the Available Ring
324 Free space is taken as granted, since this driver supports only synchronous
325 requests and host side status is processed in lock-step with request
326 submission. VirtioBlkInit() verifies the ring size in advance.
328 @param[in out] Ring The virtio ring to append the buffer to, as a
331 @param [in] BufferPhysAddr (Guest pseudo-physical) start address of the
332 transmit / receive buffer
334 @param [in] BufferSize Number of bytes to transmit or receive.
336 @param [in] Flags A bitmask of VRING_DESC_F_* flags. The caller
337 computes this mask dependent on further buffers
338 to append and transfer direction.
339 VRING_DESC_F_INDIRECT is unsupported. The
340 VRING_DESC.Next field is always set, but the
341 host only interprets it dependent on
344 @param [in] HeadIdx The index identifying the head buffer (first
345 buffer appended) belonging to this same
348 @param [in out] NextAvailIdx On input, the index identifying the next
349 descriptor available to carry the buffer. On
350 output, incremented by one, modulo 2^16.
359 IN UINTN BufferPhysAddr
,
360 IN UINT32 BufferSize
,
363 IN OUT UINT16
*NextAvailIdx
366 volatile VRING_DESC
*Desc
;
368 Desc
= &Ring
->Desc
[*NextAvailIdx
% Ring
->QueueSize
];
369 Desc
->Addr
= BufferPhysAddr
;
370 Desc
->Len
= BufferSize
;
372 Ring
->Avail
.Ring
[(*NextAvailIdx
)++ % Ring
->QueueSize
] =
373 HeadIdx
% Ring
->QueueSize
;
374 Desc
->Next
= *NextAvailIdx
% Ring
->QueueSize
;
380 Format a read / write / flush request as three consecutive virtio
381 descriptors, push them to the host, and poll for the response.
383 This is the main workhorse function. Two use cases are supported, read/write
384 and flush. The function may only be called after the request parameters have
386 - specific checks in ReadBlocks() / WriteBlocks() / FlushBlocks(), and
387 - VerifyReadWriteRequest() (for read/write only).
389 Parameters handled commonly:
391 @param[in] Dev The virtio-blk device the request is targeted
396 @param[in] Lba Must be zero.
398 @param[in] BufferSize Must be zero.
400 @param[in out] Buffer Ignored by the function.
402 @param[in] RequestIsWrite Must be TRUE.
406 @param[in] Lba Logical Block Address: number of logical blocks
407 to skip from the beginning of the device.
409 @param[in] BufferSize Size of buffer to transfer, in bytes. The caller
410 is responsible to ensure this parameter is
413 @param[in out] Buffer The guest side area to read data from the device
414 into, or write data to the device from.
416 @param[in] RequestIsWrite TRUE iff data transfer goes from guest to
419 Return values are common to both use cases, and are appropriate to be
420 forwarded by the EFI_BLOCK_IO_PROTOCOL functions (ReadBlocks(),
421 WriteBlocks(), FlushBlocks()).
424 @retval EFI_SUCCESS Transfer complete.
426 @retval EFI_DEVICE_ERROR Failed to notify host side via PCI write, or
427 unable to parse host response, or host response
428 is not VIRTIO_BLK_S_OK.
439 IN OUT
volatile VOID
*Buffer
,
440 IN BOOLEAN RequestIsWrite
444 volatile VIRTIO_BLK_REQ Request
;
445 volatile UINT8 HostStatus
;
446 UINT16 FirstAvailIdx
;
448 UINTN PollPeriodUsecs
;
450 BlockSize
= Dev
->BlockIoMedia
.BlockSize
;
453 // ensured by VirtioBlkInit()
455 ASSERT (BlockSize
> 0);
456 ASSERT (BlockSize
% 512 == 0);
459 // ensured by contract above, plus VerifyReadWriteRequest()
461 ASSERT (BufferSize
% BlockSize
== 0);
464 // Prepare virtio-blk request header, setting zero size for flush.
465 // IO Priority is homogeneously 0.
467 Request
.Type
= RequestIsWrite
?
468 (BufferSize
== 0 ? VIRTIO_BLK_T_FLUSH
: VIRTIO_BLK_T_OUT
) :
471 Request
.Sector
= Lba
* (BlockSize
/ 512);
474 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
475 // We're going to poll the answer, the host should not send an interrupt.
477 *Dev
->Ring
.Avail
.Flags
= (UINT16
) VRING_AVAIL_F_NO_INTERRUPT
;
480 // preset a host status for ourselves that we do not accept as success
482 HostStatus
= VIRTIO_BLK_S_IOERR
;
485 // ensured by VirtioBlkInit() -- this predicate, in combination with the
486 // lock-step progress, ensures we don't have to track free descriptors.
488 ASSERT (Dev
->Ring
.QueueSize
>= 3);
491 // Implement virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
493 FirstAvailIdx
= *Dev
->Ring
.Avail
.Idx
;
494 NextAvailIdx
= FirstAvailIdx
;
497 // virtio-blk header in first desc
499 AppendDesc (&Dev
->Ring
, (UINTN
) &Request
, sizeof Request
, VRING_DESC_F_NEXT
,
500 FirstAvailIdx
, &NextAvailIdx
);
503 // data buffer for read/write in second desc
505 if (BufferSize
> 0) {
507 // From virtio-0.9.5, 2.3.2 Descriptor Table:
508 // "no descriptor chain may be more than 2^32 bytes long in total".
510 // The predicate is ensured by the call contract above (for flush), or
511 // VerifyReadWriteRequest() (for read/write). It also implies that
512 // converting BufferSize to UINT32 will not truncate it.
514 ASSERT (BufferSize
<= SIZE_1GB
);
517 // VRING_DESC_F_WRITE is interpreted from the host's point of view.
519 AppendDesc (&Dev
->Ring
, (UINTN
) Buffer
, (UINT32
) BufferSize
,
520 VRING_DESC_F_NEXT
| (RequestIsWrite
? 0 : VRING_DESC_F_WRITE
),
521 FirstAvailIdx
, &NextAvailIdx
);
525 // host status in last (second or third) desc
527 AppendDesc (&Dev
->Ring
, (UINTN
) &HostStatus
, sizeof HostStatus
,
528 VRING_DESC_F_WRITE
, FirstAvailIdx
, &NextAvailIdx
);
531 // virtio-0.9.5, 2.4.1.3 Updating the Index Field
534 *Dev
->Ring
.Avail
.Idx
= NextAvailIdx
;
537 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
538 // OK. virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
541 if (EFI_ERROR (VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrQueueNotify
, 0))) {
542 return EFI_DEVICE_ERROR
;
546 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
547 // Wait until the host processes and acknowledges our 3-part descriptor
548 // chain. The condition we use for polling is greatly simplified and relies
549 // on synchronous, the lock-step progress.
551 // Keep slowing down until we reach a poll period of slightly above 1 ms.
555 while (*Dev
->Ring
.Used
.Idx
!= NextAvailIdx
) {
556 gBS
->Stall (PollPeriodUsecs
); // calls AcpiTimerLib::MicroSecondDelay
558 if (PollPeriodUsecs
< 1024) {
559 PollPeriodUsecs
*= 2;
564 if (HostStatus
== VIRTIO_BLK_S_OK
) {
568 return EFI_DEVICE_ERROR
;
574 ReadBlocks() operation for virtio-blk.
577 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
578 Protocol, EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
579 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.2. ReadBlocks() and
580 ReadBlocksEx() Implementation.
582 Parameter checks and conformant return values are implemented in
583 VerifyReadWriteRequest() and SynchronousRequest().
585 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,
592 VirtioBlkReadBlocks (
593 IN EFI_BLOCK_IO_PROTOCOL
*This
,
603 if (BufferSize
== 0) {
607 Dev
= VIRTIO_BLK_FROM_BLOCK_IO (This
);
608 Status
= VerifyReadWriteRequest (
612 FALSE
// RequestIsWrite
614 if (EFI_ERROR (Status
)) {
618 return SynchronousRequest (
623 FALSE
// RequestIsWrite
629 WriteBlocks() operation for virtio-blk.
632 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
633 Protocol, EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
634 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.3 WriteBlocks() and
635 WriteBlockEx() Implementation.
637 Parameter checks and conformant return values are implemented in
638 VerifyReadWriteRequest() and SynchronousRequest().
640 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,
647 VirtioBlkWriteBlocks (
648 IN EFI_BLOCK_IO_PROTOCOL
*This
,
658 if (BufferSize
== 0) {
662 Dev
= VIRTIO_BLK_FROM_BLOCK_IO (This
);
663 Status
= VerifyReadWriteRequest (
667 TRUE
// RequestIsWrite
669 if (EFI_ERROR (Status
)) {
673 return SynchronousRequest (
678 TRUE
// RequestIsWrite
685 FlushBlocks() operation for virtio-blk.
688 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
689 Protocol, EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
690 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.4 FlushBlocks() and
691 FlushBlocksEx() Implementation.
693 If the underlying virtio-blk device doesn't support flushing (ie.
694 write-caching), then this function should not be called by higher layers,
695 according to EFI_BLOCK_IO_MEDIA characteristics set in VirtioBlkInit().
696 Should they do nonetheless, we do nothing, successfully.
702 VirtioBlkFlushBlocks (
703 IN EFI_BLOCK_IO_PROTOCOL
*This
708 Dev
= VIRTIO_BLK_FROM_BLOCK_IO (This
);
709 return Dev
->BlockIoMedia
.WriteCaching
?
715 TRUE
// RequestIsWrite
723 Device probe function for this driver.
725 The DXE core calls this function for any given device in order to see if the
726 driver can drive the device.
728 Specs relevant in the general sense:
730 - UEFI Spec 2.3.1 + Errata C:
731 - 6.3 Protocol Handler Services -- for accessing the underlying device
732 - 10.1 EFI Driver Binding Protocol -- for exporting ourselves
734 - Driver Writer's Guide for UEFI 2.3.1 v1.01:
735 - 5.1.3.4 OpenProtocol() and CloseProtocol() -- for accessing the
737 - 9 Driver Binding Protocol -- for exporting ourselves
739 Specs relevant in the specific sense:
740 - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol
741 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design
742 Guidelines, 18.3 PCI drivers.
744 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
745 incorporating this driver (independently of
748 @param[in] DeviceHandle The device to probe.
750 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.
753 @retval EFI_SUCCESS The driver supports the device being probed.
755 @retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support
758 @return Error codes from the OpenProtocol() boot service or
765 VirtioBlkDriverBindingSupported (
766 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
767 IN EFI_HANDLE DeviceHandle
,
768 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
772 EFI_PCI_IO_PROTOCOL
*PciIo
;
776 // Attempt to open the device with the PciIo set of interfaces. On success,
777 // the protocol is "instantiated" for the PCI device. Covers duplicate open
778 // attempts (EFI_ALREADY_STARTED).
780 Status
= gBS
->OpenProtocol (
781 DeviceHandle
, // candidate device
782 &gEfiPciIoProtocolGuid
, // for generic PCI access
783 (VOID
**)&PciIo
, // handle to instantiate
784 This
->DriverBindingHandle
, // requestor driver identity
785 DeviceHandle
, // ControllerHandle, according to
786 // the UEFI Driver Model
787 EFI_OPEN_PROTOCOL_BY_DRIVER
// get exclusive PciIo access to
788 // the device; to be released
790 if (EFI_ERROR (Status
)) {
795 // Read entire PCI configuration header for more extensive check ahead.
797 Status
= PciIo
->Pci
.Read (
798 PciIo
, // (protocol, device)
800 EfiPciIoWidthUint32
, // access width & copy
803 sizeof Pci
/ sizeof (UINT32
), // Count
804 &Pci
// target buffer
807 if (Status
== EFI_SUCCESS
) {
809 // virtio-0.9.5, 2.1 PCI Discovery
811 Status
= (Pci
.Hdr
.VendorId
== 0x1AF4 &&
812 Pci
.Hdr
.DeviceId
>= 0x1000 && Pci
.Hdr
.DeviceId
<= 0x103F &&
813 Pci
.Hdr
.RevisionID
== 0x00 &&
814 Pci
.Device
.SubsystemID
== 0x02) ? EFI_SUCCESS
: EFI_UNSUPPORTED
;
818 // We needed PCI IO access only transitorily, to see whether we support the
821 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
822 This
->DriverBindingHandle
, DeviceHandle
);
829 Configure a virtio ring.
831 This function sets up internal storage (the guest-host communication area)
832 and lays out several "navigation" (ie. no-ownership) pointers to parts of
835 Relevant sections from the virtio-0.9.5 spec:
837 - 2.3 Virtqueue Configuration.
839 @param[in] The number of descriptors to allocate for the
840 virtio ring, as requested by the host.
842 @param[out] Ring The virtio ring to set up.
844 @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous
845 pages for the requested QueueSize. Fields of
846 Ring have indeterminate value.
848 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base
849 (and nothing else) is responsible for
863 volatile UINT8
*RingPagesPtr
;
865 RingSize
= ALIGN_VALUE (
866 sizeof *Ring
->Desc
* QueueSize
+
867 sizeof *Ring
->Avail
.Flags
+
868 sizeof *Ring
->Avail
.Idx
+
869 sizeof *Ring
->Avail
.Ring
* QueueSize
+
870 sizeof *Ring
->Avail
.UsedEvent
,
873 RingSize
+= ALIGN_VALUE (
874 sizeof *Ring
->Used
.Flags
+
875 sizeof *Ring
->Used
.Idx
+
876 sizeof *Ring
->Used
.UsedElem
* QueueSize
+
877 sizeof *Ring
->Used
.AvailEvent
,
880 Ring
->NumPages
= EFI_SIZE_TO_PAGES (RingSize
);
881 Ring
->Base
= AllocatePages (Ring
->NumPages
);
882 if (Ring
->Base
== NULL
) {
883 return EFI_OUT_OF_RESOURCES
;
885 SetMem (Ring
->Base
, RingSize
, 0x00);
886 RingPagesPtr
= Ring
->Base
;
888 Ring
->Desc
= (volatile VOID
*) RingPagesPtr
;
889 RingPagesPtr
+= sizeof *Ring
->Desc
* QueueSize
;
891 Ring
->Avail
.Flags
= (volatile VOID
*) RingPagesPtr
;
892 RingPagesPtr
+= sizeof *Ring
->Avail
.Flags
;
894 Ring
->Avail
.Idx
= (volatile VOID
*) RingPagesPtr
;
895 RingPagesPtr
+= sizeof *Ring
->Avail
.Idx
;
897 Ring
->Avail
.Ring
= (volatile VOID
*) RingPagesPtr
;
898 RingPagesPtr
+= sizeof *Ring
->Avail
.Ring
* QueueSize
;
900 Ring
->Avail
.UsedEvent
= (volatile VOID
*) RingPagesPtr
;
901 RingPagesPtr
+= sizeof *Ring
->Avail
.UsedEvent
;
903 RingPagesPtr
= (volatile UINT8
*) Ring
->Base
+
904 ALIGN_VALUE (RingPagesPtr
- (volatile UINT8
*) Ring
->Base
,
907 Ring
->Used
.Flags
= (volatile VOID
*) RingPagesPtr
;
908 RingPagesPtr
+= sizeof *Ring
->Used
.Flags
;
910 Ring
->Used
.Idx
= (volatile VOID
*) RingPagesPtr
;
911 RingPagesPtr
+= sizeof *Ring
->Used
.Idx
;
913 Ring
->Used
.UsedElem
= (volatile VOID
*) RingPagesPtr
;
914 RingPagesPtr
+= sizeof *Ring
->Used
.UsedElem
* QueueSize
;
916 Ring
->Used
.AvailEvent
= (volatile VOID
*) RingPagesPtr
;
917 RingPagesPtr
+= sizeof *Ring
->Used
.AvailEvent
;
919 Ring
->QueueSize
= QueueSize
;
926 Tear down the internal resources of a configured virtio ring.
928 The caller is responsible to stop the host from using this ring before
929 invoking this function: the VSTAT_DRIVER_OK bit must be clear in
932 @param[out] Ring The virtio ring to clean up.
944 FreePages (Ring
->Base
, Ring
->NumPages
);
945 SetMem (Ring
, sizeof *Ring
, 0x00);
951 Set up all BlockIo and virtio-blk aspects of this driver for the specified
954 @param[in out] Dev The driver instance to configure. The caller is
955 responsible for Dev->PciIo's validity (ie. working IO
956 access to the underlying virtio-blk PCI device).
958 @retval EFI_SUCCESS Setup complete.
960 @retval EFI_UNSUPPORTED The driver is unable to work with the virtio ring or
961 virtio-blk attributes the host provides.
963 @return Error codes from VirtioRingInit() or
964 VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE().
984 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
986 NextDevStat
= 0; // step 1 -- reset device
987 Status
= VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrDeviceStatus
, NextDevStat
);
988 if (EFI_ERROR (Status
)) {
992 NextDevStat
|= VSTAT_ACK
; // step 2 -- acknowledge device presence
993 Status
= VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrDeviceStatus
, NextDevStat
);
994 if (EFI_ERROR (Status
)) {
998 NextDevStat
|= VSTAT_DRIVER
; // step 3 -- we know how to drive it
999 Status
= VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrDeviceStatus
, NextDevStat
);
1000 if (EFI_ERROR (Status
)) {
1005 // step 4a -- retrieve and validate features
1007 Status
= VIRTIO_CFG_READ (Dev
, Generic
.VhdrDeviceFeatureBits
, &Features
);
1008 if (EFI_ERROR (Status
)) {
1011 Status
= VIRTIO_CFG_READ (Dev
, VhdrCapacity
, &NumSectors
);
1012 if (EFI_ERROR (Status
)) {
1015 if (NumSectors
== 0) {
1016 Status
= EFI_UNSUPPORTED
;
1020 if (Features
& VIRTIO_BLK_F_BLK_SIZE
) {
1021 Status
= VIRTIO_CFG_READ (Dev
, VhdrBlkSize
, &BlockSize
);
1022 if (EFI_ERROR (Status
)) {
1025 if (BlockSize
== 0 || BlockSize
% 512 != 0 ||
1026 NumSectors
% (BlockSize
/ 512) != 0) {
1028 // We can only handle a logical block consisting of whole sectors,
1029 // and only a disk composed of whole logical blocks.
1031 Status
= EFI_UNSUPPORTED
;
1040 // step 4b -- allocate virtqueue
1042 Status
= VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrQueueSelect
, 0);
1043 if (EFI_ERROR (Status
)) {
1046 Status
= VIRTIO_CFG_READ (Dev
, Generic
.VhdrQueueSize
, &QueueSize
);
1047 if (EFI_ERROR (Status
)) {
1050 if (QueueSize
< 3) { // SynchronousRequest() uses at most three descriptors
1051 Status
= EFI_UNSUPPORTED
;
1055 Status
= VirtioRingInit (QueueSize
, &Dev
->Ring
);
1056 if (EFI_ERROR (Status
)) {
1061 // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything
1062 // fails from here on, we must release the ring resources.
1064 Status
= VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrQueueAddress
,
1065 (UINTN
) Dev
->Ring
.Base
>> EFI_PAGE_SHIFT
);
1066 if (EFI_ERROR (Status
)) {
1071 // step 5 -- Report understood features. There are no virtio-blk specific
1072 // features to negotiate in virtio-0.9.5, plus we do not want any of the
1073 // device-independent (known or unknown) VIRTIO_F_* capabilities (see
1076 Status
= VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrGuestFeatureBits
, 0);
1077 if (EFI_ERROR (Status
)) {
1082 // step 6 -- initialization complete
1084 NextDevStat
|= VSTAT_DRIVER_OK
;
1085 Status
= VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrDeviceStatus
, NextDevStat
);
1086 if (EFI_ERROR (Status
)) {
1091 // Populate the exported interface's attributes; see UEFI spec v2.3.1 +
1092 // Errata C, 12.8 EFI Block I/O Protocol. We stick to the lowest possible
1093 // EFI_BLOCK_IO_PROTOCOL revision for now.
1095 Dev
->BlockIo
.Revision
= 0;
1096 Dev
->BlockIo
.Media
= &Dev
->BlockIoMedia
;
1097 Dev
->BlockIo
.Reset
= &VirtioBlkReset
;
1098 Dev
->BlockIo
.ReadBlocks
= &VirtioBlkReadBlocks
;
1099 Dev
->BlockIo
.WriteBlocks
= &VirtioBlkWriteBlocks
;
1100 Dev
->BlockIo
.FlushBlocks
= &VirtioBlkFlushBlocks
;
1101 Dev
->BlockIoMedia
.MediaId
= 0;
1102 Dev
->BlockIoMedia
.RemovableMedia
= FALSE
;
1103 Dev
->BlockIoMedia
.MediaPresent
= TRUE
;
1104 Dev
->BlockIoMedia
.LogicalPartition
= FALSE
;
1105 Dev
->BlockIoMedia
.ReadOnly
= !!(Features
& VIRTIO_BLK_F_RO
);
1106 Dev
->BlockIoMedia
.WriteCaching
= !!(Features
& VIRTIO_BLK_F_FLUSH
);
1107 Dev
->BlockIoMedia
.BlockSize
= BlockSize
;
1108 Dev
->BlockIoMedia
.IoAlign
= 0;
1109 Dev
->BlockIoMedia
.LastBlock
= NumSectors
/ (BlockSize
/ 512) - 1;
1113 VirtioRingUninit (&Dev
->Ring
);
1117 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
1118 // Status. PCI IO access failure here should not mask the original error.
1120 NextDevStat
|= VSTAT_FAILED
;
1121 VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrDeviceStatus
, NextDevStat
);
1123 return Status
; // reached only via Failed above
1129 Uninitialize the internals of a virtio-blk device that has been successfully
1130 set up with VirtioBlkInit().
1132 @param[in out] Dev The device to clean up.
1140 IN OUT VBLK_DEV
*Dev
1144 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
1145 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
1146 // the old comms area.
1148 VIRTIO_CFG_WRITE (Dev
, Generic
.VhdrDeviceStatus
, 0);
1150 VirtioRingUninit (&Dev
->Ring
);
1152 SetMem (&Dev
->BlockIo
, sizeof Dev
->BlockIo
, 0x00);
1153 SetMem (&Dev
->BlockIoMedia
, sizeof Dev
->BlockIoMedia
, 0x00);
1159 After we've pronounced support for a specific device in
1160 DriverBindingSupported(), we start managing said device (passed in by the
1161 Driver Exeuction Environment) with the following service.
1163 See DriverBindingSupported() for specification references.
1165 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
1166 incorporating this driver (independently of
1169 @param[in] DeviceHandle The supported device to drive.
1171 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.
1174 @retval EFI_SUCCESS Driver instance has been created and
1175 initialized for the virtio-blk PCI device, it
1176 is now accessibla via EFI_BLOCK_IO_PROTOCOL.
1178 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1180 @return Error codes from the OpenProtocol() boot
1181 service, the PciIo protocol, VirtioBlkInit(),
1182 or the InstallProtocolInterface() boot service.
1188 VirtioBlkDriverBindingStart (
1189 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1190 IN EFI_HANDLE DeviceHandle
,
1191 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1197 Dev
= (VBLK_DEV
*) AllocateZeroPool (sizeof *Dev
);
1199 return EFI_OUT_OF_RESOURCES
;
1202 Status
= gBS
->OpenProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1203 (VOID
**)&Dev
->PciIo
, This
->DriverBindingHandle
,
1204 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
1205 if (EFI_ERROR (Status
)) {
1210 // We must retain and ultimately restore the original PCI attributes of the
1211 // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /
1212 // 18.3.2 Start() and Stop().
1214 // The third parameter ("Attributes", input) is ignored by the Get operation.
1215 // The fourth parameter ("Result", output) is ignored by the Enable and Set
1218 // For virtio-blk we only need IO space access.
1220 Status
= Dev
->PciIo
->Attributes (Dev
->PciIo
, EfiPciIoAttributeOperationGet
,
1221 0, &Dev
->OriginalPciAttributes
);
1222 if (EFI_ERROR (Status
)) {
1226 Status
= Dev
->PciIo
->Attributes (Dev
->PciIo
,
1227 EfiPciIoAttributeOperationEnable
,
1228 EFI_PCI_IO_ATTRIBUTE_IO
, NULL
);
1229 if (EFI_ERROR (Status
)) {
1234 // PCI IO access granted, configure virtio-blk device.
1236 Status
= VirtioBlkInit (Dev
);
1237 if (EFI_ERROR (Status
)) {
1238 goto RestorePciAttributes
;
1242 // Setup complete, attempt to export the driver instance's BlockIo interface.
1244 Dev
->Signature
= VBLK_SIG
;
1245 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
1246 &gEfiBlockIoProtocolGuid
, EFI_NATIVE_INTERFACE
,
1248 if (EFI_ERROR (Status
)) {
1255 VirtioBlkUninit (Dev
);
1257 RestorePciAttributes
:
1258 Dev
->PciIo
->Attributes (Dev
->PciIo
, EfiPciIoAttributeOperationSet
,
1259 Dev
->OriginalPciAttributes
, NULL
);
1262 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1263 This
->DriverBindingHandle
, DeviceHandle
);
1274 Stop driving a virtio-blk device and remove its BlockIo interface.
1276 This function replays the success path of DriverBindingStart() in reverse.
1277 The host side virtio-blk device is reset, so that the OS boot loader or the
1278 OS may reinitialize it.
1280 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
1281 incorporating this driver (independently of any
1284 @param[in] DeviceHandle Stop driving this device.
1286 @param[in] NumberOfChildren Since this function belongs to a device driver
1287 only (as opposed to a bus driver), the caller
1288 environment sets NumberOfChildren to zero, and
1291 @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).
1297 VirtioBlkDriverBindingStop (
1298 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1299 IN EFI_HANDLE DeviceHandle
,
1300 IN UINTN NumberOfChildren
,
1301 IN EFI_HANDLE
*ChildHandleBuffer
1307 Dev
= VIRTIO_BLK_FROM_BLOCK_IO (This
);
1310 // If DriverBindingStop() is called with the driver instance still in use,
1311 // or any of the parameters are invalid, we've caught a bug.
1313 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
1314 &gEfiBlockIoProtocolGuid
, &Dev
->BlockIo
);
1315 ASSERT (Status
== EFI_SUCCESS
);
1317 VirtioBlkUninit (Dev
);
1319 Dev
->PciIo
->Attributes (Dev
->PciIo
, EfiPciIoAttributeOperationSet
,
1320 Dev
->OriginalPciAttributes
, NULL
);
1322 gBS
->CloseProtocol (DeviceHandle
, &gEfiPciIoProtocolGuid
,
1323 This
->DriverBindingHandle
, DeviceHandle
);
1332 // The static object that groups the Supported() (ie. probe), Start() and
1333 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
1334 // C, 10.1 EFI Driver Binding Protocol.
1336 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding
= {
1337 &VirtioBlkDriverBindingSupported
,
1338 &VirtioBlkDriverBindingStart
,
1339 &VirtioBlkDriverBindingStop
,
1340 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1341 NULL
, // ImageHandle, to be overwritten by
1342 // EfiLibInstallDriverBindingComponentName2() in VirtioBlkEntryPoint()
1343 NULL
// DriverBindingHandle, ditto
1348 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
1349 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
1350 // in English, for display on standard console devices. This is recommended for
1351 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
1352 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
1354 // Device type names ("Virtio Block Device") are not formatted because the
1355 // driver supports only that device type. Therefore the driver name suffices
1356 // for unambiguous identification.
1359 STATIC GLOBAL_REMOVE_IF_UNREFERENCED
1360 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
1361 { "eng;en", L
"Virtio Block Driver" },
1365 STATIC GLOBAL_REMOVE_IF_UNREFERENCED
1366 EFI_COMPONENT_NAME_PROTOCOL gComponentName
;
1370 VirtioBlkGetDriverName (
1371 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1373 OUT CHAR16
**DriverName
1376 return LookupUnicodeString2 (
1378 This
->SupportedLanguages
,
1381 (BOOLEAN
)(This
== &gComponentName
) // Iso639Language
1387 VirtioBlkGetDeviceName (
1388 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
1389 IN EFI_HANDLE DeviceHandle
,
1390 IN EFI_HANDLE ChildHandle
,
1392 OUT CHAR16
**ControllerName
1395 return EFI_UNSUPPORTED
;
1398 STATIC GLOBAL_REMOVE_IF_UNREFERENCED
1399 EFI_COMPONENT_NAME_PROTOCOL gComponentName
= {
1400 &VirtioBlkGetDriverName
,
1401 &VirtioBlkGetDeviceName
,
1402 "eng" // SupportedLanguages, ISO 639-2 language codes
1405 STATIC GLOBAL_REMOVE_IF_UNREFERENCED
1406 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2
= {
1407 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &VirtioBlkGetDriverName
,
1408 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &VirtioBlkGetDeviceName
,
1409 "en" // SupportedLanguages, RFC 4646 language codes
1414 // Entry point of this driver.
1418 VirtioBlkEntryPoint (
1419 IN EFI_HANDLE ImageHandle
,
1420 IN EFI_SYSTEM_TABLE
*SystemTable
1423 return EfiLibInstallDriverBindingComponentName2 (