3 This driver produces EFI_RNG_PROTOCOL instances for virtio-rng devices.
5 The implementation is based on OvmfPkg/VirtioScsiDxe/VirtioScsi.c
7 Copyright (C) 2012, Red Hat, Inc.
8 Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
9 Copyright (c) 2017, AMD Inc, All rights reserved.<BR>
13 Copyright (C) 2016, Linaro Ltd.
15 SPDX-License-Identifier: BSD-2-Clause-Patent
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiLib.h>
24 #include <Library/VirtioLib.h>
26 #include "VirtioRng.h"
29 Returns information about the random number generation implementation.
31 @param[in] This A pointer to the EFI_RNG_PROTOCOL
33 @param[in,out] RNGAlgorithmListSize On input, the size in bytes of
35 On output with a return code of
36 EFI_SUCCESS, the size in bytes of the
37 data returned in RNGAlgorithmList. On
38 output with a return code of
39 EFI_BUFFER_TOO_SMALL, the size of
40 RNGAlgorithmList required to obtain the
42 @param[out] RNGAlgorithmList A caller-allocated memory buffer filled
43 by the driver with one EFI_RNG_ALGORITHM
44 element for each supported RNG algorithm.
45 The list must not change across multiple
46 calls to the same driver. The first
47 algorithm in the list is the default
48 algorithm for the driver.
50 @retval EFI_SUCCESS The RNG algorithm list was returned
52 @retval EFI_UNSUPPORTED The services is not supported by this
54 @retval EFI_DEVICE_ERROR The list of algorithms could not be
55 retrieved due to a hardware or firmware
57 @retval EFI_INVALID_PARAMETER One or more of the parameters are
59 @retval EFI_BUFFER_TOO_SMALL The buffer RNGAlgorithmList is too small
67 IN EFI_RNG_PROTOCOL
*This
,
68 IN OUT UINTN
*RNGAlgorithmListSize
,
69 OUT EFI_RNG_ALGORITHM
*RNGAlgorithmList
72 if ((This
== NULL
) || (RNGAlgorithmListSize
== NULL
)) {
73 return EFI_INVALID_PARAMETER
;
76 if (*RNGAlgorithmListSize
< sizeof (EFI_RNG_ALGORITHM
)) {
77 *RNGAlgorithmListSize
= sizeof (EFI_RNG_ALGORITHM
);
78 return EFI_BUFFER_TOO_SMALL
;
81 if (RNGAlgorithmList
== NULL
) {
82 return EFI_INVALID_PARAMETER
;
85 *RNGAlgorithmListSize
= sizeof (EFI_RNG_ALGORITHM
);
86 CopyGuid (RNGAlgorithmList
, &gEfiRngAlgorithmRaw
);
92 Produces and returns an RNG value using either the default or specified RNG
95 @param[in] This A pointer to the EFI_RNG_PROTOCOL
97 @param[in] RNGAlgorithm A pointer to the EFI_RNG_ALGORITHM that
98 identifies the RNG algorithm to use. May
99 be NULL in which case the function will
100 use its default RNG algorithm.
101 @param[in] RNGValueLength The length in bytes of the memory buffer
102 pointed to by RNGValue. The driver shall
103 return exactly this numbers of bytes.
104 @param[out] RNGValue A caller-allocated memory buffer filled
105 by the driver with the resulting RNG
108 @retval EFI_SUCCESS The RNG value was returned successfully.
109 @retval EFI_UNSUPPORTED The algorithm specified by RNGAlgorithm
110 is not supported by this driver.
111 @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due
112 to a hardware or firmware error.
113 @retval EFI_NOT_READY There is not enough random data available
114 to satisfy the length requested by
116 @retval EFI_INVALID_PARAMETER RNGValue is NULL or RNGValueLength is
124 IN EFI_RNG_PROTOCOL
*This
,
125 IN EFI_RNG_ALGORITHM
*RNGAlgorithm OPTIONAL
,
126 IN UINTN RNGValueLength
,
131 DESC_INDICES Indices
;
132 volatile UINT8
*Buffer
;
137 EFI_PHYSICAL_ADDRESS DeviceAddress
;
140 if ((This
== NULL
) || (RNGValueLength
== 0) || (RNGValue
== NULL
)) {
141 return EFI_INVALID_PARAMETER
;
145 // We only support the raw algorithm, so reject requests for anything else
147 if ((RNGAlgorithm
!= NULL
) &&
148 !CompareGuid (RNGAlgorithm
, &gEfiRngAlgorithmRaw
))
150 return EFI_UNSUPPORTED
;
153 Buffer
= (volatile UINT8
*)AllocatePool (RNGValueLength
);
154 if (Buffer
== NULL
) {
155 return EFI_DEVICE_ERROR
;
158 Dev
= VIRTIO_ENTROPY_SOURCE_FROM_RNG (This
);
160 // Map Buffer's system physical address to device address
162 Status
= VirtioMapAllBytesInSharedBuffer (
164 VirtioOperationBusMasterWrite
,
170 if (EFI_ERROR (Status
)) {
171 Status
= EFI_DEVICE_ERROR
;
176 // The Virtio RNG device may return less data than we asked it to, and can
177 // only return MAX_UINT32 bytes per invocation. So loop as long as needed to
178 // get all the entropy we were asked for.
180 for (Index
= 0; Index
< RNGValueLength
; Index
+= Len
) {
181 BufferSize
= (UINT32
)MIN (RNGValueLength
- Index
, (UINTN
)MAX_UINT32
);
183 VirtioPrepare (&Dev
->Ring
, &Indices
);
186 DeviceAddress
+ Index
,
192 if (VirtioFlush (Dev
->VirtIo
, 0, &Dev
->Ring
, &Indices
, &Len
) !=
195 Status
= EFI_DEVICE_ERROR
;
200 ASSERT (Len
<= BufferSize
);
204 // Unmap the device buffer before accessing it.
206 Status
= Dev
->VirtIo
->UnmapSharedBuffer (Dev
->VirtIo
, Mapping
);
207 if (EFI_ERROR (Status
)) {
208 Status
= EFI_DEVICE_ERROR
;
212 for (Index
= 0; Index
< RNGValueLength
; Index
++) {
213 RNGValue
[Index
] = Buffer
[Index
];
216 Status
= EFI_SUCCESS
;
220 // If we are reached here due to the error then unmap the buffer otherwise
221 // the buffer is already unmapped after VirtioFlush().
223 if (EFI_ERROR (Status
)) {
224 Dev
->VirtIo
->UnmapSharedBuffer (Dev
->VirtIo
, Mapping
);
228 FreePool ((VOID
*)Buffer
);
236 IN OUT VIRTIO_RNG_DEV
*Dev
243 UINT64 RingBaseShift
;
246 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
248 NextDevStat
= 0; // step 1 -- reset device
249 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
250 if (EFI_ERROR (Status
)) {
254 NextDevStat
|= VSTAT_ACK
; // step 2 -- acknowledge device presence
255 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
256 if (EFI_ERROR (Status
)) {
260 NextDevStat
|= VSTAT_DRIVER
; // step 3 -- we know how to drive it
261 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
262 if (EFI_ERROR (Status
)) {
267 // Set Page Size - MMIO VirtIo Specific
269 Status
= Dev
->VirtIo
->SetPageSize (Dev
->VirtIo
, EFI_PAGE_SIZE
);
270 if (EFI_ERROR (Status
)) {
275 // step 4a -- retrieve and validate features
277 Status
= Dev
->VirtIo
->GetDeviceFeatures (Dev
->VirtIo
, &Features
);
278 if (EFI_ERROR (Status
)) {
282 Features
&= VIRTIO_F_VERSION_1
| VIRTIO_F_IOMMU_PLATFORM
;
285 // In virtio-1.0, feature negotiation is expected to complete before queue
286 // discovery, and the device can also reject the selected set of features.
288 if (Dev
->VirtIo
->Revision
>= VIRTIO_SPEC_REVISION (1, 0, 0)) {
289 Status
= Virtio10WriteFeatures (Dev
->VirtIo
, Features
, &NextDevStat
);
290 if (EFI_ERROR (Status
)) {
296 // step 4b -- allocate request virtqueue, just use #0
298 Status
= Dev
->VirtIo
->SetQueueSel (Dev
->VirtIo
, 0);
299 if (EFI_ERROR (Status
)) {
303 Status
= Dev
->VirtIo
->GetQueueNumMax (Dev
->VirtIo
, &QueueSize
);
304 if (EFI_ERROR (Status
)) {
309 // VirtioRngGetRNG() uses one descriptor
312 Status
= EFI_UNSUPPORTED
;
316 Status
= VirtioRingInit (Dev
->VirtIo
, QueueSize
, &Dev
->Ring
);
317 if (EFI_ERROR (Status
)) {
322 // If anything fails from here on, we must release the ring resources.
324 Status
= VirtioRingMap (
330 if (EFI_ERROR (Status
)) {
335 // Additional steps for MMIO: align the queue appropriately, and set the
336 // size. If anything fails from here on, we must unmap the ring resources.
338 Status
= Dev
->VirtIo
->SetQueueNum (Dev
->VirtIo
, QueueSize
);
339 if (EFI_ERROR (Status
)) {
343 Status
= Dev
->VirtIo
->SetQueueAlign (Dev
->VirtIo
, EFI_PAGE_SIZE
);
344 if (EFI_ERROR (Status
)) {
349 // step 4c -- Report GPFN (guest-physical frame number) of queue.
351 Status
= Dev
->VirtIo
->SetQueueAddress (
356 if (EFI_ERROR (Status
)) {
361 // step 5 -- Report understood features and guest-tuneables.
363 if (Dev
->VirtIo
->Revision
< VIRTIO_SPEC_REVISION (1, 0, 0)) {
364 Features
&= ~(UINT64
)(VIRTIO_F_VERSION_1
| VIRTIO_F_IOMMU_PLATFORM
);
365 Status
= Dev
->VirtIo
->SetGuestFeatures (Dev
->VirtIo
, Features
);
366 if (EFI_ERROR (Status
)) {
372 // step 6 -- initialization complete
374 NextDevStat
|= VSTAT_DRIVER_OK
;
375 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
376 if (EFI_ERROR (Status
)) {
381 // populate the exported interface's attributes
383 Dev
->Rng
.GetInfo
= VirtioRngGetInfo
;
384 Dev
->Rng
.GetRNG
= VirtioRngGetRNG
;
389 Dev
->VirtIo
->UnmapSharedBuffer (Dev
->VirtIo
, Dev
->RingMap
);
392 VirtioRingUninit (Dev
->VirtIo
, &Dev
->Ring
);
396 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
397 // Status. VirtIo access failure here should not mask the original error.
399 NextDevStat
|= VSTAT_FAILED
;
400 Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
402 return Status
; // reached only via Failed above
409 IN OUT VIRTIO_RNG_DEV
*Dev
413 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
414 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
415 // the old comms area.
417 Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, 0);
419 Dev
->VirtIo
->UnmapSharedBuffer (Dev
->VirtIo
, Dev
->RingMap
);
421 VirtioRingUninit (Dev
->VirtIo
, &Dev
->Ring
);
425 // Event notification function enqueued by ExitBootServices().
438 DEBUG ((DEBUG_VERBOSE
, "%a: Context=0x%p\n", __FUNCTION__
, Context
));
440 // Reset the device. This causes the hypervisor to forget about the virtio
443 // We allocated said ring in EfiBootServicesData type memory, and code
444 // executing after ExitBootServices() is permitted to overwrite it.
447 Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, 0);
451 // Probe, start and stop functions of this driver, called by the DXE core for
454 // The following specifications document these interfaces:
455 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
456 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
458 // The implementation follows:
459 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
460 // - 5.1.3.4 OpenProtocol() and CloseProtocol()
461 // - UEFI Spec 2.3.1 + Errata C
462 // - 6.3 Protocol Handler Services
468 VirtioRngDriverBindingSupported (
469 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
470 IN EFI_HANDLE DeviceHandle
,
471 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
475 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
478 // Attempt to open the device with the VirtIo set of interfaces. On success,
479 // the protocol is "instantiated" for the VirtIo device. Covers duplicate
480 // open attempts (EFI_ALREADY_STARTED).
482 Status
= gBS
->OpenProtocol (
483 DeviceHandle
, // candidate device
484 &gVirtioDeviceProtocolGuid
, // for generic VirtIo access
485 (VOID
**)&VirtIo
, // handle to instantiate
486 This
->DriverBindingHandle
, // requestor driver identity
487 DeviceHandle
, // ControllerHandle, according to
488 // the UEFI Driver Model
489 EFI_OPEN_PROTOCOL_BY_DRIVER
// get exclusive VirtIo access to
490 // the device; to be released
492 if (EFI_ERROR (Status
)) {
496 if (VirtIo
->SubSystemDeviceId
!= VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
) {
497 Status
= EFI_UNSUPPORTED
;
501 // We needed VirtIo access only transitorily, to see whether we support the
506 &gVirtioDeviceProtocolGuid
,
507 This
->DriverBindingHandle
,
516 VirtioRngDriverBindingStart (
517 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
518 IN EFI_HANDLE DeviceHandle
,
519 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
525 Dev
= (VIRTIO_RNG_DEV
*)AllocateZeroPool (sizeof *Dev
);
527 return EFI_OUT_OF_RESOURCES
;
530 Status
= gBS
->OpenProtocol (
532 &gVirtioDeviceProtocolGuid
,
533 (VOID
**)&Dev
->VirtIo
,
534 This
->DriverBindingHandle
,
536 EFI_OPEN_PROTOCOL_BY_DRIVER
538 if (EFI_ERROR (Status
)) {
543 // VirtIo access granted, configure virtio-rng device.
545 Status
= VirtioRngInit (Dev
);
546 if (EFI_ERROR (Status
)) {
550 Status
= gBS
->CreateEvent (
551 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
557 if (EFI_ERROR (Status
)) {
562 // Setup complete, attempt to export the driver instance's EFI_RNG_PROTOCOL
565 Dev
->Signature
= VIRTIO_RNG_SIG
;
566 Status
= gBS
->InstallProtocolInterface (
568 &gEfiRngProtocolGuid
,
569 EFI_NATIVE_INTERFACE
,
572 if (EFI_ERROR (Status
)) {
579 gBS
->CloseEvent (Dev
->ExitBoot
);
582 VirtioRngUninit (Dev
);
587 &gVirtioDeviceProtocolGuid
,
588 This
->DriverBindingHandle
,
601 VirtioRngDriverBindingStop (
602 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
603 IN EFI_HANDLE DeviceHandle
,
604 IN UINTN NumberOfChildren
,
605 IN EFI_HANDLE
*ChildHandleBuffer
609 EFI_RNG_PROTOCOL
*Rng
;
612 Status
= gBS
->OpenProtocol (
613 DeviceHandle
, // candidate device
614 &gEfiRngProtocolGuid
, // retrieve the RNG iface
615 (VOID
**)&Rng
, // target pointer
616 This
->DriverBindingHandle
, // requestor driver ident.
617 DeviceHandle
, // lookup req. for dev.
618 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// lookup only, no new ref.
620 if (EFI_ERROR (Status
)) {
624 Dev
= VIRTIO_ENTROPY_SOURCE_FROM_RNG (Rng
);
627 // Handle Stop() requests for in-use driver instances gracefully.
629 Status
= gBS
->UninstallProtocolInterface (
631 &gEfiRngProtocolGuid
,
634 if (EFI_ERROR (Status
)) {
638 gBS
->CloseEvent (Dev
->ExitBoot
);
640 VirtioRngUninit (Dev
);
644 &gVirtioDeviceProtocolGuid
,
645 This
->DriverBindingHandle
,
655 // The static object that groups the Supported() (ie. probe), Start() and
656 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
657 // C, 10.1 EFI Driver Binding Protocol.
659 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding
= {
660 &VirtioRngDriverBindingSupported
,
661 &VirtioRngDriverBindingStart
,
662 &VirtioRngDriverBindingStop
,
663 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
664 NULL
, // ImageHandle, to be overwritten by
665 // EfiLibInstallDriverBindingComponentName2() in VirtioRngEntryPoint()
666 NULL
// DriverBindingHandle, ditto
670 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
671 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
672 // in English, for display on standard console devices. This is recommended for
673 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
674 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
678 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
679 { "eng;en", L
"Virtio Random Number Generator Driver" },
684 EFI_COMPONENT_NAME_PROTOCOL gComponentName
;
689 VirtioRngGetDriverName (
690 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
692 OUT CHAR16
**DriverName
695 return LookupUnicodeString2 (
697 This
->SupportedLanguages
,
700 (BOOLEAN
)(This
== &gComponentName
) // Iso639Language
707 VirtioRngGetDeviceName (
708 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
709 IN EFI_HANDLE DeviceHandle
,
710 IN EFI_HANDLE ChildHandle
,
712 OUT CHAR16
**ControllerName
715 return EFI_UNSUPPORTED
;
719 EFI_COMPONENT_NAME_PROTOCOL gComponentName
= {
720 &VirtioRngGetDriverName
,
721 &VirtioRngGetDeviceName
,
722 "eng" // SupportedLanguages, ISO 639-2 language codes
726 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2
= {
727 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
)&VirtioRngGetDriverName
,
728 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
)&VirtioRngGetDeviceName
,
729 "en" // SupportedLanguages, RFC 4646 language codes
733 // Entry point of this driver.
737 VirtioRngEntryPoint (
738 IN EFI_HANDLE ImageHandle
,
739 IN EFI_SYSTEM_TABLE
*SystemTable
742 return EfiLibInstallDriverBindingComponentName2 (