TianoCore EDK2 master
Loading...
Searching...
No Matches
VirtioBlk.c
Go to the documentation of this file.
1
24#include <Library/DebugLib.h>
27#include <Library/UefiLib.h>
28#include <Library/VirtioLib.h>
29
30#include "VirtioBlk.h"
31
60#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \
61 (Dev)->VirtIo, \
62 OFFSET_OF_VBLK (Field), \
63 SIZE_OF_VBLK (Field), \
64 (Value) \
65 ))
66
67#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \
68 (Dev)->VirtIo, \
69 OFFSET_OF_VBLK (Field), \
70 SIZE_OF_VBLK (Field), \
71 sizeof *(Pointer), \
72 (Pointer) \
73 ))
74
75//
76// UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol
77// Driver Writer's Guide for UEFI 2.3.1 v1.01,
78// 24.2 Block I/O Protocol Implementations
79//
81EFIAPI
82VirtioBlkReset (
84 IN BOOLEAN ExtendedVerification
85 )
86{
87 //
88 // If we managed to initialize and install the driver, then the device is
89 // working correctly.
90 //
91 return EFI_SUCCESS;
92}
93
142STATIC
144EFIAPI
146 IN EFI_BLOCK_IO_MEDIA *Media,
147 IN EFI_LBA Lba,
148 IN UINTN PositiveBufferSize,
149 IN BOOLEAN RequestIsWrite
150 )
151{
152 UINTN BlockCount;
153
154 ASSERT (PositiveBufferSize > 0);
155
156 if ((PositiveBufferSize > SIZE_1GB) ||
157 (PositiveBufferSize % Media->BlockSize > 0))
158 {
159 return EFI_BAD_BUFFER_SIZE;
160 }
161
162 BlockCount = PositiveBufferSize / Media->BlockSize;
163
164 //
165 // Avoid unsigned wraparound on either side in the second comparison.
166 //
167 if ((Lba > Media->LastBlock) || (BlockCount - 1 > Media->LastBlock - Lba)) {
168 return EFI_INVALID_PARAMETER;
169 }
170
171 if (RequestIsWrite && Media->ReadOnly) {
172 return EFI_WRITE_PROTECTED;
173 }
174
175 return EFI_SUCCESS;
176}
177
232STATIC
234EFIAPI
236 IN VBLK_DEV *Dev,
237 IN EFI_LBA Lba,
238 IN UINTN BufferSize,
239 IN OUT volatile VOID *Buffer,
240 IN BOOLEAN RequestIsWrite
241 )
242{
243 UINT32 BlockSize;
244 volatile VIRTIO_BLK_REQ *Request;
245 volatile UINT8 *HostStatus;
246 VOID *HostStatusBuffer;
247 DESC_INDICES Indices;
248 VOID *RequestMapping;
249 VOID *StatusMapping;
250 VOID *BufferMapping;
251 EFI_PHYSICAL_ADDRESS BufferDeviceAddress;
252 EFI_PHYSICAL_ADDRESS HostStatusDeviceAddress;
253 EFI_PHYSICAL_ADDRESS RequestDeviceAddress;
254 EFI_STATUS Status;
255 EFI_STATUS UnmapStatus;
256
257 BlockSize = Dev->BlockIoMedia.BlockSize;
258
259 //
260 // Set BufferMapping and BufferDeviceAddress to suppress incorrect
261 // compiler/analyzer warnings.
262 //
263 BufferMapping = NULL;
264 BufferDeviceAddress = 0;
265
266 //
267 // ensured by VirtioBlkInit()
268 //
269 ASSERT (BlockSize > 0);
270 ASSERT (BlockSize % 512 == 0);
271
272 //
273 // ensured by contract above, plus VerifyReadWriteRequest()
274 //
275 ASSERT (BufferSize % BlockSize == 0);
276
277 Request = AllocateZeroPool (sizeof (*Request));
278 if (Request == NULL) {
279 return EFI_DEVICE_ERROR;
280 }
281
282 //
283 // Prepare virtio-blk request header, setting zero size for flush.
284 // IO Priority is homogeneously 0.
285 //
286 Request->Type = RequestIsWrite ?
287 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :
288 VIRTIO_BLK_T_IN;
289 Request->IoPrio = 0;
290 Request->Sector = MultU64x32 (Lba, BlockSize / 512);
291
292 //
293 // Host status is bi-directional (we preset with a value and expect the
294 // device to update it). Allocate a host status buffer which can be mapped
295 // to access equally by both processor and the device.
296 //
297 Status = Dev->VirtIo->AllocateSharedPages (
298 Dev->VirtIo,
299 EFI_SIZE_TO_PAGES (sizeof *HostStatus),
300 &HostStatusBuffer
301 );
302 if (EFI_ERROR (Status)) {
303 Status = EFI_DEVICE_ERROR;
304 goto FreeBlkRequest;
305 }
306
307 HostStatus = HostStatusBuffer;
308
309 //
310 // Map virtio-blk request header (must be done after request header is
311 // populated)
312 //
314 Dev->VirtIo,
315 VirtioOperationBusMasterRead,
316 (VOID *)Request,
317 sizeof (*Request),
318 &RequestDeviceAddress,
319 &RequestMapping
320 );
321 if (EFI_ERROR (Status)) {
322 Status = EFI_DEVICE_ERROR;
323 goto FreeHostStatusBuffer;
324 }
325
326 //
327 // Map data buffer
328 //
329 if (BufferSize > 0) {
331 Dev->VirtIo,
332 (RequestIsWrite ?
333 VirtioOperationBusMasterRead :
334 VirtioOperationBusMasterWrite),
335 (VOID *)Buffer,
336 BufferSize,
337 &BufferDeviceAddress,
338 &BufferMapping
339 );
340 if (EFI_ERROR (Status)) {
341 Status = EFI_DEVICE_ERROR;
342 goto UnmapRequestBuffer;
343 }
344 }
345
346 //
347 // preset a host status for ourselves that we do not accept as success
348 //
349 *HostStatus = VIRTIO_BLK_S_IOERR;
350
351 //
352 // Map the Status Buffer with VirtioOperationBusMasterCommonBuffer so that
353 // both processor and device can access it.
354 //
356 Dev->VirtIo,
357 VirtioOperationBusMasterCommonBuffer,
358 HostStatusBuffer,
359 sizeof *HostStatus,
360 &HostStatusDeviceAddress,
361 &StatusMapping
362 );
363 if (EFI_ERROR (Status)) {
364 Status = EFI_DEVICE_ERROR;
365 goto UnmapDataBuffer;
366 }
367
368 VirtioPrepare (&Dev->Ring, &Indices);
369
370 //
371 // ensured by VirtioBlkInit() -- this predicate, in combination with the
372 // lock-step progress, ensures we don't have to track free descriptors.
373 //
374 ASSERT (Dev->Ring.QueueSize >= 3);
375
376 //
377 // virtio-blk header in first desc
378 //
380 &Dev->Ring,
381 RequestDeviceAddress,
382 sizeof (*Request),
383 VRING_DESC_F_NEXT,
384 &Indices
385 );
386
387 //
388 // data buffer for read/write in second desc
389 //
390 if (BufferSize > 0) {
391 //
392 // From virtio-0.9.5, 2.3.2 Descriptor Table:
393 // "no descriptor chain may be more than 2^32 bytes long in total".
394 //
395 // The predicate is ensured by the call contract above (for flush), or
396 // VerifyReadWriteRequest() (for read/write). It also implies that
397 // converting BufferSize to UINT32 will not truncate it.
398 //
399 ASSERT (BufferSize <= SIZE_1GB);
400
401 //
402 // VRING_DESC_F_WRITE is interpreted from the host's point of view.
403 //
405 &Dev->Ring,
406 BufferDeviceAddress,
407 (UINT32)BufferSize,
408 VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),
409 &Indices
410 );
411 }
412
413 //
414 // host status in last (second or third) desc
415 //
417 &Dev->Ring,
418 HostStatusDeviceAddress,
419 sizeof *HostStatus,
420 VRING_DESC_F_WRITE,
421 &Indices
422 );
423
424 //
425 // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
426 //
427 if ((VirtioFlush (
428 Dev->VirtIo,
429 0,
430 &Dev->Ring,
431 &Indices,
432 NULL
433 ) == EFI_SUCCESS) &&
434 (*HostStatus == VIRTIO_BLK_S_OK))
435 {
436 Status = EFI_SUCCESS;
437 } else {
438 Status = EFI_DEVICE_ERROR;
439 }
440
441 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);
442
443UnmapDataBuffer:
444 if (BufferSize > 0) {
445 UnmapStatus = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping);
446 if (EFI_ERROR (UnmapStatus) && !RequestIsWrite && !EFI_ERROR (Status)) {
447 //
448 // Data from the bus master may not reach the caller; fail the request.
449 //
450 Status = EFI_DEVICE_ERROR;
451 }
452 }
453
454UnmapRequestBuffer:
455 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);
456
457FreeHostStatusBuffer:
458 Dev->VirtIo->FreeSharedPages (
459 Dev->VirtIo,
460 EFI_SIZE_TO_PAGES (sizeof *HostStatus),
461 HostStatusBuffer
462 );
463
464FreeBlkRequest:
465 FreePool ((VOID *)Request);
466
467 return Status;
468}
469
488EFIAPI
491 IN UINT32 MediaId,
492 IN EFI_LBA Lba,
493 IN UINTN BufferSize,
494 OUT VOID *Buffer
495 )
496{
497 VBLK_DEV *Dev;
498 EFI_STATUS Status;
499
500 if (BufferSize == 0) {
501 return EFI_SUCCESS;
502 }
503
504 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
505 Status = VerifyReadWriteRequest (
506 &Dev->BlockIoMedia,
507 Lba,
508 BufferSize,
509 FALSE // RequestIsWrite
510 );
511 if (EFI_ERROR (Status)) {
512 return Status;
513 }
514
515 return SynchronousRequest (
516 Dev,
517 Lba,
518 BufferSize,
519 Buffer,
520 FALSE // RequestIsWrite
521 );
522}
523
542EFIAPI
545 IN UINT32 MediaId,
546 IN EFI_LBA Lba,
547 IN UINTN BufferSize,
548 IN VOID *Buffer
549 )
550{
551 VBLK_DEV *Dev;
552 EFI_STATUS Status;
553
554 if (BufferSize == 0) {
555 return EFI_SUCCESS;
556 }
557
558 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
559 Status = VerifyReadWriteRequest (
560 &Dev->BlockIoMedia,
561 Lba,
562 BufferSize,
563 TRUE // RequestIsWrite
564 );
565 if (EFI_ERROR (Status)) {
566 return Status;
567 }
568
569 return SynchronousRequest (
570 Dev,
571 Lba,
572 BufferSize,
573 Buffer,
574 TRUE // RequestIsWrite
575 );
576}
577
595EFIAPI
598 )
599{
600 VBLK_DEV *Dev;
601
602 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
603 return Dev->BlockIoMedia.WriteCaching ?
605 Dev,
606 0, // Lba
607 0, // BufferSize
608 NULL, // Buffer
609 TRUE // RequestIsWrite
610 ) :
612}
613
651EFIAPI
654 IN EFI_HANDLE DeviceHandle,
655 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
656 )
657{
658 EFI_STATUS Status;
660
661 //
662 // Attempt to open the device with the VirtIo set of interfaces. On success,
663 // the protocol is "instantiated" for the VirtIo device. Covers duplicate
664 // open attempts (EFI_ALREADY_STARTED).
665 //
666 Status = gBS->OpenProtocol (
667 DeviceHandle, // candidate device
668 &gVirtioDeviceProtocolGuid, // for generic VirtIo access
669 (VOID **)&VirtIo, // handle to instantiate
670 This->DriverBindingHandle, // requestor driver identity
671 DeviceHandle, // ControllerHandle, according to
672 // the UEFI Driver Model
673 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
674 // the device; to be released
675 );
676 if (EFI_ERROR (Status)) {
677 return Status;
678 }
679
680 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
681 Status = EFI_UNSUPPORTED;
682 }
683
684 //
685 // We needed VirtIo access only transitorily, to see whether we support the
686 // device or not.
687 //
688 gBS->CloseProtocol (
689 DeviceHandle,
690 &gVirtioDeviceProtocolGuid,
691 This->DriverBindingHandle,
692 DeviceHandle
693 );
694 return Status;
695}
696
716STATIC
718EFIAPI
720 IN OUT VBLK_DEV *Dev
721 )
722{
723 UINT8 NextDevStat;
724 EFI_STATUS Status;
725
726 UINT64 Features;
727 UINT64 NumSectors;
728 UINT32 BlockSize;
729 UINT8 PhysicalBlockExp;
730 UINT8 AlignmentOffset;
731 UINT32 OptIoSize;
732 UINT16 QueueSize;
733 UINT64 RingBaseShift;
734
735 PhysicalBlockExp = 0;
736 AlignmentOffset = 0;
737 OptIoSize = 0;
738
739 //
740 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
741 //
742 NextDevStat = 0; // step 1 -- reset device
743 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
744 if (EFI_ERROR (Status)) {
745 goto Failed;
746 }
747
748 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
749 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
750 if (EFI_ERROR (Status)) {
751 goto Failed;
752 }
753
754 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
755 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
756 if (EFI_ERROR (Status)) {
757 goto Failed;
758 }
759
760 //
761 // Set Page Size - MMIO VirtIo Specific
762 //
763 Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
764 if (EFI_ERROR (Status)) {
765 goto Failed;
766 }
767
768 //
769 // step 4a -- retrieve and validate features
770 //
771 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
772 if (EFI_ERROR (Status)) {
773 goto Failed;
774 }
775
776 Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
777 if (EFI_ERROR (Status)) {
778 goto Failed;
779 }
780
781 if (NumSectors == 0) {
782 Status = EFI_UNSUPPORTED;
783 goto Failed;
784 }
785
786 if (Features & VIRTIO_BLK_F_BLK_SIZE) {
787 Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
788 if (EFI_ERROR (Status)) {
789 goto Failed;
790 }
791
792 if ((BlockSize == 0) || (BlockSize % 512 != 0) ||
793 (ModU64x32 (NumSectors, BlockSize / 512) != 0))
794 {
795 //
796 // We can only handle a logical block consisting of whole sectors,
797 // and only a disk composed of whole logical blocks.
798 //
799 Status = EFI_UNSUPPORTED;
800 goto Failed;
801 }
802 } else {
803 BlockSize = 512;
804 }
805
806 if (Features & VIRTIO_BLK_F_TOPOLOGY) {
807 Status = VIRTIO_CFG_READ (
808 Dev,
809 Topology.PhysicalBlockExp,
810 &PhysicalBlockExp
811 );
812 if (EFI_ERROR (Status)) {
813 goto Failed;
814 }
815
816 if (PhysicalBlockExp >= 32) {
817 Status = EFI_UNSUPPORTED;
818 goto Failed;
819 }
820
821 Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);
822 if (EFI_ERROR (Status)) {
823 goto Failed;
824 }
825
826 Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);
827 if (EFI_ERROR (Status)) {
828 goto Failed;
829 }
830 }
831
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;
835
836 //
837 // In virtio-1.0, feature negotiation is expected to complete before queue
838 // discovery, and the device can also reject the selected set of features.
839 //
840 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
841 Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
842 if (EFI_ERROR (Status)) {
843 goto Failed;
844 }
845 }
846
847 //
848 // step 4b -- allocate virtqueue
849 //
850 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
851 if (EFI_ERROR (Status)) {
852 goto Failed;
853 }
854
855 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
856 if (EFI_ERROR (Status)) {
857 goto Failed;
858 }
859
860 if (QueueSize < 3) {
861 // SynchronousRequest() uses at most three descriptors
862 Status = EFI_UNSUPPORTED;
863 goto Failed;
864 }
865
866 Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);
867 if (EFI_ERROR (Status)) {
868 goto Failed;
869 }
870
871 //
872 // If anything fails from here on, we must release the ring resources
873 //
874 Status = VirtioRingMap (
875 Dev->VirtIo,
876 &Dev->Ring,
877 &RingBaseShift,
878 &Dev->RingMap
879 );
880 if (EFI_ERROR (Status)) {
881 goto ReleaseQueue;
882 }
883
884 //
885 // Additional steps for MMIO: align the queue appropriately, and set the
886 // size. If anything fails from here on, we must unmap the ring resources.
887 //
888 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
889 if (EFI_ERROR (Status)) {
890 goto UnmapQueue;
891 }
892
893 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
894 if (EFI_ERROR (Status)) {
895 goto UnmapQueue;
896 }
897
898 //
899 // step 4c -- Report GPFN (guest-physical frame number) of queue.
900 //
901 Status = Dev->VirtIo->SetQueueAddress (
902 Dev->VirtIo,
903 &Dev->Ring,
904 RingBaseShift
905 );
906 if (EFI_ERROR (Status)) {
907 goto UnmapQueue;
908 }
909
910 //
911 // step 5 -- Report understood features.
912 //
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)) {
917 goto UnmapQueue;
918 }
919 }
920
921 //
922 // step 6 -- initialization complete
923 //
924 NextDevStat |= VSTAT_DRIVER_OK;
925 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
926 if (EFI_ERROR (Status)) {
927 goto UnmapQueue;
928 }
929
930 //
931 // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI
932 // Block I/O Protocol.
933 //
934 Dev->BlockIo.Revision = 0;
935 Dev->BlockIo.Media = &Dev->BlockIoMedia;
936 Dev->BlockIo.Reset = &VirtioBlkReset;
937 Dev->BlockIo.ReadBlocks = &VirtioBlkReadBlocks;
938 Dev->BlockIo.WriteBlocks = &VirtioBlkWriteBlocks;
939 Dev->BlockIo.FlushBlocks = &VirtioBlkFlushBlocks;
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 (
949 NumSectors,
950 BlockSize / 512
951 ) - 1;
952
953 DEBUG ((
954 DEBUG_INFO,
955 "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",
956 __func__,
957 Dev->BlockIoMedia.BlockSize,
958 Dev->BlockIoMedia.LastBlock + 1
959 ));
960
961 if (Features & VIRTIO_BLK_F_TOPOLOGY) {
962 Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
963
964 Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;
965 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;
966 Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;
967
968 DEBUG ((
969 DEBUG_INFO,
970 "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",
971 __func__,
972 Dev->BlockIoMedia.LowestAlignedLba,
973 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock
974 ));
975 DEBUG ((
976 DEBUG_INFO,
977 "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",
978 __func__,
979 Dev->BlockIoMedia.OptimalTransferLengthGranularity
980 ));
981 }
982
983 return EFI_SUCCESS;
984
985UnmapQueue:
986 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
987
988ReleaseQueue:
989 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
990
991Failed:
992 //
993 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
994 // Status. VirtIo access failure here should not mask the original error.
995 //
996 NextDevStat |= VSTAT_FAILED;
997 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
998
999 return Status; // reached only via Failed above
1000}
1001
1010STATIC
1011VOID
1012EFIAPI
1014 IN OUT VBLK_DEV *Dev
1015 )
1016{
1017 //
1018 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
1019 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
1020 // the old comms area.
1021 //
1022 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1023
1024 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
1025 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
1026
1027 SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00);
1028 SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);
1029}
1030
1040STATIC
1041VOID
1042EFIAPI
1044 IN EFI_EVENT Event,
1045 IN VOID *Context
1046 )
1047{
1048 VBLK_DEV *Dev;
1049
1050 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __func__, Context));
1051 //
1052 // Reset the device. This causes the hypervisor to forget about the virtio
1053 // ring.
1054 //
1055 // We allocated said ring in EfiBootServicesData type memory, and code
1056 // executing after ExitBootServices() is permitted to overwrite it.
1057 //
1058 Dev = Context;
1059 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1060}
1061
1091EFIAPI
1094 IN EFI_HANDLE DeviceHandle,
1095 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1096 )
1097{
1098 VBLK_DEV *Dev;
1099 EFI_STATUS Status;
1100
1101 Dev = (VBLK_DEV *)AllocateZeroPool (sizeof *Dev);
1102 if (Dev == NULL) {
1103 return EFI_OUT_OF_RESOURCES;
1104 }
1105
1106 Status = gBS->OpenProtocol (
1107 DeviceHandle,
1108 &gVirtioDeviceProtocolGuid,
1109 (VOID **)&Dev->VirtIo,
1110 This->DriverBindingHandle,
1111 DeviceHandle,
1112 EFI_OPEN_PROTOCOL_BY_DRIVER
1113 );
1114 if (EFI_ERROR (Status)) {
1115 goto FreeVirtioBlk;
1116 }
1117
1118 //
1119 // VirtIo access granted, configure virtio-blk device.
1120 //
1121 Status = VirtioBlkInit (Dev);
1122 if (EFI_ERROR (Status)) {
1123 goto CloseVirtIo;
1124 }
1125
1126 Status = gBS->CreateEvent (
1127 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1128 TPL_CALLBACK,
1130 Dev,
1131 &Dev->ExitBoot
1132 );
1133 if (EFI_ERROR (Status)) {
1134 goto UninitDev;
1135 }
1136
1137 //
1138 // Setup complete, attempt to export the driver instance's BlockIo interface.
1139 //
1140 Dev->Signature = VBLK_SIG;
1141 Status = gBS->InstallProtocolInterface (
1142 &DeviceHandle,
1143 &gEfiBlockIoProtocolGuid,
1145 &Dev->BlockIo
1146 );
1147 if (EFI_ERROR (Status)) {
1148 goto CloseExitBoot;
1149 }
1150
1151 return EFI_SUCCESS;
1152
1153CloseExitBoot:
1154 gBS->CloseEvent (Dev->ExitBoot);
1155
1156UninitDev:
1157 VirtioBlkUninit (Dev);
1158
1159CloseVirtIo:
1160 gBS->CloseProtocol (
1161 DeviceHandle,
1162 &gVirtioDeviceProtocolGuid,
1163 This->DriverBindingHandle,
1164 DeviceHandle
1165 );
1166
1167FreeVirtioBlk:
1168 FreePool (Dev);
1169
1170 return Status;
1171}
1172
1196EFIAPI
1199 IN EFI_HANDLE DeviceHandle,
1200 IN UINTN NumberOfChildren,
1201 IN EFI_HANDLE *ChildHandleBuffer
1202 )
1203{
1204 EFI_STATUS Status;
1205 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1206 VBLK_DEV *Dev;
1207
1208 Status = gBS->OpenProtocol (
1209 DeviceHandle, // candidate device
1210 &gEfiBlockIoProtocolGuid, // retrieve the BlockIo iface
1211 (VOID **)&BlockIo, // target pointer
1212 This->DriverBindingHandle, // requestor driver identity
1213 DeviceHandle, // requesting lookup for dev.
1214 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added
1215 );
1216 if (EFI_ERROR (Status)) {
1217 return Status;
1218 }
1219
1220 Dev = VIRTIO_BLK_FROM_BLOCK_IO (BlockIo);
1221
1222 //
1223 // Handle Stop() requests for in-use driver instances gracefully.
1224 //
1225 Status = gBS->UninstallProtocolInterface (
1226 DeviceHandle,
1227 &gEfiBlockIoProtocolGuid,
1228 &Dev->BlockIo
1229 );
1230 if (EFI_ERROR (Status)) {
1231 return Status;
1232 }
1233
1234 gBS->CloseEvent (Dev->ExitBoot);
1235
1236 VirtioBlkUninit (Dev);
1237
1238 gBS->CloseProtocol (
1239 DeviceHandle,
1240 &gVirtioDeviceProtocolGuid,
1241 This->DriverBindingHandle,
1242 DeviceHandle
1243 );
1244
1245 FreePool (Dev);
1246
1247 return EFI_SUCCESS;
1248}
1249
1250//
1251// The static object that groups the Supported() (ie. probe), Start() and
1252// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
1253// C, 10.1 EFI Driver Binding Protocol.
1254//
1255STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
1259 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1260 NULL, // ImageHandle, to be overwritten by
1261 // EfiLibInstallDriverBindingComponentName2() in VirtioBlkEntryPoint()
1262 NULL // DriverBindingHandle, ditto
1263};
1264
1265//
1266// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
1267// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
1268// in English, for display on standard console devices. This is recommended for
1269// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
1270// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
1271//
1272// Device type names ("Virtio Block Device") are not formatted because the
1273// driver supports only that device type. Therefore the driver name suffices
1274// for unambiguous identification.
1275//
1276
1277STATIC
1278EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1279 { "eng;en", L"Virtio Block Driver" },
1280 { NULL, NULL }
1281};
1282
1283STATIC
1284EFI_COMPONENT_NAME_PROTOCOL gComponentName;
1285
1287EFIAPI
1288VirtioBlkGetDriverName (
1290 IN CHAR8 *Language,
1291 OUT CHAR16 **DriverName
1292 )
1293{
1294 return LookupUnicodeString2 (
1295 Language,
1296 This->SupportedLanguages,
1297 mDriverNameTable,
1298 DriverName,
1299 (BOOLEAN)(This == &gComponentName) // Iso639Language
1300 );
1301}
1302
1304EFIAPI
1305VirtioBlkGetDeviceName (
1307 IN EFI_HANDLE DeviceHandle,
1308 IN EFI_HANDLE ChildHandle,
1309 IN CHAR8 *Language,
1310 OUT CHAR16 **ControllerName
1311 )
1312{
1313 return EFI_UNSUPPORTED;
1314}
1315
1316STATIC
1317EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
1318 &VirtioBlkGetDriverName,
1319 &VirtioBlkGetDeviceName,
1320 "eng" // SupportedLanguages, ISO 639-2 language codes
1321};
1322
1323STATIC
1324EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
1325 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioBlkGetDriverName,
1326 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioBlkGetDeviceName,
1327 "en" // SupportedLanguages, RFC 4646 language codes
1328};
1329
1330//
1331// Entry point of this driver.
1332//
1334EFIAPI
1335VirtioBlkEntryPoint (
1336 IN EFI_HANDLE ImageHandle,
1337 IN EFI_SYSTEM_TABLE *SystemTable
1338 )
1339{
1341 ImageHandle,
1342 SystemTable,
1343 &gDriverBinding,
1344 ImageHandle,
1345 &gComponentName,
1346 &gComponentName2
1347 );
1348}
UINT64 UINTN
UINT64 EFIAPI DivU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
Definition: DivU64x32.c:29
UINT32 EFIAPI ModU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
Definition: ModU64x32.c:29
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
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 NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
UINT64 EFI_LBA
Definition: UefiBaseType.h:45
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
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)
Definition: UefiLib.c:801
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)
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
STATIC VOID EFIAPI VirtioBlkExitBoot(IN EFI_EVENT Event, IN VOID *Context)
Definition: VirtioBlk.c:1043
STATIC EFI_STATUS EFIAPI VirtioBlkInit(IN OUT VBLK_DEV *Dev)
Definition: VirtioBlk.c:719
EFI_STATUS EFIAPI VirtioBlkDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer)
Definition: VirtioBlk.c:1197
STATIC EFI_STATUS EFIAPI SynchronousRequest(IN VBLK_DEV *Dev, IN EFI_LBA Lba, IN UINTN BufferSize, IN OUT volatile VOID *Buffer, IN BOOLEAN RequestIsWrite)
Definition: VirtioBlk.c:235
EFI_STATUS EFIAPI VirtioBlkReadBlocks(IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, OUT VOID *Buffer)
Definition: VirtioBlk.c:489
EFI_STATUS EFIAPI VirtioBlkWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL *This, IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, IN VOID *Buffer)
Definition: VirtioBlk.c:543
EFI_STATUS EFIAPI VirtioBlkFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL *This)
Definition: VirtioBlk.c:596
STATIC EFI_STATUS EFIAPI VerifyReadWriteRequest(IN EFI_BLOCK_IO_MEDIA *Media, IN EFI_LBA Lba, IN UINTN PositiveBufferSize, IN BOOLEAN RequestIsWrite)
Definition: VirtioBlk.c:145
EFI_STATUS EFIAPI VirtioBlkDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
Definition: VirtioBlk.c:652
STATIC VOID EFIAPI VirtioBlkUninit(IN OUT VBLK_DEV *Dev)
Definition: VirtioBlk.c:1013
EFI_STATUS EFIAPI VirtioBlkDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
Definition: VirtioBlk.c:1092
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)
Definition: VirtioLib.c:469
VOID EFIAPI VirtioAppendDesc(IN OUT VRING *Ring, IN UINT64 BufferDeviceAddress, IN UINT32 BufferSize, IN UINT16 Flags, IN OUT DESC_INDICES *Indices)
Definition: VirtioLib.c:228
EFI_STATUS EFIAPI VirtioFlush(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT16 VirtQueueId, IN OUT VRING *Ring, IN DESC_INDICES *Indices, OUT UINT32 *UsedLen OPTIONAL)
Definition: VirtioLib.c:274
EFI_STATUS EFIAPI VirtioRingMap(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN VRING *Ring, OUT UINT64 *RingBaseShift, OUT VOID **Mapping)
Definition: VirtioLib.c:529
EFI_STATUS EFIAPI Virtio10WriteFeatures(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT64 Features, IN OUT UINT8 *DeviceStatus)
Definition: VirtioLib.c:391
VOID EFIAPI VirtioPrepare(IN OUT VRING *Ring, OUT DESC_INDICES *Indices)
Definition: VirtioLib.c:167
EFI_STATUS EFIAPI VirtioRingInit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT16 QueueSize, OUT VRING *Ring)
Definition: VirtioLib.c:49
VOID EFIAPI VirtioRingUninit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN OUT VRING *Ring)
Definition: VirtioLib.c:144
BOOLEAN WriteCaching
Definition: BlockIo.h:161