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