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