VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/VirtioBlkDxe/VirtioBlk.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 37.9 KB
Line 
1/** @file
2
3 This driver produces Block I/O Protocol instances for virtio-blk devices.
4
5 The implementation is basic:
6
7 - No attach/detach (ie. removable media).
8
9 - Although the non-blocking interfaces of EFI_BLOCK_IO2_PROTOCOL could be a
10 good match for multiple in-flight virtio-blk requests, we stick to
11 synchronous requests and EFI_BLOCK_IO_PROTOCOL for now.
12
13 Copyright (C) 2012, Red Hat, Inc.
14 Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
15 Copyright (c) 2017, AMD Inc, All rights reserved.<BR>
16 Copyright (c) 2024, Arm Limited. All rights reserved.<BR>
17
18 SPDX-License-Identifier: BSD-2-Clause-Patent
19
20**/
21
22#include <IndustryStandard/VirtioBlk.h>
23#include <Library/BaseMemoryLib.h>
24#include <Library/DebugLib.h>
25#include <Library/MemoryAllocationLib.h>
26#include <Library/UefiBootServicesTableLib.h>
27#include <Library/UefiLib.h>
28#include <Library/VirtioLib.h>
29
30#include "VirtioBlk.h"
31
32/**
33
34 Convenience macros to read and write region 0 IO space elements of the
35 virtio-blk device, for configuration purposes.
36
37 The following macros make it possible to specify only the "core parameters"
38 for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
39 returns, the transaction will have been completed.
40
41 @param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space
42 we're accessing. Dev->VirtIo must be valid.
43
44 @param[in] Field A field name from VBLK_HDR, identifying the virtio-blk
45 configuration item to access.
46
47 @param[in] Value (VIRTIO_CFG_WRITE() only.) The value to write to the
48 selected configuration item.
49
50 @param[out] Pointer (VIRTIO_CFG_READ() only.) The object to receive the
51 value read from the configuration item. Its type must be
52 one of UINT8, UINT16, UINT32, UINT64.
53
54
55 @return Status code returned by Virtio->WriteDevice() /
56 Virtio->ReadDevice().
57
58**/
59
60#define VIRTIO_CFG_WRITE(Dev, Field, Value) ((Dev)->VirtIo->WriteDevice ( \
61 (Dev)->VirtIo, \
62 OFFSET_OF_VBLK (Field), \
63 SIZE_OF_VBLK (Field), \
64 (Value) \
65 ))
66
67#define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice ( \
68 (Dev)->VirtIo, \
69 OFFSET_OF_VBLK (Field), \
70 SIZE_OF_VBLK (Field), \
71 sizeof *(Pointer), \
72 (Pointer) \
73 ))
74
75//
76// UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol
77// Driver Writer's Guide for UEFI 2.3.1 v1.01,
78// 24.2 Block I/O Protocol Implementations
79//
80EFI_STATUS
81EFIAPI
82VirtioBlkReset (
83 IN EFI_BLOCK_IO_PROTOCOL *This,
84 IN BOOLEAN ExtendedVerification
85 )
86{
87 //
88 // If we managed to initialize and install the driver, then the device is
89 // working correctly.
90 //
91 return EFI_SUCCESS;
92}
93
94/**
95
96 Verify correctness of the read/write (not flush) request submitted to the
97 EFI_BLOCK_IO_PROTOCOL instance.
98
99 This function provides most verification steps described in:
100
101 UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
102 Protocol,
103 - EFI_BLOCK_IO_PROTOCOL.ReadBlocks()
104 - EFI_BLOCK_IO_PROTOCOL.WriteBlocks()
105
106 Driver Writer's Guide for UEFI 2.3.1 v1.01,
107 - 24.2.2. ReadBlocks() and ReadBlocksEx() Implementation
108 - 24.2.3 WriteBlocks() and WriteBlockEx() Implementation
109
110 Request sizes are limited to 1 GB (checked). This is not a practical
111 limitation, just conformance to virtio-0.9.5, 2.3.2 Descriptor Table: "no
112 descriptor chain may be more than 2^32 bytes long in total".
113
114 Some Media characteristics are hardcoded in VirtioBlkInit() below (like
115 non-removable media, no restriction on buffer alignment etc); we rely on
116 those here without explicit mention.
117
118 @param[in] Media The EFI_BLOCK_IO_MEDIA characteristics for
119 this driver instance, extracted from the
120 underlying virtio-blk device at initialization
121 time. We validate the request against this set
122 of attributes.
123
124
125 @param[in] Lba Logical Block Address: number of logical
126 blocks to skip from the beginning of the
127 device.
128
129 @param[in] PositiveBufferSize Size of buffer to transfer, in bytes. The
130 caller is responsible to ensure this parameter
131 is positive.
132
133 @param[in] RequestIsWrite TRUE iff data transfer goes from guest to
134 device.
135
136
137 @@return Validation result to be forwarded outwards by
138 ReadBlocks() and WriteBlocks, as required by
139 the specs above.
140
141**/
142STATIC
143EFI_STATUS
144EFIAPI
145VerifyReadWriteRequest (
146 IN EFI_BLOCK_IO_MEDIA *Media,
147 IN EFI_LBA Lba,
148 IN UINTN PositiveBufferSize,
149 IN BOOLEAN RequestIsWrite
150 )
151{
152 UINTN BlockCount;
153
154 ASSERT (PositiveBufferSize > 0);
155
156 if ((PositiveBufferSize > SIZE_1GB) ||
157 (PositiveBufferSize % Media->BlockSize > 0))
158 {
159 return EFI_BAD_BUFFER_SIZE;
160 }
161
162 BlockCount = PositiveBufferSize / Media->BlockSize;
163
164 //
165 // Avoid unsigned wraparound on either side in the second comparison.
166 //
167 if ((Lba > Media->LastBlock) || (BlockCount - 1 > Media->LastBlock - Lba)) {
168 return EFI_INVALID_PARAMETER;
169 }
170
171 if (RequestIsWrite && Media->ReadOnly) {
172 return EFI_WRITE_PROTECTED;
173 }
174
175 return EFI_SUCCESS;
176}
177
178/**
179
180 Format a read / write / flush request as three consecutive virtio
181 descriptors, push them to the host, and poll for the response.
182
183 This is the main workhorse function. Two use cases are supported, read/write
184 and flush. The function may only be called after the request parameters have
185 been verified by
186 - specific checks in ReadBlocks() / WriteBlocks() / FlushBlocks(), and
187 - VerifyReadWriteRequest() (for read/write only).
188
189 Parameters handled commonly:
190
191 @param[in] Dev The virtio-blk device the request is targeted
192 at.
193
194 Flush request:
195
196 @param[in] Lba Must be zero.
197
198 @param[in] BufferSize Must be zero.
199
200 @param[in out] Buffer Ignored by the function.
201
202 @param[in] RequestIsWrite Must be TRUE.
203
204 Read/Write request:
205
206 @param[in] Lba Logical Block Address: number of logical blocks
207 to skip from the beginning of the device.
208
209 @param[in] BufferSize Size of buffer to transfer, in bytes. The caller
210 is responsible to ensure this parameter is
211 positive.
212
213 @param[in out] Buffer The guest side area to read data from the device
214 into, or write data to the device from.
215
216 @param[in] RequestIsWrite TRUE iff data transfer goes from guest to
217 device.
218
219 Return values are common to both use cases, and are appropriate to be
220 forwarded by the EFI_BLOCK_IO_PROTOCOL functions (ReadBlocks(),
221 WriteBlocks(), FlushBlocks()).
222
223
224 @retval EFI_SUCCESS Transfer complete.
225
226 @retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or
227 unable to parse host response, or host response
228 is not VIRTIO_BLK_S_OK or failed to map Buffer
229 for a bus master operation.
230
231**/
232STATIC
233EFI_STATUS
234EFIAPI
235SynchronousRequest (
236 IN VBLK_DEV *Dev,
237 IN EFI_LBA Lba,
238 IN UINTN BufferSize,
239 IN OUT volatile VOID *Buffer,
240 IN BOOLEAN RequestIsWrite
241 )
242{
243 UINT32 BlockSize;
244 volatile VIRTIO_BLK_REQ *Request;
245 volatile UINT8 *HostStatus;
246 VOID *HostStatusBuffer;
247 DESC_INDICES Indices;
248 VOID *RequestMapping;
249 VOID *StatusMapping;
250 VOID *BufferMapping;
251 EFI_PHYSICAL_ADDRESS BufferDeviceAddress;
252 EFI_PHYSICAL_ADDRESS HostStatusDeviceAddress;
253 EFI_PHYSICAL_ADDRESS RequestDeviceAddress;
254 EFI_STATUS Status;
255 EFI_STATUS UnmapStatus;
256
257 BlockSize = Dev->BlockIoMedia.BlockSize;
258
259 //
260 // Set BufferMapping and BufferDeviceAddress to suppress incorrect
261 // compiler/analyzer warnings.
262 //
263 BufferMapping = NULL;
264 BufferDeviceAddress = 0;
265
266 //
267 // ensured by VirtioBlkInit()
268 //
269 ASSERT (BlockSize > 0);
270 ASSERT (BlockSize % 512 == 0);
271
272 //
273 // ensured by contract above, plus VerifyReadWriteRequest()
274 //
275 ASSERT (BufferSize % BlockSize == 0);
276
277 Request = AllocateZeroPool (sizeof (*Request));
278 if (Request == NULL) {
279 return EFI_DEVICE_ERROR;
280 }
281
282 //
283 // Prepare virtio-blk request header, setting zero size for flush.
284 // IO Priority is homogeneously 0.
285 //
286 Request->Type = RequestIsWrite ?
287 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :
288 VIRTIO_BLK_T_IN;
289 Request->IoPrio = 0;
290 Request->Sector = MultU64x32 (Lba, BlockSize / 512);
291
292 //
293 // Host status is bi-directional (we preset with a value and expect the
294 // device to update it). Allocate a host status buffer which can be mapped
295 // to access equally by both processor and the device.
296 //
297 Status = Dev->VirtIo->AllocateSharedPages (
298 Dev->VirtIo,
299 EFI_SIZE_TO_PAGES (sizeof *HostStatus),
300 &HostStatusBuffer
301 );
302 if (EFI_ERROR (Status)) {
303 Status = EFI_DEVICE_ERROR;
304 goto FreeBlkRequest;
305 }
306
307 HostStatus = HostStatusBuffer;
308
309 //
310 // Map virtio-blk request header (must be done after request header is
311 // populated)
312 //
313 Status = VirtioMapAllBytesInSharedBuffer (
314 Dev->VirtIo,
315 VirtioOperationBusMasterRead,
316 (VOID *)Request,
317 sizeof (*Request),
318 &RequestDeviceAddress,
319 &RequestMapping
320 );
321 if (EFI_ERROR (Status)) {
322 Status = EFI_DEVICE_ERROR;
323 goto FreeHostStatusBuffer;
324 }
325
326 //
327 // Map data buffer
328 //
329 if (BufferSize > 0) {
330 Status = VirtioMapAllBytesInSharedBuffer (
331 Dev->VirtIo,
332 (RequestIsWrite ?
333 VirtioOperationBusMasterRead :
334 VirtioOperationBusMasterWrite),
335 (VOID *)Buffer,
336 BufferSize,
337 &BufferDeviceAddress,
338 &BufferMapping
339 );
340 if (EFI_ERROR (Status)) {
341 Status = EFI_DEVICE_ERROR;
342 goto UnmapRequestBuffer;
343 }
344 }
345
346 //
347 // preset a host status for ourselves that we do not accept as success
348 //
349 *HostStatus = VIRTIO_BLK_S_IOERR;
350
351 //
352 // Map the Status Buffer with VirtioOperationBusMasterCommonBuffer so that
353 // both processor and device can access it.
354 //
355 Status = VirtioMapAllBytesInSharedBuffer (
356 Dev->VirtIo,
357 VirtioOperationBusMasterCommonBuffer,
358 HostStatusBuffer,
359 sizeof *HostStatus,
360 &HostStatusDeviceAddress,
361 &StatusMapping
362 );
363 if (EFI_ERROR (Status)) {
364 Status = EFI_DEVICE_ERROR;
365 goto UnmapDataBuffer;
366 }
367
368 VirtioPrepare (&Dev->Ring, &Indices);
369
370 //
371 // ensured by VirtioBlkInit() -- this predicate, in combination with the
372 // lock-step progress, ensures we don't have to track free descriptors.
373 //
374 ASSERT (Dev->Ring.QueueSize >= 3);
375
376 //
377 // virtio-blk header in first desc
378 //
379 VirtioAppendDesc (
380 &Dev->Ring,
381 RequestDeviceAddress,
382 sizeof (*Request),
383 VRING_DESC_F_NEXT,
384 &Indices
385 );
386
387 //
388 // data buffer for read/write in second desc
389 //
390 if (BufferSize > 0) {
391 //
392 // From virtio-0.9.5, 2.3.2 Descriptor Table:
393 // "no descriptor chain may be more than 2^32 bytes long in total".
394 //
395 // The predicate is ensured by the call contract above (for flush), or
396 // VerifyReadWriteRequest() (for read/write). It also implies that
397 // converting BufferSize to UINT32 will not truncate it.
398 //
399 ASSERT (BufferSize <= SIZE_1GB);
400
401 //
402 // VRING_DESC_F_WRITE is interpreted from the host's point of view.
403 //
404 VirtioAppendDesc (
405 &Dev->Ring,
406 BufferDeviceAddress,
407 (UINT32)BufferSize,
408 VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),
409 &Indices
410 );
411 }
412
413 //
414 // host status in last (second or third) desc
415 //
416 VirtioAppendDesc (
417 &Dev->Ring,
418 HostStatusDeviceAddress,
419 sizeof *HostStatus,
420 VRING_DESC_F_WRITE,
421 &Indices
422 );
423
424 //
425 // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).
426 //
427 if ((VirtioFlush (
428 Dev->VirtIo,
429 0,
430 &Dev->Ring,
431 &Indices,
432 NULL
433 ) == EFI_SUCCESS) &&
434 (*HostStatus == VIRTIO_BLK_S_OK))
435 {
436 Status = EFI_SUCCESS;
437 } else {
438 Status = EFI_DEVICE_ERROR;
439 }
440
441 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);
442
443UnmapDataBuffer:
444 if (BufferSize > 0) {
445 UnmapStatus = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping);
446 if (EFI_ERROR (UnmapStatus) && !RequestIsWrite && !EFI_ERROR (Status)) {
447 //
448 // Data from the bus master may not reach the caller; fail the request.
449 //
450 Status = EFI_DEVICE_ERROR;
451 }
452 }
453
454UnmapRequestBuffer:
455 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);
456
457FreeHostStatusBuffer:
458 Dev->VirtIo->FreeSharedPages (
459 Dev->VirtIo,
460 EFI_SIZE_TO_PAGES (sizeof *HostStatus),
461 HostStatusBuffer
462 );
463
464FreeBlkRequest:
465 FreePool ((VOID *)Request);
466
467 return Status;
468}
469
470/**
471
472 ReadBlocks() operation for virtio-blk.
473
474 See
475 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
476 Protocol, EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
477 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.2. ReadBlocks() and
478 ReadBlocksEx() Implementation.
479
480 Parameter checks and conformant return values are implemented in
481 VerifyReadWriteRequest() and SynchronousRequest().
482
483 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,
484 successfully.
485
486**/
487EFI_STATUS
488EFIAPI
489VirtioBlkReadBlocks (
490 IN EFI_BLOCK_IO_PROTOCOL *This,
491 IN UINT32 MediaId,
492 IN EFI_LBA Lba,
493 IN UINTN BufferSize,
494 OUT VOID *Buffer
495 )
496{
497 VBLK_DEV *Dev;
498 EFI_STATUS Status;
499
500 if (BufferSize == 0) {
501 return EFI_SUCCESS;
502 }
503
504 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
505 Status = VerifyReadWriteRequest (
506 &Dev->BlockIoMedia,
507 Lba,
508 BufferSize,
509 FALSE // RequestIsWrite
510 );
511 if (EFI_ERROR (Status)) {
512 return Status;
513 }
514
515 return SynchronousRequest (
516 Dev,
517 Lba,
518 BufferSize,
519 Buffer,
520 FALSE // RequestIsWrite
521 );
522}
523
524/**
525
526 WriteBlocks() operation for virtio-blk.
527
528 See
529 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
530 Protocol, EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
531 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.3 WriteBlocks() and
532 WriteBlockEx() Implementation.
533
534 Parameter checks and conformant return values are implemented in
535 VerifyReadWriteRequest() and SynchronousRequest().
536
537 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,
538 successfully.
539
540**/
541EFI_STATUS
542EFIAPI
543VirtioBlkWriteBlocks (
544 IN EFI_BLOCK_IO_PROTOCOL *This,
545 IN UINT32 MediaId,
546 IN EFI_LBA Lba,
547 IN UINTN BufferSize,
548 IN VOID *Buffer
549 )
550{
551 VBLK_DEV *Dev;
552 EFI_STATUS Status;
553
554 if (BufferSize == 0) {
555 return EFI_SUCCESS;
556 }
557
558 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
559 Status = VerifyReadWriteRequest (
560 &Dev->BlockIoMedia,
561 Lba,
562 BufferSize,
563 TRUE // RequestIsWrite
564 );
565 if (EFI_ERROR (Status)) {
566 return Status;
567 }
568
569 return SynchronousRequest (
570 Dev,
571 Lba,
572 BufferSize,
573 Buffer,
574 TRUE // RequestIsWrite
575 );
576}
577
578/**
579
580 FlushBlocks() operation for virtio-blk.
581
582 See
583 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O
584 Protocol, EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
585 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.4 FlushBlocks() and
586 FlushBlocksEx() Implementation.
587
588 If the underlying virtio-blk device doesn't support flushing (ie.
589 write-caching), then this function should not be called by higher layers,
590 according to EFI_BLOCK_IO_MEDIA characteristics set in VirtioBlkInit().
591 Should they do nonetheless, we do nothing, successfully.
592
593**/
594EFI_STATUS
595EFIAPI
596VirtioBlkFlushBlocks (
597 IN EFI_BLOCK_IO_PROTOCOL *This
598 )
599{
600 VBLK_DEV *Dev;
601
602 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);
603 return Dev->BlockIoMedia.WriteCaching ?
604 SynchronousRequest (
605 Dev,
606 0, // Lba
607 0, // BufferSize
608 NULL, // Buffer
609 TRUE // RequestIsWrite
610 ) :
611 EFI_SUCCESS;
612}
613
614/**
615
616 Device probe function for this driver.
617
618 The DXE core calls this function for any given device in order to see if the
619 driver can drive the device.
620
621 Specs relevant in the general sense:
622
623 - UEFI Spec 2.3.1 + Errata C:
624 - 6.3 Protocol Handler Services -- for accessing the underlying device
625 - 10.1 EFI Driver Binding Protocol -- for exporting ourselves
626
627 - Driver Writer's Guide for UEFI 2.3.1 v1.01:
628 - 5.1.3.4 OpenProtocol() and CloseProtocol() -- for accessing the
629 underlying device
630 - 9 Driver Binding Protocol -- for exporting ourselves
631
632 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
633 incorporating this driver (independently of
634 any device).
635
636 @param[in] DeviceHandle The device to probe.
637
638 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.
639
640
641 @retval EFI_SUCCESS The driver supports the device being probed.
642
643 @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support
644 the device.
645
646 @return Error codes from the OpenProtocol() boot service or
647 the VirtIo protocol.
648
649**/
650EFI_STATUS
651EFIAPI
652VirtioBlkDriverBindingSupported (
653 IN EFI_DRIVER_BINDING_PROTOCOL *This,
654 IN EFI_HANDLE DeviceHandle,
655 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
656 )
657{
658 EFI_STATUS Status;
659 VIRTIO_DEVICE_PROTOCOL *VirtIo;
660
661 //
662 // Attempt to open the device with the VirtIo set of interfaces. On success,
663 // the protocol is "instantiated" for the VirtIo device. Covers duplicate
664 // open attempts (EFI_ALREADY_STARTED).
665 //
666 Status = gBS->OpenProtocol (
667 DeviceHandle, // candidate device
668 &gVirtioDeviceProtocolGuid, // for generic VirtIo access
669 (VOID **)&VirtIo, // handle to instantiate
670 This->DriverBindingHandle, // requestor driver identity
671 DeviceHandle, // ControllerHandle, according to
672 // the UEFI Driver Model
673 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
674 // the device; to be released
675 );
676 if (EFI_ERROR (Status)) {
677 return Status;
678 }
679
680 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {
681 Status = EFI_UNSUPPORTED;
682 }
683
684 //
685 // We needed VirtIo access only transitorily, to see whether we support the
686 // device or not.
687 //
688 gBS->CloseProtocol (
689 DeviceHandle,
690 &gVirtioDeviceProtocolGuid,
691 This->DriverBindingHandle,
692 DeviceHandle
693 );
694 return Status;
695}
696
697/**
698
699 Set up all BlockIo and virtio-blk aspects of this driver for the specified
700 device.
701
702 @param[in out] Dev The driver instance to configure. The caller is
703 responsible for Dev->VirtIo's validity (ie. working IO
704 access to the underlying virtio-blk device).
705
706 @retval EFI_SUCCESS Setup complete.
707
708 @retval EFI_UNSUPPORTED The driver is unable to work with the virtio ring or
709 virtio-blk attributes the host provides.
710
711 @return Error codes from VirtioRingInit() or
712 VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE or
713 VirtioRingMap().
714
715**/
716STATIC
717EFI_STATUS
718EFIAPI
719VirtioBlkInit (
720 IN OUT VBLK_DEV *Dev
721 )
722{
723 UINT8 NextDevStat;
724 EFI_STATUS Status;
725
726 UINT64 Features;
727 UINT64 NumSectors;
728 UINT32 BlockSize;
729 UINT8 PhysicalBlockExp;
730 UINT8 AlignmentOffset;
731 UINT32 OptIoSize;
732 UINT16 QueueSize;
733 UINT64 RingBaseShift;
734
735 PhysicalBlockExp = 0;
736 AlignmentOffset = 0;
737 OptIoSize = 0;
738
739 //
740 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
741 //
742 NextDevStat = 0; // step 1 -- reset device
743 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
744 if (EFI_ERROR (Status)) {
745 goto Failed;
746 }
747
748 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
749 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
750 if (EFI_ERROR (Status)) {
751 goto Failed;
752 }
753
754 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
755 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
756 if (EFI_ERROR (Status)) {
757 goto Failed;
758 }
759
760 //
761 // Set Page Size - MMIO VirtIo Specific
762 //
763 Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
764 if (EFI_ERROR (Status)) {
765 goto Failed;
766 }
767
768 //
769 // step 4a -- retrieve and validate features
770 //
771 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
772 if (EFI_ERROR (Status)) {
773 goto Failed;
774 }
775
776 Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
777 if (EFI_ERROR (Status)) {
778 goto Failed;
779 }
780
781 if (NumSectors == 0) {
782 Status = EFI_UNSUPPORTED;
783 goto Failed;
784 }
785
786 if (Features & VIRTIO_BLK_F_BLK_SIZE) {
787 Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
788 if (EFI_ERROR (Status)) {
789 goto Failed;
790 }
791
792 if ((BlockSize == 0) || (BlockSize % 512 != 0) ||
793 (ModU64x32 (NumSectors, BlockSize / 512) != 0))
794 {
795 //
796 // We can only handle a logical block consisting of whole sectors,
797 // and only a disk composed of whole logical blocks.
798 //
799 Status = EFI_UNSUPPORTED;
800 goto Failed;
801 }
802 } else {
803 BlockSize = 512;
804 }
805
806 if (Features & VIRTIO_BLK_F_TOPOLOGY) {
807 Status = VIRTIO_CFG_READ (
808 Dev,
809 Topology.PhysicalBlockExp,
810 &PhysicalBlockExp
811 );
812 if (EFI_ERROR (Status)) {
813 goto Failed;
814 }
815
816 if (PhysicalBlockExp >= 32) {
817 Status = EFI_UNSUPPORTED;
818 goto Failed;
819 }
820
821 Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);
822 if (EFI_ERROR (Status)) {
823 goto Failed;
824 }
825
826 Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);
827 if (EFI_ERROR (Status)) {
828 goto Failed;
829 }
830 }
831
832 Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |
833 VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |
834 VIRTIO_F_IOMMU_PLATFORM;
835
836 //
837 // In virtio-1.0, feature negotiation is expected to complete before queue
838 // discovery, and the device can also reject the selected set of features.
839 //
840 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
841 Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
842 if (EFI_ERROR (Status)) {
843 goto Failed;
844 }
845 }
846
847 //
848 // step 4b -- allocate virtqueue
849 //
850 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
851 if (EFI_ERROR (Status)) {
852 goto Failed;
853 }
854
855 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
856 if (EFI_ERROR (Status)) {
857 goto Failed;
858 }
859
860 if (QueueSize < 3) {
861 // SynchronousRequest() uses at most three descriptors
862 Status = EFI_UNSUPPORTED;
863 goto Failed;
864 }
865
866 Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);
867 if (EFI_ERROR (Status)) {
868 goto Failed;
869 }
870
871 //
872 // If anything fails from here on, we must release the ring resources
873 //
874 Status = VirtioRingMap (
875 Dev->VirtIo,
876 &Dev->Ring,
877 &RingBaseShift,
878 &Dev->RingMap
879 );
880 if (EFI_ERROR (Status)) {
881 goto ReleaseQueue;
882 }
883
884 //
885 // Additional steps for MMIO: align the queue appropriately, and set the
886 // size. If anything fails from here on, we must unmap the ring resources.
887 //
888 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
889 if (EFI_ERROR (Status)) {
890 goto UnmapQueue;
891 }
892
893 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
894 if (EFI_ERROR (Status)) {
895 goto UnmapQueue;
896 }
897
898 //
899 // step 4c -- Report GPFN (guest-physical frame number) of queue.
900 //
901 Status = Dev->VirtIo->SetQueueAddress (
902 Dev->VirtIo,
903 &Dev->Ring,
904 RingBaseShift
905 );
906 if (EFI_ERROR (Status)) {
907 goto UnmapQueue;
908 }
909
910 //
911 // step 5 -- Report understood features.
912 //
913 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
914 Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
915 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
916 if (EFI_ERROR (Status)) {
917 goto UnmapQueue;
918 }
919 }
920
921 //
922 // step 6 -- initialization complete
923 //
924 NextDevStat |= VSTAT_DRIVER_OK;
925 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
926 if (EFI_ERROR (Status)) {
927 goto UnmapQueue;
928 }
929
930 //
931 // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI
932 // Block I/O Protocol.
933 //
934 Dev->BlockIo.Revision = 0;
935 Dev->BlockIo.Media = &Dev->BlockIoMedia;
936 Dev->BlockIo.Reset = &VirtioBlkReset;
937 Dev->BlockIo.ReadBlocks = &VirtioBlkReadBlocks;
938 Dev->BlockIo.WriteBlocks = &VirtioBlkWriteBlocks;
939 Dev->BlockIo.FlushBlocks = &VirtioBlkFlushBlocks;
940 Dev->BlockIoMedia.MediaId = 0;
941 Dev->BlockIoMedia.RemovableMedia = FALSE;
942 Dev->BlockIoMedia.MediaPresent = TRUE;
943 Dev->BlockIoMedia.LogicalPartition = FALSE;
944 Dev->BlockIoMedia.ReadOnly = (BOOLEAN)((Features & VIRTIO_BLK_F_RO) != 0);
945 Dev->BlockIoMedia.WriteCaching = (BOOLEAN)((Features & VIRTIO_BLK_F_FLUSH) != 0);
946 Dev->BlockIoMedia.BlockSize = BlockSize;
947 Dev->BlockIoMedia.IoAlign = 0;
948 Dev->BlockIoMedia.LastBlock = DivU64x32 (
949 NumSectors,
950 BlockSize / 512
951 ) - 1;
952
953 DEBUG ((
954 DEBUG_INFO,
955 "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",
956 __func__,
957 Dev->BlockIoMedia.BlockSize,
958 Dev->BlockIoMedia.LastBlock + 1
959 ));
960
961 if (Features & VIRTIO_BLK_F_TOPOLOGY) {
962 Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
963
964 Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;
965 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;
966 Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;
967
968 DEBUG ((
969 DEBUG_INFO,
970 "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",
971 __func__,
972 Dev->BlockIoMedia.LowestAlignedLba,
973 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock
974 ));
975 DEBUG ((
976 DEBUG_INFO,
977 "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",
978 __func__,
979 Dev->BlockIoMedia.OptimalTransferLengthGranularity
980 ));
981 }
982
983 return EFI_SUCCESS;
984
985UnmapQueue:
986 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
987
988ReleaseQueue:
989 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
990
991Failed:
992 //
993 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
994 // Status. VirtIo access failure here should not mask the original error.
995 //
996 NextDevStat |= VSTAT_FAILED;
997 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
998
999 return Status; // reached only via Failed above
1000}
1001
1002/**
1003
1004 Uninitialize the internals of a virtio-blk device that has been successfully
1005 set up with VirtioBlkInit().
1006
1007 @param[in out] Dev The device to clean up.
1008
1009**/
1010STATIC
1011VOID
1012EFIAPI
1013VirtioBlkUninit (
1014 IN OUT VBLK_DEV *Dev
1015 )
1016{
1017 //
1018 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
1019 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
1020 // the old comms area.
1021 //
1022 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1023
1024 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
1025 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
1026
1027 SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00);
1028 SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);
1029}
1030
1031/**
1032
1033 Event notification function enqueued by ExitBootServices().
1034
1035 @param[in] Event Event whose notification function is being invoked.
1036
1037 @param[in] Context Pointer to the VBLK_DEV structure.
1038
1039**/
1040STATIC
1041VOID
1042EFIAPI
1043VirtioBlkExitBoot (
1044 IN EFI_EVENT Event,
1045 IN VOID *Context
1046 )
1047{
1048 VBLK_DEV *Dev;
1049
1050 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __func__, Context));
1051 //
1052 // Reset the device. This causes the hypervisor to forget about the virtio
1053 // ring.
1054 //
1055 // We allocated said ring in EfiBootServicesData type memory, and code
1056 // executing after ExitBootServices() is permitted to overwrite it.
1057 //
1058 Dev = Context;
1059 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1060}
1061
1062/**
1063
1064 After we've pronounced support for a specific device in
1065 DriverBindingSupported(), we start managing said device (passed in by the
1066 Driver Execution Environment) with the following service.
1067
1068 See DriverBindingSupported() for specification references.
1069
1070 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
1071 incorporating this driver (independently of
1072 any device).
1073
1074 @param[in] DeviceHandle The supported device to drive.
1075
1076 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.
1077
1078
1079 @retval EFI_SUCCESS Driver instance has been created and
1080 initialized for the virtio-blk device, it
1081 is now accessible via EFI_BLOCK_IO_PROTOCOL.
1082
1083 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
1084
1085 @return Error codes from the OpenProtocol() boot
1086 service, the VirtIo protocol, VirtioBlkInit(),
1087 or the InstallProtocolInterface() boot service.
1088
1089**/
1090EFI_STATUS
1091EFIAPI
1092VirtioBlkDriverBindingStart (
1093 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1094 IN EFI_HANDLE DeviceHandle,
1095 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1096 )
1097{
1098 VBLK_DEV *Dev;
1099 EFI_STATUS Status;
1100
1101 Dev = (VBLK_DEV *)AllocateZeroPool (sizeof *Dev);
1102 if (Dev == NULL) {
1103 return EFI_OUT_OF_RESOURCES;
1104 }
1105
1106 Status = gBS->OpenProtocol (
1107 DeviceHandle,
1108 &gVirtioDeviceProtocolGuid,
1109 (VOID **)&Dev->VirtIo,
1110 This->DriverBindingHandle,
1111 DeviceHandle,
1112 EFI_OPEN_PROTOCOL_BY_DRIVER
1113 );
1114 if (EFI_ERROR (Status)) {
1115 goto FreeVirtioBlk;
1116 }
1117
1118 //
1119 // VirtIo access granted, configure virtio-blk device.
1120 //
1121 Status = VirtioBlkInit (Dev);
1122 if (EFI_ERROR (Status)) {
1123 goto CloseVirtIo;
1124 }
1125
1126 Status = gBS->CreateEvent (
1127 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1128 TPL_CALLBACK,
1129 &VirtioBlkExitBoot,
1130 Dev,
1131 &Dev->ExitBoot
1132 );
1133 if (EFI_ERROR (Status)) {
1134 goto UninitDev;
1135 }
1136
1137 //
1138 // Setup complete, attempt to export the driver instance's BlockIo interface.
1139 //
1140 Dev->Signature = VBLK_SIG;
1141 Status = gBS->InstallProtocolInterface (
1142 &DeviceHandle,
1143 &gEfiBlockIoProtocolGuid,
1144 EFI_NATIVE_INTERFACE,
1145 &Dev->BlockIo
1146 );
1147 if (EFI_ERROR (Status)) {
1148 goto CloseExitBoot;
1149 }
1150
1151 return EFI_SUCCESS;
1152
1153CloseExitBoot:
1154 gBS->CloseEvent (Dev->ExitBoot);
1155
1156UninitDev:
1157 VirtioBlkUninit (Dev);
1158
1159CloseVirtIo:
1160 gBS->CloseProtocol (
1161 DeviceHandle,
1162 &gVirtioDeviceProtocolGuid,
1163 This->DriverBindingHandle,
1164 DeviceHandle
1165 );
1166
1167FreeVirtioBlk:
1168 FreePool (Dev);
1169
1170 return Status;
1171}
1172
1173/**
1174
1175 Stop driving a virtio-blk device and remove its BlockIo interface.
1176
1177 This function replays the success path of DriverBindingStart() in reverse.
1178 The host side virtio-blk device is reset, so that the OS boot loader or the
1179 OS may reinitialize it.
1180
1181 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
1182 incorporating this driver (independently of any
1183 device).
1184
1185 @param[in] DeviceHandle Stop driving this device.
1186
1187 @param[in] NumberOfChildren Since this function belongs to a device driver
1188 only (as opposed to a bus driver), the caller
1189 environment sets NumberOfChildren to zero, and
1190 we ignore it.
1191
1192 @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).
1193
1194**/
1195EFI_STATUS
1196EFIAPI
1197VirtioBlkDriverBindingStop (
1198 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1199 IN EFI_HANDLE DeviceHandle,
1200 IN UINTN NumberOfChildren,
1201 IN EFI_HANDLE *ChildHandleBuffer
1202 )
1203{
1204 EFI_STATUS Status;
1205 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1206 VBLK_DEV *Dev;
1207
1208 Status = gBS->OpenProtocol (
1209 DeviceHandle, // candidate device
1210 &gEfiBlockIoProtocolGuid, // retrieve the BlockIo iface
1211 (VOID **)&BlockIo, // target pointer
1212 This->DriverBindingHandle, // requestor driver identity
1213 DeviceHandle, // requesting lookup for dev.
1214 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added
1215 );
1216 if (EFI_ERROR (Status)) {
1217 return Status;
1218 }
1219
1220 Dev = VIRTIO_BLK_FROM_BLOCK_IO (BlockIo);
1221
1222 //
1223 // Handle Stop() requests for in-use driver instances gracefully.
1224 //
1225 Status = gBS->UninstallProtocolInterface (
1226 DeviceHandle,
1227 &gEfiBlockIoProtocolGuid,
1228 &Dev->BlockIo
1229 );
1230 if (EFI_ERROR (Status)) {
1231 return Status;
1232 }
1233
1234 gBS->CloseEvent (Dev->ExitBoot);
1235
1236 VirtioBlkUninit (Dev);
1237
1238 gBS->CloseProtocol (
1239 DeviceHandle,
1240 &gVirtioDeviceProtocolGuid,
1241 This->DriverBindingHandle,
1242 DeviceHandle
1243 );
1244
1245 FreePool (Dev);
1246
1247 return EFI_SUCCESS;
1248}
1249
1250//
1251// The static object that groups the Supported() (ie. probe), Start() and
1252// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
1253// C, 10.1 EFI Driver Binding Protocol.
1254//
1255STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
1256 &VirtioBlkDriverBindingSupported,
1257 &VirtioBlkDriverBindingStart,
1258 &VirtioBlkDriverBindingStop,
1259 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1260 NULL, // ImageHandle, to be overwritten by
1261 // EfiLibInstallDriverBindingComponentName2() in VirtioBlkEntryPoint()
1262 NULL // DriverBindingHandle, ditto
1263};
1264
1265//
1266// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
1267// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
1268// in English, for display on standard console devices. This is recommended for
1269// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
1270// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
1271//
1272// Device type names ("Virtio Block Device") are not formatted because the
1273// driver supports only that device type. Therefore the driver name suffices
1274// for unambiguous identification.
1275//
1276
1277STATIC
1278EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1279 { "eng;en", L"Virtio Block Driver" },
1280 { NULL, NULL }
1281};
1282
1283STATIC
1284EFI_COMPONENT_NAME_PROTOCOL gComponentName;
1285
1286EFI_STATUS
1287EFIAPI
1288VirtioBlkGetDriverName (
1289 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1290 IN CHAR8 *Language,
1291 OUT CHAR16 **DriverName
1292 )
1293{
1294 return LookupUnicodeString2 (
1295 Language,
1296 This->SupportedLanguages,
1297 mDriverNameTable,
1298 DriverName,
1299 (BOOLEAN)(This == &gComponentName) // Iso639Language
1300 );
1301}
1302
1303EFI_STATUS
1304EFIAPI
1305VirtioBlkGetDeviceName (
1306 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1307 IN EFI_HANDLE DeviceHandle,
1308 IN EFI_HANDLE ChildHandle,
1309 IN CHAR8 *Language,
1310 OUT CHAR16 **ControllerName
1311 )
1312{
1313 return EFI_UNSUPPORTED;
1314}
1315
1316STATIC
1317EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
1318 &VirtioBlkGetDriverName,
1319 &VirtioBlkGetDeviceName,
1320 "eng" // SupportedLanguages, ISO 639-2 language codes
1321};
1322
1323STATIC
1324EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
1325 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioBlkGetDriverName,
1326 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioBlkGetDeviceName,
1327 "en" // SupportedLanguages, RFC 4646 language codes
1328};
1329
1330//
1331// Entry point of this driver.
1332//
1333EFI_STATUS
1334EFIAPI
1335VirtioBlkEntryPoint (
1336 IN EFI_HANDLE ImageHandle,
1337 IN EFI_SYSTEM_TABLE *SystemTable
1338 )
1339{
1340 return EfiLibInstallDriverBindingComponentName2 (
1341 ImageHandle,
1342 SystemTable,
1343 &gDriverBinding,
1344 ImageHandle,
1345 &gComponentName,
1346 &gComponentName2
1347 );
1348}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette