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