]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/VirtioLib/VirtioLib.c
78405c7d9d7d42e815d94158e6bf30d0427b3697
[mirror_edk2.git] / OvmfPkg / Library / VirtioLib / VirtioLib.c
1 /** @file
2
3 Utility functions used by virtio device drivers.
4
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>
8
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
13
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.
16
17 **/
18
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24
25 #include <Library/VirtioLib.h>
26
27
28 /**
29
30 Configure a virtio ring.
31
32 This function sets up internal storage (the guest-host communication area)
33 and lays out several "navigation" (ie. no-ownership) pointers to parts of
34 that storage.
35
36 Relevant sections from the virtio-0.9.5 spec:
37 - 1.1 Virtqueues,
38 - 2.3 Virtqueue Configuration.
39
40 @param[in] VirtIo The virtio device which will use the ring.
41
42 @param[in] The number of descriptors to allocate for the
43 virtio ring, as requested by the host.
44
45 @param[out] Ring The virtio ring to set up.
46
47 @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous
48 pages for the requested QueueSize. Fields of
49 Ring have indeterminate value.
50
51 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base
52 (and nothing else) is responsible for
53 deallocation.
54
55 **/
56 EFI_STATUS
57 EFIAPI
58 VirtioRingInit (
59 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
60 IN UINT16 QueueSize,
61 OUT VRING *Ring
62 )
63 {
64 UINTN RingSize;
65 volatile UINT8 *RingPagesPtr;
66
67 RingSize = ALIGN_VALUE (
68 sizeof *Ring->Desc * QueueSize +
69 sizeof *Ring->Avail.Flags +
70 sizeof *Ring->Avail.Idx +
71 sizeof *Ring->Avail.Ring * QueueSize +
72 sizeof *Ring->Avail.UsedEvent,
73 EFI_PAGE_SIZE);
74
75 RingSize += ALIGN_VALUE (
76 sizeof *Ring->Used.Flags +
77 sizeof *Ring->Used.Idx +
78 sizeof *Ring->Used.UsedElem * QueueSize +
79 sizeof *Ring->Used.AvailEvent,
80 EFI_PAGE_SIZE);
81
82 Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);
83 Ring->Base = AllocatePages (Ring->NumPages);
84 if (Ring->Base == NULL) {
85 return EFI_OUT_OF_RESOURCES;
86 }
87 SetMem (Ring->Base, RingSize, 0x00);
88 RingPagesPtr = Ring->Base;
89
90 Ring->Desc = (volatile VOID *) RingPagesPtr;
91 RingPagesPtr += sizeof *Ring->Desc * QueueSize;
92
93 Ring->Avail.Flags = (volatile VOID *) RingPagesPtr;
94 RingPagesPtr += sizeof *Ring->Avail.Flags;
95
96 Ring->Avail.Idx = (volatile VOID *) RingPagesPtr;
97 RingPagesPtr += sizeof *Ring->Avail.Idx;
98
99 Ring->Avail.Ring = (volatile VOID *) RingPagesPtr;
100 RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;
101
102 Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr;
103 RingPagesPtr += sizeof *Ring->Avail.UsedEvent;
104
105 RingPagesPtr = (volatile UINT8 *) Ring->Base +
106 ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base,
107 EFI_PAGE_SIZE);
108
109 Ring->Used.Flags = (volatile VOID *) RingPagesPtr;
110 RingPagesPtr += sizeof *Ring->Used.Flags;
111
112 Ring->Used.Idx = (volatile VOID *) RingPagesPtr;
113 RingPagesPtr += sizeof *Ring->Used.Idx;
114
115 Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;
116 RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;
117
118 Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;
119 RingPagesPtr += sizeof *Ring->Used.AvailEvent;
120
121 Ring->QueueSize = QueueSize;
122 return EFI_SUCCESS;
123 }
124
125
126 /**
127
128 Tear down the internal resources of a configured virtio ring.
129
130 The caller is responsible to stop the host from using this ring before
131 invoking this function: the VSTAT_DRIVER_OK bit must be clear in
132 VhdrDeviceStatus.
133
134 @param[in] VirtIo The virtio device which was using the ring.
135
136 @param[out] Ring The virtio ring to clean up.
137
138 **/
139 VOID
140 EFIAPI
141 VirtioRingUninit (
142 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
143 IN OUT VRING *Ring
144 )
145 {
146 FreePages (Ring->Base, Ring->NumPages);
147 SetMem (Ring, sizeof *Ring, 0x00);
148 }
149
150
151 /**
152
153 Turn off interrupt notifications from the host, and prepare for appending
154 multiple descriptors to the virtio ring.
155
156 The calling driver must be in VSTAT_DRIVER_OK state.
157
158 @param[in,out] Ring The virtio ring we intend to append descriptors to.
159
160 @param[out] Indices The DESC_INDICES structure to initialize.
161
162 **/
163 VOID
164 EFIAPI
165 VirtioPrepare (
166 IN OUT VRING *Ring,
167 OUT DESC_INDICES *Indices
168 )
169 {
170 //
171 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.
172 // We're going to poll the answer, the host should not send an interrupt.
173 //
174 *Ring->Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;
175
176 //
177 // Prepare for virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.
178 //
179 // Since we support only one in-flight descriptor chain, we can always build
180 // that chain starting at entry #0 of the descriptor table.
181 //
182 Indices->HeadDescIdx = 0;
183 Indices->NextDescIdx = Indices->HeadDescIdx;
184 }
185
186
187 /**
188
189 Append a contiguous buffer for transmission / reception via the virtio ring.
190
191 This function implements the following section from virtio-0.9.5:
192 - 2.4.1.1 Placing Buffers into the Descriptor Table
193
194 Free space is taken as granted, since the individual drivers support only
195 synchronous requests and host side status is processed in lock-step with
196 request submission. It is the calling driver's responsibility to verify the
197 ring size in advance.
198
199 The caller is responsible for initializing *Indices with VirtioPrepare()
200 first.
201
202 @param[in,out] Ring The virtio ring to append the buffer to, as a
203 descriptor.
204
205 @param[in] BufferPhysAddr (Guest pseudo-physical) start address of the
206 transmit / receive buffer.
207
208 @param[in] BufferSize Number of bytes to transmit or receive.
209
210 @param[in] Flags A bitmask of VRING_DESC_F_* flags. The caller
211 computes this mask dependent on further buffers to
212 append and transfer direction.
213 VRING_DESC_F_INDIRECT is unsupported. The
214 VRING_DESC.Next field is always set, but the host
215 only interprets it dependent on VRING_DESC_F_NEXT.
216
217 @param[in,out] Indices Indices->HeadDescIdx is not accessed.
218 On input, Indices->NextDescIdx identifies the next
219 descriptor to carry the buffer. On output,
220 Indices->NextDescIdx is incremented by one, modulo
221 2^16.
222
223 **/
224 VOID
225 EFIAPI
226 VirtioAppendDesc (
227 IN OUT VRING *Ring,
228 IN UINTN BufferPhysAddr,
229 IN UINT32 BufferSize,
230 IN UINT16 Flags,
231 IN OUT DESC_INDICES *Indices
232 )
233 {
234 volatile VRING_DESC *Desc;
235
236 Desc = &Ring->Desc[Indices->NextDescIdx++ % Ring->QueueSize];
237 Desc->Addr = BufferPhysAddr;
238 Desc->Len = BufferSize;
239 Desc->Flags = Flags;
240 Desc->Next = Indices->NextDescIdx % Ring->QueueSize;
241 }
242
243
244 /**
245
246 Notify the host about the descriptor chain just built, and wait until the
247 host processes it.
248
249 @param[in] VirtIo The target virtio device to notify.
250
251 @param[in] VirtQueueId Identifies the queue for the target device.
252
253 @param[in,out] Ring The virtio ring with descriptors to submit.
254
255 @param[in] Indices Indices->NextDescIdx is not accessed.
256 Indices->HeadDescIdx identifies the head descriptor
257 of the descriptor chain.
258
259 @param[out] UsedLen On success, the total number of bytes, consecutively
260 across the buffers linked by the descriptor chain,
261 that the host wrote. May be NULL if the caller
262 doesn't care, or can compute the same information
263 from device-specific request structures linked by the
264 descriptor chain.
265
266 @return Error code from VirtIo->SetQueueNotify() if it fails.
267
268 @retval EFI_SUCCESS Otherwise, the host processed all descriptors.
269
270 **/
271 EFI_STATUS
272 EFIAPI
273 VirtioFlush (
274 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
275 IN UINT16 VirtQueueId,
276 IN OUT VRING *Ring,
277 IN DESC_INDICES *Indices,
278 OUT UINT32 *UsedLen OPTIONAL
279 )
280 {
281 UINT16 NextAvailIdx;
282 UINT16 LastUsedIdx;
283 EFI_STATUS Status;
284 UINTN PollPeriodUsecs;
285
286 //
287 // virtio-0.9.5, 2.4.1.2 Updating the Available Ring
288 //
289 // It is not exactly clear from the wording of the virtio-0.9.5
290 // specification, but each entry in the Available Ring references only the
291 // head descriptor of any given descriptor chain.
292 //
293 NextAvailIdx = *Ring->Avail.Idx;
294 //
295 // (Due to our lock-step progress, this is where the host will produce the
296 // used element with the head descriptor's index in it.)
297 //
298 LastUsedIdx = NextAvailIdx;
299 Ring->Avail.Ring[NextAvailIdx++ % Ring->QueueSize] =
300 Indices->HeadDescIdx % Ring->QueueSize;
301
302 //
303 // virtio-0.9.5, 2.4.1.3 Updating the Index Field
304 //
305 MemoryFence();
306 *Ring->Avail.Idx = NextAvailIdx;
307
308 //
309 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are
310 // OK.
311 //
312 MemoryFence();
313 Status = VirtIo->SetQueueNotify (VirtIo, VirtQueueId);
314 if (EFI_ERROR (Status)) {
315 return Status;
316 }
317
318 //
319 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
320 // Wait until the host processes and acknowledges our descriptor chain. The
321 // condition we use for polling is greatly simplified and relies on the
322 // synchronous, lock-step progress.
323 //
324 // Keep slowing down until we reach a poll period of slightly above 1 ms.
325 //
326 PollPeriodUsecs = 1;
327 MemoryFence();
328 while (*Ring->Used.Idx != NextAvailIdx) {
329 gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay
330
331 if (PollPeriodUsecs < 1024) {
332 PollPeriodUsecs *= 2;
333 }
334 MemoryFence();
335 }
336
337 MemoryFence();
338
339 if (UsedLen != NULL) {
340 volatile CONST VRING_USED_ELEM *UsedElem;
341
342 UsedElem = &Ring->Used.UsedElem[LastUsedIdx % Ring->QueueSize];
343 ASSERT (UsedElem->Id == Indices->HeadDescIdx);
344 *UsedLen = UsedElem->Len;
345 }
346
347 return EFI_SUCCESS;
348 }
349
350
351 /**
352
353 Report the feature bits to the VirtIo 1.0 device that the VirtIo 1.0 driver
354 understands.
355
356 In VirtIo 1.0, a device can reject a self-inconsistent feature bitmap through
357 the new VSTAT_FEATURES_OK status bit. (For example if the driver requests a
358 higher level feature but clears a prerequisite feature.) This function is a
359 small wrapper around VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures() that also
360 verifies if the VirtIo 1.0 device accepts the feature bitmap.
361
362 @param[in] VirtIo Report feature bits to this device.
363
364 @param[in] Features The set of feature bits that the driver wishes
365 to report. The caller is responsible to perform
366 any masking before calling this function; the
367 value is directly written with
368 VIRTIO_DEVICE_PROTOCOL.SetGuestFeatures().
369
370 @param[in,out] DeviceStatus On input, the status byte most recently written
371 to the device's status register. On output (even
372 on error), DeviceStatus will be updated so that
373 it is suitable for further status bit
374 manipulation and writing to the device's status
375 register.
376
377 @retval EFI_SUCCESS The device accepted the configuration in Features.
378
379 @return EFI_UNSUPPORTED The device rejected the configuration in Features.
380
381 @retval EFI_UNSUPPORTED VirtIo->Revision is smaller than 1.0.0.
382
383 @return Error codes from the SetGuestFeatures(),
384 SetDeviceStatus(), GetDeviceStatus() member
385 functions.
386
387 **/
388 EFI_STATUS
389 EFIAPI
390 Virtio10WriteFeatures (
391 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
392 IN UINT64 Features,
393 IN OUT UINT8 *DeviceStatus
394 )
395 {
396 EFI_STATUS Status;
397
398 if (VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
399 return EFI_UNSUPPORTED;
400 }
401
402 Status = VirtIo->SetGuestFeatures (VirtIo, Features);
403 if (EFI_ERROR (Status)) {
404 return Status;
405 }
406
407 *DeviceStatus |= VSTAT_FEATURES_OK;
408 Status = VirtIo->SetDeviceStatus (VirtIo, *DeviceStatus);
409 if (EFI_ERROR (Status)) {
410 return Status;
411 }
412
413 Status = VirtIo->GetDeviceStatus (VirtIo, DeviceStatus);
414 if (EFI_ERROR (Status)) {
415 return Status;
416 }
417
418 if ((*DeviceStatus & VSTAT_FEATURES_OK) == 0) {
419 Status = EFI_UNSUPPORTED;
420 }
421
422 return Status;
423 }
424
425 /**
426 Provides the virtio device address required to access system memory from a
427 DMA bus master.
428
429 The interface follows the same usage pattern as defined in UEFI spec 2.6
430 (Section 13.2 PCI Root Bridge I/O Protocol)
431
432 The VirtioMapAllBytesInSharedBuffer() is similar to VIRTIO_MAP_SHARED
433 with exception that NumberOfBytes is IN-only parameter. The function
434 maps all the bytes specified in NumberOfBytes param in one consecutive
435 range.
436
437 @param[in] VirtIo The virtio device for which the mapping is
438 requested.
439
440 @param[in] Operation Indicates if the bus master is going to
441 read or write to system memory.
442
443 @param[in] HostAddress The system memory address to map to shared
444 buffer address.
445
446 @param[in] NumberOfBytes Number of bytes to map.
447
448 @param[out] DeviceAddress The resulting shared map address for the
449 bus master to access the hosts HostAddress.
450
451 @param[out] Mapping A resulting token to pass to
452 VIRTIO_UNMAP_SHARED.
453
454
455 @retval EFI_SUCCESS The NumberOfBytes is succesfully mapped.
456 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a
457 common buffer.
458 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
459 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
460 a lack of resources. This includes the case
461 when NumberOfBytes bytes cannot be mapped
462 in one consecutive range.
463 @retval EFI_DEVICE_ERROR The system hardware could not map the
464 requested address.
465 **/
466 EFI_STATUS
467 EFIAPI
468 VirtioMapAllBytesInSharedBuffer (
469 IN VIRTIO_DEVICE_PROTOCOL *VirtIo,
470 IN VIRTIO_MAP_OPERATION Operation,
471 IN VOID *HostAddress,
472 IN UINTN NumberOfBytes,
473 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
474 OUT VOID **Mapping
475 )
476 {
477 EFI_STATUS Status;
478 VOID *MapInfo;
479 UINTN Size;
480 EFI_PHYSICAL_ADDRESS PhysicalAddress;
481
482 Size = NumberOfBytes;
483 Status = VirtIo->MapSharedBuffer (
484 VirtIo,
485 Operation,
486 HostAddress,
487 &Size,
488 &PhysicalAddress,
489 &MapInfo
490 );
491 if (EFI_ERROR (Status)) {
492 return Status;
493 }
494
495 if (Size < NumberOfBytes) {
496 goto Failed;
497 }
498
499 *Mapping = MapInfo;
500 *DeviceAddress = PhysicalAddress;
501
502 return EFI_SUCCESS;
503
504 Failed:
505 VirtIo->UnmapSharedBuffer (VirtIo, MapInfo);
506 return EFI_OUT_OF_RESOURCES;
507 }