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