]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/VirtioRngDxe/VirtioRng.c
OvmfPkg: VirtioRngDxe: adapt feature negotiation to virtio-1.0
[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 Features &= VIRTIO_F_VERSION_1;
246
247 //
248 // In virtio-1.0, feature negotiation is expected to complete before queue
249 // discovery, and the device can also reject the selected set of features.
250 //
251 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
252 Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
253 if (EFI_ERROR (Status)) {
254 goto Failed;
255 }
256 }
257
258 //
259 // step 4b -- allocate request virtqueue, just use #0
260 //
261 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
262 if (EFI_ERROR (Status)) {
263 goto Failed;
264 }
265 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
266 if (EFI_ERROR (Status)) {
267 goto Failed;
268 }
269
270 //
271 // VirtioRngGetRNG() uses one descriptor
272 //
273 if (QueueSize < 1) {
274 Status = EFI_UNSUPPORTED;
275 goto Failed;
276 }
277
278 Status = VirtioRingInit (QueueSize, &Dev->Ring);
279 if (EFI_ERROR (Status)) {
280 goto Failed;
281 }
282
283 //
284 // Additional steps for MMIO: align the queue appropriately, and set the
285 // size. If anything fails from here on, we must release the ring resources.
286 //
287 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
288 if (EFI_ERROR (Status)) {
289 goto ReleaseQueue;
290 }
291
292 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
293 if (EFI_ERROR (Status)) {
294 goto ReleaseQueue;
295 }
296
297 //
298 // step 4c -- Report GPFN (guest-physical frame number) of queue.
299 //
300 Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, &Dev->Ring);
301 if (EFI_ERROR (Status)) {
302 goto ReleaseQueue;
303 }
304
305 //
306 // step 5 -- Report understood features and guest-tuneables.
307 //
308 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
309 Features &= ~(UINT64)VIRTIO_F_VERSION_1;
310 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
311 if (EFI_ERROR (Status)) {
312 goto ReleaseQueue;
313 }
314 }
315
316 //
317 // step 6 -- initialization complete
318 //
319 NextDevStat |= VSTAT_DRIVER_OK;
320 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
321 if (EFI_ERROR (Status)) {
322 goto ReleaseQueue;
323 }
324
325 //
326 // populate the exported interface's attributes
327 //
328 Dev->Rng.GetInfo = VirtioRngGetInfo;
329 Dev->Rng.GetRNG = VirtioRngGetRNG;
330
331 return EFI_SUCCESS;
332
333 ReleaseQueue:
334 VirtioRingUninit (&Dev->Ring);
335
336 Failed:
337 //
338 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
339 // Status. VirtIo access failure here should not mask the original error.
340 //
341 NextDevStat |= VSTAT_FAILED;
342 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
343
344 return Status; // reached only via Failed above
345 }
346
347
348 STATIC
349 VOID
350 EFIAPI
351 VirtioRngUninit (
352 IN OUT VIRTIO_RNG_DEV *Dev
353 )
354 {
355 //
356 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
357 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
358 // the old comms area.
359 //
360 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
361 VirtioRingUninit (&Dev->Ring);
362 }
363
364 //
365 // Event notification function enqueued by ExitBootServices().
366 //
367
368 STATIC
369 VOID
370 EFIAPI
371 VirtioRngExitBoot (
372 IN EFI_EVENT Event,
373 IN VOID *Context
374 )
375 {
376 VIRTIO_RNG_DEV *Dev;
377
378 //
379 // Reset the device. This causes the hypervisor to forget about the virtio
380 // ring.
381 //
382 // We allocated said ring in EfiBootServicesData type memory, and code
383 // executing after ExitBootServices() is permitted to overwrite it.
384 //
385 Dev = Context;
386 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
387 }
388
389
390 //
391 // Probe, start and stop functions of this driver, called by the DXE core for
392 // specific devices.
393 //
394 // The following specifications document these interfaces:
395 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
396 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
397 //
398 // The implementation follows:
399 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
400 // - 5.1.3.4 OpenProtocol() and CloseProtocol()
401 // - UEFI Spec 2.3.1 + Errata C
402 // - 6.3 Protocol Handler Services
403 //
404
405 STATIC
406 EFI_STATUS
407 EFIAPI
408 VirtioRngDriverBindingSupported (
409 IN EFI_DRIVER_BINDING_PROTOCOL *This,
410 IN EFI_HANDLE DeviceHandle,
411 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
412 )
413 {
414 EFI_STATUS Status;
415 VIRTIO_DEVICE_PROTOCOL *VirtIo;
416
417 //
418 // Attempt to open the device with the VirtIo set of interfaces. On success,
419 // the protocol is "instantiated" for the VirtIo device. Covers duplicate
420 // open attempts (EFI_ALREADY_STARTED).
421 //
422 Status = gBS->OpenProtocol (
423 DeviceHandle, // candidate device
424 &gVirtioDeviceProtocolGuid, // for generic VirtIo access
425 (VOID **)&VirtIo, // handle to instantiate
426 This->DriverBindingHandle, // requestor driver identity
427 DeviceHandle, // ControllerHandle, according to
428 // the UEFI Driver Model
429 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
430 // the device; to be released
431 );
432 if (EFI_ERROR (Status)) {
433 return Status;
434 }
435
436 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_ENTROPY_SOURCE) {
437 Status = EFI_UNSUPPORTED;
438 }
439
440 //
441 // We needed VirtIo access only transitorily, to see whether we support the
442 // device or not.
443 //
444 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
445 This->DriverBindingHandle, DeviceHandle);
446 return Status;
447 }
448
449 STATIC
450 EFI_STATUS
451 EFIAPI
452 VirtioRngDriverBindingStart (
453 IN EFI_DRIVER_BINDING_PROTOCOL *This,
454 IN EFI_HANDLE DeviceHandle,
455 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
456 )
457 {
458 VIRTIO_RNG_DEV *Dev;
459 EFI_STATUS Status;
460
461 Dev = (VIRTIO_RNG_DEV *) AllocateZeroPool (sizeof *Dev);
462 if (Dev == NULL) {
463 return EFI_OUT_OF_RESOURCES;
464 }
465
466 Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
467 (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
468 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
469 if (EFI_ERROR (Status)) {
470 goto FreeVirtioRng;
471 }
472
473 //
474 // VirtIo access granted, configure virtio-rng device.
475 //
476 Status = VirtioRngInit (Dev);
477 if (EFI_ERROR (Status)) {
478 goto CloseVirtIo;
479 }
480
481 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
482 &VirtioRngExitBoot, Dev, &Dev->ExitBoot);
483 if (EFI_ERROR (Status)) {
484 goto UninitDev;
485 }
486
487 //
488 // Setup complete, attempt to export the driver instance's EFI_RNG_PROTOCOL
489 // interface.
490 //
491 Dev->Signature = VIRTIO_RNG_SIG;
492 Status = gBS->InstallProtocolInterface (&DeviceHandle,
493 &gEfiRngProtocolGuid, EFI_NATIVE_INTERFACE,
494 &Dev->Rng);
495 if (EFI_ERROR (Status)) {
496 goto CloseExitBoot;
497 }
498
499 return EFI_SUCCESS;
500
501 CloseExitBoot:
502 gBS->CloseEvent (Dev->ExitBoot);
503
504 UninitDev:
505 VirtioRngUninit (Dev);
506
507 CloseVirtIo:
508 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
509 This->DriverBindingHandle, DeviceHandle);
510
511 FreeVirtioRng:
512 FreePool (Dev);
513
514 return Status;
515 }
516
517
518 STATIC
519 EFI_STATUS
520 EFIAPI
521 VirtioRngDriverBindingStop (
522 IN EFI_DRIVER_BINDING_PROTOCOL *This,
523 IN EFI_HANDLE DeviceHandle,
524 IN UINTN NumberOfChildren,
525 IN EFI_HANDLE *ChildHandleBuffer
526 )
527 {
528 EFI_STATUS Status;
529 EFI_RNG_PROTOCOL *Rng;
530 VIRTIO_RNG_DEV *Dev;
531
532 Status = gBS->OpenProtocol (
533 DeviceHandle, // candidate device
534 &gEfiRngProtocolGuid, // retrieve the RNG iface
535 (VOID **)&Rng, // target pointer
536 This->DriverBindingHandle, // requestor driver ident.
537 DeviceHandle, // lookup req. for dev.
538 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no new ref.
539 );
540 if (EFI_ERROR (Status)) {
541 return Status;
542 }
543
544 Dev = VIRTIO_ENTROPY_SOURCE_FROM_RNG (Rng);
545
546 //
547 // Handle Stop() requests for in-use driver instances gracefully.
548 //
549 Status = gBS->UninstallProtocolInterface (DeviceHandle,
550 &gEfiRngProtocolGuid, &Dev->Rng);
551 if (EFI_ERROR (Status)) {
552 return Status;
553 }
554
555 gBS->CloseEvent (Dev->ExitBoot);
556
557 VirtioRngUninit (Dev);
558
559 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
560 This->DriverBindingHandle, DeviceHandle);
561
562 FreePool (Dev);
563
564 return EFI_SUCCESS;
565 }
566
567
568 //
569 // The static object that groups the Supported() (ie. probe), Start() and
570 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
571 // C, 10.1 EFI Driver Binding Protocol.
572 //
573 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
574 &VirtioRngDriverBindingSupported,
575 &VirtioRngDriverBindingStart,
576 &VirtioRngDriverBindingStop,
577 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
578 NULL, // ImageHandle, to be overwritten by
579 // EfiLibInstallDriverBindingComponentName2() in VirtioRngEntryPoint()
580 NULL // DriverBindingHandle, ditto
581 };
582
583
584 //
585 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
586 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
587 // in English, for display on standard console devices. This is recommended for
588 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
589 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
590 //
591
592 STATIC
593 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
594 { "eng;en", L"Virtio Random Number Generator Driver" },
595 { NULL, NULL }
596 };
597
598 STATIC
599 EFI_COMPONENT_NAME_PROTOCOL gComponentName;
600
601 STATIC
602 EFI_STATUS
603 EFIAPI
604 VirtioRngGetDriverName (
605 IN EFI_COMPONENT_NAME_PROTOCOL *This,
606 IN CHAR8 *Language,
607 OUT CHAR16 **DriverName
608 )
609 {
610 return LookupUnicodeString2 (
611 Language,
612 This->SupportedLanguages,
613 mDriverNameTable,
614 DriverName,
615 (BOOLEAN)(This == &gComponentName) // Iso639Language
616 );
617 }
618
619 STATIC
620 EFI_STATUS
621 EFIAPI
622 VirtioRngGetDeviceName (
623 IN EFI_COMPONENT_NAME_PROTOCOL *This,
624 IN EFI_HANDLE DeviceHandle,
625 IN EFI_HANDLE ChildHandle,
626 IN CHAR8 *Language,
627 OUT CHAR16 **ControllerName
628 )
629 {
630 return EFI_UNSUPPORTED;
631 }
632
633 STATIC
634 EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
635 &VirtioRngGetDriverName,
636 &VirtioRngGetDeviceName,
637 "eng" // SupportedLanguages, ISO 639-2 language codes
638 };
639
640 STATIC
641 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
642 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioRngGetDriverName,
643 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioRngGetDeviceName,
644 "en" // SupportedLanguages, RFC 4646 language codes
645 };
646
647
648 //
649 // Entry point of this driver.
650 //
651 EFI_STATUS
652 EFIAPI
653 VirtioRngEntryPoint (
654 IN EFI_HANDLE ImageHandle,
655 IN EFI_SYSTEM_TABLE *SystemTable
656 )
657 {
658 return EfiLibInstallDriverBindingComponentName2 (
659 ImageHandle,
660 SystemTable,
661 &gDriverBinding,
662 ImageHandle,
663 &gComponentName,
664 &gComponentName2
665 );
666 }