diff options
Diffstat (limited to 'OvmfPkg/VirtioBlkDxe/VirtioBlk.c')
-rw-r--r-- | OvmfPkg/VirtioBlkDxe/VirtioBlk.c | 214 |
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);
|