3 Utility functions used by virtio device drivers.
5 Copyright (C) 2012-2016, Red Hat, Inc.
6 Portion of Copyright (C) 2013, ARM Ltd.
7 Copyright (C) 2017, AMD Inc, All rights reserved.<BR>
9 This program and the accompanying materials are licensed and made available
10 under the terms and conditions of the BSD License which accompanies this
11 distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
15 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
24 #include <Library/VirtioLib.h>
29 Configure a virtio ring.
31 This function sets up internal storage (the guest-host communication area)
32 and lays out several "navigation" (ie. no-ownership) pointers to parts of
35 Relevant sections from the virtio-0.9.5 spec:
37 - 2.3 Virtqueue Configuration.
39 @param[in] VirtIo The virtio device which will use the ring.
41 @param[in] The number of descriptors to allocate for the
42 virtio ring, as requested by the host.
44 @param[out] Ring The virtio ring to set up.
46 @return Status codes propagated from
47 VirtIo->AllocateSharedPages().
49 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base
50 (and nothing else) is responsible for
57 IN VIRTIO_DEVICE_PROTOCOL
*VirtIo
,
64 volatile UINT8
*RingPagesPtr
;
66 RingSize
= ALIGN_VALUE (
67 sizeof *Ring
->Desc
* QueueSize
+
68 sizeof *Ring
->Avail
.Flags
+
69 sizeof *Ring
->Avail
.Idx
+
70 sizeof *Ring
->Avail
.Ring
* QueueSize
+
71 sizeof *Ring
->Avail
.UsedEvent
,
74 RingSize
+= ALIGN_VALUE (
75 sizeof *Ring
->Used
.Flags
+
76 sizeof *Ring
->Used
.Idx
+
77 sizeof *Ring
->Used
.UsedElem
* QueueSize
+
78 sizeof *Ring
->Used
.AvailEvent
,
82 // Allocate a shared ring buffer
84 Ring
->NumPages
= EFI_SIZE_TO_PAGES (RingSize
);
85 Status
= VirtIo
->AllocateSharedPages (
90 if (EFI_ERROR (Status
)) {
93 SetMem (Ring
->Base
, RingSize
, 0x00);
94 RingPagesPtr
= Ring
->Base
;
96 Ring
->Desc
= (volatile VOID
*) RingPagesPtr
;
97 RingPagesPtr
+= sizeof *Ring
->Desc
* QueueSize
;
99 Ring
->Avail
.Flags
= (volatile VOID
*) RingPagesPtr
;
100 RingPagesPtr
+= sizeof *Ring
->Avail
.Flags
;
102 Ring
->Avail
.Idx
= (volatile VOID
*) RingPagesPtr
;
103 RingPagesPtr
+= sizeof *Ring
->Avail
.Idx
;
105 Ring
->Avail
.Ring
= (volatile VOID
*) RingPagesPtr
;
106 RingPagesPtr
+= sizeof *Ring
->Avail
.Ring
* QueueSize
;
108 Ring
->Avail
.UsedEvent
= (volatile VOID
*) RingPagesPtr
;
109 RingPagesPtr
+= sizeof *Ring
->Avail
.UsedEvent
;
111 RingPagesPtr
= (volatile UINT8
*) Ring
->Base
+
112 ALIGN_VALUE (RingPagesPtr
- (volatile UINT8
*) Ring
->Base
,
115 Ring
->Used
.Flags
= (volatile VOID
*) RingPagesPtr
;
116 RingPagesPtr
+= sizeof *Ring
->Used
.Flags
;
118 Ring
->Used
.Idx
= (volatile VOID
*) RingPagesPtr
;
119 RingPagesPtr
+= sizeof *Ring
->Used
.Idx
;
121 Ring
->Used
.UsedElem
= (volatile VOID
*) RingPagesPtr
;
122 RingPagesPtr
+= sizeof *Ring
->Used
.UsedElem
* QueueSize
;
124 Ring
->Used
.AvailEvent
= (volatile VOID
*) RingPagesPtr
;
125 RingPagesPtr
+= sizeof *Ring
->Used
.AvailEvent
;
127 Ring
->QueueSize
= QueueSize
;
134 Tear down the internal resources of a configured virtio ring.
136 The caller is responsible to stop the host from using this ring before
137 invoking this function: the VSTAT_DRIVER_OK bit must be clear in
140 @param[in] VirtIo The virtio device which was using the ring.
142 @param[out] Ring The virtio ring to clean up.
148 IN VIRTIO_DEVICE_PROTOCOL
*VirtIo
,
152 VirtIo
->FreeSharedPages (VirtIo
, Ring
->NumPages
, Ring
->Base
);
153 SetMem (Ring
, sizeof *Ring
, 0x00);
159 Turn off interrupt notifications from the host, and prepare for appending
160 multiple descriptors to the virtio ring.
162 The calling driver must be in VSTAT_DRIVER_OK state.
164 @param[in,out] Ring The virtio ring we intend to append descriptors to.
166 @param[out] Indices The DESC_INDICES structure to initialize.
173 OUT DESC_INDICES
*Indices
177 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
178 // We're going to poll the answer, the host should not send an interrupt.
180 *Ring
->Avail
.Flags
= (UINT16
) VRING_AVAIL_F_NO_INTERRUPT
;
183 // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
185 // Since we support only one in-flight descriptor chain, we can always build
186 // that chain starting at entry #0 of the descriptor table.
188 Indices
->HeadDescIdx
= 0;
189 Indices
->NextDescIdx
= Indices
->HeadDescIdx
;
195 Append a contiguous buffer for transmission / reception via the virtio ring.
197 This function implements the following section from virtio-0.9.5:
198 - 2.4.1.1 Placing Buffers into the Descriptor Table
200 Free space is taken as granted, since the individual drivers support only
201 synchronous requests and host side status is processed in lock-step with
202 request submission. It is the calling driver's responsibility to verify the
203 ring size in advance.
205 The caller is responsible for initializing *Indices with VirtioPrepare()
208 @param[in,out] Ring The virtio ring to append the buffer to, as a
211 @param[in] BufferPhysAddr (Guest pseudo-physical) start address of the
212 transmit / receive buffer.
214 @param[in] BufferSize Number of bytes to transmit or receive.
216 @param[in] Flags A bitmask of VRING_DESC_F_* flags. The caller
217 computes this mask dependent on further buffers to
218 append and transfer direction.
219 VRING_DESC_F_INDIRECT is unsupported. The
220 VRING_DESC.Next field is always set, but the host
221 only interprets it dependent on VRING_DESC_F_NEXT.
223 @param[in,out] Indices Indices->HeadDescIdx is not accessed.
224 On input, Indices->NextDescIdx identifies the next
225 descriptor to carry the buffer. On output,
226 Indices->NextDescIdx is incremented by one, modulo
234 IN UINTN BufferPhysAddr
,
235 IN UINT32 BufferSize
,
237 IN OUT DESC_INDICES
*Indices
240 volatile VRING_DESC
*Desc
;
242 Desc
= &Ring
->Desc
[Indices
->NextDescIdx
++ % Ring
->QueueSize
];
243 Desc
->Addr
= BufferPhysAddr
;
244 Desc
->Len
= BufferSize
;
246 Desc
->Next
= Indices
->NextDescIdx
% Ring
->QueueSize
;
252 Notify the host about the descriptor chain just built, and wait until the
255 @param[in] VirtIo The target virtio device to notify.
257 @param[in] VirtQueueId Identifies the queue for the target device.
259 @param[in,out] Ring The virtio ring with descriptors to submit.
261 @param[in] Indices Indices->NextDescIdx is not accessed.
262 Indices->HeadDescIdx identifies the head descriptor
263 of the descriptor chain.
265 @param[out] UsedLen On success, the total number of bytes, consecutively
266 across the buffers linked by the descriptor chain,
267 that the host wrote. May be NULL if the caller
268 doesn't care, or can compute the same information
269 from device-specific request structures linked by the
272 @return Error code from VirtIo->SetQueueNotify() if it fails.
274 @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
280 IN VIRTIO_DEVICE_PROTOCOL
*VirtIo
,
281 IN UINT16 VirtQueueId
,
283 IN DESC_INDICES
*Indices
,
284 OUT UINT32
*UsedLen OPTIONAL
290 UINTN PollPeriodUsecs
;
293 // virtio-0.9.5, 2.4.1.2 Updating the Available Ring
295 // It is not exactly clear from the wording of the virtio-0.9.5
296 // specification, but each entry in the Available Ring references only the
297 // head descriptor of any given descriptor chain.
299 NextAvailIdx
= *Ring
->Avail
.Idx
;
301 // (Due to our lock-step progress, this is where the host will produce the
302 // used element with the head descriptor's index in it.)
304 LastUsedIdx
= NextAvailIdx
;
305 Ring
->Avail
.Ring
[NextAvailIdx
++ % Ring
->QueueSize
] =
306 Indices
->HeadDescIdx
% Ring
->QueueSize
;
309 // virtio-0.9.5, 2.4.1.3 Updating the Index Field
312 *Ring
->Avail
.Idx
= NextAvailIdx
;
315 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
319 Status
= VirtIo
->SetQueueNotify (VirtIo
, VirtQueueId
);
320 if (EFI_ERROR (Status
)) {
325 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
326 // Wait until the host processes and acknowledges our descriptor chain. The
327 // condition we use for polling is greatly simplified and relies on the
328 // synchronous, lock-step progress.
330 // Keep slowing down until we reach a poll period of slightly above 1 ms.
334 while (*Ring
->Used
.Idx
!= NextAvailIdx
) {
335 gBS
->Stall (PollPeriodUsecs
); // calls AcpiTimerLib::MicroSecondDelay
337 if (PollPeriodUsecs
< 1024) {
338 PollPeriodUsecs
*= 2;
345 if (UsedLen
!= NULL
) {
346 volatile CONST VRING_USED_ELEM
*UsedElem
;
348 UsedElem
= &Ring
->Used
.UsedElem
[LastUsedIdx
% Ring
->QueueSize
];
349 ASSERT (UsedElem
->Id
== Indices
->HeadDescIdx
);
350 *UsedLen
= UsedElem
->Len
;
359 Report the feature bits to the VirtIo 1.0 device that the VirtIo 1.0 driver
362 In VirtIo 1.0, a device can reject a self-inconsistent feature bitmap through
363 the new VSTAT_FEATURES_OK status bit. (For example if the driver requests a
364 higher level feature but clears a prerequisite feature.) This function is a
365 small wrapper around VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures() that also
366 verifies if the VirtIo 1.0 device accepts the feature bitmap.
368 @param[in] VirtIo Report feature bits to this device.
370 @param[in] Features The set of feature bits that the driver wishes
371 to report. The caller is responsible to perform
372 any masking before calling this function; the
373 value is directly written with
374 VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures().
376 @param[in,out] DeviceStatus On input, the status byte most recently written
377 to the device's status register. On output (even
378 on error), DeviceStatus will be updated so that
379 it is suitable for further status bit
380 manipulation and writing to the device's status
383 @retval EFI_SUCCESS The device accepted the configuration in Features.
385 @return EFI_UNSUPPORTED The device rejected the configuration in Features.
387 @retval EFI_UNSUPPORTED VirtIo->Revision is smaller than 1.0.0.
389 @return Error codes from the SetGuestFeatures(),
390 SetDeviceStatus(), GetDeviceStatus() member
396 Virtio10WriteFeatures (
397 IN VIRTIO_DEVICE_PROTOCOL
*VirtIo
,
399 IN OUT UINT8
*DeviceStatus
404 if (VirtIo
->Revision
< VIRTIO_SPEC_REVISION (1, 0, 0)) {
405 return EFI_UNSUPPORTED
;
408 Status
= VirtIo
->SetGuestFeatures (VirtIo
, Features
);
409 if (EFI_ERROR (Status
)) {
413 *DeviceStatus
|= VSTAT_FEATURES_OK
;
414 Status
= VirtIo
->SetDeviceStatus (VirtIo
, *DeviceStatus
);
415 if (EFI_ERROR (Status
)) {
419 Status
= VirtIo
->GetDeviceStatus (VirtIo
, DeviceStatus
);
420 if (EFI_ERROR (Status
)) {
424 if ((*DeviceStatus
& VSTAT_FEATURES_OK
) == 0) {
425 Status
= EFI_UNSUPPORTED
;
432 Provides the virtio device address required to access system memory from a
435 The interface follows the same usage pattern as defined in UEFI spec 2.6
436 (Section 13.2 PCI Root Bridge I/O Protocol)
438 The VirtioMapAllBytesInSharedBuffer() is similar to VIRTIO_MAP_SHARED
439 with exception that NumberOfBytes is IN-only parameter. The function
440 maps all the bytes specified in NumberOfBytes param in one consecutive
443 @param[in] VirtIo The virtio device for which the mapping is
446 @param[in] Operation Indicates if the bus master is going to
447 read or write to system memory.
449 @param[in] HostAddress The system memory address to map to shared
452 @param[in] NumberOfBytes Number of bytes to map.
454 @param[out] DeviceAddress The resulting shared map address for the
455 bus master to access the hosts HostAddress.
457 @param[out] Mapping A resulting token to pass to
461 @retval EFI_SUCCESS The NumberOfBytes is succesfully mapped.
462 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a
464 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
465 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
466 a lack of resources. This includes the case
467 when NumberOfBytes bytes cannot be mapped
468 in one consecutive range.
469 @retval EFI_DEVICE_ERROR The system hardware could not map the
474 VirtioMapAllBytesInSharedBuffer (
475 IN VIRTIO_DEVICE_PROTOCOL
*VirtIo
,
476 IN VIRTIO_MAP_OPERATION Operation
,
477 IN VOID
*HostAddress
,
478 IN UINTN NumberOfBytes
,
479 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
486 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
488 Size
= NumberOfBytes
;
489 Status
= VirtIo
->MapSharedBuffer (
497 if (EFI_ERROR (Status
)) {
501 if (Size
< NumberOfBytes
) {
506 *DeviceAddress
= PhysicalAddress
;
511 VirtIo
->UnmapSharedBuffer (VirtIo
, MapInfo
);
512 return EFI_OUT_OF_RESOURCES
;
517 Map the ring buffer so that it can be accessed equally by both guest
520 @param[in] VirtIo The virtio device instance.
522 @param[in] Ring The virtio ring to map.
524 @param[out] RingBaseShift A resulting translation offset, to be
525 passed to VirtIo->SetQueueAddress().
527 @param[out] Mapping A resulting token to pass to
528 VirtIo->UnmapSharedBuffer().
530 @return Status code from VirtIo->MapSharedBuffer()
535 IN VIRTIO_DEVICE_PROTOCOL
*VirtIo
,
537 OUT UINT64
*RingBaseShift
,
542 EFI_PHYSICAL_ADDRESS DeviceAddress
;
544 Status
= VirtioMapAllBytesInSharedBuffer (
546 VirtioOperationBusMasterCommonBuffer
,
548 EFI_PAGES_TO_SIZE (Ring
->NumPages
),
552 if (EFI_ERROR (Status
)) {
556 *RingBaseShift
= DeviceAddress
- (UINT64
)(UINTN
)Ring
->Base
;