summaryrefslogtreecommitdiff
path: root/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/VirtioBlkDxe/VirtioBlk.c')
-rw-r--r--OvmfPkg/VirtioBlkDxe/VirtioBlk.c214
1 files changed, 131 insertions, 83 deletions
diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
index 08edf23fc..35fc88e35 100644
--- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
+++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c
@@ -36,14 +36,14 @@
/**
Convenience macros to read and write region 0 IO space elements of the
- virtio-blk device, for configuration purposes.
+ virtio-blk device, for configuration purposes.
The following macros make it possible to specify only the "core parameters"
for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
returns, the transaction will have been completed.
- @param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space
- we're accessing. Dev->VirtIo must be valid.
+ @param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space
+ we're accessing. Dev->VirtIo must be valid.
@param[in] Field A field name from VBLK_HDR, identifying the virtio-blk
configuration item to access.
@@ -56,23 +56,24 @@
one of UINT8, UINT16, UINT32, UINT64.
- @return Status code returned by Virtio->WriteDevice() / Virtio->ReadDevice().
+ @return Status code returned by Virtio->WriteDevice() /
+ Virtio->ReadDevice().
**/
-#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \
- (Dev)->VirtIo, \
- OFFSET_OF_VBLK (Field), \
- SIZE_OF_VBLK (Field), \
- (Value) \
+#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \
+ (Dev)->VirtIo, \
+ OFFSET_OF_VBLK (Field), \
+ SIZE_OF_VBLK (Field), \
+ (Value) \
))
-#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \
- (Dev)->VirtIo, \
- OFFSET_OF_VBLK (Field), \
- SIZE_OF_VBLK (Field), \
- sizeof *(Pointer), \
- (Pointer) \
+#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \
+ (Dev)->VirtIo, \
+ OFFSET_OF_VBLK (Field), \
+ SIZE_OF_VBLK (Field), \
+ sizeof *(Pointer), \
+ (Pointer) \
))
@@ -228,7 +229,7 @@ VerifyReadWriteRequest (
@retval EFI_SUCCESS Transfer complete.
- @retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or
+ @retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or
unable to parse host response, or host response
is not VIRTIO_BLK_S_OK.
@@ -323,7 +324,7 @@ SynchronousRequest (
//
// virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
//
- if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&
+ if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&
HostStatus == VIRTIO_BLK_S_OK) {
return EFI_SUCCESS;
}
@@ -510,11 +511,11 @@ VirtioBlkFlushBlocks (
@retval EFI_SUCCESS The driver supports the device being probed.
- @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support
+ @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support
the device.
@return Error codes from the OpenProtocol() boot service or
- the VirtIo protocol.
+ the VirtIo protocol.
**/
@@ -527,36 +528,36 @@ VirtioBlkDriverBindingSupported (
)
{
EFI_STATUS Status;
- VIRTIO_DEVICE_PROTOCOL *VirtIo;
+ VIRTIO_DEVICE_PROTOCOL *VirtIo;
//
- // Attempt to open the device with the VirtIo set of interfaces. On success,
- // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
- // attempts (EFI_ALREADY_STARTED).
+ // Attempt to open the device with the VirtIo set of interfaces. On success,
+ // the protocol is "instantiated" for the VirtIo device. Covers duplicate
+ // open attempts (EFI_ALREADY_STARTED).
//
Status = gBS->OpenProtocol (
DeviceHandle, // candidate device
- &gVirtioDeviceProtocolGuid, // for generic VirtIo access
- (VOID **)&VirtIo, // handle to instantiate
+ &gVirtioDeviceProtocolGuid, // for generic VirtIo access
+ (VOID **)&VirtIo, // handle to instantiate
This->DriverBindingHandle, // requestor driver identity
DeviceHandle, // ControllerHandle, according to
// the UEFI Driver Model
- EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
+ EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
// the device; to be released
);
if (EFI_ERROR (Status)) {
return Status;
}
- if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
- Status = EFI_UNSUPPORTED;
+ if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
+ Status = EFI_UNSUPPORTED;
}
//
- // We needed VirtIo access only transitorily, to see whether we support the
+ // We needed VirtIo access only transitorily, to see whether we support the
// device or not.
//
- gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
return Status;
}
@@ -568,8 +569,8 @@ VirtioBlkDriverBindingSupported (
device.
@param[in out] Dev The driver instance to configure. The caller is
- responsible for Dev->VirtIo's validity (ie. working IO
- access to the underlying virtio-blk device).
+ responsible for Dev->VirtIo's validity (ie. working IO
+ access to the underlying virtio-blk device).
@retval EFI_SUCCESS Setup complete.
@@ -594,46 +595,53 @@ VirtioBlkInit (
UINT32 Features;
UINT64 NumSectors;
UINT32 BlockSize;
+ UINT8 PhysicalBlockExp;
+ UINT8 AlignmentOffset;
+ UINT32 OptIoSize;
UINT16 QueueSize;
+ PhysicalBlockExp = 0;
+ AlignmentOffset = 0;
+ OptIoSize = 0;
+
//
// Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
//
NextDevStat = 0; // step 1 -- reset device
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) {
goto Failed;
}
NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // Set Page Size - MMIO VirtIo Specific
+ //
+ Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
if (EFI_ERROR (Status)) {
goto Failed;
}
//
- // Set Page Size - MMIO VirtIo Specific
- //
- Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
- if (EFI_ERROR (Status)) {
- goto ReleaseQueue;
- }
-
- //
// step 4a -- retrieve and validate features
//
- Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
+ Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
if (EFI_ERROR (Status)) {
goto Failed;
}
-
- Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
+
+ Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -643,7 +651,7 @@ VirtioBlkInit (
}
if (Features & VIRTIO_BLK_F_BLK_SIZE) {
- Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
+ Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -661,14 +669,36 @@ VirtioBlkInit (
BlockSize = 512;
}
+ if (Features & VIRTIO_BLK_F_TOPOLOGY) {
+ Status = VIRTIO_CFG_READ (Dev, Topology.PhysicalBlockExp,
+ &PhysicalBlockExp);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+ if (PhysicalBlockExp >= 32) {
+ Status = EFI_UNSUPPORTED;
+ goto Failed;
+ }
+
+ Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+ }
+
//
// step 4b -- allocate virtqueue
//
- Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
+ Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
if (EFI_ERROR (Status)) {
goto Failed;
}
- Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
+ Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
if (EFI_ERROR (Status)) {
goto Failed;
}
@@ -683,31 +713,36 @@ VirtioBlkInit (
}
//
- // Additional steps for MMIO: align the queue appropriately, and set the size
- Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
- Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
- if (EFI_ERROR (Status)) {
- goto ReleaseQueue;
- }
-
- //
- // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything
- // fails from here on, we must release the ring resources.
+ // Additional steps for MMIO: align the queue appropriately, and set the
+ // size. If anything fails from here on, we must release the ring resources.
//
- Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
- (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);
+ Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
-
+ Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
+ if (EFI_ERROR (Status)) {
+ goto ReleaseQueue;
+ }
+
+ //
+ // step 4c -- Report GPFN (guest-physical frame number) of queue.
+ //
+ Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
+ (UINT32) ((UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT));
+ if (EFI_ERROR (Status)) {
+ goto ReleaseQueue;
+ }
+
+
//
// step 5 -- Report understood features. There are no virtio-blk specific
// features to negotiate in virtio-0.9.5, plus we do not want any of the
// device-independent (known or unknown) VIRTIO_F_* capabilities (see
// Appendix B).
//
- Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0);
+ Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
@@ -716,15 +751,14 @@ VirtioBlkInit (
// step 6 -- initialization complete
//
NextDevStat |= VSTAT_DRIVER_OK;
- Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
if (EFI_ERROR (Status)) {
goto ReleaseQueue;
}
//
- // Populate the exported interface's attributes; see UEFI spec v2.3.1 +
- // Errata C, 12.8 EFI Block I/O Protocol. We stick to the lowest possible
- // EFI_BLOCK_IO_PROTOCOL revision for now.
+ // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI
+ // Block I/O Protocol.
//
Dev->BlockIo.Revision = 0;
Dev->BlockIo.Media = &Dev->BlockIoMedia;
@@ -742,6 +776,24 @@ VirtioBlkInit (
Dev->BlockIoMedia.IoAlign = 0;
Dev->BlockIoMedia.LastBlock = DivU64x32 (NumSectors,
BlockSize / 512) - 1;
+
+ DEBUG ((DEBUG_INFO, "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",
+ __FUNCTION__, Dev->BlockIoMedia.BlockSize,
+ Dev->BlockIoMedia.LastBlock + 1));
+
+ if (Features & VIRTIO_BLK_F_TOPOLOGY) {
+ Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
+
+ Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;
+ Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;
+ Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;
+
+ DEBUG ((DEBUG_INFO, "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",
+ __FUNCTION__, Dev->BlockIoMedia.LowestAlignedLba,
+ Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock));
+ DEBUG ((DEBUG_INFO, "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",
+ __FUNCTION__, Dev->BlockIoMedia.OptimalTransferLengthGranularity));
+ }
return EFI_SUCCESS;
ReleaseQueue:
@@ -750,10 +802,10 @@ ReleaseQueue:
Failed:
//
// Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
- // Status. VirtIo access failure here should not mask the original error.
+ // Status. VirtIo access failure here should not mask the original error.
//
NextDevStat |= VSTAT_FAILED;
- Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
return Status; // reached only via Failed above
}
@@ -780,7 +832,7 @@ VirtioBlkUninit (
// VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
// the old comms area.
//
- Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
VirtioRingUninit (&Dev->Ring);
@@ -807,13 +859,13 @@ VirtioBlkUninit (
@retval EFI_SUCCESS Driver instance has been created and
- initialized for the virtio-blk device, it
+ initialized for the virtio-blk device, it
is now accessibla via EFI_BLOCK_IO_PROTOCOL.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@return Error codes from the OpenProtocol() boot
- service, the VirtIo protocol, VirtioBlkInit(),
+ service, the VirtIo protocol, VirtioBlkInit(),
or the InstallProtocolInterface() boot service.
**/
@@ -834,23 +886,19 @@ VirtioBlkDriverBindingStart (
return EFI_OUT_OF_RESOURCES;
}
- Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
- (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
+ Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
+ (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) {
goto FreeVirtioBlk;
}
- if (Dev->VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
- return EFI_UNSUPPORTED;
- }
-
//
- // VirtIo access granted, configure virtio-blk device.
+ // VirtIo access granted, configure virtio-blk device.
//
Status = VirtioBlkInit (Dev);
if (EFI_ERROR (Status)) {
- goto CloseVirtIo;
+ goto CloseVirtIo;
}
//
@@ -869,8 +917,8 @@ VirtioBlkDriverBindingStart (
UninitDev:
VirtioBlkUninit (Dev);
-CloseVirtIo:
- gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
+CloseVirtIo:
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
FreeVirtioBlk:
@@ -941,7 +989,7 @@ VirtioBlkDriverBindingStop (
VirtioBlkUninit (Dev);
- gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
+ gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
This->DriverBindingHandle, DeviceHandle);
FreePool (Dev);