1 /** @file
2 
3   This driver produces EFI_RNG_PROTOCOL instances for virtio-rng devices.
4 
5   The implementation is based on OvmfPkg/VirtioScsiDxe/VirtioScsi.c
6 
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>
10 
11   This driver:
12 
13   Copyright (C) 2016, Linaro Ltd.
14 
15   SPDX-License-Identifier: BSD-2-Clause-Patent
16 
17 **/
18 
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>
25 
26 #include "VirtioRng.h"
27 
28 /**
29   Returns information about the random number generation implementation.
30 
31   @param[in]     This                 A pointer to the EFI_RNG_PROTOCOL
32                                       instance.
33   @param[in,out] RNGAlgorithmListSize On input, the size in bytes of
34                                       RNGAlgorithmList.
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
41                                       list.
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.
49 
50   @retval EFI_SUCCESS                 The RNG algorithm list was returned
51                                       successfully.
52   @retval EFI_UNSUPPORTED             The services is not supported by this
53                                       driver.
54   @retval EFI_DEVICE_ERROR            The list of algorithms could not be
55                                       retrieved due to a hardware or firmware
56                                       error.
57   @retval EFI_INVALID_PARAMETER       One or more of the parameters are
58                                       incorrect.
59   @retval EFI_BUFFER_TOO_SMALL        The buffer RNGAlgorithmList is too small
60                                       to hold the result.
61 
62 **/
63 STATIC
64 EFI_STATUS
65 EFIAPI
VirtioRngGetInfo(IN EFI_RNG_PROTOCOL * This,IN OUT UINTN * RNGAlgorithmListSize,OUT EFI_RNG_ALGORITHM * RNGAlgorithmList)66 VirtioRngGetInfo (
67   IN      EFI_RNG_PROTOCOL        *This,
68   IN OUT  UINTN                   *RNGAlgorithmListSize,
69   OUT     EFI_RNG_ALGORITHM       *RNGAlgorithmList
70   )
71 {
72   if (This == NULL || RNGAlgorithmListSize == NULL) {
73     return EFI_INVALID_PARAMETER;
74   }
75 
76   if (*RNGAlgorithmListSize < sizeof (EFI_RNG_ALGORITHM)) {
77     *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM);
78     return EFI_BUFFER_TOO_SMALL;
79   }
80 
81   if (RNGAlgorithmList == NULL) {
82     return EFI_INVALID_PARAMETER;
83   }
84 
85   *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM);
86   CopyGuid (RNGAlgorithmList, &gEfiRngAlgorithmRaw);
87 
88   return EFI_SUCCESS;
89 }
90 
91 /**
92   Produces and returns an RNG value using either the default or specified RNG
93   algorithm.
94 
95   @param[in]  This                    A pointer to the EFI_RNG_PROTOCOL
96                                       instance.
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
106                                       value.
107 
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
115                                       RNGValueLength.
116   @retval EFI_INVALID_PARAMETER       RNGValue is NULL or RNGValueLength is
117                                       zero.
118 
119 **/
120 STATIC
121 EFI_STATUS
122 EFIAPI
VirtioRngGetRNG(IN EFI_RNG_PROTOCOL * This,IN EFI_RNG_ALGORITHM * RNGAlgorithm,OPTIONAL IN UINTN RNGValueLength,OUT UINT8 * RNGValue)123 VirtioRngGetRNG (
124   IN EFI_RNG_PROTOCOL            *This,
125   IN EFI_RNG_ALGORITHM           *RNGAlgorithm, OPTIONAL
126   IN UINTN                       RNGValueLength,
127   OUT UINT8                      *RNGValue
128   )
129 {
130   VIRTIO_RNG_DEV            *Dev;
131   DESC_INDICES              Indices;
132   volatile UINT8            *Buffer;
133   UINTN                     Index;
134   UINT32                    Len;
135   UINT32                    BufferSize;
136   EFI_STATUS                Status;
137   EFI_PHYSICAL_ADDRESS      DeviceAddress;
138   VOID                      *Mapping;
139 
140   if (This == NULL || RNGValueLength == 0 || RNGValue == NULL) {
141     return EFI_INVALID_PARAMETER;
142   }
143 
144   //
145   // We only support the raw algorithm, so reject requests for anything else
146   //
147   if (RNGAlgorithm != NULL &&
148       !CompareGuid (RNGAlgorithm, &gEfiRngAlgorithmRaw)) {
149     return EFI_UNSUPPORTED;
150   }
151 
152   Buffer = (volatile UINT8 *)AllocatePool (RNGValueLength);
153   if (Buffer == NULL) {
154     return EFI_DEVICE_ERROR;
155   }
156 
157   Dev = VIRTIO_ENTROPY_SOURCE_FROM_RNG (This);
158   //
159   // Map Buffer's system phyiscal address to device address
160   //
161   Status = VirtioMapAllBytesInSharedBuffer (
162              Dev->VirtIo,
163              VirtioOperationBusMasterWrite,
164              (VOID *)Buffer,
165              RNGValueLength,
166              &DeviceAddress,
167              &Mapping
168              );
169   if (EFI_ERROR (Status)) {
170     Status = EFI_DEVICE_ERROR;
171     goto FreeBuffer;
172   }
173 
174   //
175   // The Virtio RNG device may return less data than we asked it to, and can
176   // only return MAX_UINT32 bytes per invocation. So loop as long as needed to
177   // get all the entropy we were asked for.
178   //
179   for (Index = 0; Index < RNGValueLength; Index += Len) {
180     BufferSize = (UINT32)MIN (RNGValueLength - Index, (UINTN)MAX_UINT32);
181 
182     VirtioPrepare (&Dev->Ring, &Indices);
183     VirtioAppendDesc (&Dev->Ring,
184       DeviceAddress + Index,
185       BufferSize,
186       VRING_DESC_F_WRITE,
187       &Indices);
188 
189     if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices, &Len) !=
190         EFI_SUCCESS) {
191       Status = EFI_DEVICE_ERROR;
192       goto UnmapBuffer;
193     }
194     ASSERT (Len > 0);
195     ASSERT (Len <= BufferSize);
196   }
197 
198   //
199   // Unmap the device buffer before accessing it.
200   //
201   Status = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);
202   if (EFI_ERROR (Status)) {
203     Status = EFI_DEVICE_ERROR;
204     goto FreeBuffer;
205   }
206 
207   for (Index = 0; Index < RNGValueLength; Index++) {
208     RNGValue[Index] = Buffer[Index];
209   }
210   Status = EFI_SUCCESS;
211 
212 UnmapBuffer:
213   //
214   // If we are reached here due to the error then unmap the buffer otherwise
215   // the buffer is already unmapped after VirtioFlush().
216   //
217   if (EFI_ERROR (Status)) {
218     Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);
219   }
220 
221 FreeBuffer:
222   FreePool ((VOID *)Buffer);
223   return Status;
224 }
225 
226 STATIC
227 EFI_STATUS
228 EFIAPI
VirtioRngInit(IN OUT VIRTIO_RNG_DEV * Dev)229 VirtioRngInit (
230   IN OUT VIRTIO_RNG_DEV *Dev
231   )
232 {
233   UINT8      NextDevStat;
234   EFI_STATUS Status;
235   UINT16     QueueSize;
236   UINT64     Features;
237   UINT64     RingBaseShift;
238 
239   //
240   // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
241   //
242   NextDevStat = 0;             // step 1 -- reset device
243   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
244   if (EFI_ERROR (Status)) {
245     goto Failed;
246   }
247 
248   NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
249   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
250   if (EFI_ERROR (Status)) {
251     goto Failed;
252   }
253 
254   NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
255   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
256   if (EFI_ERROR (Status)) {
257     goto Failed;
258   }
259 
260   //
261   // Set Page Size - MMIO VirtIo Specific
262   //
263   Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
264   if (EFI_ERROR (Status)) {
265     goto Failed;
266   }
267 
268   //
269   // step 4a -- retrieve and validate features
270   //
271   Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
272   if (EFI_ERROR (Status)) {
273     goto Failed;
274   }
275 
276   Features &= VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM;
277 
278   //
279   // In virtio-1.0, feature negotiation is expected to complete before queue
280   // discovery, and the device can also reject the selected set of features.
281   //
282   if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
283     Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
284     if (EFI_ERROR (Status)) {
285       goto Failed;
286     }
287   }
288 
289   //
290   // step 4b -- allocate request virtqueue, just use #0
291   //
292   Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
293   if (EFI_ERROR (Status)) {
294     goto Failed;
295   }
296   Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
297   if (EFI_ERROR (Status)) {
298     goto Failed;
299   }
300 
301   //
302   // VirtioRngGetRNG() uses one descriptor
303   //
304   if (QueueSize < 1) {
305     Status = EFI_UNSUPPORTED;
306     goto Failed;
307   }
308 
309   Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);
310   if (EFI_ERROR (Status)) {
311     goto Failed;
312   }
313 
314   //
315   // If anything fails from here on, we must release the ring resources.
316   //
317   Status = VirtioRingMap (
318              Dev->VirtIo,
319              &Dev->Ring,
320              &RingBaseShift,
321              &Dev->RingMap
322              );
323   if (EFI_ERROR (Status)) {
324     goto ReleaseQueue;
325   }
326 
327   //
328   // Additional steps for MMIO: align the queue appropriately, and set the
329   // size. If anything fails from here on, we must unmap the ring resources.
330   //
331   Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
332   if (EFI_ERROR (Status)) {
333     goto UnmapQueue;
334   }
335 
336   Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
337   if (EFI_ERROR (Status)) {
338     goto UnmapQueue;
339   }
340 
341   //
342   // step 4c -- Report GPFN (guest-physical frame number) of queue.
343   //
344   Status = Dev->VirtIo->SetQueueAddress (
345                           Dev->VirtIo,
346                           &Dev->Ring,
347                           RingBaseShift
348                           );
349   if (EFI_ERROR (Status)) {
350     goto UnmapQueue;
351   }
352 
353   //
354   // step 5 -- Report understood features and guest-tuneables.
355   //
356   if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
357     Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
358     Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
359     if (EFI_ERROR (Status)) {
360       goto UnmapQueue;
361     }
362   }
363 
364   //
365   // step 6 -- initialization complete
366   //
367   NextDevStat |= VSTAT_DRIVER_OK;
368   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
369   if (EFI_ERROR (Status)) {
370     goto UnmapQueue;
371   }
372 
373   //
374   // populate the exported interface's attributes
375   //
376   Dev->Rng.GetInfo    = VirtioRngGetInfo;
377   Dev->Rng.GetRNG     = VirtioRngGetRNG;
378 
379   return EFI_SUCCESS;
380 
381 UnmapQueue:
382   Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
383 
384 ReleaseQueue:
385   VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
386 
387 Failed:
388   //
389   // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
390   // Status. VirtIo access failure here should not mask the original error.
391   //
392   NextDevStat |= VSTAT_FAILED;
393   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
394 
395   return Status; // reached only via Failed above
396 }
397 
398 
399 STATIC
400 VOID
401 EFIAPI
VirtioRngUninit(IN OUT VIRTIO_RNG_DEV * Dev)402 VirtioRngUninit (
403   IN OUT VIRTIO_RNG_DEV *Dev
404   )
405 {
406   //
407   // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
408   // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
409   // the old comms area.
410   //
411   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
412 
413   Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
414 
415   VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
416 }
417 
418 //
419 // Event notification function enqueued by ExitBootServices().
420 //
421 
422 STATIC
423 VOID
424 EFIAPI
VirtioRngExitBoot(IN EFI_EVENT Event,IN VOID * Context)425 VirtioRngExitBoot (
426   IN  EFI_EVENT Event,
427   IN  VOID      *Context
428   )
429 {
430   VIRTIO_RNG_DEV *Dev;
431 
432   DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
433   //
434   // Reset the device. This causes the hypervisor to forget about the virtio
435   // ring.
436   //
437   // We allocated said ring in EfiBootServicesData type memory, and code
438   // executing after ExitBootServices() is permitted to overwrite it.
439   //
440   Dev = Context;
441   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
442 }
443 
444 
445 //
446 // Probe, start and stop functions of this driver, called by the DXE core for
447 // specific devices.
448 //
449 // The following specifications document these interfaces:
450 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
451 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
452 //
453 // The implementation follows:
454 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
455 //   - 5.1.3.4 OpenProtocol() and CloseProtocol()
456 // - UEFI Spec 2.3.1 + Errata C
457 //   -  6.3 Protocol Handler Services
458 //
459 
460 STATIC
461 EFI_STATUS
462 EFIAPI
VirtioRngDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)463 VirtioRngDriverBindingSupported (
464   IN EFI_DRIVER_BINDING_PROTOCOL *This,
465   IN EFI_HANDLE                  DeviceHandle,
466   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
467   )
468 {
469   EFI_STATUS             Status;
470   VIRTIO_DEVICE_PROTOCOL *VirtIo;
471 
472   //
473   // Attempt to open the device with the VirtIo set of interfaces. On success,
474   // the protocol is "instantiated" for the VirtIo device. Covers duplicate
475   // open attempts (EFI_ALREADY_STARTED).
476   //
477   Status = gBS->OpenProtocol (
478                   DeviceHandle,               // candidate device
479                   &gVirtioDeviceProtocolGuid, // for generic VirtIo access
480                   (VOID **)&VirtIo,           // handle to instantiate
481                   This->DriverBindingHandle,  // requestor driver identity
482                   DeviceHandle,               // ControllerHandle, according to
483                                               // the UEFI Driver Model
484                   EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
485                                               // the device; to be released
486                   );
487   if (EFI_ERROR (Status)) {
488     return Status;
489   }
490 
491   if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) {
492     Status = EFI_UNSUPPORTED;
493   }
494 
495   //
496   // We needed VirtIo access only transitorily, to see whether we support the
497   // device or not.
498   //
499   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
500          This->DriverBindingHandle, DeviceHandle);
501   return Status;
502 }
503 
504 STATIC
505 EFI_STATUS
506 EFIAPI
VirtioRngDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)507 VirtioRngDriverBindingStart (
508   IN EFI_DRIVER_BINDING_PROTOCOL *This,
509   IN EFI_HANDLE                  DeviceHandle,
510   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
511   )
512 {
513   VIRTIO_RNG_DEV  *Dev;
514   EFI_STATUS Status;
515 
516   Dev = (VIRTIO_RNG_DEV *) AllocateZeroPool (sizeof *Dev);
517   if (Dev == NULL) {
518     return EFI_OUT_OF_RESOURCES;
519   }
520 
521   Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
522                   (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
523                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
524   if (EFI_ERROR (Status)) {
525     goto FreeVirtioRng;
526   }
527 
528   //
529   // VirtIo access granted, configure virtio-rng device.
530   //
531   Status = VirtioRngInit (Dev);
532   if (EFI_ERROR (Status)) {
533     goto CloseVirtIo;
534   }
535 
536   Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
537                   &VirtioRngExitBoot, Dev, &Dev->ExitBoot);
538   if (EFI_ERROR (Status)) {
539     goto UninitDev;
540   }
541 
542   //
543   // Setup complete, attempt to export the driver instance's EFI_RNG_PROTOCOL
544   // interface.
545   //
546   Dev->Signature = VIRTIO_RNG_SIG;
547   Status = gBS->InstallProtocolInterface (&DeviceHandle,
548                   &gEfiRngProtocolGuid, EFI_NATIVE_INTERFACE,
549                   &Dev->Rng);
550   if (EFI_ERROR (Status)) {
551     goto CloseExitBoot;
552   }
553 
554   return EFI_SUCCESS;
555 
556 CloseExitBoot:
557   gBS->CloseEvent (Dev->ExitBoot);
558 
559 UninitDev:
560   VirtioRngUninit (Dev);
561 
562 CloseVirtIo:
563   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
564          This->DriverBindingHandle, DeviceHandle);
565 
566 FreeVirtioRng:
567   FreePool (Dev);
568 
569   return Status;
570 }
571 
572 
573 STATIC
574 EFI_STATUS
575 EFIAPI
VirtioRngDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)576 VirtioRngDriverBindingStop (
577   IN EFI_DRIVER_BINDING_PROTOCOL *This,
578   IN EFI_HANDLE                  DeviceHandle,
579   IN UINTN                       NumberOfChildren,
580   IN EFI_HANDLE                  *ChildHandleBuffer
581   )
582 {
583   EFI_STATUS                      Status;
584   EFI_RNG_PROTOCOL                *Rng;
585   VIRTIO_RNG_DEV                  *Dev;
586 
587   Status = gBS->OpenProtocol (
588                   DeviceHandle,                     // candidate device
589                   &gEfiRngProtocolGuid,             // retrieve the RNG iface
590                   (VOID **)&Rng,                    // target pointer
591                   This->DriverBindingHandle,        // requestor driver ident.
592                   DeviceHandle,                     // lookup req. for dev.
593                   EFI_OPEN_PROTOCOL_GET_PROTOCOL    // lookup only, no new ref.
594                   );
595   if (EFI_ERROR (Status)) {
596     return Status;
597   }
598 
599   Dev = VIRTIO_ENTROPY_SOURCE_FROM_RNG (Rng);
600 
601   //
602   // Handle Stop() requests for in-use driver instances gracefully.
603   //
604   Status = gBS->UninstallProtocolInterface (DeviceHandle,
605                   &gEfiRngProtocolGuid, &Dev->Rng);
606   if (EFI_ERROR (Status)) {
607     return Status;
608   }
609 
610   gBS->CloseEvent (Dev->ExitBoot);
611 
612   VirtioRngUninit (Dev);
613 
614   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
615          This->DriverBindingHandle, DeviceHandle);
616 
617   FreePool (Dev);
618 
619   return EFI_SUCCESS;
620 }
621 
622 
623 //
624 // The static object that groups the Supported() (ie. probe), Start() and
625 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
626 // C, 10.1 EFI Driver Binding Protocol.
627 //
628 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
629   &VirtioRngDriverBindingSupported,
630   &VirtioRngDriverBindingStart,
631   &VirtioRngDriverBindingStop,
632   0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
633   NULL, // ImageHandle, to be overwritten by
634         // EfiLibInstallDriverBindingComponentName2() in VirtioRngEntryPoint()
635   NULL  // DriverBindingHandle, ditto
636 };
637 
638 
639 //
640 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
641 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
642 // in English, for display on standard console devices. This is recommended for
643 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
644 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
645 //
646 
647 STATIC
648 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
649   { "eng;en", L"Virtio Random Number Generator Driver" },
650   { NULL,     NULL                   }
651 };
652 
653 STATIC
654 EFI_COMPONENT_NAME_PROTOCOL gComponentName;
655 
656 STATIC
657 EFI_STATUS
658 EFIAPI
VirtioRngGetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN CHAR8 * Language,OUT CHAR16 ** DriverName)659 VirtioRngGetDriverName (
660   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
661   IN  CHAR8                       *Language,
662   OUT CHAR16                      **DriverName
663   )
664 {
665   return LookupUnicodeString2 (
666            Language,
667            This->SupportedLanguages,
668            mDriverNameTable,
669            DriverName,
670            (BOOLEAN)(This == &gComponentName) // Iso639Language
671            );
672 }
673 
674 STATIC
675 EFI_STATUS
676 EFIAPI
VirtioRngGetDeviceName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_HANDLE ChildHandle,IN CHAR8 * Language,OUT CHAR16 ** ControllerName)677 VirtioRngGetDeviceName (
678   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
679   IN  EFI_HANDLE                  DeviceHandle,
680   IN  EFI_HANDLE                  ChildHandle,
681   IN  CHAR8                       *Language,
682   OUT CHAR16                      **ControllerName
683   )
684 {
685   return EFI_UNSUPPORTED;
686 }
687 
688 STATIC
689 EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
690   &VirtioRngGetDriverName,
691   &VirtioRngGetDeviceName,
692   "eng" // SupportedLanguages, ISO 639-2 language codes
693 };
694 
695 STATIC
696 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
697   (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &VirtioRngGetDriverName,
698   (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioRngGetDeviceName,
699   "en" // SupportedLanguages, RFC 4646 language codes
700 };
701 
702 
703 //
704 // Entry point of this driver.
705 //
706 EFI_STATUS
707 EFIAPI
VirtioRngEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)708 VirtioRngEntryPoint (
709   IN EFI_HANDLE       ImageHandle,
710   IN EFI_SYSTEM_TABLE *SystemTable
711   )
712 {
713   return EfiLibInstallDriverBindingComponentName2 (
714            ImageHandle,
715            SystemTable,
716            &gDriverBinding,
717            ImageHandle,
718            &gComponentName,
719            &gComponentName2
720            );
721 }
722