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>
12 Copyright (C) 2016, Linaro Ltd.
14 This program and the accompanying materials are licensed and made available
15 under the terms and conditions of the BSD License which accompanies this
16 distribution. The full text of the license may be found at
17 http://opensource.org/licenses/bsd-license.php
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
20 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/MemoryAllocationLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/UefiLib.h>
29 #include <Library/VirtioLib.h>
31 #include "VirtioRng.h"
34 Returns information about the random number generation implementation.
36 @param[in] This A pointer to the EFI_RNG_PROTOCOL
38 @param[in,out] RNGAlgorithmListSize On input, the size in bytes of
40 On output with a return code of
41 EFI_SUCCESS, the size in bytes of the
42 data returned in RNGAlgorithmList. On
43 output with a return code of
44 EFI_BUFFER_TOO_SMALL, the size of
45 RNGAlgorithmList required to obtain the
47 @param[out] RNGAlgorithmList A caller-allocated memory buffer filled
48 by the driver with one EFI_RNG_ALGORITHM
49 element for each supported RNG algorithm.
50 The list must not change across multiple
51 calls to the same driver. The first
52 algorithm in the list is the default
53 algorithm for the driver.
55 @retval EFI_SUCCESS The RNG algorithm list was returned
57 @retval EFI_UNSUPPORTED The services is not supported by this
59 @retval EFI_DEVICE_ERROR The list of algorithms could not be
60 retrieved due to a hardware or firmware
62 @retval EFI_INVALID_PARAMETER One or more of the parameters are
64 @retval EFI_BUFFER_TOO_SMALL The buffer RNGAlgorithmList is too small
72 IN EFI_RNG_PROTOCOL
*This
,
73 IN OUT UINTN
*RNGAlgorithmListSize
,
74 OUT EFI_RNG_ALGORITHM
*RNGAlgorithmList
77 if (This
== NULL
|| RNGAlgorithmListSize
== NULL
) {
78 return EFI_INVALID_PARAMETER
;
81 if (*RNGAlgorithmListSize
< sizeof (EFI_RNG_ALGORITHM
)) {
82 *RNGAlgorithmListSize
= sizeof (EFI_RNG_ALGORITHM
);
83 return EFI_BUFFER_TOO_SMALL
;
86 if (RNGAlgorithmList
== NULL
) {
87 return EFI_INVALID_PARAMETER
;
90 *RNGAlgorithmListSize
= sizeof (EFI_RNG_ALGORITHM
);
91 CopyGuid (RNGAlgorithmList
, &gEfiRngAlgorithmRaw
);
97 Produces and returns an RNG value using either the default or specified RNG
100 @param[in] This A pointer to the EFI_RNG_PROTOCOL
102 @param[in] RNGAlgorithm A pointer to the EFI_RNG_ALGORITHM that
103 identifies the RNG algorithm to use. May
104 be NULL in which case the function will
105 use its default RNG algorithm.
106 @param[in] RNGValueLength The length in bytes of the memory buffer
107 pointed to by RNGValue. The driver shall
108 return exactly this numbers of bytes.
109 @param[out] RNGValue A caller-allocated memory buffer filled
110 by the driver with the resulting RNG
113 @retval EFI_SUCCESS The RNG value was returned successfully.
114 @retval EFI_UNSUPPORTED The algorithm specified by RNGAlgorithm
115 is not supported by this driver.
116 @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due
117 to a hardware or firmware error.
118 @retval EFI_NOT_READY There is not enough random data available
119 to satisfy the length requested by
121 @retval EFI_INVALID_PARAMETER RNGValue is NULL or RNGValueLength is
129 IN EFI_RNG_PROTOCOL
*This
,
130 IN EFI_RNG_ALGORITHM
*RNGAlgorithm
, OPTIONAL
131 IN UINTN RNGValueLength
,
136 DESC_INDICES Indices
;
137 volatile UINT8
*Buffer
;
143 if (This
== NULL
|| RNGValueLength
== 0 || RNGValue
== NULL
) {
144 return EFI_INVALID_PARAMETER
;
148 // We only support the raw algorithm, so reject requests for anything else
150 if (RNGAlgorithm
!= NULL
&&
151 !CompareGuid (RNGAlgorithm
, &gEfiRngAlgorithmRaw
)) {
152 return EFI_UNSUPPORTED
;
155 Buffer
= (volatile UINT8
*)AllocatePool (RNGValueLength
);
156 if (Buffer
== NULL
) {
157 return EFI_DEVICE_ERROR
;
160 Dev
= VIRTIO_ENTROPY_SOURCE_FROM_RNG (This
);
163 // The Virtio RNG device may return less data than we asked it to, and can
164 // only return MAX_UINT32 bytes per invocation. So loop as long as needed to
165 // get all the entropy we were asked for.
167 for (Index
= 0; Index
< RNGValueLength
; Index
+= Len
) {
168 BufferSize
= (UINT32
)MIN (RNGValueLength
- Index
, (UINTN
)MAX_UINT32
);
170 VirtioPrepare (&Dev
->Ring
, &Indices
);
171 VirtioAppendDesc (&Dev
->Ring
,
172 (UINTN
)Buffer
+ Index
,
177 if (VirtioFlush (Dev
->VirtIo
, 0, &Dev
->Ring
, &Indices
, &Len
) !=
179 Status
= EFI_DEVICE_ERROR
;
183 ASSERT (Len
<= BufferSize
);
186 for (Index
= 0; Index
< RNGValueLength
; Index
++) {
187 RNGValue
[Index
] = Buffer
[Index
];
189 Status
= EFI_SUCCESS
;
192 FreePool ((VOID
*)Buffer
);
200 IN OUT VIRTIO_RNG_DEV
*Dev
209 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
211 NextDevStat
= 0; // step 1 -- reset device
212 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
213 if (EFI_ERROR (Status
)) {
217 NextDevStat
|= VSTAT_ACK
; // step 2 -- acknowledge device presence
218 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
219 if (EFI_ERROR (Status
)) {
223 NextDevStat
|= VSTAT_DRIVER
; // step 3 -- we know how to drive it
224 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
225 if (EFI_ERROR (Status
)) {
230 // Set Page Size - MMIO VirtIo Specific
232 Status
= Dev
->VirtIo
->SetPageSize (Dev
->VirtIo
, EFI_PAGE_SIZE
);
233 if (EFI_ERROR (Status
)) {
238 // step 4a -- retrieve and validate features
240 Status
= Dev
->VirtIo
->GetDeviceFeatures (Dev
->VirtIo
, &Features
);
241 if (EFI_ERROR (Status
)) {
246 // step 4b -- allocate request virtqueue, just use #0
248 Status
= Dev
->VirtIo
->SetQueueSel (Dev
->VirtIo
, 0);
249 if (EFI_ERROR (Status
)) {
252 Status
= Dev
->VirtIo
->GetQueueNumMax (Dev
->VirtIo
, &QueueSize
);
253 if (EFI_ERROR (Status
)) {
258 // VirtioRngGetRNG() uses one descriptor
261 Status
= EFI_UNSUPPORTED
;
265 Status
= VirtioRingInit (QueueSize
, &Dev
->Ring
);
266 if (EFI_ERROR (Status
)) {
271 // Additional steps for MMIO: align the queue appropriately, and set the
272 // size. If anything fails from here on, we must release the ring resources.
274 Status
= Dev
->VirtIo
->SetQueueNum (Dev
->VirtIo
, QueueSize
);
275 if (EFI_ERROR (Status
)) {
279 Status
= Dev
->VirtIo
->SetQueueAlign (Dev
->VirtIo
, EFI_PAGE_SIZE
);
280 if (EFI_ERROR (Status
)) {
285 // step 4c -- Report GPFN (guest-physical frame number) of queue.
287 Status
= Dev
->VirtIo
->SetQueueAddress (Dev
->VirtIo
, &Dev
->Ring
);
288 if (EFI_ERROR (Status
)) {
293 // step 5 -- Report understood features and guest-tuneables. None are
294 // currently defined for VirtioRng, and no generic features are needed by
297 Status
= Dev
->VirtIo
->SetGuestFeatures (Dev
->VirtIo
, 0);
298 if (EFI_ERROR (Status
)) {
303 // step 6 -- initialization complete
305 NextDevStat
|= VSTAT_DRIVER_OK
;
306 Status
= Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
307 if (EFI_ERROR (Status
)) {
312 // populate the exported interface's attributes
314 Dev
->Rng
.GetInfo
= VirtioRngGetInfo
;
315 Dev
->Rng
.GetRNG
= VirtioRngGetRNG
;
320 VirtioRingUninit (&Dev
->Ring
);
324 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
325 // Status. VirtIo access failure here should not mask the original error.
327 NextDevStat
|= VSTAT_FAILED
;
328 Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, NextDevStat
);
330 return Status
; // reached only via Failed above
338 IN OUT VIRTIO_RNG_DEV
*Dev
342 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
343 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
344 // the old comms area.
346 Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, 0);
347 VirtioRingUninit (&Dev
->Ring
);
351 // Event notification function enqueued by ExitBootServices().
365 // Reset the device. This causes the hypervisor to forget about the virtio
368 // We allocated said ring in EfiBootServicesData type memory, and code
369 // executing after ExitBootServices() is permitted to overwrite it.
372 Dev
->VirtIo
->SetDeviceStatus (Dev
->VirtIo
, 0);
377 // Probe, start and stop functions of this driver, called by the DXE core for
380 // The following specifications document these interfaces:
381 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
382 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
384 // The implementation follows:
385 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
386 // - 5.1.3.4 OpenProtocol() and CloseProtocol()
387 // - UEFI Spec 2.3.1 + Errata C
388 // - 6.3 Protocol Handler Services
394 VirtioRngDriverBindingSupported (
395 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
396 IN EFI_HANDLE DeviceHandle
,
397 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
401 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
404 // Attempt to open the device with the VirtIo set of interfaces. On success,
405 // the protocol is "instantiated" for the VirtIo device. Covers duplicate
406 // open attempts (EFI_ALREADY_STARTED).
408 Status
= gBS
->OpenProtocol (
409 DeviceHandle
, // candidate device
410 &gVirtioDeviceProtocolGuid
, // for generic VirtIo access
411 (VOID
**)&VirtIo
, // handle to instantiate
412 This
->DriverBindingHandle
, // requestor driver identity
413 DeviceHandle
, // ControllerHandle, according to
414 // the UEFI Driver Model
415 EFI_OPEN_PROTOCOL_BY_DRIVER
// get exclusive VirtIo access to
416 // the device; to be released
418 if (EFI_ERROR (Status
)) {
422 if (VirtIo
->SubSystemDeviceId
!= VIRTIO_SUBSYSTEM_ENTROPY_SOURCE
) {
423 Status
= EFI_UNSUPPORTED
;
427 // We needed VirtIo access only transitorily, to see whether we support the
430 gBS
->CloseProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
431 This
->DriverBindingHandle
, DeviceHandle
);
438 VirtioRngDriverBindingStart (
439 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
440 IN EFI_HANDLE DeviceHandle
,
441 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
447 Dev
= (VIRTIO_RNG_DEV
*) AllocateZeroPool (sizeof *Dev
);
449 return EFI_OUT_OF_RESOURCES
;
452 Status
= gBS
->OpenProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
453 (VOID
**)&Dev
->VirtIo
, This
->DriverBindingHandle
,
454 DeviceHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
455 if (EFI_ERROR (Status
)) {
460 // VirtIo access granted, configure virtio-rng device.
462 Status
= VirtioRngInit (Dev
);
463 if (EFI_ERROR (Status
)) {
467 Status
= gBS
->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES
, TPL_CALLBACK
,
468 &VirtioRngExitBoot
, Dev
, &Dev
->ExitBoot
);
469 if (EFI_ERROR (Status
)) {
474 // Setup complete, attempt to export the driver instance's EFI_RNG_PROTOCOL
477 Dev
->Signature
= VIRTIO_RNG_SIG
;
478 Status
= gBS
->InstallProtocolInterface (&DeviceHandle
,
479 &gEfiRngProtocolGuid
, EFI_NATIVE_INTERFACE
,
481 if (EFI_ERROR (Status
)) {
488 gBS
->CloseEvent (Dev
->ExitBoot
);
491 VirtioRngUninit (Dev
);
494 gBS
->CloseProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
495 This
->DriverBindingHandle
, DeviceHandle
);
507 VirtioRngDriverBindingStop (
508 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
509 IN EFI_HANDLE DeviceHandle
,
510 IN UINTN NumberOfChildren
,
511 IN EFI_HANDLE
*ChildHandleBuffer
515 EFI_RNG_PROTOCOL
*Rng
;
518 Status
= gBS
->OpenProtocol (
519 DeviceHandle
, // candidate device
520 &gEfiRngProtocolGuid
, // retrieve the RNG iface
521 (VOID
**)&Rng
, // target pointer
522 This
->DriverBindingHandle
, // requestor driver ident.
523 DeviceHandle
, // lookup req. for dev.
524 EFI_OPEN_PROTOCOL_GET_PROTOCOL
// lookup only, no new ref.
526 if (EFI_ERROR (Status
)) {
530 Dev
= VIRTIO_ENTROPY_SOURCE_FROM_RNG (Rng
);
533 // Handle Stop() requests for in-use driver instances gracefully.
535 Status
= gBS
->UninstallProtocolInterface (DeviceHandle
,
536 &gEfiRngProtocolGuid
, &Dev
->Rng
);
537 if (EFI_ERROR (Status
)) {
541 gBS
->CloseEvent (Dev
->ExitBoot
);
543 VirtioRngUninit (Dev
);
545 gBS
->CloseProtocol (DeviceHandle
, &gVirtioDeviceProtocolGuid
,
546 This
->DriverBindingHandle
, DeviceHandle
);
555 // The static object that groups the Supported() (ie. probe), Start() and
556 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
557 // C, 10.1 EFI Driver Binding Protocol.
559 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding
= {
560 &VirtioRngDriverBindingSupported
,
561 &VirtioRngDriverBindingStart
,
562 &VirtioRngDriverBindingStop
,
563 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
564 NULL
, // ImageHandle, to be overwritten by
565 // EfiLibInstallDriverBindingComponentName2() in VirtioRngEntryPoint()
566 NULL
// DriverBindingHandle, ditto
571 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
572 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
573 // in English, for display on standard console devices. This is recommended for
574 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
575 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
579 EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
580 { "eng;en", L
"Virtio Random Number Generator Driver" },
585 EFI_COMPONENT_NAME_PROTOCOL gComponentName
;
590 VirtioRngGetDriverName (
591 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
593 OUT CHAR16
**DriverName
596 return LookupUnicodeString2 (
598 This
->SupportedLanguages
,
601 (BOOLEAN
)(This
== &gComponentName
) // Iso639Language
608 VirtioRngGetDeviceName (
609 IN EFI_COMPONENT_NAME_PROTOCOL
*This
,
610 IN EFI_HANDLE DeviceHandle
,
611 IN EFI_HANDLE ChildHandle
,
613 OUT CHAR16
**ControllerName
616 return EFI_UNSUPPORTED
;
620 EFI_COMPONENT_NAME_PROTOCOL gComponentName
= {
621 &VirtioRngGetDriverName
,
622 &VirtioRngGetDeviceName
,
623 "eng" // SupportedLanguages, ISO 639-2 language codes
627 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2
= {
628 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME
) &VirtioRngGetDriverName
,
629 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME
) &VirtioRngGetDeviceName
,
630 "en" // SupportedLanguages, RFC 4646 language codes
635 // Entry point of this driver.
639 VirtioRngEntryPoint (
640 IN EFI_HANDLE ImageHandle
,
641 IN EFI_SYSTEM_TABLE
*SystemTable
644 return EfiLibInstallDriverBindingComponentName2 (