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