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