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