From patchwork Wed Feb 24 08:34:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 62779 Delivered-To: patch@linaro.org Received: by 10.112.43.199 with SMTP id y7csp2271962lbl; Wed, 24 Feb 2016 00:34:55 -0800 (PST) X-Received: by 10.98.64.4 with SMTP id n4mr52684060pfa.58.1456302895563; Wed, 24 Feb 2016 00:34:55 -0800 (PST) Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id 79si3459488pfm.61.2016.02.24.00.34.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 24 Feb 2016 00:34:55 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dkim=neutral (body hash did not verify) header.i=@linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 7CB951A1FAA; Wed, 24 Feb 2016 00:34:58 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-wm0-x232.google.com (mail-wm0-x232.google.com [IPv6:2a00:1450:400c:c09::232]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D728A1A1F25 for ; Wed, 24 Feb 2016 00:34:56 -0800 (PST) Received: by mail-wm0-x232.google.com with SMTP id g62so18770252wme.0 for ; Wed, 24 Feb 2016 00:34:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=b+7a/3oZUmRMX/Mtn5Bp3Nv8PqoO+xGPH6KGRbeBmss=; b=Lw/57evcd5CypOAwmU80EA8WyTBL+sOqgKXAUuBJAchj9lmbxOpDl+uyKcu9rtoKOV 7L3ABkMmboLNTGj447E6qNn1ejvLekDeiwP35hedu8dCVRYMYj/65dYCFadBOO1UnLnv 8U2NYroA8B9u2p8616vFvCtkiiS5tHytMhhlY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=b+7a/3oZUmRMX/Mtn5Bp3Nv8PqoO+xGPH6KGRbeBmss=; b=lJpwgN+HLf3287aZUtPS2g82ce5pei0r+UIg0x/GCub1zbaY1pSUjB47xKT/Q1p8PR 9n5hrV681Q35ZQpw8VzXAiqwIprA3pGF7MFylgkuue/K17/RwGevNfwcHzWZbfqTVYvQ pI55hB1WO9B7Bo3wSMPB5kSRfHbJ+Fl2zDXitig+KLCIHNziDonawb+fJX3DK+1a+kQs sd/itJHF5Ij7g4xhDRhy/78bCrPttUa4G/0nJWBxWwidql15B3vIfzedo7uYq/lji0WV H8gwCbdWI1jTQEx911mGFMAnzqqHBNXeQ1jlP3ehJK3+k0N/puSyDs5d4KegliGFg//i horw== X-Gm-Message-State: AG10YOTTblDBbXZ9CwkFCV9OEnii53OHiMLILLLvhFwmlAXCA5+4WSn8oZ97kanU1lkRWBde X-Received: by 10.28.12.80 with SMTP id 77mr22734206wmm.19.1456302892184; Wed, 24 Feb 2016 00:34:52 -0800 (PST) Received: from localhost.localdomain ([195.55.142.58]) by smtp.gmail.com with ESMTPSA id za6sm1822367wjc.18.2016.02.24.00.34.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 24 Feb 2016 00:34:51 -0800 (PST) From: Ard Biesheuvel To: edk2-devel@lists.01.org, lersek@redhat.com, jordan.l.justen@intel.com Date: Wed, 24 Feb 2016 09:34:34 +0100 Message-Id: <1456302876-24702-3-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1456302876-24702-1-git-send-email-ard.biesheuvel@linaro.org> References: <1456302876-24702-1-git-send-email-ard.biesheuvel@linaro.org> Cc: Ard Biesheuvel Subject: [edk2] [PATCH v4 2/4] OvmfPkg: implement UEFI driver for Virtio RNG devices X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" This implements a UEFI driver model driver for Virtio devices of type VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and exposes them via instances of the EFI_RNG_PROTOCOL protocol, supporting the EFI_RNG_ALGORITHM_RAW algorithm only. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel Reviewed-by: Laszlo Ersek --- OvmfPkg/VirtioRngDxe/VirtioRng.c | 653 ++++++++++++++++++++ OvmfPkg/VirtioRngDxe/VirtioRng.h | 46 ++ OvmfPkg/VirtioRngDxe/VirtioRng.inf | 45 ++ 3 files changed, 744 insertions(+) -- 2.5.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/OvmfPkg/VirtioRngDxe/VirtioRng.c b/OvmfPkg/VirtioRngDxe/VirtioRng.c new file mode 100644 index 000000000000..8eb1aa300b50 --- /dev/null +++ b/OvmfPkg/VirtioRngDxe/VirtioRng.c @@ -0,0 +1,653 @@ +/** @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.
+ + 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 +#include +#include +#include +#include +#include + +#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; + UINT32 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; + } + + // + // 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, + (UINT32) ((UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT)); + if (EFI_ERROR (Status)) { + goto ReleaseQueue; + } + + // + // step 5 -- Report understood features and guest-tuneables. None are + // currently defined for VirtioRng, and no generic features are needed by + // this driver. + // + Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0); + 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 + ); +} diff --git a/OvmfPkg/VirtioRngDxe/VirtioRng.h b/OvmfPkg/VirtioRngDxe/VirtioRng.h new file mode 100644 index 000000000000..844550a00c17 --- /dev/null +++ b/OvmfPkg/VirtioRngDxe/VirtioRng.h @@ -0,0 +1,46 @@ +/** @file + + Private definitions of the VirtioRng RNG 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. + +**/ + +#ifndef _VIRTIO_RNG_DXE_H_ +#define _VIRTIO_RNG_DXE_H_ + +#include +#include +#include + +#include + +#define VIRTIO_RNG_SIG SIGNATURE_32 ('V', 'R', 'N', 'G') + +typedef struct { + // + // Parts of this structure are initialized / torn down in various functions + // at various call depths. The table to the right should make it easier to + // track them. + // + // field init function init depth + // ---------------- ------------------ ---------- + UINT32 Signature; // DriverBindingStart 0 + VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0 + EFI_EVENT ExitBoot; // DriverBindingStart 0 + VRING Ring; // VirtioRingInit 2 + EFI_RNG_PROTOCOL Rng; // VirtioRngInit 1 +} VIRTIO_RNG_DEV; + +#define VIRTIO_ENTROPY_SOURCE_FROM_RNG(RngPointer) \ + CR (RngPointer, VIRTIO_RNG_DEV, Rng, VIRTIO_RNG_SIG) + +#endif diff --git a/OvmfPkg/VirtioRngDxe/VirtioRng.inf b/OvmfPkg/VirtioRngDxe/VirtioRng.inf new file mode 100644 index 000000000000..471beb37bc7f --- /dev/null +++ b/OvmfPkg/VirtioRngDxe/VirtioRng.inf @@ -0,0 +1,45 @@ +## @file +# This driver produces EFI_RNG_PROTOCOL instances for virtio-rng devices. +# +# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VirtioRngDxe + FILE_GUID = 58E26F0D-CBAC-4BBA-B70F-18221415665A + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = VirtioRngEntryPoint + +[Sources] + VirtioRng.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + VirtioLib + +[Protocols] + gEfiRngProtocolGuid ## BY_START + gVirtioDeviceProtocolGuid ## TO_START + +[Guids] + gEfiRngAlgorithmRaw