X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FVirtioBlkDxe%2FVirtioBlk.c;h=55598843455dd9165678626bf1744086dafffc2a;hb=1dd46be315d555bd8b9df8ae6f3bad1c18d32673;hp=b2bfcdf7b72aecb2c66613b77933bc8c8aee772c;hpb=c8c2e4d61339592056931dff5c209b7d06fb466c;p=mirror_edk2.git diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c index b2bfcdf7b7..5559884345 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c @@ -11,7 +11,8 @@ synchronous requests and EFI_BLOCK_IO_PROTOCOL for now. Copyright (C) 2012, Red Hat, Inc. - Copyright (c) 2012, Intel Corporation. All rights reserved.
+ Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2017, AMD Inc, All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this @@ -23,7 +24,6 @@ **/ -#include #include #include #include @@ -37,14 +37,14 @@ /** Convenience macros to read and write region 0 IO space elements of the - virtio-blk PCI 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 PCI IO space - we're accessing. Dev->PciIo 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. @@ -57,23 +57,24 @@ one of UINT8, UINT16, UINT32, UINT64. - @return Status code returned by VirtioWrite() / VirtioRead(). + @return Status code returned by Virtio->WriteDevice() / + Virtio->ReadDevice(). **/ -#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \ - (Dev)->PciIo, \ - 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) (VirtioRead ( \ - (Dev)->PciIo, \ - 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) \ )) @@ -229,9 +230,10 @@ VerifyReadWriteRequest ( @retval EFI_SUCCESS Transfer complete. - @retval EFI_DEVICE_ERROR Failed to notify host side via PCI 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. + is not VIRTIO_BLK_S_OK or failed to map Buffer + for a bus master operation. **/ @@ -248,8 +250,17 @@ SynchronousRequest ( { UINT32 BlockSize; volatile VIRTIO_BLK_REQ Request; - volatile UINT8 HostStatus; + volatile UINT8 *HostStatus; + VOID *HostStatusBuffer; DESC_INDICES Indices; + VOID *RequestMapping; + VOID *StatusMapping; + VOID *BufferMapping; + EFI_PHYSICAL_ADDRESS BufferDeviceAddress; + EFI_PHYSICAL_ADDRESS HostStatusDeviceAddress; + EFI_PHYSICAL_ADDRESS RequestDeviceAddress; + EFI_STATUS Status; + EFI_STATUS UnmapStatus; BlockSize = Dev->BlockIoMedia.BlockSize; @@ -274,12 +285,82 @@ SynchronousRequest ( Request.IoPrio = 0; Request.Sector = MultU64x32(Lba, BlockSize / 512); - VirtioPrepare (&Dev->Ring, &Indices); + // + // Host status is bi-directional (we preset with a value and expect the + // device to update it). Allocate a host status buffer which can be mapped + // to access equally by both processor and the device. + // + Status = Dev->VirtIo->AllocateSharedPages ( + Dev->VirtIo, + EFI_SIZE_TO_PAGES (sizeof *HostStatus), + &HostStatusBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + HostStatus = HostStatusBuffer; + + // + // Map virtio-blk request header (must be done after request header is + // populated) + // + Status = VirtioMapAllBytesInSharedBuffer ( + Dev->VirtIo, + VirtioOperationBusMasterRead, + (VOID *) &Request, + sizeof Request, + &RequestDeviceAddress, + &RequestMapping + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto FreeHostStatusBuffer; + } + + // + // Map data buffer + // + if (BufferSize > 0) { + Status = VirtioMapAllBytesInSharedBuffer ( + Dev->VirtIo, + (RequestIsWrite ? + VirtioOperationBusMasterRead : + VirtioOperationBusMasterWrite), + (VOID *) Buffer, + BufferSize, + &BufferDeviceAddress, + &BufferMapping + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto UnmapRequestBuffer; + } + } // // preset a host status for ourselves that we do not accept as success // - HostStatus = VIRTIO_BLK_S_IOERR; + *HostStatus = VIRTIO_BLK_S_IOERR; + + // + // Map the Status Buffer with VirtioOperationBusMasterCommonBuffer so that + // both processor and device can access it. + // + Status = VirtioMapAllBytesInSharedBuffer ( + Dev->VirtIo, + VirtioOperationBusMasterCommonBuffer, + HostStatusBuffer, + sizeof *HostStatus, + &HostStatusDeviceAddress, + &StatusMapping + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto UnmapDataBuffer; + } + + VirtioPrepare (&Dev->Ring, &Indices); // // ensured by VirtioBlkInit() -- this predicate, in combination with the @@ -290,8 +371,13 @@ SynchronousRequest ( // // virtio-blk header in first desc // - VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request, - VRING_DESC_F_NEXT, &Indices); + VirtioAppendDesc ( + &Dev->Ring, + RequestDeviceAddress, + sizeof Request, + VRING_DESC_F_NEXT, + &Indices + ); // // data buffer for read/write in second desc @@ -310,26 +396,61 @@ SynchronousRequest ( // // VRING_DESC_F_WRITE is interpreted from the host's point of view. // - VirtioAppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize, + VirtioAppendDesc ( + &Dev->Ring, + BufferDeviceAddress, + (UINT32) BufferSize, VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE), - &Indices); + &Indices + ); } // // host status in last (second or third) desc // - VirtioAppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus, - VRING_DESC_F_WRITE, &Indices); + VirtioAppendDesc ( + &Dev->Ring, + HostStatusDeviceAddress, + sizeof *HostStatus, + VRING_DESC_F_WRITE, + &Indices + ); // // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D). // - if (VirtioFlush (Dev->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS && - HostStatus == VIRTIO_BLK_S_OK) { - return EFI_SUCCESS; + if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices, + NULL) == EFI_SUCCESS && + *HostStatus == VIRTIO_BLK_S_OK) { + Status = EFI_SUCCESS; + } else { + Status = EFI_DEVICE_ERROR; + } + + Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping); + +UnmapDataBuffer: + if (BufferSize > 0) { + UnmapStatus = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping); + if (EFI_ERROR (UnmapStatus) && !RequestIsWrite && !EFI_ERROR (Status)) { + // + // Data from the bus master may not reach the caller; fail the request. + // + Status = EFI_DEVICE_ERROR; + } } - return EFI_DEVICE_ERROR; +UnmapRequestBuffer: + Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping); + +FreeHostStatusBuffer: + Dev->VirtIo->FreeSharedPages ( + Dev->VirtIo, + EFI_SIZE_TO_PAGES (sizeof *HostStatus), + HostStatusBuffer + ); + + return Status; } @@ -500,11 +621,6 @@ VirtioBlkFlushBlocks ( underlying device - 9 Driver Binding Protocol -- for exporting ourselves - Specs relevant in the specific sense: - - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol - - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design - Guidelines, 18.3 PCI drivers. - @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object incorporating this driver (independently of any device). @@ -516,11 +632,11 @@ VirtioBlkFlushBlocks ( @retval EFI_SUCCESS The driver supports the device being probed. - @retval EFI_UNSUPPORTED Based on virtio-blk PCI 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 PciIo protocol. + the VirtIo protocol. **/ @@ -533,56 +649,36 @@ VirtioBlkDriverBindingSupported ( ) { EFI_STATUS Status; - EFI_PCI_IO_PROTOCOL *PciIo; - PCI_TYPE00 Pci; + VIRTIO_DEVICE_PROTOCOL *VirtIo; // - // Attempt to open the device with the PciIo set of interfaces. On success, - // the protocol is "instantiated" for the PCI 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 - &gEfiPciIoProtocolGuid, // for generic PCI access - (VOID **)&PciIo, // 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 PciIo access to + EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to // the device; to be released ); if (EFI_ERROR (Status)) { return Status; } - // - // Read entire PCI configuration header for more extensive check ahead. - // - Status = PciIo->Pci.Read ( - PciIo, // (protocol, device) - // handle - EfiPciIoWidthUint32, // access width & copy - // mode - 0, // Offset - sizeof Pci / sizeof (UINT32), // Count - &Pci // target buffer - ); - - if (Status == EFI_SUCCESS) { - // - // virtio-0.9.5, 2.1 PCI Discovery - // - Status = (Pci.Hdr.VendorId == 0x1AF4 && - Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F && - Pci.Hdr.RevisionID == 0x00 && - Pci.Device.SubsystemID == 0x02) ? EFI_SUCCESS : EFI_UNSUPPORTED; + if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) { + Status = EFI_UNSUPPORTED; } // - // We needed PCI IO 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, &gEfiPciIoProtocolGuid, + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); return Status; } @@ -594,8 +690,8 @@ VirtioBlkDriverBindingSupported ( device. @param[in out] Dev The driver instance to configure. The caller is - responsible for Dev->PciIo's validity (ie. working IO - access to the underlying virtio-blk PCI device). + responsible for Dev->VirtIo's validity (ie. working IO + access to the underlying virtio-blk device). @retval EFI_SUCCESS Setup complete. @@ -603,7 +699,8 @@ VirtioBlkDriverBindingSupported ( virtio-blk attributes the host provides. @return Error codes from VirtioRingInit() or - VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE(). + VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE or + VirtioRingMap(). **/ @@ -617,28 +714,44 @@ VirtioBlkInit ( UINT8 NextDevStat; EFI_STATUS Status; - UINT32 Features; + UINT64 Features; UINT64 NumSectors; UINT32 BlockSize; + UINT8 PhysicalBlockExp; + UINT8 AlignmentOffset; + UINT32 OptIoSize; UINT16 QueueSize; + UINT64 RingBaseShift; + + PhysicalBlockExp = 0; + AlignmentOffset = 0; + OptIoSize = 0; // // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence. // NextDevStat = 0; // step 1 -- reset device - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) { goto Failed; } NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 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 = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 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; } @@ -646,11 +759,12 @@ VirtioBlkInit ( // // step 4a -- retrieve and validate features // - Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features); + Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features); if (EFI_ERROR (Status)) { goto Failed; } - Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors); + + Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors); if (EFI_ERROR (Status)) { goto Failed; } @@ -660,7 +774,7 @@ VirtioBlkInit ( } if (Features & VIRTIO_BLK_F_BLK_SIZE) { - Status = VIRTIO_CFG_READ (Dev, VhdrBlkSize, &BlockSize); + Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize); if (EFI_ERROR (Status)) { goto Failed; } @@ -678,14 +792,51 @@ 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; + } + } + + Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO | + VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 | + VIRTIO_F_IOMMU_PLATFORM; + + // + // In virtio-1.0, feature negotiation is expected to complete before queue + // discovery, and the device can also reject the selected set of features. + // + if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) { + Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat); + if (EFI_ERROR (Status)) { + goto Failed; + } + } + // // step 4b -- allocate virtqueue // - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0); + Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0); if (EFI_ERROR (Status)) { goto Failed; } - Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize); + Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize); if (EFI_ERROR (Status)) { goto Failed; } @@ -694,45 +845,74 @@ VirtioBlkInit ( goto Failed; } - Status = VirtioRingInit (QueueSize, &Dev->Ring); + Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring); if (EFI_ERROR (Status)) { goto Failed; } // - // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything - // fails from here on, we must release the ring resources. + // If anything fails from here on, we must release the ring resources // - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress, - (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT); + Status = VirtioRingMap ( + Dev->VirtIo, + &Dev->Ring, + &RingBaseShift, + &Dev->RingMap + ); 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). + // Additional steps for MMIO: align the queue appropriately, and set the + // size. If anything fails from here on, we must unmap the ring resources. // - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0); + Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize); if (EFI_ERROR (Status)) { - goto ReleaseQueue; + goto UnmapQueue; + } + + Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE); + if (EFI_ERROR (Status)) { + goto UnmapQueue; + } + + // + // step 4c -- Report GPFN (guest-physical frame number) of queue. + // + Status = Dev->VirtIo->SetQueueAddress ( + Dev->VirtIo, + &Dev->Ring, + RingBaseShift + ); + if (EFI_ERROR (Status)) { + goto UnmapQueue; + } + + + // + // step 5 -- Report understood features. + // + if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) { + Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM); + Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features); + if (EFI_ERROR (Status)) { + goto UnmapQueue; + } } // // step 6 -- initialization complete // NextDevStat |= VSTAT_DRIVER_OK; - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) { - goto ReleaseQueue; + goto UnmapQueue; } // - // 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; @@ -744,24 +924,45 @@ VirtioBlkInit ( Dev->BlockIoMedia.RemovableMedia = FALSE; Dev->BlockIoMedia.MediaPresent = TRUE; Dev->BlockIoMedia.LogicalPartition = FALSE; - Dev->BlockIoMedia.ReadOnly = !!(Features & VIRTIO_BLK_F_RO); - Dev->BlockIoMedia.WriteCaching = !!(Features & VIRTIO_BLK_F_FLUSH); + Dev->BlockIoMedia.ReadOnly = (BOOLEAN) ((Features & VIRTIO_BLK_F_RO) != 0); + Dev->BlockIoMedia.WriteCaching = (BOOLEAN) ((Features & VIRTIO_BLK_F_FLUSH) != 0); Dev->BlockIoMedia.BlockSize = BlockSize; 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; +UnmapQueue: + Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap); + ReleaseQueue: - VirtioRingUninit (&Dev->Ring); + VirtioRingUninit (Dev->VirtIo, &Dev->Ring); Failed: // // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device - // Status. PCI IO access failure here should not mask the original error. + // Status. VirtIo access failure here should not mask the original error. // NextDevStat |= VSTAT_FAILED; - VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); return Status; // reached only via Failed above } @@ -788,20 +989,53 @@ VirtioBlkUninit ( // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from // the old comms area. // - VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0); + Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); - VirtioRingUninit (&Dev->Ring); + Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap); + VirtioRingUninit (Dev->VirtIo, &Dev->Ring); SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00); SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00); } +/** + + Event notification function enqueued by ExitBootServices(). + + @param[in] Event Event whose notification function is being invoked. + + @param[in] Context Pointer to the VBLK_DEV structure. + +**/ + +STATIC +VOID +EFIAPI +VirtioBlkExitBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + VBLK_DEV *Dev; + + DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context)); + // + // Reset the device. This causes the hypervisor to forget about the virtio + // ring. + // + // We allocated said ring in EfiBootServicesData type memory, and code + // executing after ExitBootServices() is permitted to overwrite it. + // + Dev = Context; + Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); +} + /** After we've pronounced support for a specific device in DriverBindingSupported(), we start managing said device (passed in by the - Driver Exeuction Environment) with the following service. + Driver Execution Environment) with the following service. See DriverBindingSupported() for specification references. @@ -815,13 +1049,13 @@ VirtioBlkUninit ( @retval EFI_SUCCESS Driver instance has been created and - initialized for the virtio-blk PCI device, it - is now accessibla via EFI_BLOCK_IO_PROTOCOL. + initialized for the virtio-blk device, it + is now accessible via EFI_BLOCK_IO_PROTOCOL. @retval EFI_OUT_OF_RESOURCES Memory allocation failed. @return Error codes from the OpenProtocol() boot - service, the PciIo protocol, VirtioBlkInit(), + service, the VirtIo protocol, VirtioBlkInit(), or the InstallProtocolInterface() boot service. **/ @@ -842,43 +1076,25 @@ VirtioBlkDriverBindingStart ( return EFI_OUT_OF_RESOURCES; } - Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, - (VOID **)&Dev->PciIo, This->DriverBindingHandle, + Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, + (VOID **)&Dev->VirtIo, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR (Status)) { goto FreeVirtioBlk; } // - // We must retain and ultimately restore the original PCI attributes of the - // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers / - // 18.3.2 Start() and Stop(). - // - // The third parameter ("Attributes", input) is ignored by the Get operation. - // The fourth parameter ("Result", output) is ignored by the Enable and Set - // operations. + // VirtIo access granted, configure virtio-blk device. // - // For virtio-blk we only need IO space access. - // - Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet, - 0, &Dev->OriginalPciAttributes); - if (EFI_ERROR (Status)) { - goto ClosePciIo; - } - - Status = Dev->PciIo->Attributes (Dev->PciIo, - EfiPciIoAttributeOperationEnable, - EFI_PCI_IO_ATTRIBUTE_IO, NULL); + Status = VirtioBlkInit (Dev); if (EFI_ERROR (Status)) { - goto ClosePciIo; + goto CloseVirtIo; } - // - // PCI IO access granted, configure virtio-blk device. - // - Status = VirtioBlkInit (Dev); + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, + &VirtioBlkExitBoot, Dev, &Dev->ExitBoot); if (EFI_ERROR (Status)) { - goto RestorePciAttributes; + goto UninitDev; } // @@ -889,20 +1105,19 @@ VirtioBlkDriverBindingStart ( &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE, &Dev->BlockIo); if (EFI_ERROR (Status)) { - goto UninitDev; + goto CloseExitBoot; } return EFI_SUCCESS; +CloseExitBoot: + gBS->CloseEvent (Dev->ExitBoot); + UninitDev: VirtioBlkUninit (Dev); -RestorePciAttributes: - Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, - Dev->OriginalPciAttributes, NULL); - -ClosePciIo: - gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, +CloseVirtIo: + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); FreeVirtioBlk: @@ -971,12 +1186,11 @@ VirtioBlkDriverBindingStop ( return Status; } - VirtioBlkUninit (Dev); + gBS->CloseEvent (Dev->ExitBoot); - Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, - Dev->OriginalPciAttributes, NULL); + VirtioBlkUninit (Dev); - gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); FreePool (Dev);