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