VirtioLib.c revision 56f65ed838e8d73e91d54a8ed984d777c936843c
1/** @file 2 3 Utility functions used by virtio device drivers. 4 5 Copyright (C) 2012, Red Hat, Inc. 6 Portion of Copyright (C) 2013, ARM Ltd. 7 8 This program and the accompanying materials are licensed and made available 9 under the terms and conditions of the BSD License which accompanies this 10 distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT 14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16**/ 17 18#include <Library/BaseLib.h> 19#include <Library/BaseMemoryLib.h> 20#include <Library/DebugLib.h> 21#include <Library/MemoryAllocationLib.h> 22#include <Library/UefiBootServicesTableLib.h> 23 24#include <Library/VirtioLib.h> 25 26 27/** 28 29 Write a word into Region 0 of the device specified by VirtIo. 30 31 Region 0 must be an iomem region. This is an internal function for the 32 driver-specific VIRTIO_CFG_WRITE() macros. 33 34 @param[in] VirtIo Target VirtIo device. 35 36 @param[in] FieldOffset Destination offset. 37 38 @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }. 39 40 @param[in] Value Little endian value to write, converted to UINT64. 41 The least significant FieldSize bytes will be used. 42 43 44 @return Status code returned by VirtIo->Io.Write(). 45 46**/ 47EFI_STATUS 48EFIAPI 49VirtioWriteDevice ( 50 IN VIRTIO_DEVICE_PROTOCOL *VirtIo, 51 IN UINTN FieldOffset, 52 IN UINTN FieldSize, 53 IN UINT64 Value 54 ) 55{ 56 return VirtIo->WriteDevice (VirtIo, FieldOffset, FieldSize, Value); 57} 58 59 60/** 61 62 Read a word from Region 0 of the device specified by VirtIo. 63 64 Region 0 must be an iomem region. This is an internal function for the 65 driver-specific VIRTIO_CFG_READ() macros. 66 67 @param[in] VirtIo Source VirtIo device. 68 69 @param[in] FieldOffset Source offset. 70 71 @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }. 72 73 @param[in] BufferSize Number of bytes available in the target buffer. Must 74 equal FieldSize. 75 76 @param[out] Buffer Target buffer. 77 78 79 @return Status code returned by VirtIo->Io.Read(). 80 81**/ 82EFI_STATUS 83EFIAPI 84VirtioReadDevice ( 85 IN VIRTIO_DEVICE_PROTOCOL *VirtIo, 86 IN UINTN FieldOffset, 87 IN UINTN FieldSize, 88 IN UINTN BufferSize, 89 OUT VOID *Buffer 90 ) 91{ 92 return VirtIo->ReadDevice (VirtIo, FieldOffset, FieldSize, BufferSize, Buffer); 93} 94 95 96/** 97 98 Configure a virtio ring. 99 100 This function sets up internal storage (the guest-host communication area) 101 and lays out several "navigation" (ie. no-ownership) pointers to parts of 102 that storage. 103 104 Relevant sections from the virtio-0.9.5 spec: 105 - 1.1 Virtqueues, 106 - 2.3 Virtqueue Configuration. 107 108 @param[in] The number of descriptors to allocate for the 109 virtio ring, as requested by the host. 110 111 @param[out] Ring The virtio ring to set up. 112 113 @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous 114 pages for the requested QueueSize. Fields of 115 Ring have indeterminate value. 116 117 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base 118 (and nothing else) is responsible for 119 deallocation. 120 121**/ 122EFI_STATUS 123EFIAPI 124VirtioRingInit ( 125 IN UINT16 QueueSize, 126 OUT VRING *Ring 127 ) 128{ 129 UINTN RingSize; 130 volatile UINT8 *RingPagesPtr; 131 132 RingSize = ALIGN_VALUE ( 133 sizeof *Ring->Desc * QueueSize + 134 sizeof *Ring->Avail.Flags + 135 sizeof *Ring->Avail.Idx + 136 sizeof *Ring->Avail.Ring * QueueSize + 137 sizeof *Ring->Avail.UsedEvent, 138 EFI_PAGE_SIZE); 139 140 RingSize += ALIGN_VALUE ( 141 sizeof *Ring->Used.Flags + 142 sizeof *Ring->Used.Idx + 143 sizeof *Ring->Used.UsedElem * QueueSize + 144 sizeof *Ring->Used.AvailEvent, 145 EFI_PAGE_SIZE); 146 147 Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize); 148 Ring->Base = AllocatePages (Ring->NumPages); 149 if (Ring->Base == NULL) { 150 return EFI_OUT_OF_RESOURCES; 151 } 152 SetMem (Ring->Base, RingSize, 0x00); 153 RingPagesPtr = Ring->Base; 154 155 Ring->Desc = (volatile VOID *) RingPagesPtr; 156 RingPagesPtr += sizeof *Ring->Desc * QueueSize; 157 158 Ring->Avail.Flags = (volatile VOID *) RingPagesPtr; 159 RingPagesPtr += sizeof *Ring->Avail.Flags; 160 161 Ring->Avail.Idx = (volatile VOID *) RingPagesPtr; 162 RingPagesPtr += sizeof *Ring->Avail.Idx; 163 164 Ring->Avail.Ring = (volatile VOID *) RingPagesPtr; 165 RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize; 166 167 Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr; 168 RingPagesPtr += sizeof *Ring->Avail.UsedEvent; 169 170 RingPagesPtr = (volatile UINT8 *) Ring->Base + 171 ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base, 172 EFI_PAGE_SIZE); 173 174 Ring->Used.Flags = (volatile VOID *) RingPagesPtr; 175 RingPagesPtr += sizeof *Ring->Used.Flags; 176 177 Ring->Used.Idx = (volatile VOID *) RingPagesPtr; 178 RingPagesPtr += sizeof *Ring->Used.Idx; 179 180 Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr; 181 RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize; 182 183 Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr; 184 RingPagesPtr += sizeof *Ring->Used.AvailEvent; 185 186 Ring->QueueSize = QueueSize; 187 return EFI_SUCCESS; 188} 189 190 191/** 192 193 Tear down the internal resources of a configured virtio ring. 194 195 The caller is responsible to stop the host from using this ring before 196 invoking this function: the VSTAT_DRIVER_OK bit must be clear in 197 VhdrDeviceStatus. 198 199 @param[out] Ring The virtio ring to clean up. 200 201**/ 202VOID 203EFIAPI 204VirtioRingUninit ( 205 IN OUT VRING *Ring 206 ) 207{ 208 FreePages (Ring->Base, Ring->NumPages); 209 SetMem (Ring, sizeof *Ring, 0x00); 210} 211 212 213/** 214 215 Turn off interrupt notifications from the host, and prepare for appending 216 multiple descriptors to the virtio ring. 217 218 The calling driver must be in VSTAT_DRIVER_OK state. 219 220 @param[in,out] Ring The virtio ring we intend to append descriptors to. 221 222 @param[out] Indices The DESC_INDICES structure to initialize. 223 224**/ 225VOID 226EFIAPI 227VirtioPrepare ( 228 IN OUT VRING *Ring, 229 OUT DESC_INDICES *Indices 230 ) 231{ 232 // 233 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device. 234 // We're going to poll the answer, the host should not send an interrupt. 235 // 236 *Ring->Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT; 237 238 // 239 // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device. 240 // 241 // Since we support only one in-flight descriptor chain, we can always build 242 // that chain starting at entry #0 of the descriptor table. 243 // 244 Indices->HeadDescIdx = 0; 245 Indices->NextDescIdx = Indices->HeadDescIdx; 246} 247 248 249/** 250 251 Append a contiguous buffer for transmission / reception via the virtio ring. 252 253 This function implements the following section from virtio-0.9.5: 254 - 2.4.1.1 Placing Buffers into the Descriptor Table 255 256 Free space is taken as granted, since the individual drivers support only 257 synchronous requests and host side status is processed in lock-step with 258 request submission. It is the calling driver's responsibility to verify the 259 ring size in advance. 260 261 The caller is responsible for initializing *Indices with VirtioPrepare() 262 first. 263 264 @param[in,out] Ring The virtio ring to append the buffer to, as a 265 descriptor. 266 267 @param[in] BufferPhysAddr (Guest pseudo-physical) start address of the 268 transmit / receive buffer. 269 270 @param[in] BufferSize Number of bytes to transmit or receive. 271 272 @param[in] Flags A bitmask of VRING_DESC_F_* flags. The caller 273 computes this mask dependent on further buffers to 274 append and transfer direction. 275 VRING_DESC_F_INDIRECT is unsupported. The 276 VRING_DESC.Next field is always set, but the host 277 only interprets it dependent on VRING_DESC_F_NEXT. 278 279 @param[in,out] Indices Indices->HeadDescIdx is not accessed. 280 On input, Indices->NextDescIdx identifies the next 281 descriptor to carry the buffer. On output, 282 Indices->NextDescIdx is incremented by one, modulo 283 2^16. 284 285**/ 286VOID 287EFIAPI 288VirtioAppendDesc ( 289 IN OUT VRING *Ring, 290 IN UINTN BufferPhysAddr, 291 IN UINT32 BufferSize, 292 IN UINT16 Flags, 293 IN OUT DESC_INDICES *Indices 294 ) 295{ 296 volatile VRING_DESC *Desc; 297 298 Desc = &Ring->Desc[Indices->NextDescIdx++ % Ring->QueueSize]; 299 Desc->Addr = BufferPhysAddr; 300 Desc->Len = BufferSize; 301 Desc->Flags = Flags; 302 Desc->Next = Indices->NextDescIdx % Ring->QueueSize; 303} 304 305 306/** 307 308 Notify the host about the descriptor chain just built, and wait until the 309 host processes it. 310 311 @param[in] VirtIo The target virtio device to notify. 312 313 @param[in] VirtQueueId Identifies the queue for the target device. 314 315 @param[in,out] Ring The virtio ring with descriptors to submit. 316 317 @param[in] Indices Indices->NextDescIdx is not accessed. 318 Indices->HeadDescIdx identifies the head descriptor 319 of the descriptor chain. 320 321 322 @return Error code from VirtIo->SetQueueNotify() if it fails. 323 324 @retval EFI_SUCCESS Otherwise, the host processed all descriptors. 325 326**/ 327EFI_STATUS 328EFIAPI 329VirtioFlush ( 330 IN VIRTIO_DEVICE_PROTOCOL *VirtIo, 331 IN UINT16 VirtQueueId, 332 IN OUT VRING *Ring, 333 IN DESC_INDICES *Indices 334 ) 335{ 336 UINT16 NextAvailIdx; 337 EFI_STATUS Status; 338 UINTN PollPeriodUsecs; 339 340 // 341 // virtio-0.9.5, 2.4.1.2 Updating the Available Ring 342 // 343 // It is not exactly clear from the wording of the virtio-0.9.5 344 // specification, but each entry in the Available Ring references only the 345 // head descriptor of any given descriptor chain. 346 // 347 NextAvailIdx = *Ring->Avail.Idx; 348 Ring->Avail.Ring[NextAvailIdx++ % Ring->QueueSize] = 349 Indices->HeadDescIdx % Ring->QueueSize; 350 351 // 352 // virtio-0.9.5, 2.4.1.3 Updating the Index Field 353 // 354 MemoryFence(); 355 *Ring->Avail.Idx = NextAvailIdx; 356 357 // 358 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are 359 // OK. 360 // 361 MemoryFence(); 362 Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId); 363 if (EFI_ERROR (Status)) { 364 return Status; 365 } 366 367 // 368 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device 369 // Wait until the host processes and acknowledges our descriptor chain. The 370 // condition we use for polling is greatly simplified and relies on the 371 // synchronous, lock-step progress. 372 // 373 // Keep slowing down until we reach a poll period of slightly above 1 ms. 374 // 375 PollPeriodUsecs = 1; 376 MemoryFence(); 377 while (*Ring->Used.Idx != NextAvailIdx) { 378 gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay 379 380 if (PollPeriodUsecs < 1024) { 381 PollPeriodUsecs *= 2; 382 } 383 MemoryFence(); 384 } 385 386 MemoryFence(); 387 return EFI_SUCCESS; 388} 389