]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/VirtioBlkDxe/VirtioBlk.c
OvmfPkg: Include/IndustryStandard: extract VirtioBlk.h from Virtio.h
[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
14\r
15 This program and the accompanying materials are licensed and made available\r
16 under the terms and conditions of the BSD License which accompanies this\r
17 distribution. The full text of the license may be found at\r
18 http://opensource.org/licenses/bsd-license.php\r
19\r
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
21 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
22\r
23**/\r
24\r
25#include <IndustryStandard/Pci.h>\r
6b28fe9e 26#include <IndustryStandard/VirtioBlk.h>\r
fd51d759 27#include <Library/BaseMemoryLib.h>\r
28#include <Library/DebugLib.h>\r
29#include <Library/MemoryAllocationLib.h>\r
30#include <Library/UefiBootServicesTableLib.h>\r
31#include <Library/UefiLib.h>\r
32\r
33#include "VirtioBlk.h"\r
34\r
35/**\r
36\r
37 Write a word into Region 0 of the device specified by PciIo.\r
38\r
39 Region 0 must be an iomem region. This is an internal function for the\r
40 VIRTIO_CFG_WRITE() macro below.\r
41\r
42 @param[in] PciIo Target PCI device.\r
43\r
44 @param[in] FieldOffset Destination offset.\r
45\r
46 @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.\r
47\r
48 @param[in] Value Little endian value to write, converted to UINT64.\r
49 The least significant FieldSize bytes will be used.\r
50\r
51\r
52 @return Status code returned by PciIo->Io.Write().\r
53\r
54**/\r
55STATIC\r
56EFIAPI\r
57EFI_STATUS\r
58VirtioWrite (\r
59 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
60 IN UINTN FieldOffset,\r
61 IN UINTN FieldSize,\r
62 IN UINT64 Value\r
63 )\r
64{\r
65 UINTN Count;\r
66 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
67\r
68 Count = 1;\r
69 switch (FieldSize) {\r
70 case 1:\r
71 Width = EfiPciIoWidthUint8;\r
72 break;\r
73\r
74 case 2:\r
75 Width = EfiPciIoWidthUint16;\r
76 break;\r
77\r
78 case 8:\r
79 Count = 2;\r
80 // fall through\r
81\r
82 case 4:\r
83 Width = EfiPciIoWidthUint32;\r
84 break;\r
85\r
86 default:\r
87 ASSERT (FALSE);\r
88 }\r
89\r
90 return PciIo->Io.Write (\r
91 PciIo,\r
92 Width,\r
93 PCI_BAR_IDX0,\r
94 FieldOffset,\r
95 Count,\r
96 &Value\r
97 );\r
98}\r
99\r
100\r
101/**\r
102\r
103 Read a word from Region 0 of the device specified by PciIo.\r
104\r
105 Region 0 must be an iomem region. This is an internal function for the\r
106 VIRTIO_CFG_READ() macro below.\r
107\r
108 @param[in] PciIo Source PCI device.\r
109\r
110 @param[in] FieldOffset Source offset.\r
111\r
112 @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.\r
113\r
114 @param[in] BufferSize Number of bytes available in the target buffer. Must\r
115 equal FieldSize.\r
116\r
117 @param[out] Buffer Target buffer.\r
118\r
119\r
120 @return Status code returned by PciIo->Io.Read().\r
121\r
122**/\r
123STATIC\r
124EFIAPI\r
125EFI_STATUS\r
126VirtioRead (\r
127 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
128 IN UINTN FieldOffset,\r
129 IN UINTN FieldSize,\r
130 IN UINTN BufferSize,\r
131 OUT VOID *Buffer\r
132 )\r
133{\r
134 UINTN Count;\r
135 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
136\r
137 ASSERT (FieldSize == BufferSize);\r
138\r
139 Count = 1;\r
140 switch (FieldSize) {\r
141 case 1:\r
142 Width = EfiPciIoWidthUint8;\r
143 break;\r
144\r
145 case 2:\r
146 Width = EfiPciIoWidthUint16;\r
147 break;\r
148\r
149 case 8:\r
150 Count = 2;\r
151 // fall through\r
152\r
153 case 4:\r
154 Width = EfiPciIoWidthUint32;\r
155 break;\r
156\r
157 default:\r
158 ASSERT (FALSE);\r
159 }\r
160\r
161 return PciIo->Io.Read (\r
162 PciIo,\r
163 Width,\r
164 PCI_BAR_IDX0,\r
165 FieldOffset,\r
166 Count,\r
167 Buffer\r
168 );\r
169}\r
170\r
171\r
172/**\r
173\r
174 Convenience macros to read and write region 0 IO space elements of the\r
175 virtio-blk PCI device, for configuration purposes.\r
176\r
177 The following macros make it possible to specify only the "core parameters"\r
178 for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()\r
179 returns, the transaction will have been completed.\r
180\r
181 @param[in] Dev Pointer to the VBLK_DEV structure whose PCI IO space\r
182 we're accessing. Dev->PciIo must be valid.\r
183\r
184 @param[in] Field A field name from VBLK_HDR, identifying the virtio-blk\r
185 configuration item to access.\r
186\r
187 @param[in] Value (VIRTIO_CFG_WRITE() only.) The value to write to the\r
188 selected configuration item.\r
189\r
190 @param[out] Pointer (VIRTIO_CFG_READ() only.) The object to receive the\r
191 value read from the configuration item. Its type must be\r
192 one of UINT8, UINT16, UINT32, UINT64.\r
193\r
194\r
195 @return Status code returned by VirtioWrite() / VirtioRead().\r
196\r
197**/\r
198\r
199#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \\r
200 (Dev)->PciIo, \\r
a9624f94 201 OFFSET_OF_VBLK (Field), \\r
202 SIZE_OF_VBLK (Field), \\r
fd51d759 203 (Value) \\r
204 ))\r
205\r
206#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \\r
207 (Dev)->PciIo, \\r
a9624f94 208 OFFSET_OF_VBLK (Field), \\r
209 SIZE_OF_VBLK (Field), \\r
fd51d759 210 sizeof *(Pointer), \\r
211 (Pointer) \\r
212 ))\r
213\r
214\r
215//\r
216// UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol\r
217// Driver Writer's Guide for UEFI 2.3.1 v1.01,\r
218// 24.2 Block I/O Protocol Implementations\r
219//\r
220EFI_STATUS\r
221EFIAPI\r
222VirtioBlkReset (\r
223 IN EFI_BLOCK_IO_PROTOCOL *This,\r
224 IN BOOLEAN ExtendedVerification\r
225 )\r
226{\r
227 //\r
228 // If we managed to initialize and install the driver, then the device is\r
229 // working correctly.\r
230 //\r
231 return EFI_SUCCESS;\r
232}\r
233\r
234/**\r
235\r
236 Verify correctness of the read/write (not flush) request submitted to the\r
237 EFI_BLOCK_IO_PROTOCOL instance.\r
238\r
239 This function provides most verification steps described in:\r
240\r
241 UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
242 Protocol,\r
243 - EFI_BLOCK_IO_PROTOCOL.ReadBlocks()\r
244 - EFI_BLOCK_IO_PROTOCOL.WriteBlocks()\r
245\r
246 Driver Writer's Guide for UEFI 2.3.1 v1.01,\r
247 - 24.2.2. ReadBlocks() and ReadBlocksEx() Implementation\r
248 - 24.2.3 WriteBlocks() and WriteBlockEx() Implementation\r
249\r
250 Request sizes are limited to 1 GB (checked). This is not a practical\r
251 limitation, just conformance to virtio-0.9.5, 2.3.2 Descriptor Table: "no\r
252 descriptor chain may be more than 2^32 bytes long in total".\r
253\r
254 Some Media characteristics are hardcoded in VirtioBlkInit() below (like\r
255 non-removable media, no restriction on buffer alignment etc); we rely on\r
256 those here without explicit mention.\r
257\r
258 @param[in] Media The EFI_BLOCK_IO_MEDIA characteristics for\r
259 this driver instance, extracted from the\r
260 underlying virtio-blk device at initialization\r
261 time. We validate the request against this set\r
262 of attributes.\r
263\r
264\r
265 @param[in] Lba Logical Block Address: number of logical\r
266 blocks to skip from the beginning of the\r
267 device.\r
268\r
269 @param[in] PositiveBufferSize Size of buffer to transfer, in bytes. The\r
270 caller is responsible to ensure this parameter\r
271 is positive.\r
272\r
273 @param[in] RequestIsWrite TRUE iff data transfer goes from guest to\r
274 device.\r
275\r
276\r
277 @@return Validation result to be forwarded outwards by\r
278 ReadBlocks() and WriteBlocks, as required by\r
279 the specs above.\r
280\r
281**/\r
282STATIC\r
283EFI_STATUS\r
284EFIAPI\r
285VerifyReadWriteRequest (\r
286 IN EFI_BLOCK_IO_MEDIA *Media,\r
287 IN EFI_LBA Lba,\r
288 IN UINTN PositiveBufferSize,\r
289 IN BOOLEAN RequestIsWrite\r
290 )\r
291{\r
292 UINTN BlockCount;\r
293\r
294 ASSERT (PositiveBufferSize > 0);\r
295\r
296 if (PositiveBufferSize > SIZE_1GB ||\r
297 PositiveBufferSize % Media->BlockSize > 0) {\r
298 return EFI_BAD_BUFFER_SIZE;\r
299 }\r
300 BlockCount = PositiveBufferSize / Media->BlockSize;\r
301\r
302 //\r
303 // Avoid unsigned wraparound on either side in the second comparison.\r
304 //\r
305 if (Lba > Media->LastBlock || BlockCount - 1 > Media->LastBlock - Lba) {\r
306 return EFI_INVALID_PARAMETER;\r
307 }\r
308\r
309 if (RequestIsWrite && Media->ReadOnly) {\r
310 return EFI_WRITE_PROTECTED;\r
311 }\r
312\r
313 return EFI_SUCCESS;\r
314}\r
315\r
316\r
317/**\r
318\r
319 Append a contiguous buffer for transmission / reception via the virtio ring.\r
320\r
321 This function implements the following sections from virtio-0.9.5:\r
322 - 2.4.1.1 Placing Buffers into the Descriptor Table\r
323 - 2.4.1.2 Updating the Available Ring\r
324\r
325 Free space is taken as granted, since this driver supports only synchronous\r
326 requests and host side status is processed in lock-step with request\r
327 submission. VirtioBlkInit() verifies the ring size in advance.\r
328\r
329 @param[in out] Ring The virtio ring to append the buffer to, as a\r
330 descriptor.\r
331\r
332 @param [in] BufferPhysAddr (Guest pseudo-physical) start address of the\r
333 transmit / receive buffer\r
334\r
335 @param [in] BufferSize Number of bytes to transmit or receive.\r
336\r
337 @param [in] Flags A bitmask of VRING_DESC_F_* flags. The caller\r
338 computes this mask dependent on further buffers\r
339 to append and transfer direction.\r
340 VRING_DESC_F_INDIRECT is unsupported. The\r
341 VRING_DESC.Next field is always set, but the\r
342 host only interprets it dependent on\r
343 VRING_DESC_F_NEXT.\r
344\r
345 @param [in] HeadIdx The index identifying the head buffer (first\r
346 buffer appended) belonging to this same\r
347 request.\r
348\r
349 @param [in out] NextAvailIdx On input, the index identifying the next\r
350 descriptor available to carry the buffer. On\r
351 output, incremented by one, modulo 2^16.\r
352\r
353**/\r
354\r
355STATIC\r
356VOID\r
357EFIAPI\r
358AppendDesc (\r
359 IN OUT VRING *Ring,\r
360 IN UINTN BufferPhysAddr,\r
361 IN UINT32 BufferSize,\r
362 IN UINT16 Flags,\r
363 IN UINT16 HeadIdx,\r
364 IN OUT UINT16 *NextAvailIdx\r
365 )\r
366{\r
367 volatile VRING_DESC *Desc;\r
368\r
369 Desc = &Ring->Desc[*NextAvailIdx % Ring->QueueSize];\r
370 Desc->Addr = BufferPhysAddr;\r
371 Desc->Len = BufferSize;\r
372 Desc->Flags = Flags;\r
373 Ring->Avail.Ring[(*NextAvailIdx)++ % Ring->QueueSize] =\r
374 HeadIdx % Ring->QueueSize;\r
375 Desc->Next = *NextAvailIdx % Ring->QueueSize;\r
376}\r
377\r
378\r
379/**\r
380\r
381 Format a read / write / flush request as three consecutive virtio\r
382 descriptors, push them to the host, and poll for the response.\r
383\r
384 This is the main workhorse function. Two use cases are supported, read/write\r
385 and flush. The function may only be called after the request parameters have\r
386 been verified by\r
387 - specific checks in ReadBlocks() / WriteBlocks() / FlushBlocks(), and\r
388 - VerifyReadWriteRequest() (for read/write only).\r
389\r
390 Parameters handled commonly:\r
391\r
392 @param[in] Dev The virtio-blk device the request is targeted\r
393 at.\r
394\r
395 Flush request:\r
396\r
397 @param[in] Lba Must be zero.\r
398\r
399 @param[in] BufferSize Must be zero.\r
400\r
401 @param[in out] Buffer Ignored by the function.\r
402\r
403 @param[in] RequestIsWrite Must be TRUE.\r
404\r
405 Read/Write request:\r
406\r
407 @param[in] Lba Logical Block Address: number of logical blocks\r
408 to skip from the beginning of the device.\r
409\r
410 @param[in] BufferSize Size of buffer to transfer, in bytes. The caller\r
411 is responsible to ensure this parameter is\r
412 positive.\r
413\r
414 @param[in out] Buffer The guest side area to read data from the device\r
415 into, or write data to the device from.\r
416\r
417 @param[in] RequestIsWrite TRUE iff data transfer goes from guest to\r
418 device.\r
419\r
420 Return values are common to both use cases, and are appropriate to be\r
421 forwarded by the EFI_BLOCK_IO_PROTOCOL functions (ReadBlocks(),\r
422 WriteBlocks(), FlushBlocks()).\r
423\r
424\r
425 @retval EFI_SUCCESS Transfer complete.\r
426\r
427 @retval EFI_DEVICE_ERROR Failed to notify host side via PCI write, or\r
428 unable to parse host response, or host response\r
429 is not VIRTIO_BLK_S_OK.\r
430\r
431**/\r
432\r
433STATIC\r
434EFI_STATUS\r
435EFIAPI\r
436SynchronousRequest (\r
437 IN VBLK_DEV *Dev,\r
438 IN EFI_LBA Lba,\r
439 IN UINTN BufferSize,\r
440 IN OUT volatile VOID *Buffer,\r
441 IN BOOLEAN RequestIsWrite\r
442 )\r
443{\r
444 UINT32 BlockSize;\r
445 volatile VIRTIO_BLK_REQ Request;\r
446 volatile UINT8 HostStatus;\r
447 UINT16 FirstAvailIdx;\r
448 UINT16 NextAvailIdx;\r
449 UINTN PollPeriodUsecs;\r
450\r
451 BlockSize = Dev->BlockIoMedia.BlockSize;\r
452\r
453 //\r
454 // ensured by VirtioBlkInit()\r
455 //\r
456 ASSERT (BlockSize > 0);\r
457 ASSERT (BlockSize % 512 == 0);\r
458\r
459 //\r
460 // ensured by contract above, plus VerifyReadWriteRequest()\r
461 //\r
462 ASSERT (BufferSize % BlockSize == 0);\r
463\r
464 //\r
465 // Prepare virtio-blk request header, setting zero size for flush.\r
466 // IO Priority is homogeneously 0.\r
467 //\r
468 Request.Type = RequestIsWrite ?\r
469 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :\r
470 VIRTIO_BLK_T_IN;\r
471 Request.IoPrio = 0;\r
472 Request.Sector = Lba * (BlockSize / 512);\r
473\r
474 //\r
475 // Prepare for virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device.\r
476 // We're going to poll the answer, the host should not send an interrupt.\r
477 //\r
478 *Dev->Ring.Avail.Flags = (UINT16) VRING_AVAIL_F_NO_INTERRUPT;\r
479\r
480 //\r
481 // preset a host status for ourselves that we do not accept as success\r
482 //\r
483 HostStatus = VIRTIO_BLK_S_IOERR;\r
484\r
485 //\r
486 // ensured by VirtioBlkInit() -- this predicate, in combination with the\r
487 // lock-step progress, ensures we don't have to track free descriptors.\r
488 //\r
489 ASSERT (Dev->Ring.QueueSize >= 3);\r
490\r
491 //\r
492 // Implement virtio-0.9.5, 2.4.1 Supplying Buffers to the Device.\r
493 //\r
494 FirstAvailIdx = *Dev->Ring.Avail.Idx;\r
495 NextAvailIdx = FirstAvailIdx;\r
496\r
497 //\r
498 // virtio-blk header in first desc\r
499 //\r
500 AppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request, VRING_DESC_F_NEXT,\r
501 FirstAvailIdx, &NextAvailIdx);\r
502\r
503 //\r
504 // data buffer for read/write in second desc\r
505 //\r
506 if (BufferSize > 0) {\r
507 //\r
508 // From virtio-0.9.5, 2.3.2 Descriptor Table:\r
509 // "no descriptor chain may be more than 2^32 bytes long in total".\r
510 //\r
511 // The predicate is ensured by the call contract above (for flush), or\r
512 // VerifyReadWriteRequest() (for read/write). It also implies that\r
513 // converting BufferSize to UINT32 will not truncate it.\r
514 //\r
515 ASSERT (BufferSize <= SIZE_1GB);\r
516\r
517 //\r
518 // VRING_DESC_F_WRITE is interpreted from the host's point of view.\r
519 //\r
520 AppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize,\r
521 VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),\r
522 FirstAvailIdx, &NextAvailIdx);\r
523 }\r
524\r
525 //\r
526 // host status in last (second or third) desc\r
527 //\r
528 AppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus,\r
529 VRING_DESC_F_WRITE, FirstAvailIdx, &NextAvailIdx);\r
530\r
531 //\r
532 // virtio-0.9.5, 2.4.1.3 Updating the Index Field\r
533 //\r
534 MemoryFence();\r
535 *Dev->Ring.Avail.Idx = NextAvailIdx;\r
536\r
537 //\r
538 // virtio-0.9.5, 2.4.1.4 Notifying the Device -- gratuitous notifications are\r
539 // OK. virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
540 //\r
541 MemoryFence();\r
55c3443a 542 if (EFI_ERROR (VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueNotify, 0))) {\r
fd51d759 543 return EFI_DEVICE_ERROR;\r
544 }\r
545\r
546 //\r
547 // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device\r
548 // Wait until the host processes and acknowledges our 3-part descriptor\r
549 // chain. The condition we use for polling is greatly simplified and relies\r
550 // on synchronous, the lock-step progress.\r
551 //\r
552 // Keep slowing down until we reach a poll period of slightly above 1 ms.\r
553 //\r
554 PollPeriodUsecs = 1;\r
555 MemoryFence();\r
556 while (*Dev->Ring.Used.Idx != NextAvailIdx) {\r
557 gBS->Stall (PollPeriodUsecs); // calls AcpiTimerLib::MicroSecondDelay\r
558\r
559 if (PollPeriodUsecs < 1024) {\r
560 PollPeriodUsecs *= 2;\r
561 }\r
562 MemoryFence();\r
563 }\r
564\r
565 if (HostStatus == VIRTIO_BLK_S_OK) {\r
566 return EFI_SUCCESS;\r
567 }\r
568\r
569 return EFI_DEVICE_ERROR;\r
570}\r
571\r
572\r
573/**\r
574\r
575 ReadBlocks() operation for virtio-blk.\r
576\r
577 See\r
578 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
579 Protocol, EFI_BLOCK_IO_PROTOCOL.ReadBlocks().\r
580 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.2. ReadBlocks() and\r
581 ReadBlocksEx() Implementation.\r
582\r
583 Parameter checks and conformant return values are implemented in\r
584 VerifyReadWriteRequest() and SynchronousRequest().\r
585\r
586 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,\r
587 successfully.\r
588\r
589**/\r
590\r
591EFI_STATUS\r
592EFIAPI\r
593VirtioBlkReadBlocks (\r
594 IN EFI_BLOCK_IO_PROTOCOL *This,\r
595 IN UINT32 MediaId,\r
596 IN EFI_LBA Lba,\r
597 IN UINTN BufferSize,\r
598 OUT VOID *Buffer\r
599 )\r
600{\r
601 VBLK_DEV *Dev;\r
602 EFI_STATUS Status;\r
603\r
604 if (BufferSize == 0) {\r
605 return EFI_SUCCESS;\r
606 }\r
607\r
608 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
609 Status = VerifyReadWriteRequest (\r
610 &Dev->BlockIoMedia,\r
611 Lba,\r
612 BufferSize,\r
613 FALSE // RequestIsWrite\r
614 );\r
615 if (EFI_ERROR (Status)) {\r
616 return Status;\r
617 }\r
618\r
619 return SynchronousRequest (\r
620 Dev,\r
621 Lba,\r
622 BufferSize,\r
623 Buffer,\r
624 FALSE // RequestIsWrite\r
625 );\r
626}\r
627\r
628/**\r
629\r
630 WriteBlocks() operation for virtio-blk.\r
631\r
632 See\r
633 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
634 Protocol, EFI_BLOCK_IO_PROTOCOL.WriteBlocks().\r
635 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.3 WriteBlocks() and\r
636 WriteBlockEx() Implementation.\r
637\r
638 Parameter checks and conformant return values are implemented in\r
639 VerifyReadWriteRequest() and SynchronousRequest().\r
640\r
641 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,\r
642 successfully.\r
643\r
644**/\r
645\r
646EFI_STATUS\r
647EFIAPI\r
648VirtioBlkWriteBlocks (\r
649 IN EFI_BLOCK_IO_PROTOCOL *This,\r
650 IN UINT32 MediaId,\r
651 IN EFI_LBA Lba,\r
652 IN UINTN BufferSize,\r
653 IN VOID *Buffer\r
654 )\r
655{\r
656 VBLK_DEV *Dev;\r
657 EFI_STATUS Status;\r
658\r
659 if (BufferSize == 0) {\r
660 return EFI_SUCCESS;\r
661 }\r
662\r
663 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
664 Status = VerifyReadWriteRequest (\r
665 &Dev->BlockIoMedia,\r
666 Lba,\r
667 BufferSize,\r
668 TRUE // RequestIsWrite\r
669 );\r
670 if (EFI_ERROR (Status)) {\r
671 return Status;\r
672 }\r
673\r
674 return SynchronousRequest (\r
675 Dev,\r
676 Lba,\r
677 BufferSize,\r
678 Buffer,\r
679 TRUE // RequestIsWrite\r
680 );\r
681}\r
682\r
683\r
684/**\r
685\r
686 FlushBlocks() operation for virtio-blk.\r
687\r
688 See\r
689 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
690 Protocol, EFI_BLOCK_IO_PROTOCOL.FlushBlocks().\r
691 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.4 FlushBlocks() and\r
692 FlushBlocksEx() Implementation.\r
693\r
694 If the underlying virtio-blk device doesn't support flushing (ie.\r
695 write-caching), then this function should not be called by higher layers,\r
696 according to EFI_BLOCK_IO_MEDIA characteristics set in VirtioBlkInit().\r
697 Should they do nonetheless, we do nothing, successfully.\r
698\r
699**/\r
700\r
701EFI_STATUS\r
702EFIAPI\r
703VirtioBlkFlushBlocks (\r
704 IN EFI_BLOCK_IO_PROTOCOL *This\r
705 )\r
706{\r
707 VBLK_DEV *Dev;\r
708\r
709 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
710 return Dev->BlockIoMedia.WriteCaching ?\r
711 SynchronousRequest (\r
712 Dev,\r
713 0, // Lba\r
714 0, // BufferSize\r
715 NULL, // Buffer\r
716 TRUE // RequestIsWrite\r
717 ) :\r
718 EFI_SUCCESS;\r
719}\r
720\r
721\r
722/**\r
723\r
724 Device probe function for this driver.\r
725\r
726 The DXE core calls this function for any given device in order to see if the\r
727 driver can drive the device.\r
728\r
729 Specs relevant in the general sense:\r
730\r
731 - UEFI Spec 2.3.1 + Errata C:\r
732 - 6.3 Protocol Handler Services -- for accessing the underlying device\r
733 - 10.1 EFI Driver Binding Protocol -- for exporting ourselves\r
734\r
735 - Driver Writer's Guide for UEFI 2.3.1 v1.01:\r
736 - 5.1.3.4 OpenProtocol() and CloseProtocol() -- for accessing the\r
737 underlying device\r
738 - 9 Driver Binding Protocol -- for exporting ourselves\r
739\r
740 Specs relevant in the specific sense:\r
741 - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol\r
742 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design\r
743 Guidelines, 18.3 PCI drivers.\r
744\r
745 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
746 incorporating this driver (independently of\r
747 any device).\r
748\r
749 @param[in] DeviceHandle The device to probe.\r
750\r
751 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r
752\r
753\r
754 @retval EFI_SUCCESS The driver supports the device being probed.\r
755\r
756 @retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support\r
757 the device.\r
758\r
759 @return Error codes from the OpenProtocol() boot service or\r
760 the PciIo protocol.\r
761\r
762**/\r
763\r
764EFI_STATUS\r
765EFIAPI\r
766VirtioBlkDriverBindingSupported (\r
767 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
768 IN EFI_HANDLE DeviceHandle,\r
769 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
770 )\r
771{\r
772 EFI_STATUS Status;\r
773 EFI_PCI_IO_PROTOCOL *PciIo;\r
774 PCI_TYPE00 Pci;\r
775\r
776 //\r
777 // Attempt to open the device with the PciIo set of interfaces. On success,\r
778 // the protocol is "instantiated" for the PCI device. Covers duplicate open\r
779 // attempts (EFI_ALREADY_STARTED).\r
780 //\r
781 Status = gBS->OpenProtocol (\r
782 DeviceHandle, // candidate device\r
783 &gEfiPciIoProtocolGuid, // for generic PCI access\r
784 (VOID **)&PciIo, // handle to instantiate\r
785 This->DriverBindingHandle, // requestor driver identity\r
786 DeviceHandle, // ControllerHandle, according to\r
787 // the UEFI Driver Model\r
788 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to\r
789 // the device; to be released\r
790 );\r
791 if (EFI_ERROR (Status)) {\r
792 return Status;\r
793 }\r
794\r
795 //\r
796 // Read entire PCI configuration header for more extensive check ahead.\r
797 //\r
798 Status = PciIo->Pci.Read (\r
799 PciIo, // (protocol, device)\r
800 // handle\r
801 EfiPciIoWidthUint32, // access width & copy\r
802 // mode\r
803 0, // Offset\r
804 sizeof Pci / sizeof (UINT32), // Count\r
805 &Pci // target buffer\r
806 );\r
807\r
808 if (Status == EFI_SUCCESS) {\r
809 //\r
810 // virtio-0.9.5, 2.1 PCI Discovery\r
811 //\r
812 Status = (Pci.Hdr.VendorId == 0x1AF4 &&\r
813 Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&\r
814 Pci.Hdr.RevisionID == 0x00 &&\r
815 Pci.Device.SubsystemID == 0x02) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
816 }\r
817\r
818 //\r
819 // We needed PCI IO access only transitorily, to see whether we support the\r
820 // device or not.\r
821 //\r
822 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
823 This->DriverBindingHandle, DeviceHandle);\r
824 return Status;\r
825}\r
826\r
827\r
828/**\r
829\r
830 Configure a virtio ring.\r
831\r
832 This function sets up internal storage (the guest-host communication area)\r
833 and lays out several "navigation" (ie. no-ownership) pointers to parts of\r
834 that storage.\r
835\r
836 Relevant sections from the virtio-0.9.5 spec:\r
837 - 1.1 Virtqueues,\r
838 - 2.3 Virtqueue Configuration.\r
839\r
840 @param[in] The number of descriptors to allocate for the\r
841 virtio ring, as requested by the host.\r
842\r
843 @param[out] Ring The virtio ring to set up.\r
844\r
845 @retval EFI_OUT_OF_RESOURCES AllocatePages() failed to allocate contiguous\r
846 pages for the requested QueueSize. Fields of\r
847 Ring have indeterminate value.\r
848\r
849 @retval EFI_SUCCESS Allocation and setup successful. Ring->Base\r
850 (and nothing else) is responsible for\r
851 deallocation.\r
852\r
853**/\r
854\r
855STATIC\r
856EFI_STATUS\r
857EFIAPI\r
858VirtioRingInit (\r
859 IN UINT16 QueueSize,\r
860 OUT VRING *Ring\r
861 )\r
862{\r
863 UINTN RingSize;\r
864 volatile UINT8 *RingPagesPtr;\r
865\r
866 RingSize = ALIGN_VALUE (\r
867 sizeof *Ring->Desc * QueueSize +\r
868 sizeof *Ring->Avail.Flags +\r
869 sizeof *Ring->Avail.Idx +\r
870 sizeof *Ring->Avail.Ring * QueueSize +\r
871 sizeof *Ring->Avail.UsedEvent,\r
872 EFI_PAGE_SIZE);\r
873\r
874 RingSize += ALIGN_VALUE (\r
875 sizeof *Ring->Used.Flags +\r
876 sizeof *Ring->Used.Idx +\r
877 sizeof *Ring->Used.UsedElem * QueueSize +\r
878 sizeof *Ring->Used.AvailEvent,\r
879 EFI_PAGE_SIZE);\r
880\r
881 Ring->NumPages = EFI_SIZE_TO_PAGES (RingSize);\r
882 Ring->Base = AllocatePages (Ring->NumPages);\r
883 if (Ring->Base == NULL) {\r
884 return EFI_OUT_OF_RESOURCES;\r
885 }\r
886 SetMem (Ring->Base, RingSize, 0x00);\r
887 RingPagesPtr = Ring->Base;\r
888\r
889 Ring->Desc = (volatile VOID *) RingPagesPtr;\r
890 RingPagesPtr += sizeof *Ring->Desc * QueueSize;\r
891\r
892 Ring->Avail.Flags = (volatile VOID *) RingPagesPtr;\r
893 RingPagesPtr += sizeof *Ring->Avail.Flags;\r
894\r
895 Ring->Avail.Idx = (volatile VOID *) RingPagesPtr;\r
896 RingPagesPtr += sizeof *Ring->Avail.Idx;\r
897\r
898 Ring->Avail.Ring = (volatile VOID *) RingPagesPtr;\r
899 RingPagesPtr += sizeof *Ring->Avail.Ring * QueueSize;\r
900\r
901 Ring->Avail.UsedEvent = (volatile VOID *) RingPagesPtr;\r
902 RingPagesPtr += sizeof *Ring->Avail.UsedEvent;\r
903\r
904 RingPagesPtr = (volatile UINT8 *) Ring->Base +\r
905 ALIGN_VALUE (RingPagesPtr - (volatile UINT8 *) Ring->Base,\r
906 EFI_PAGE_SIZE);\r
907\r
908 Ring->Used.Flags = (volatile VOID *) RingPagesPtr;\r
909 RingPagesPtr += sizeof *Ring->Used.Flags;\r
910\r
911 Ring->Used.Idx = (volatile VOID *) RingPagesPtr;\r
912 RingPagesPtr += sizeof *Ring->Used.Idx;\r
913\r
914 Ring->Used.UsedElem = (volatile VOID *) RingPagesPtr;\r
915 RingPagesPtr += sizeof *Ring->Used.UsedElem * QueueSize;\r
916\r
917 Ring->Used.AvailEvent = (volatile VOID *) RingPagesPtr;\r
918 RingPagesPtr += sizeof *Ring->Used.AvailEvent;\r
919\r
920 Ring->QueueSize = QueueSize;\r
921 return EFI_SUCCESS;\r
922}\r
923\r
924\r
925/**\r
926\r
927 Tear down the internal resources of a configured virtio ring.\r
928\r
929 The caller is responsible to stop the host from using this ring before\r
930 invoking this function: the VSTAT_DRIVER_OK bit must be clear in\r
931 VhdrDeviceStatus.\r
932\r
933 @param[out] Ring The virtio ring to clean up.\r
934\r
935**/\r
936\r
937\r
938STATIC\r
939VOID\r
940EFIAPI\r
941VirtioRingUninit (\r
942 IN OUT VRING *Ring\r
943 )\r
944{\r
945 FreePages (Ring->Base, Ring->NumPages);\r
946 SetMem (Ring, sizeof *Ring, 0x00);\r
947}\r
948\r
949\r
950/**\r
951\r
952 Set up all BlockIo and virtio-blk aspects of this driver for the specified\r
953 device.\r
954\r
955 @param[in out] Dev The driver instance to configure. The caller is\r
956 responsible for Dev->PciIo's validity (ie. working IO\r
957 access to the underlying virtio-blk PCI device).\r
958\r
959 @retval EFI_SUCCESS Setup complete.\r
960\r
961 @retval EFI_UNSUPPORTED The driver is unable to work with the virtio ring or\r
962 virtio-blk attributes the host provides.\r
963\r
964 @return Error codes from VirtioRingInit() or\r
965 VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE().\r
966\r
967**/\r
968\r
969STATIC\r
970EFI_STATUS\r
971EFIAPI\r
972VirtioBlkInit (\r
973 IN OUT VBLK_DEV *Dev\r
974 )\r
975{\r
976 UINT8 NextDevStat;\r
977 EFI_STATUS Status;\r
978\r
979 UINT32 Features;\r
980 UINT64 NumSectors;\r
981 UINT32 BlockSize;\r
982 UINT16 QueueSize;\r
983\r
984 //\r
985 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.\r
986 //\r
987 NextDevStat = 0; // step 1 -- reset device\r
55c3443a 988 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 989 if (EFI_ERROR (Status)) {\r
990 goto Failed;\r
991 }\r
992\r
993 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence\r
55c3443a 994 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 995 if (EFI_ERROR (Status)) {\r
996 goto Failed;\r
997 }\r
998\r
999 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it\r
55c3443a 1000 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 1001 if (EFI_ERROR (Status)) {\r
1002 goto Failed;\r
1003 }\r
1004\r
1005 //\r
1006 // step 4a -- retrieve and validate features\r
1007 //\r
55c3443a 1008 Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);\r
fd51d759 1009 if (EFI_ERROR (Status)) {\r
1010 goto Failed;\r
1011 }\r
1012 Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors);\r
1013 if (EFI_ERROR (Status)) {\r
1014 goto Failed;\r
1015 }\r
1016 if (NumSectors == 0) {\r
1017 Status = EFI_UNSUPPORTED;\r
1018 goto Failed;\r
1019 }\r
1020\r
1021 if (Features & VIRTIO_BLK_F_BLK_SIZE) {\r
1022 Status = VIRTIO_CFG_READ (Dev, VhdrBlkSize, &BlockSize);\r
1023 if (EFI_ERROR (Status)) {\r
1024 goto Failed;\r
1025 }\r
1026 if (BlockSize == 0 || BlockSize % 512 != 0 ||\r
1027 NumSectors % (BlockSize / 512) != 0) {\r
1028 //\r
1029 // We can only handle a logical block consisting of whole sectors,\r
1030 // and only a disk composed of whole logical blocks.\r
1031 //\r
1032 Status = EFI_UNSUPPORTED;\r
1033 goto Failed;\r
1034 }\r
1035 }\r
1036 else {\r
1037 BlockSize = 512;\r
1038 }\r
1039\r
1040 //\r
1041 // step 4b -- allocate virtqueue\r
1042 //\r
55c3443a 1043 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0);\r
fd51d759 1044 if (EFI_ERROR (Status)) {\r
1045 goto Failed;\r
1046 }\r
55c3443a 1047 Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);\r
fd51d759 1048 if (EFI_ERROR (Status)) {\r
1049 goto Failed;\r
1050 }\r
1051 if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors\r
1052 Status = EFI_UNSUPPORTED;\r
1053 goto Failed;\r
1054 }\r
1055\r
1056 Status = VirtioRingInit (QueueSize, &Dev->Ring);\r
1057 if (EFI_ERROR (Status)) {\r
1058 goto Failed;\r
1059 }\r
1060\r
1061 //\r
1062 // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything\r
1063 // fails from here on, we must release the ring resources.\r
1064 //\r
55c3443a 1065 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,\r
fd51d759 1066 (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);\r
1067 if (EFI_ERROR (Status)) {\r
1068 goto ReleaseQueue;\r
1069 }\r
1070\r
1071 //\r
1072 // step 5 -- Report understood features. There are no virtio-blk specific\r
1073 // features to negotiate in virtio-0.9.5, plus we do not want any of the\r
1074 // device-independent (known or unknown) VIRTIO_F_* capabilities (see\r
1075 // Appendix B).\r
1076 //\r
55c3443a 1077 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0);\r
fd51d759 1078 if (EFI_ERROR (Status)) {\r
1079 goto ReleaseQueue;\r
1080 }\r
1081\r
1082 //\r
1083 // step 6 -- initialization complete\r
1084 //\r
1085 NextDevStat |= VSTAT_DRIVER_OK;\r
55c3443a 1086 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 1087 if (EFI_ERROR (Status)) {\r
1088 goto ReleaseQueue;\r
1089 }\r
1090\r
1091 //\r
1092 // Populate the exported interface's attributes; see UEFI spec v2.3.1 +\r
1093 // Errata C, 12.8 EFI Block I/O Protocol. We stick to the lowest possible\r
1094 // EFI_BLOCK_IO_PROTOCOL revision for now.\r
1095 //\r
1096 Dev->BlockIo.Revision = 0;\r
1097 Dev->BlockIo.Media = &Dev->BlockIoMedia;\r
1098 Dev->BlockIo.Reset = &VirtioBlkReset;\r
1099 Dev->BlockIo.ReadBlocks = &VirtioBlkReadBlocks;\r
1100 Dev->BlockIo.WriteBlocks = &VirtioBlkWriteBlocks;\r
1101 Dev->BlockIo.FlushBlocks = &VirtioBlkFlushBlocks;\r
1102 Dev->BlockIoMedia.MediaId = 0;\r
1103 Dev->BlockIoMedia.RemovableMedia = FALSE;\r
1104 Dev->BlockIoMedia.MediaPresent = TRUE;\r
1105 Dev->BlockIoMedia.LogicalPartition = FALSE;\r
1106 Dev->BlockIoMedia.ReadOnly = !!(Features & VIRTIO_BLK_F_RO);\r
1107 Dev->BlockIoMedia.WriteCaching = !!(Features & VIRTIO_BLK_F_FLUSH);\r
1108 Dev->BlockIoMedia.BlockSize = BlockSize;\r
1109 Dev->BlockIoMedia.IoAlign = 0;\r
1110 Dev->BlockIoMedia.LastBlock = NumSectors / (BlockSize / 512) - 1;\r
1111 return EFI_SUCCESS;\r
1112\r
1113ReleaseQueue:\r
1114 VirtioRingUninit (&Dev->Ring);\r
1115\r
1116Failed:\r
1117 //\r
1118 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device\r
1119 // Status. PCI IO access failure here should not mask the original error.\r
1120 //\r
1121 NextDevStat |= VSTAT_FAILED;\r
55c3443a 1122 VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 1123\r
1124 return Status; // reached only via Failed above\r
1125}\r
1126\r
1127\r
1128/**\r
1129\r
1130 Uninitialize the internals of a virtio-blk device that has been successfully\r
1131 set up with VirtioBlkInit().\r
1132\r
1133 @param[in out] Dev The device to clean up.\r
1134\r
1135**/\r
1136\r
1137STATIC\r
1138VOID\r
1139EFIAPI\r
1140VirtioBlkUninit (\r
1141 IN OUT VBLK_DEV *Dev\r
1142 )\r
1143{\r
1144 //\r
1145 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When\r
1146 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from\r
1147 // the old comms area.\r
1148 //\r
55c3443a 1149 VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);\r
fd51d759 1150\r
1151 VirtioRingUninit (&Dev->Ring);\r
1152\r
1153 SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00);\r
1154 SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);\r
1155}\r
1156\r
1157\r
1158/**\r
1159\r
1160 After we've pronounced support for a specific device in\r
1161 DriverBindingSupported(), we start managing said device (passed in by the\r
1162 Driver Exeuction Environment) with the following service.\r
1163\r
1164 See DriverBindingSupported() for specification references.\r
1165\r
1166 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
1167 incorporating this driver (independently of\r
1168 any device).\r
1169\r
1170 @param[in] DeviceHandle The supported device to drive.\r
1171\r
1172 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r
1173\r
1174\r
1175 @retval EFI_SUCCESS Driver instance has been created and\r
1176 initialized for the virtio-blk PCI device, it\r
1177 is now accessibla via EFI_BLOCK_IO_PROTOCOL.\r
1178\r
1179 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
1180\r
1181 @return Error codes from the OpenProtocol() boot\r
1182 service, the PciIo protocol, VirtioBlkInit(),\r
1183 or the InstallProtocolInterface() boot service.\r
1184\r
1185**/\r
1186\r
1187EFI_STATUS\r
1188EFIAPI\r
1189VirtioBlkDriverBindingStart (\r
1190 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1191 IN EFI_HANDLE DeviceHandle,\r
1192 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1193 )\r
1194{\r
1195 VBLK_DEV *Dev;\r
1196 EFI_STATUS Status;\r
1197\r
1198 Dev = (VBLK_DEV *) AllocateZeroPool (sizeof *Dev);\r
1199 if (Dev == NULL) {\r
1200 return EFI_OUT_OF_RESOURCES;\r
1201 }\r
1202\r
1203 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
1204 (VOID **)&Dev->PciIo, This->DriverBindingHandle,\r
1205 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
1206 if (EFI_ERROR (Status)) {\r
1207 goto FreeVirtioBlk;\r
1208 }\r
1209\r
1210 //\r
1211 // We must retain and ultimately restore the original PCI attributes of the\r
1212 // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /\r
1213 // 18.3.2 Start() and Stop().\r
1214 //\r
1215 // The third parameter ("Attributes", input) is ignored by the Get operation.\r
1216 // The fourth parameter ("Result", output) is ignored by the Enable and Set\r
1217 // operations.\r
1218 //\r
1219 // For virtio-blk we only need IO space access.\r
1220 //\r
1221 Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,\r
1222 0, &Dev->OriginalPciAttributes);\r
1223 if (EFI_ERROR (Status)) {\r
1224 goto ClosePciIo;\r
1225 }\r
1226\r
1227 Status = Dev->PciIo->Attributes (Dev->PciIo,\r
1228 EfiPciIoAttributeOperationEnable,\r
1229 EFI_PCI_IO_ATTRIBUTE_IO, NULL);\r
1230 if (EFI_ERROR (Status)) {\r
1231 goto ClosePciIo;\r
1232 }\r
1233\r
1234 //\r
1235 // PCI IO access granted, configure virtio-blk device.\r
1236 //\r
1237 Status = VirtioBlkInit (Dev);\r
1238 if (EFI_ERROR (Status)) {\r
1239 goto RestorePciAttributes;\r
1240 }\r
1241\r
1242 //\r
1243 // Setup complete, attempt to export the driver instance's BlockIo interface.\r
1244 //\r
1245 Dev->Signature = VBLK_SIG;\r
1246 Status = gBS->InstallProtocolInterface (&DeviceHandle,\r
1247 &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,\r
1248 &Dev->BlockIo);\r
1249 if (EFI_ERROR (Status)) {\r
1250 goto UninitDev;\r
1251 }\r
1252\r
1253 return EFI_SUCCESS;\r
1254\r
1255UninitDev:\r
1256 VirtioBlkUninit (Dev);\r
1257\r
1258RestorePciAttributes:\r
1259 Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
1260 Dev->OriginalPciAttributes, NULL);\r
1261\r
1262ClosePciIo:\r
1263 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
1264 This->DriverBindingHandle, DeviceHandle);\r
1265\r
1266FreeVirtioBlk:\r
1267 FreePool (Dev);\r
1268\r
1269 return Status;\r
1270}\r
1271\r
1272\r
1273/**\r
1274\r
1275 Stop driving a virtio-blk device and remove its BlockIo interface.\r
1276\r
1277 This function replays the success path of DriverBindingStart() in reverse.\r
1278 The host side virtio-blk device is reset, so that the OS boot loader or the\r
1279 OS may reinitialize it.\r
1280\r
1281 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
1282 incorporating this driver (independently of any\r
1283 device).\r
1284\r
1285 @param[in] DeviceHandle Stop driving this device.\r
1286\r
1287 @param[in] NumberOfChildren Since this function belongs to a device driver\r
1288 only (as opposed to a bus driver), the caller\r
1289 environment sets NumberOfChildren to zero, and\r
1290 we ignore it.\r
1291\r
1292 @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).\r
1293\r
1294**/\r
1295\r
1296EFI_STATUS\r
1297EFIAPI\r
1298VirtioBlkDriverBindingStop (\r
1299 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1300 IN EFI_HANDLE DeviceHandle,\r
1301 IN UINTN NumberOfChildren,\r
1302 IN EFI_HANDLE *ChildHandleBuffer\r
1303 )\r
1304{\r
1305 VBLK_DEV *Dev;\r
1306 EFI_STATUS Status;\r
1307\r
1308 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
1309\r
1310 //\r
1311 // If DriverBindingStop() is called with the driver instance still in use,\r
1312 // or any of the parameters are invalid, we've caught a bug.\r
1313 //\r
1314 Status = gBS->UninstallProtocolInterface (DeviceHandle,\r
1315 &gEfiBlockIoProtocolGuid, &Dev->BlockIo);\r
1316 ASSERT (Status == EFI_SUCCESS);\r
1317\r
1318 VirtioBlkUninit (Dev);\r
1319\r
1320 Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
1321 Dev->OriginalPciAttributes, NULL);\r
1322\r
1323 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
1324 This->DriverBindingHandle, DeviceHandle);\r
1325\r
1326 FreePool (Dev);\r
1327\r
1328 return EFI_SUCCESS;\r
1329}\r
1330\r
1331\r
1332//\r
1333// The static object that groups the Supported() (ie. probe), Start() and\r
1334// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r
1335// C, 10.1 EFI Driver Binding Protocol.\r
1336//\r
1337STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
1338 &VirtioBlkDriverBindingSupported,\r
1339 &VirtioBlkDriverBindingStart,\r
1340 &VirtioBlkDriverBindingStop,\r
1341 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r
1342 NULL, // ImageHandle, to be overwritten by\r
1343 // EfiLibInstallDriverBindingComponentName2() in VirtioBlkEntryPoint()\r
1344 NULL // DriverBindingHandle, ditto\r
1345};\r
1346\r
1347\r
1348//\r
1349// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r
1350// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r
1351// in English, for display on standard console devices. This is recommended for\r
1352// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's\r
1353// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.\r
1354//\r
1355// Device type names ("Virtio Block Device") are not formatted because the\r
1356// driver supports only that device type. Therefore the driver name suffices\r
1357// for unambiguous identification.\r
1358//\r
1359\r
1360STATIC GLOBAL_REMOVE_IF_UNREFERENCED\r
1361EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
1362 { "eng;en", L"Virtio Block Driver" },\r
1363 { NULL, NULL }\r
1364};\r
1365\r
1366STATIC GLOBAL_REMOVE_IF_UNREFERENCED\r
1367EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
1368\r
1369EFI_STATUS\r
1370EFIAPI\r
1371VirtioBlkGetDriverName (\r
1372 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1373 IN CHAR8 *Language,\r
1374 OUT CHAR16 **DriverName\r
1375 )\r
1376{\r
1377 return LookupUnicodeString2 (\r
1378 Language,\r
1379 This->SupportedLanguages,\r
1380 mDriverNameTable,\r
1381 DriverName,\r
1382 (BOOLEAN)(This == &gComponentName) // Iso639Language\r
1383 );\r
1384}\r
1385\r
1386EFI_STATUS\r
1387EFIAPI\r
1388VirtioBlkGetDeviceName (\r
1389 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1390 IN EFI_HANDLE DeviceHandle,\r
1391 IN EFI_HANDLE ChildHandle,\r
1392 IN CHAR8 *Language,\r
1393 OUT CHAR16 **ControllerName\r
1394 )\r
1395{\r
1396 return EFI_UNSUPPORTED;\r
1397}\r
1398\r
1399STATIC GLOBAL_REMOVE_IF_UNREFERENCED\r
1400EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
1401 &VirtioBlkGetDriverName,\r
1402 &VirtioBlkGetDeviceName,\r
1403 "eng" // SupportedLanguages, ISO 639-2 language codes\r
1404};\r
1405\r
1406STATIC GLOBAL_REMOVE_IF_UNREFERENCED\r
1407EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
1408 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioBlkGetDriverName,\r
1409 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioBlkGetDeviceName,\r
1410 "en" // SupportedLanguages, RFC 4646 language codes\r
1411};\r
1412\r
1413\r
1414//\r
1415// Entry point of this driver.\r
1416//\r
1417EFI_STATUS\r
1418EFIAPI\r
1419VirtioBlkEntryPoint (\r
1420 IN EFI_HANDLE ImageHandle,\r
1421 IN EFI_SYSTEM_TABLE *SystemTable\r
1422 )\r
1423{\r
1424 return EfiLibInstallDriverBindingComponentName2 (\r
1425 ImageHandle,\r
1426 SystemTable,\r
1427 &gDriverBinding,\r
1428 ImageHandle,\r
1429 &gComponentName,\r
1430 &gComponentName2\r
1431 );\r
1432}\r
1433\r