| /** @file | |
| This driver produces EFI_RNG_PROTOCOL instances for virtio-rng devices. | |
| The implementation is based on OvmfPkg/VirtioScsiDxe/VirtioScsi.c | |
| Copyright (C) 2012, Red Hat, Inc. | |
| Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR> | |
| This driver: | |
| Copyright (C) 2016, Linaro Ltd. | |
| This program and the accompanying materials are licensed and made available | |
| under the terms and conditions of the BSD License which accompanies this | |
| distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT | |
| WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/VirtioLib.h> | |
| #include "VirtioRng.h" | |
| /** | |
| Returns information about the random number generation implementation. | |
| @param[in] This A pointer to the EFI_RNG_PROTOCOL | |
| instance. | |
| @param[in,out] RNGAlgorithmListSize On input, the size in bytes of | |
| RNGAlgorithmList. | |
| On output with a return code of | |
| EFI_SUCCESS, the size in bytes of the | |
| data returned in RNGAlgorithmList. On | |
| output with a return code of | |
| EFI_BUFFER_TOO_SMALL, the size of | |
| RNGAlgorithmList required to obtain the | |
| list. | |
| @param[out] RNGAlgorithmList A caller-allocated memory buffer filled | |
| by the driver with one EFI_RNG_ALGORITHM | |
| element for each supported RNG algorithm. | |
| The list must not change across multiple | |
| calls to the same driver. The first | |
| algorithm in the list is the default | |
| algorithm for the driver. | |
| @retval EFI_SUCCESS The RNG algorithm list was returned | |
| successfully. | |
| @retval EFI_UNSUPPORTED The services is not supported by this | |
| driver. | |
| @retval EFI_DEVICE_ERROR The list of algorithms could not be | |
| retrieved due to a hardware or firmware | |
| error. | |
| @retval EFI_INVALID_PARAMETER One or more of the parameters are | |
| incorrect. | |
| @retval EFI_BUFFER_TOO_SMALL The buffer RNGAlgorithmList is too small | |
| to hold the result. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngGetInfo ( | |
| IN EFI_RNG_PROTOCOL *This, | |
| IN OUT UINTN *RNGAlgorithmListSize, | |
| OUT EFI_RNG_ALGORITHM *RNGAlgorithmList | |
| ) | |
| { | |
| if (This == NULL || RNGAlgorithmListSize == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (*RNGAlgorithmListSize < sizeof (EFI_RNG_ALGORITHM)) { | |
| *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM); | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| if (RNGAlgorithmList == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM); | |
| CopyGuid (RNGAlgorithmList, &gEfiRngAlgorithmRaw); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Produces and returns an RNG value using either the default or specified RNG | |
| algorithm. | |
| @param[in] This A pointer to the EFI_RNG_PROTOCOL | |
| instance. | |
| @param[in] RNGAlgorithm A pointer to the EFI_RNG_ALGORITHM that | |
| identifies the RNG algorithm to use. May | |
| be NULL in which case the function will | |
| use its default RNG algorithm. | |
| @param[in] RNGValueLength The length in bytes of the memory buffer | |
| pointed to by RNGValue. The driver shall | |
| return exactly this numbers of bytes. | |
| @param[out] RNGValue A caller-allocated memory buffer filled | |
| by the driver with the resulting RNG | |
| value. | |
| @retval EFI_SUCCESS The RNG value was returned successfully. | |
| @retval EFI_UNSUPPORTED The algorithm specified by RNGAlgorithm | |
| is not supported by this driver. | |
| @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due | |
| to a hardware or firmware error. | |
| @retval EFI_NOT_READY There is not enough random data available | |
| to satisfy the length requested by | |
| RNGValueLength. | |
| @retval EFI_INVALID_PARAMETER RNGValue is NULL or RNGValueLength is | |
| zero. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngGetRNG ( | |
| IN EFI_RNG_PROTOCOL *This, | |
| IN EFI_RNG_ALGORITHM *RNGAlgorithm, OPTIONAL | |
| IN UINTN RNGValueLength, | |
| OUT UINT8 *RNGValue | |
| ) | |
| { | |
| VIRTIO_RNG_DEV *Dev; | |
| DESC_INDICES Indices; | |
| volatile UINT8 *Buffer; | |
| UINTN Index; | |
| UINT32 Len; | |
| UINT32 BufferSize; | |
| EFI_STATUS Status; | |
| if (This == NULL || RNGValueLength == 0 || RNGValue == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // We only support the raw algorithm, so reject requests for anything else | |
| // | |
| if (RNGAlgorithm != NULL && | |
| !CompareGuid (RNGAlgorithm, &gEfiRngAlgorithmRaw)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| Buffer = (volatile UINT8 *)AllocatePool (RNGValueLength); | |
| if (Buffer == NULL) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| Dev = VIRTIO_ENTROPY_SOURCE_FROM_RNG (This); | |
| // | |
| // The Virtio RNG device may return less data than we asked it to, and can | |
| // only return MAX_UINT32 bytes per invocation. So loop as long as needed to | |
| // get all the entropy we were asked for. | |
| // | |
| for (Index = 0; Index < RNGValueLength; Index += Len) { | |
| BufferSize = (UINT32)MIN (RNGValueLength - Index, (UINTN)MAX_UINT32); | |
| VirtioPrepare (&Dev->Ring, &Indices); | |
| VirtioAppendDesc (&Dev->Ring, | |
| (UINTN)Buffer + Index, | |
| BufferSize, | |
| VRING_DESC_F_WRITE, | |
| &Indices); | |
| if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices, &Len) != | |
| EFI_SUCCESS) { | |
| Status = EFI_DEVICE_ERROR; | |
| goto FreeBuffer; | |
| } | |
| ASSERT (Len > 0); | |
| ASSERT (Len <= BufferSize); | |
| } | |
| for (Index = 0; Index < RNGValueLength; Index++) { | |
| RNGValue[Index] = Buffer[Index]; | |
| } | |
| Status = EFI_SUCCESS; | |
| FreeBuffer: | |
| FreePool ((VOID *)Buffer); | |
| return Status; | |
| } | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngInit ( | |
| IN OUT VIRTIO_RNG_DEV *Dev | |
| ) | |
| { | |
| UINT8 NextDevStat; | |
| EFI_STATUS Status; | |
| UINT16 QueueSize; | |
| UINT64 Features; | |
| // | |
| // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence. | |
| // | |
| NextDevStat = 0; // step 1 -- reset device | |
| Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence | |
| Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it | |
| Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| // | |
| // Set Page Size - MMIO VirtIo Specific | |
| // | |
| Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| // | |
| // step 4a -- retrieve and validate features | |
| // | |
| Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| Features &= VIRTIO_F_VERSION_1; | |
| // | |
| // In virtio-1.0, feature negotiation is expected to complete before queue | |
| // discovery, and the device can also reject the selected set of features. | |
| // | |
| if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) { | |
| Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| } | |
| // | |
| // step 4b -- allocate request virtqueue, just use #0 | |
| // | |
| Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| // | |
| // VirtioRngGetRNG() uses one descriptor | |
| // | |
| if (QueueSize < 1) { | |
| Status = EFI_UNSUPPORTED; | |
| goto Failed; | |
| } | |
| Status = VirtioRingInit (QueueSize, &Dev->Ring); | |
| if (EFI_ERROR (Status)) { | |
| goto Failed; | |
| } | |
| // | |
| // Additional steps for MMIO: align the queue appropriately, and set the | |
| // size. If anything fails from here on, we must release the ring resources. | |
| // | |
| Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize); | |
| if (EFI_ERROR (Status)) { | |
| goto ReleaseQueue; | |
| } | |
| Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE); | |
| if (EFI_ERROR (Status)) { | |
| goto ReleaseQueue; | |
| } | |
| // | |
| // step 4c -- Report GPFN (guest-physical frame number) of queue. | |
| // | |
| Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, &Dev->Ring); | |
| if (EFI_ERROR (Status)) { | |
| goto ReleaseQueue; | |
| } | |
| // | |
| // step 5 -- Report understood features and guest-tuneables. | |
| // | |
| if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) { | |
| Features &= ~(UINT64)VIRTIO_F_VERSION_1; | |
| Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features); | |
| if (EFI_ERROR (Status)) { | |
| goto ReleaseQueue; | |
| } | |
| } | |
| // | |
| // step 6 -- initialization complete | |
| // | |
| NextDevStat |= VSTAT_DRIVER_OK; | |
| Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); | |
| if (EFI_ERROR (Status)) { | |
| goto ReleaseQueue; | |
| } | |
| // | |
| // populate the exported interface's attributes | |
| // | |
| Dev->Rng.GetInfo = VirtioRngGetInfo; | |
| Dev->Rng.GetRNG = VirtioRngGetRNG; | |
| return EFI_SUCCESS; | |
| ReleaseQueue: | |
| VirtioRingUninit (&Dev->Ring); | |
| Failed: | |
| // | |
| // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device | |
| // Status. VirtIo access failure here should not mask the original error. | |
| // | |
| NextDevStat |= VSTAT_FAILED; | |
| Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); | |
| return Status; // reached only via Failed above | |
| } | |
| STATIC | |
| VOID | |
| EFIAPI | |
| VirtioRngUninit ( | |
| IN OUT VIRTIO_RNG_DEV *Dev | |
| ) | |
| { | |
| // | |
| // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When | |
| // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from | |
| // the old comms area. | |
| // | |
| Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); | |
| VirtioRingUninit (&Dev->Ring); | |
| } | |
| // | |
| // Event notification function enqueued by ExitBootServices(). | |
| // | |
| STATIC | |
| VOID | |
| EFIAPI | |
| VirtioRngExitBoot ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| VIRTIO_RNG_DEV *Dev; | |
| // | |
| // Reset the device. This causes the hypervisor to forget about the virtio | |
| // ring. | |
| // | |
| // We allocated said ring in EfiBootServicesData type memory, and code | |
| // executing after ExitBootServices() is permitted to overwrite it. | |
| // | |
| Dev = Context; | |
| Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); | |
| } | |
| // | |
| // Probe, start and stop functions of this driver, called by the DXE core for | |
| // specific devices. | |
| // | |
| // The following specifications document these interfaces: | |
| // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol | |
| // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol | |
| // | |
| // The implementation follows: | |
| // - Driver Writer's Guide for UEFI 2.3.1 v1.01 | |
| // - 5.1.3.4 OpenProtocol() and CloseProtocol() | |
| // - UEFI Spec 2.3.1 + Errata C | |
| // - 6.3 Protocol Handler Services | |
| // | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE DeviceHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VIRTIO_DEVICE_PROTOCOL *VirtIo; | |
| // | |
| // Attempt to open the device with the VirtIo set of interfaces. On success, | |
| // the protocol is "instantiated" for the VirtIo device. Covers duplicate | |
| // open attempts (EFI_ALREADY_STARTED). | |
| // | |
| Status = gBS->OpenProtocol ( | |
| DeviceHandle, // candidate device | |
| &gVirtioDeviceProtocolGuid, // for generic VirtIo access | |
| (VOID **)&VirtIo, // handle to instantiate | |
| This->DriverBindingHandle, // requestor driver identity | |
| DeviceHandle, // ControllerHandle, according to | |
| // the UEFI Driver Model | |
| EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to | |
| // the device; to be released | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) { | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| // | |
| // We needed VirtIo access only transitorily, to see whether we support the | |
| // device or not. | |
| // | |
| gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, | |
| This->DriverBindingHandle, DeviceHandle); | |
| return Status; | |
| } | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE DeviceHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| VIRTIO_RNG_DEV *Dev; | |
| EFI_STATUS Status; | |
| Dev = (VIRTIO_RNG_DEV *) AllocateZeroPool (sizeof *Dev); | |
| if (Dev == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, | |
| (VOID **)&Dev->VirtIo, This->DriverBindingHandle, | |
| DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeVirtioRng; | |
| } | |
| // | |
| // VirtIo access granted, configure virtio-rng device. | |
| // | |
| Status = VirtioRngInit (Dev); | |
| if (EFI_ERROR (Status)) { | |
| goto CloseVirtIo; | |
| } | |
| Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, | |
| &VirtioRngExitBoot, Dev, &Dev->ExitBoot); | |
| if (EFI_ERROR (Status)) { | |
| goto UninitDev; | |
| } | |
| // | |
| // Setup complete, attempt to export the driver instance's EFI_RNG_PROTOCOL | |
| // interface. | |
| // | |
| Dev->Signature = VIRTIO_RNG_SIG; | |
| Status = gBS->InstallProtocolInterface (&DeviceHandle, | |
| &gEfiRngProtocolGuid, EFI_NATIVE_INTERFACE, | |
| &Dev->Rng); | |
| if (EFI_ERROR (Status)) { | |
| goto CloseExitBoot; | |
| } | |
| return EFI_SUCCESS; | |
| CloseExitBoot: | |
| gBS->CloseEvent (Dev->ExitBoot); | |
| UninitDev: | |
| VirtioRngUninit (Dev); | |
| CloseVirtIo: | |
| gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, | |
| This->DriverBindingHandle, DeviceHandle); | |
| FreeVirtioRng: | |
| FreePool (Dev); | |
| return Status; | |
| } | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE DeviceHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_RNG_PROTOCOL *Rng; | |
| VIRTIO_RNG_DEV *Dev; | |
| Status = gBS->OpenProtocol ( | |
| DeviceHandle, // candidate device | |
| &gEfiRngProtocolGuid, // retrieve the RNG iface | |
| (VOID **)&Rng, // target pointer | |
| This->DriverBindingHandle, // requestor driver ident. | |
| DeviceHandle, // lookup req. for dev. | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no new ref. | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Dev = VIRTIO_ENTROPY_SOURCE_FROM_RNG (Rng); | |
| // | |
| // Handle Stop() requests for in-use driver instances gracefully. | |
| // | |
| Status = gBS->UninstallProtocolInterface (DeviceHandle, | |
| &gEfiRngProtocolGuid, &Dev->Rng); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| gBS->CloseEvent (Dev->ExitBoot); | |
| VirtioRngUninit (Dev); | |
| gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, | |
| This->DriverBindingHandle, DeviceHandle); | |
| FreePool (Dev); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // The static object that groups the Supported() (ie. probe), Start() and | |
| // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata | |
| // C, 10.1 EFI Driver Binding Protocol. | |
| // | |
| STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = { | |
| &VirtioRngDriverBindingSupported, | |
| &VirtioRngDriverBindingStart, | |
| &VirtioRngDriverBindingStop, | |
| 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers | |
| NULL, // ImageHandle, to be overwritten by | |
| // EfiLibInstallDriverBindingComponentName2() in VirtioRngEntryPoint() | |
| NULL // DriverBindingHandle, ditto | |
| }; | |
| // | |
| // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and | |
| // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name | |
| // in English, for display on standard console devices. This is recommended for | |
| // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's | |
| // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names. | |
| // | |
| STATIC | |
| EFI_UNICODE_STRING_TABLE mDriverNameTable[] = { | |
| { "eng;en", L"Virtio Random Number Generator Driver" }, | |
| { NULL, NULL } | |
| }; | |
| STATIC | |
| EFI_COMPONENT_NAME_PROTOCOL gComponentName; | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngGetDriverName ( | |
| IN EFI_COMPONENT_NAME_PROTOCOL *This, | |
| IN CHAR8 *Language, | |
| OUT CHAR16 **DriverName | |
| ) | |
| { | |
| return LookupUnicodeString2 ( | |
| Language, | |
| This->SupportedLanguages, | |
| mDriverNameTable, | |
| DriverName, | |
| (BOOLEAN)(This == &gComponentName) // Iso639Language | |
| ); | |
| } | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngGetDeviceName ( | |
| IN EFI_COMPONENT_NAME_PROTOCOL *This, | |
| IN EFI_HANDLE DeviceHandle, | |
| IN EFI_HANDLE ChildHandle, | |
| IN CHAR8 *Language, | |
| OUT CHAR16 **ControllerName | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| STATIC | |
| EFI_COMPONENT_NAME_PROTOCOL gComponentName = { | |
| &VirtioRngGetDriverName, | |
| &VirtioRngGetDeviceName, | |
| "eng" // SupportedLanguages, ISO 639-2 language codes | |
| }; | |
| STATIC | |
| EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = { | |
| (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioRngGetDriverName, | |
| (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioRngGetDeviceName, | |
| "en" // SupportedLanguages, RFC 4646 language codes | |
| }; | |
| // | |
| // Entry point of this driver. | |
| // | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioRngEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| return EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gDriverBinding, | |
| ImageHandle, | |
| &gComponentName, | |
| &gComponentName2 | |
| ); | |
| } |