]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioBlkDxe/VirtioBlk.c
OvmfPkg/Virtio: take RingBaseShift in SetQueueAddress()
[mirror_edk2.git] / OvmfPkg / VirtioBlkDxe / VirtioBlk.c
index f09b0d1118dca684454eec61f026fd549494b011..bff15fe3add1692f828122e284abe38f0dc1eef7 100644 (file)
@@ -11,7 +11,8 @@
     synchronous requests and EFI_BLOCK_IO_PROTOCOL for now.\r
 \r
   Copyright (C) 2012, Red Hat, Inc.\r
-  Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2017, AMD Inc, All rights reserved.<BR>\r
 \r
   This program and the accompanying materials are licensed and made available\r
   under the terms and conditions of the BSD License which accompanies this\r
                        one of UINT8, UINT16, UINT32, UINT64.\r
 \r
 \r
-  @return  Status code returned by VirtioWriteDevice() / VirtioReadDevice().\r
+  @return  Status code returned by Virtio->WriteDevice() /\r
+           Virtio->ReadDevice().\r
 \r
 **/\r
 \r
-#define VIRTIO_CFG_WRITE(Dev, Field, Value)  (VirtioWriteDevice (       \\r
-                                                (Dev)->VirtIo,          \\r
-                                                OFFSET_OF_VBLK (Field), \\r
-                                                SIZE_OF_VBLK (Field),   \\r
-                                                (Value)                 \\r
+#define VIRTIO_CFG_WRITE(Dev, Field, Value)  ((Dev)->VirtIo->WriteDevice ( \\r
+                                                (Dev)->VirtIo,             \\r
+                                                OFFSET_OF_VBLK (Field),    \\r
+                                                SIZE_OF_VBLK (Field),      \\r
+                                                (Value)                    \\r
                                                 ))\r
 \r
-#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioReadDevice (        \\r
-                                                (Dev)->VirtIo,          \\r
-                                                OFFSET_OF_VBLK (Field), \\r
-                                                SIZE_OF_VBLK (Field),   \\r
-                                                sizeof *(Pointer),      \\r
-                                                (Pointer)               \\r
+#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice (  \\r
+                                                (Dev)->VirtIo,             \\r
+                                                OFFSET_OF_VBLK (Field),    \\r
+                                                SIZE_OF_VBLK (Field),      \\r
+                                                sizeof *(Pointer),         \\r
+                                                (Pointer)                  \\r
                                                 ))\r
 \r
 \r
@@ -323,7 +325,8 @@ SynchronousRequest (
   //\r
   // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
   //\r
-  if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&\r
+  if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices,\r
+        NULL) == EFI_SUCCESS &&\r
       HostStatus == VIRTIO_BLK_S_OK) {\r
     return EFI_SUCCESS;\r
   }\r
@@ -531,8 +534,8 @@ VirtioBlkDriverBindingSupported (
 \r
   //\r
   // Attempt to open the device with the VirtIo set of interfaces. On success,\r
-  // the protocol is "instantiated" for the VirtIo device. Covers duplicate open\r
-  // attempts (EFI_ALREADY_STARTED).\r
+  // the protocol is "instantiated" for the VirtIo device. Covers duplicate\r
+  // open attempts (EFI_ALREADY_STARTED).\r
   //\r
   Status = gBS->OpenProtocol (\r
                   DeviceHandle,               // candidate device\r
@@ -591,11 +594,18 @@ VirtioBlkInit (
   UINT8      NextDevStat;\r
   EFI_STATUS Status;\r
 \r
-  UINT32     Features;\r
+  UINT64     Features;\r
   UINT64     NumSectors;\r
   UINT32     BlockSize;\r
+  UINT8      PhysicalBlockExp;\r
+  UINT8      AlignmentOffset;\r
+  UINT32     OptIoSize;\r
   UINT16     QueueSize;\r
 \r
+  PhysicalBlockExp = 0;\r
+  AlignmentOffset = 0;\r
+  OptIoSize = 0;\r
+\r
   //\r
   // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.\r
   //\r
@@ -661,6 +671,42 @@ VirtioBlkInit (
     BlockSize = 512;\r
   }\r
 \r
+  if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
+    Status = VIRTIO_CFG_READ (Dev, Topology.PhysicalBlockExp,\r
+               &PhysicalBlockExp);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+    if (PhysicalBlockExp >= 32) {\r
+      Status = EFI_UNSUPPORTED;\r
+      goto Failed;\r
+    }\r
+\r
+    Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+\r
+    Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+  }\r
+\r
+  Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |\r
+              VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1;\r
+\r
+  //\r
+  // In virtio-1.0, feature negotiation is expected to complete before queue\r
+  // discovery, and the device can also reject the selected set of features.\r
+  //\r
+  if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+  }\r
+\r
   //\r
   // step 4b -- allocate virtqueue\r
   //\r
@@ -677,7 +723,7 @@ VirtioBlkInit (
     goto Failed;\r
   }\r
 \r
-  Status = VirtioRingInit (QueueSize, &Dev->Ring);\r
+  Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -699,22 +745,21 @@ VirtioBlkInit (
   //\r
   // step 4c -- Report GPFN (guest-physical frame number) of queue.\r
   //\r
-  Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,\r
-      (UINT32)(UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);\r
+  Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, &Dev->Ring, 0);\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseQueue;\r
   }\r
 \r
 \r
   //\r
-  // step 5 -- Report understood features. There are no virtio-blk specific\r
-  // features to negotiate in virtio-0.9.5, plus we do not want any of the\r
-  // device-independent (known or unknown) VIRTIO_F_* capabilities (see\r
-  // Appendix B).\r
+  // step 5 -- Report understood features.\r
   //\r
-  Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0);\r
-  if (EFI_ERROR (Status)) {\r
-    goto ReleaseQueue;\r
+  if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Features &= ~(UINT64)VIRTIO_F_VERSION_1;\r
+    Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReleaseQueue;\r
+    }\r
   }\r
 \r
   //\r
@@ -727,9 +772,8 @@ VirtioBlkInit (
   }\r
 \r
   //\r
-  // Populate the exported interface's attributes; see UEFI spec v2.3.1 +\r
-  // Errata C, 12.8 EFI Block I/O Protocol. We stick to the lowest possible\r
-  // EFI_BLOCK_IO_PROTOCOL revision for now.\r
+  // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI\r
+  // Block I/O Protocol.\r
   //\r
   Dev->BlockIo.Revision              = 0;\r
   Dev->BlockIo.Media                 = &Dev->BlockIoMedia;\r
@@ -741,16 +785,34 @@ VirtioBlkInit (
   Dev->BlockIoMedia.RemovableMedia   = FALSE;\r
   Dev->BlockIoMedia.MediaPresent     = TRUE;\r
   Dev->BlockIoMedia.LogicalPartition = FALSE;\r
-  Dev->BlockIoMedia.ReadOnly         = !!(Features & VIRTIO_BLK_F_RO);\r
-  Dev->BlockIoMedia.WriteCaching     = !!(Features & VIRTIO_BLK_F_FLUSH);\r
+  Dev->BlockIoMedia.ReadOnly         = (BOOLEAN) ((Features & VIRTIO_BLK_F_RO) != 0);\r
+  Dev->BlockIoMedia.WriteCaching     = (BOOLEAN) ((Features & VIRTIO_BLK_F_FLUSH) != 0);\r
   Dev->BlockIoMedia.BlockSize        = BlockSize;\r
   Dev->BlockIoMedia.IoAlign          = 0;\r
   Dev->BlockIoMedia.LastBlock        = DivU64x32 (NumSectors,\r
                                          BlockSize / 512) - 1;\r
+\r
+  DEBUG ((DEBUG_INFO, "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",\r
+    __FUNCTION__, Dev->BlockIoMedia.BlockSize,\r
+    Dev->BlockIoMedia.LastBlock + 1));\r
+\r
+  if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
+    Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;\r
+\r
+    Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;\r
+    Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;\r
+    Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;\r
+\r
+    DEBUG ((DEBUG_INFO, "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",\r
+      __FUNCTION__, Dev->BlockIoMedia.LowestAlignedLba,\r
+      Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock));\r
+    DEBUG ((DEBUG_INFO, "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",\r
+      __FUNCTION__, Dev->BlockIoMedia.OptimalTransferLengthGranularity));\r
+  }\r
   return EFI_SUCCESS;\r
 \r
 ReleaseQueue:\r
-  VirtioRingUninit (&Dev->Ring);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
 \r
 Failed:\r
   //\r
@@ -787,18 +849,49 @@ VirtioBlkUninit (
   //\r
   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
 \r
-  VirtioRingUninit (&Dev->Ring);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
 \r
   SetMem (&Dev->BlockIo,      sizeof Dev->BlockIo,      0x00);\r
   SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);\r
 }\r
 \r
 \r
+/**\r
+\r
+  Event notification function enqueued by ExitBootServices().\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+\r
+  @param[in] Context  Pointer to the VBLK_DEV structure.\r
+\r
+**/\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+VirtioBlkExitBoot (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  )\r
+{\r
+  VBLK_DEV *Dev;\r
+\r
+  //\r
+  // Reset the device. This causes the hypervisor to forget about the virtio\r
+  // ring.\r
+  //\r
+  // We allocated said ring in EfiBootServicesData type memory, and code\r
+  // executing after ExitBootServices() is permitted to overwrite it.\r
+  //\r
+  Dev = Context;\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
+}\r
+\r
 /**\r
 \r
   After we've pronounced support for a specific device in\r
   DriverBindingSupported(), we start managing said device (passed in by the\r
-  Driver Exeuction Environment) with the following service.\r
+  Driver Execution Environment) with the following service.\r
 \r
   See DriverBindingSupported() for specification references.\r
 \r
@@ -813,7 +906,7 @@ VirtioBlkUninit (
 \r
   @retval EFI_SUCCESS           Driver instance has been created and\r
                                 initialized  for the virtio-blk device, it\r
-                                is now accessibla via EFI_BLOCK_IO_PROTOCOL.\r
+                                is now accessible via EFI_BLOCK_IO_PROTOCOL.\r
 \r
   @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
 \r
@@ -854,6 +947,12 @@ VirtioBlkDriverBindingStart (
     goto CloseVirtIo;\r
   }\r
 \r
+  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
+                  &VirtioBlkExitBoot, Dev, &Dev->ExitBoot);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninitDev;\r
+  }\r
+\r
   //\r
   // Setup complete, attempt to export the driver instance's BlockIo interface.\r
   //\r
@@ -862,11 +961,14 @@ VirtioBlkDriverBindingStart (
                   &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,\r
                   &Dev->BlockIo);\r
   if (EFI_ERROR (Status)) {\r
-    goto UninitDev;\r
+    goto CloseExitBoot;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
+CloseExitBoot:\r
+  gBS->CloseEvent (Dev->ExitBoot);\r
+\r
 UninitDev:\r
   VirtioBlkUninit (Dev);\r
 \r
@@ -940,6 +1042,8 @@ VirtioBlkDriverBindingStop (
     return Status;\r
   }\r
 \r
+  gBS->CloseEvent (Dev->ExitBoot);\r
+\r
   VirtioBlkUninit (Dev);\r
 \r
   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r