60#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \
62 OFFSET_OF_VBLK (Field), \
63 SIZE_OF_VBLK (Field), \
67#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \
69 OFFSET_OF_VBLK (Field), \
70 SIZE_OF_VBLK (Field), \
84 IN BOOLEAN ExtendedVerification
149 IN BOOLEAN RequestIsWrite
154 ASSERT (PositiveBufferSize > 0);
156 if ((PositiveBufferSize > SIZE_1GB) ||
157 (PositiveBufferSize % Media->BlockSize > 0))
159 return EFI_BAD_BUFFER_SIZE;
162 BlockCount = PositiveBufferSize / Media->BlockSize;
167 if ((Lba > Media->LastBlock) || (BlockCount - 1 > Media->LastBlock - Lba)) {
168 return EFI_INVALID_PARAMETER;
171 if (RequestIsWrite && Media->ReadOnly) {
172 return EFI_WRITE_PROTECTED;
239 IN OUT volatile VOID *Buffer,
240 IN BOOLEAN RequestIsWrite
245 volatile UINT8 *HostStatus;
246 VOID *HostStatusBuffer;
248 VOID *RequestMapping;
257 BlockSize = Dev->BlockIoMedia.BlockSize;
263 BufferMapping =
NULL;
264 BufferDeviceAddress = 0;
269 ASSERT (BlockSize > 0);
270 ASSERT (BlockSize % 512 == 0);
275 ASSERT (BufferSize % BlockSize == 0);
278 if (Request ==
NULL) {
279 return EFI_DEVICE_ERROR;
286 Request->Type = RequestIsWrite ?
287 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :
290 Request->Sector =
MultU64x32 (Lba, BlockSize / 512);
297 Status = Dev->VirtIo->AllocateSharedPages (
302 if (EFI_ERROR (Status)) {
303 Status = EFI_DEVICE_ERROR;
307 HostStatus = HostStatusBuffer;
315 VirtioOperationBusMasterRead,
318 &RequestDeviceAddress,
321 if (EFI_ERROR (Status)) {
322 Status = EFI_DEVICE_ERROR;
323 goto FreeHostStatusBuffer;
329 if (BufferSize > 0) {
333 VirtioOperationBusMasterRead :
334 VirtioOperationBusMasterWrite),
337 &BufferDeviceAddress,
340 if (EFI_ERROR (Status)) {
341 Status = EFI_DEVICE_ERROR;
342 goto UnmapRequestBuffer;
349 *HostStatus = VIRTIO_BLK_S_IOERR;
357 VirtioOperationBusMasterCommonBuffer,
360 &HostStatusDeviceAddress,
363 if (EFI_ERROR (Status)) {
364 Status = EFI_DEVICE_ERROR;
365 goto UnmapDataBuffer;
374 ASSERT (Dev->Ring.QueueSize >= 3);
381 RequestDeviceAddress,
390 if (BufferSize > 0) {
399 ASSERT (BufferSize <= SIZE_1GB);
408 VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),
418 HostStatusDeviceAddress,
434 (*HostStatus == VIRTIO_BLK_S_OK))
438 Status = EFI_DEVICE_ERROR;
441 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);
444 if (BufferSize > 0) {
445 UnmapStatus = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping);
446 if (EFI_ERROR (UnmapStatus) && !RequestIsWrite && !EFI_ERROR (Status)) {
450 Status = EFI_DEVICE_ERROR;
455 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);
458 Dev->VirtIo->FreeSharedPages (
500 if (BufferSize == 0) {
504 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
511 if (EFI_ERROR (Status)) {
554 if (BufferSize == 0) {
558 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
565 if (EFI_ERROR (Status)) {
602 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
666 Status =
gBS->OpenProtocol (
668 &gVirtioDeviceProtocolGuid,
670 This->DriverBindingHandle,
673 EFI_OPEN_PROTOCOL_BY_DRIVER
676 if (EFI_ERROR (Status)) {
680 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
681 Status = EFI_UNSUPPORTED;
690 &gVirtioDeviceProtocolGuid,
691 This->DriverBindingHandle,
729 UINT8 PhysicalBlockExp;
730 UINT8 AlignmentOffset;
733 UINT64 RingBaseShift;
735 PhysicalBlockExp = 0;
743 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
744 if (EFI_ERROR (Status)) {
748 NextDevStat |= VSTAT_ACK;
749 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
750 if (EFI_ERROR (Status)) {
754 NextDevStat |= VSTAT_DRIVER;
755 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
756 if (EFI_ERROR (Status)) {
763 Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
764 if (EFI_ERROR (Status)) {
771 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
772 if (EFI_ERROR (Status)) {
776 Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
777 if (EFI_ERROR (Status)) {
781 if (NumSectors == 0) {
782 Status = EFI_UNSUPPORTED;
786 if (Features & VIRTIO_BLK_F_BLK_SIZE) {
787 Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
788 if (EFI_ERROR (Status)) {
792 if ((BlockSize == 0) || (BlockSize % 512 != 0) ||
793 (
ModU64x32 (NumSectors, BlockSize / 512) != 0))
799 Status = EFI_UNSUPPORTED;
806 if (Features & VIRTIO_BLK_F_TOPOLOGY) {
807 Status = VIRTIO_CFG_READ (
809 Topology.PhysicalBlockExp,
812 if (EFI_ERROR (Status)) {
816 if (PhysicalBlockExp >= 32) {
817 Status = EFI_UNSUPPORTED;
821 Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);
822 if (EFI_ERROR (Status)) {
826 Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);
827 if (EFI_ERROR (Status)) {
832 Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |
833 VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |
834 VIRTIO_F_IOMMU_PLATFORM;
840 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
842 if (EFI_ERROR (Status)) {
850 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
851 if (EFI_ERROR (Status)) {
855 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
856 if (EFI_ERROR (Status)) {
862 Status = EFI_UNSUPPORTED;
867 if (EFI_ERROR (Status)) {
880 if (EFI_ERROR (Status)) {
888 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
889 if (EFI_ERROR (Status)) {
893 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
894 if (EFI_ERROR (Status)) {
901 Status = Dev->VirtIo->SetQueueAddress (
906 if (EFI_ERROR (Status)) {
913 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
914 Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
915 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
916 if (EFI_ERROR (Status)) {
924 NextDevStat |= VSTAT_DRIVER_OK;
925 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
926 if (EFI_ERROR (Status)) {
934 Dev->BlockIo.Revision = 0;
935 Dev->BlockIo.Media = &Dev->BlockIoMedia;
936 Dev->BlockIo.Reset = &VirtioBlkReset;
940 Dev->BlockIoMedia.MediaId = 0;
941 Dev->BlockIoMedia.RemovableMedia =
FALSE;
942 Dev->BlockIoMedia.MediaPresent =
TRUE;
943 Dev->BlockIoMedia.LogicalPartition =
FALSE;
944 Dev->BlockIoMedia.ReadOnly = (BOOLEAN)((Features & VIRTIO_BLK_F_RO) != 0);
945 Dev->BlockIoMedia.WriteCaching = (BOOLEAN)((Features & VIRTIO_BLK_F_FLUSH) != 0);
946 Dev->BlockIoMedia.BlockSize = BlockSize;
947 Dev->BlockIoMedia.IoAlign = 0;
948 Dev->BlockIoMedia.LastBlock =
DivU64x32 (
955 "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",
957 Dev->BlockIoMedia.BlockSize,
958 Dev->BlockIoMedia.LastBlock + 1
961 if (Features & VIRTIO_BLK_F_TOPOLOGY) {
962 Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
964 Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;
965 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;
966 Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;
970 "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",
972 Dev->BlockIoMedia.LowestAlignedLba,
973 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock
977 "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",
979 Dev->BlockIoMedia.OptimalTransferLengthGranularity
986 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
996 NextDevStat |= VSTAT_FAILED;
997 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
1022 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1024 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
1027 SetMem (&Dev->BlockIo,
sizeof Dev->BlockIo, 0x00);
1028 SetMem (&Dev->BlockIoMedia,
sizeof Dev->BlockIoMedia, 0x00);
1050 DEBUG ((DEBUG_VERBOSE,
"%a: Context=0x%p\n", __func__, Context));
1059 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1103 return EFI_OUT_OF_RESOURCES;
1106 Status =
gBS->OpenProtocol (
1108 &gVirtioDeviceProtocolGuid,
1109 (VOID **)&Dev->VirtIo,
1110 This->DriverBindingHandle,
1112 EFI_OPEN_PROTOCOL_BY_DRIVER
1114 if (EFI_ERROR (Status)) {
1122 if (EFI_ERROR (Status)) {
1126 Status =
gBS->CreateEvent (
1127 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1133 if (EFI_ERROR (Status)) {
1140 Dev->Signature = VBLK_SIG;
1141 Status =
gBS->InstallProtocolInterface (
1143 &gEfiBlockIoProtocolGuid,
1147 if (EFI_ERROR (Status)) {
1154 gBS->CloseEvent (Dev->ExitBoot);
1160 gBS->CloseProtocol (
1162 &gVirtioDeviceProtocolGuid,
1163 This->DriverBindingHandle,
1208 Status =
gBS->OpenProtocol (
1210 &gEfiBlockIoProtocolGuid,
1212 This->DriverBindingHandle,
1214 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1216 if (EFI_ERROR (Status)) {
1220 Dev = VIRTIO_BLK_FROM_BLOCK_IO (BlockIo);
1225 Status =
gBS->UninstallProtocolInterface (
1227 &gEfiBlockIoProtocolGuid,
1230 if (EFI_ERROR (Status)) {
1234 gBS->CloseEvent (Dev->ExitBoot);
1238 gBS->CloseProtocol (
1240 &gVirtioDeviceProtocolGuid,
1241 This->DriverBindingHandle,
1279 {
"eng;en", L
"Virtio Block Driver" },
1288VirtioBlkGetDriverName (
1291 OUT CHAR16 **DriverName
1296 This->SupportedLanguages,
1299 (BOOLEAN)(This == &gComponentName)
1305VirtioBlkGetDeviceName (
1310 OUT CHAR16 **ControllerName
1313 return EFI_UNSUPPORTED;
1318 &VirtioBlkGetDriverName,
1319 &VirtioBlkGetDeviceName,
1335VirtioBlkEntryPoint (
UINT64 EFIAPI DivU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
UINT32 EFIAPI ModU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
EFI_STATUS(EFIAPI * EFI_COMPONENT_NAME2_GET_DRIVER_NAME)(IN EFI_COMPONENT_NAME2_PROTOCOL *This, IN CHAR8 *Language, OUT CHAR16 **DriverName)
EFI_STATUS(EFIAPI * EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)(IN EFI_COMPONENT_NAME2_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, OUT CHAR16 **ControllerName)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define DEBUG(Expression)
UINT64 EFI_PHYSICAL_ADDRESS
#define EFI_SIZE_TO_PAGES(Size)
EFI_STATUS EFIAPI LookupUnicodeString2(IN CONST CHAR8 *Language, IN CONST CHAR8 *SupportedLanguages, IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable, OUT CHAR16 **UnicodeString, IN BOOLEAN Iso639Language)
EFI_STATUS EFIAPI EfiLibInstallDriverBindingComponentName2(IN CONST EFI_HANDLE ImageHandle, IN CONST EFI_SYSTEM_TABLE *SystemTable, IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, IN EFI_HANDLE DriverBindingHandle, IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName OPTIONAL, IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL)
STATIC VOID EFIAPI VirtioBlkExitBoot(IN EFI_EVENT Event, IN VOID *Context)
STATIC EFI_STATUS EFIAPI VirtioBlkInit(IN OUT VBLK_DEV *Dev)
EFI_STATUS EFIAPI VirtioBlkDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer)
STATIC EFI_STATUS EFIAPI SynchronousRequest(IN VBLK_DEV *Dev, IN EFI_LBA Lba, IN UINTN BufferSize, IN OUT volatile VOID *Buffer, IN BOOLEAN RequestIsWrite)
EFI_STATUS EFIAPI VirtioBlkReadBlocks(IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, OUT VOID *Buffer)
EFI_STATUS EFIAPI VirtioBlkWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer)
EFI_STATUS EFIAPI VirtioBlkFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL *This)
STATIC EFI_STATUS EFIAPI VerifyReadWriteRequest(IN EFI_BLOCK_IO_MEDIA *Media, IN EFI_LBA Lba, IN UINTN PositiveBufferSize, IN BOOLEAN RequestIsWrite)
EFI_STATUS EFIAPI VirtioBlkDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
STATIC VOID EFIAPI VirtioBlkUninit(IN OUT VBLK_DEV *Dev)
EFI_STATUS EFIAPI VirtioBlkDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
EFI_STATUS EFIAPI VirtioMapAllBytesInSharedBuffer(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN VIRTIO_MAP_OPERATION Operation, IN VOID *HostAddress, IN UINTN NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
VOID EFIAPI VirtioAppendDesc(IN OUT VRING *Ring, IN UINT64 BufferDeviceAddress, IN UINT32 BufferSize, IN UINT16 Flags, IN OUT DESC_INDICES *Indices)
EFI_STATUS EFIAPI VirtioFlush(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT16 VirtQueueId, IN OUT VRING *Ring, IN DESC_INDICES *Indices, OUT UINT32 *UsedLen OPTIONAL)
EFI_STATUS EFIAPI VirtioRingMap(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN VRING *Ring, OUT UINT64 *RingBaseShift, OUT VOID **Mapping)
EFI_STATUS EFIAPI Virtio10WriteFeatures(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT64 Features, IN OUT UINT8 *DeviceStatus)
VOID EFIAPI VirtioPrepare(IN OUT VRING *Ring, OUT DESC_INDICES *Indices)
EFI_STATUS EFIAPI VirtioRingInit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT16 QueueSize, OUT VRING *Ring)
VOID EFIAPI VirtioRingUninit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN OUT VRING *Ring)