]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/VirtioBlkDxe/VirtioBlk.c
OvmfPkg: VirtioBlkDxe: fix div & mod of 64-bit dividends on IA32/gcc-4.4
[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
e371e7e5 251 DESC_INDICES Indices;\r
fd51d759 252\r
253 BlockSize = Dev->BlockIoMedia.BlockSize;\r
254\r
255 //\r
256 // ensured by VirtioBlkInit()\r
257 //\r
258 ASSERT (BlockSize > 0);\r
259 ASSERT (BlockSize % 512 == 0);\r
260\r
261 //\r
262 // ensured by contract above, plus VerifyReadWriteRequest()\r
263 //\r
264 ASSERT (BufferSize % BlockSize == 0);\r
265\r
266 //\r
267 // Prepare virtio-blk request header, setting zero size for flush.\r
268 // IO Priority is homogeneously 0.\r
269 //\r
270 Request.Type = RequestIsWrite ?\r
271 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :\r
272 VIRTIO_BLK_T_IN;\r
273 Request.IoPrio = 0;\r
274 Request.Sector = Lba * (BlockSize / 512);\r
275\r
e371e7e5 276 VirtioPrepare (&Dev->Ring, &Indices);\r
fd51d759 277\r
278 //\r
279 // preset a host status for ourselves that we do not accept as success\r
280 //\r
281 HostStatus = VIRTIO_BLK_S_IOERR;\r
282\r
283 //\r
284 // ensured by VirtioBlkInit() -- this predicate, in combination with the\r
285 // lock-step progress, ensures we don't have to track free descriptors.\r
286 //\r
287 ASSERT (Dev->Ring.QueueSize >= 3);\r
288\r
fd51d759 289 //\r
290 // virtio-blk header in first desc\r
291 //\r
7fcacd6c 292 VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request,\r
e371e7e5 293 VRING_DESC_F_NEXT, &Indices);\r
fd51d759 294\r
295 //\r
296 // data buffer for read/write in second desc\r
297 //\r
298 if (BufferSize > 0) {\r
299 //\r
300 // From virtio-0.9.5, 2.3.2 Descriptor Table:\r
301 // "no descriptor chain may be more than 2^32 bytes long in total".\r
302 //\r
303 // The predicate is ensured by the call contract above (for flush), or\r
304 // VerifyReadWriteRequest() (for read/write). It also implies that\r
305 // converting BufferSize to UINT32 will not truncate it.\r
306 //\r
307 ASSERT (BufferSize <= SIZE_1GB);\r
308\r
309 //\r
310 // VRING_DESC_F_WRITE is interpreted from the host's point of view.\r
311 //\r
7fcacd6c 312 VirtioAppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize,\r
fd51d759 313 VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),\r
e371e7e5 314 &Indices);\r
fd51d759 315 }\r
316\r
317 //\r
318 // host status in last (second or third) desc\r
319 //\r
7fcacd6c 320 VirtioAppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus,\r
e371e7e5 321 VRING_DESC_F_WRITE, &Indices);\r
fd51d759 322\r
323 //\r
e371e7e5 324 // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
fd51d759 325 //\r
e371e7e5 326 if (VirtioFlush (Dev->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS &&\r
327 HostStatus == VIRTIO_BLK_S_OK) {\r
fd51d759 328 return EFI_SUCCESS;\r
329 }\r
330\r
331 return EFI_DEVICE_ERROR;\r
332}\r
333\r
334\r
335/**\r
336\r
337 ReadBlocks() operation for virtio-blk.\r
338\r
339 See\r
340 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
341 Protocol, EFI_BLOCK_IO_PROTOCOL.ReadBlocks().\r
342 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.2. ReadBlocks() and\r
343 ReadBlocksEx() Implementation.\r
344\r
345 Parameter checks and conformant return values are implemented in\r
346 VerifyReadWriteRequest() and SynchronousRequest().\r
347\r
348 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,\r
349 successfully.\r
350\r
351**/\r
352\r
353EFI_STATUS\r
354EFIAPI\r
355VirtioBlkReadBlocks (\r
356 IN EFI_BLOCK_IO_PROTOCOL *This,\r
357 IN UINT32 MediaId,\r
358 IN EFI_LBA Lba,\r
359 IN UINTN BufferSize,\r
360 OUT VOID *Buffer\r
361 )\r
362{\r
363 VBLK_DEV *Dev;\r
364 EFI_STATUS Status;\r
365\r
366 if (BufferSize == 0) {\r
367 return EFI_SUCCESS;\r
368 }\r
369\r
370 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
371 Status = VerifyReadWriteRequest (\r
372 &Dev->BlockIoMedia,\r
373 Lba,\r
374 BufferSize,\r
375 FALSE // RequestIsWrite\r
376 );\r
377 if (EFI_ERROR (Status)) {\r
378 return Status;\r
379 }\r
380\r
381 return SynchronousRequest (\r
382 Dev,\r
383 Lba,\r
384 BufferSize,\r
385 Buffer,\r
386 FALSE // RequestIsWrite\r
387 );\r
388}\r
389\r
390/**\r
391\r
392 WriteBlocks() operation for virtio-blk.\r
393\r
394 See\r
395 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
396 Protocol, EFI_BLOCK_IO_PROTOCOL.WriteBlocks().\r
397 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.3 WriteBlocks() and\r
398 WriteBlockEx() Implementation.\r
399\r
400 Parameter checks and conformant return values are implemented in\r
401 VerifyReadWriteRequest() and SynchronousRequest().\r
402\r
403 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,\r
404 successfully.\r
405\r
406**/\r
407\r
408EFI_STATUS\r
409EFIAPI\r
410VirtioBlkWriteBlocks (\r
411 IN EFI_BLOCK_IO_PROTOCOL *This,\r
412 IN UINT32 MediaId,\r
413 IN EFI_LBA Lba,\r
414 IN UINTN BufferSize,\r
415 IN VOID *Buffer\r
416 )\r
417{\r
418 VBLK_DEV *Dev;\r
419 EFI_STATUS Status;\r
420\r
421 if (BufferSize == 0) {\r
422 return EFI_SUCCESS;\r
423 }\r
424\r
425 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
426 Status = VerifyReadWriteRequest (\r
427 &Dev->BlockIoMedia,\r
428 Lba,\r
429 BufferSize,\r
430 TRUE // RequestIsWrite\r
431 );\r
432 if (EFI_ERROR (Status)) {\r
433 return Status;\r
434 }\r
435\r
436 return SynchronousRequest (\r
437 Dev,\r
438 Lba,\r
439 BufferSize,\r
440 Buffer,\r
441 TRUE // RequestIsWrite\r
442 );\r
443}\r
444\r
445\r
446/**\r
447\r
448 FlushBlocks() operation for virtio-blk.\r
449\r
450 See\r
451 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
452 Protocol, EFI_BLOCK_IO_PROTOCOL.FlushBlocks().\r
453 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.4 FlushBlocks() and\r
454 FlushBlocksEx() Implementation.\r
455\r
456 If the underlying virtio-blk device doesn't support flushing (ie.\r
457 write-caching), then this function should not be called by higher layers,\r
458 according to EFI_BLOCK_IO_MEDIA characteristics set in VirtioBlkInit().\r
459 Should they do nonetheless, we do nothing, successfully.\r
460\r
461**/\r
462\r
463EFI_STATUS\r
464EFIAPI\r
465VirtioBlkFlushBlocks (\r
466 IN EFI_BLOCK_IO_PROTOCOL *This\r
467 )\r
468{\r
469 VBLK_DEV *Dev;\r
470\r
471 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
472 return Dev->BlockIoMedia.WriteCaching ?\r
473 SynchronousRequest (\r
474 Dev,\r
475 0, // Lba\r
476 0, // BufferSize\r
477 NULL, // Buffer\r
478 TRUE // RequestIsWrite\r
479 ) :\r
480 EFI_SUCCESS;\r
481}\r
482\r
483\r
484/**\r
485\r
486 Device probe function for this driver.\r
487\r
488 The DXE core calls this function for any given device in order to see if the\r
489 driver can drive the device.\r
490\r
491 Specs relevant in the general sense:\r
492\r
493 - UEFI Spec 2.3.1 + Errata C:\r
494 - 6.3 Protocol Handler Services -- for accessing the underlying device\r
495 - 10.1 EFI Driver Binding Protocol -- for exporting ourselves\r
496\r
497 - Driver Writer's Guide for UEFI 2.3.1 v1.01:\r
498 - 5.1.3.4 OpenProtocol() and CloseProtocol() -- for accessing the\r
499 underlying device\r
500 - 9 Driver Binding Protocol -- for exporting ourselves\r
501\r
502 Specs relevant in the specific sense:\r
503 - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol\r
504 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design\r
505 Guidelines, 18.3 PCI drivers.\r
506\r
507 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
508 incorporating this driver (independently of\r
509 any device).\r
510\r
511 @param[in] DeviceHandle The device to probe.\r
512\r
513 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r
514\r
515\r
516 @retval EFI_SUCCESS The driver supports the device being probed.\r
517\r
518 @retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support\r
519 the device.\r
520\r
521 @return Error codes from the OpenProtocol() boot service or\r
522 the PciIo protocol.\r
523\r
524**/\r
525\r
526EFI_STATUS\r
527EFIAPI\r
528VirtioBlkDriverBindingSupported (\r
529 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
530 IN EFI_HANDLE DeviceHandle,\r
531 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
532 )\r
533{\r
534 EFI_STATUS Status;\r
535 EFI_PCI_IO_PROTOCOL *PciIo;\r
536 PCI_TYPE00 Pci;\r
537\r
538 //\r
539 // Attempt to open the device with the PciIo set of interfaces. On success,\r
540 // the protocol is "instantiated" for the PCI device. Covers duplicate open\r
541 // attempts (EFI_ALREADY_STARTED).\r
542 //\r
543 Status = gBS->OpenProtocol (\r
544 DeviceHandle, // candidate device\r
545 &gEfiPciIoProtocolGuid, // for generic PCI access\r
546 (VOID **)&PciIo, // handle to instantiate\r
547 This->DriverBindingHandle, // requestor driver identity\r
548 DeviceHandle, // ControllerHandle, according to\r
549 // the UEFI Driver Model\r
550 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to\r
551 // the device; to be released\r
552 );\r
553 if (EFI_ERROR (Status)) {\r
554 return Status;\r
555 }\r
556\r
557 //\r
558 // Read entire PCI configuration header for more extensive check ahead.\r
559 //\r
560 Status = PciIo->Pci.Read (\r
561 PciIo, // (protocol, device)\r
562 // handle\r
563 EfiPciIoWidthUint32, // access width & copy\r
564 // mode\r
565 0, // Offset\r
566 sizeof Pci / sizeof (UINT32), // Count\r
567 &Pci // target buffer\r
568 );\r
569\r
570 if (Status == EFI_SUCCESS) {\r
571 //\r
572 // virtio-0.9.5, 2.1 PCI Discovery\r
573 //\r
574 Status = (Pci.Hdr.VendorId == 0x1AF4 &&\r
575 Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F &&\r
576 Pci.Hdr.RevisionID == 0x00 &&\r
577 Pci.Device.SubsystemID == 0x02) ? EFI_SUCCESS : EFI_UNSUPPORTED;\r
578 }\r
579\r
580 //\r
581 // We needed PCI IO access only transitorily, to see whether we support the\r
582 // device or not.\r
583 //\r
584 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
585 This->DriverBindingHandle, DeviceHandle);\r
586 return Status;\r
587}\r
588\r
589\r
fd51d759 590/**\r
591\r
592 Set up all BlockIo and virtio-blk aspects of this driver for the specified\r
593 device.\r
594\r
595 @param[in out] Dev The driver instance to configure. The caller is\r
596 responsible for Dev->PciIo's validity (ie. working IO\r
597 access to the underlying virtio-blk PCI device).\r
598\r
599 @retval EFI_SUCCESS Setup complete.\r
600\r
601 @retval EFI_UNSUPPORTED The driver is unable to work with the virtio ring or\r
602 virtio-blk attributes the host provides.\r
603\r
604 @return Error codes from VirtioRingInit() or\r
605 VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE().\r
606\r
607**/\r
608\r
609STATIC\r
610EFI_STATUS\r
611EFIAPI\r
612VirtioBlkInit (\r
613 IN OUT VBLK_DEV *Dev\r
614 )\r
615{\r
616 UINT8 NextDevStat;\r
617 EFI_STATUS Status;\r
618\r
619 UINT32 Features;\r
620 UINT64 NumSectors;\r
621 UINT32 BlockSize;\r
622 UINT16 QueueSize;\r
623\r
624 //\r
625 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.\r
626 //\r
627 NextDevStat = 0; // step 1 -- reset device\r
55c3443a 628 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 629 if (EFI_ERROR (Status)) {\r
630 goto Failed;\r
631 }\r
632\r
633 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence\r
55c3443a 634 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 635 if (EFI_ERROR (Status)) {\r
636 goto Failed;\r
637 }\r
638\r
639 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it\r
55c3443a 640 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 641 if (EFI_ERROR (Status)) {\r
642 goto Failed;\r
643 }\r
644\r
645 //\r
646 // step 4a -- retrieve and validate features\r
647 //\r
55c3443a 648 Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features);\r
fd51d759 649 if (EFI_ERROR (Status)) {\r
650 goto Failed;\r
651 }\r
652 Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors);\r
653 if (EFI_ERROR (Status)) {\r
654 goto Failed;\r
655 }\r
656 if (NumSectors == 0) {\r
657 Status = EFI_UNSUPPORTED;\r
658 goto Failed;\r
659 }\r
660\r
661 if (Features & VIRTIO_BLK_F_BLK_SIZE) {\r
662 Status = VIRTIO_CFG_READ (Dev, VhdrBlkSize, &BlockSize);\r
663 if (EFI_ERROR (Status)) {\r
664 goto Failed;\r
665 }\r
666 if (BlockSize == 0 || BlockSize % 512 != 0 ||\r
2f03f796 667 ModU64x32 (NumSectors, BlockSize / 512) != 0) {\r
fd51d759 668 //\r
669 // We can only handle a logical block consisting of whole sectors,\r
670 // and only a disk composed of whole logical blocks.\r
671 //\r
672 Status = EFI_UNSUPPORTED;\r
673 goto Failed;\r
674 }\r
675 }\r
676 else {\r
677 BlockSize = 512;\r
678 }\r
679\r
680 //\r
681 // step 4b -- allocate virtqueue\r
682 //\r
55c3443a 683 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0);\r
fd51d759 684 if (EFI_ERROR (Status)) {\r
685 goto Failed;\r
686 }\r
55c3443a 687 Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize);\r
fd51d759 688 if (EFI_ERROR (Status)) {\r
689 goto Failed;\r
690 }\r
691 if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors\r
692 Status = EFI_UNSUPPORTED;\r
693 goto Failed;\r
694 }\r
695\r
696 Status = VirtioRingInit (QueueSize, &Dev->Ring);\r
697 if (EFI_ERROR (Status)) {\r
698 goto Failed;\r
699 }\r
700\r
701 //\r
702 // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything\r
703 // fails from here on, we must release the ring resources.\r
704 //\r
55c3443a 705 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress,\r
fd51d759 706 (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT);\r
707 if (EFI_ERROR (Status)) {\r
708 goto ReleaseQueue;\r
709 }\r
710\r
711 //\r
712 // step 5 -- Report understood features. There are no virtio-blk specific\r
713 // features to negotiate in virtio-0.9.5, plus we do not want any of the\r
714 // device-independent (known or unknown) VIRTIO_F_* capabilities (see\r
715 // Appendix B).\r
716 //\r
55c3443a 717 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0);\r
fd51d759 718 if (EFI_ERROR (Status)) {\r
719 goto ReleaseQueue;\r
720 }\r
721\r
722 //\r
723 // step 6 -- initialization complete\r
724 //\r
725 NextDevStat |= VSTAT_DRIVER_OK;\r
55c3443a 726 Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 727 if (EFI_ERROR (Status)) {\r
728 goto ReleaseQueue;\r
729 }\r
730\r
731 //\r
732 // Populate the exported interface's attributes; see UEFI spec v2.3.1 +\r
733 // Errata C, 12.8 EFI Block I/O Protocol. We stick to the lowest possible\r
734 // EFI_BLOCK_IO_PROTOCOL revision for now.\r
735 //\r
736 Dev->BlockIo.Revision = 0;\r
737 Dev->BlockIo.Media = &Dev->BlockIoMedia;\r
738 Dev->BlockIo.Reset = &VirtioBlkReset;\r
739 Dev->BlockIo.ReadBlocks = &VirtioBlkReadBlocks;\r
740 Dev->BlockIo.WriteBlocks = &VirtioBlkWriteBlocks;\r
741 Dev->BlockIo.FlushBlocks = &VirtioBlkFlushBlocks;\r
742 Dev->BlockIoMedia.MediaId = 0;\r
743 Dev->BlockIoMedia.RemovableMedia = FALSE;\r
744 Dev->BlockIoMedia.MediaPresent = TRUE;\r
745 Dev->BlockIoMedia.LogicalPartition = FALSE;\r
746 Dev->BlockIoMedia.ReadOnly = !!(Features & VIRTIO_BLK_F_RO);\r
747 Dev->BlockIoMedia.WriteCaching = !!(Features & VIRTIO_BLK_F_FLUSH);\r
748 Dev->BlockIoMedia.BlockSize = BlockSize;\r
749 Dev->BlockIoMedia.IoAlign = 0;\r
2f03f796 750 Dev->BlockIoMedia.LastBlock = DivU64x32 (NumSectors,\r
751 BlockSize / 512) - 1;\r
fd51d759 752 return EFI_SUCCESS;\r
753\r
754ReleaseQueue:\r
755 VirtioRingUninit (&Dev->Ring);\r
756\r
757Failed:\r
758 //\r
759 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device\r
760 // Status. PCI IO access failure here should not mask the original error.\r
761 //\r
762 NextDevStat |= VSTAT_FAILED;\r
55c3443a 763 VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat);\r
fd51d759 764\r
765 return Status; // reached only via Failed above\r
766}\r
767\r
768\r
769/**\r
770\r
771 Uninitialize the internals of a virtio-blk device that has been successfully\r
772 set up with VirtioBlkInit().\r
773\r
774 @param[in out] Dev The device to clean up.\r
775\r
776**/\r
777\r
778STATIC\r
779VOID\r
780EFIAPI\r
781VirtioBlkUninit (\r
782 IN OUT VBLK_DEV *Dev\r
783 )\r
784{\r
785 //\r
786 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When\r
787 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from\r
788 // the old comms area.\r
789 //\r
55c3443a 790 VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0);\r
fd51d759 791\r
792 VirtioRingUninit (&Dev->Ring);\r
793\r
794 SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00);\r
795 SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);\r
796}\r
797\r
798\r
799/**\r
800\r
801 After we've pronounced support for a specific device in\r
802 DriverBindingSupported(), we start managing said device (passed in by the\r
803 Driver Exeuction Environment) with the following service.\r
804\r
805 See DriverBindingSupported() for specification references.\r
806\r
807 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
808 incorporating this driver (independently of\r
809 any device).\r
810\r
811 @param[in] DeviceHandle The supported device to drive.\r
812\r
813 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r
814\r
815\r
816 @retval EFI_SUCCESS Driver instance has been created and\r
817 initialized for the virtio-blk PCI device, it\r
818 is now accessibla via EFI_BLOCK_IO_PROTOCOL.\r
819\r
820 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
821\r
822 @return Error codes from the OpenProtocol() boot\r
823 service, the PciIo protocol, VirtioBlkInit(),\r
824 or the InstallProtocolInterface() boot service.\r
825\r
826**/\r
827\r
828EFI_STATUS\r
829EFIAPI\r
830VirtioBlkDriverBindingStart (\r
831 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
832 IN EFI_HANDLE DeviceHandle,\r
833 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
834 )\r
835{\r
836 VBLK_DEV *Dev;\r
837 EFI_STATUS Status;\r
838\r
839 Dev = (VBLK_DEV *) AllocateZeroPool (sizeof *Dev);\r
840 if (Dev == NULL) {\r
841 return EFI_OUT_OF_RESOURCES;\r
842 }\r
843\r
844 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
845 (VOID **)&Dev->PciIo, This->DriverBindingHandle,\r
846 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
847 if (EFI_ERROR (Status)) {\r
848 goto FreeVirtioBlk;\r
849 }\r
850\r
851 //\r
852 // We must retain and ultimately restore the original PCI attributes of the\r
853 // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /\r
854 // 18.3.2 Start() and Stop().\r
855 //\r
856 // The third parameter ("Attributes", input) is ignored by the Get operation.\r
857 // The fourth parameter ("Result", output) is ignored by the Enable and Set\r
858 // operations.\r
859 //\r
860 // For virtio-blk we only need IO space access.\r
861 //\r
862 Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet,\r
863 0, &Dev->OriginalPciAttributes);\r
864 if (EFI_ERROR (Status)) {\r
865 goto ClosePciIo;\r
866 }\r
867\r
868 Status = Dev->PciIo->Attributes (Dev->PciIo,\r
869 EfiPciIoAttributeOperationEnable,\r
870 EFI_PCI_IO_ATTRIBUTE_IO, NULL);\r
871 if (EFI_ERROR (Status)) {\r
872 goto ClosePciIo;\r
873 }\r
874\r
875 //\r
876 // PCI IO access granted, configure virtio-blk device.\r
877 //\r
878 Status = VirtioBlkInit (Dev);\r
879 if (EFI_ERROR (Status)) {\r
880 goto RestorePciAttributes;\r
881 }\r
882\r
883 //\r
884 // Setup complete, attempt to export the driver instance's BlockIo interface.\r
885 //\r
886 Dev->Signature = VBLK_SIG;\r
887 Status = gBS->InstallProtocolInterface (&DeviceHandle,\r
888 &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,\r
889 &Dev->BlockIo);\r
890 if (EFI_ERROR (Status)) {\r
891 goto UninitDev;\r
892 }\r
893\r
894 return EFI_SUCCESS;\r
895\r
896UninitDev:\r
897 VirtioBlkUninit (Dev);\r
898\r
899RestorePciAttributes:\r
900 Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
901 Dev->OriginalPciAttributes, NULL);\r
902\r
903ClosePciIo:\r
904 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
905 This->DriverBindingHandle, DeviceHandle);\r
906\r
907FreeVirtioBlk:\r
908 FreePool (Dev);\r
909\r
910 return Status;\r
911}\r
912\r
913\r
914/**\r
915\r
916 Stop driving a virtio-blk device and remove its BlockIo interface.\r
917\r
918 This function replays the success path of DriverBindingStart() in reverse.\r
919 The host side virtio-blk device is reset, so that the OS boot loader or the\r
920 OS may reinitialize it.\r
921\r
922 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
923 incorporating this driver (independently of any\r
924 device).\r
925\r
926 @param[in] DeviceHandle Stop driving this device.\r
927\r
928 @param[in] NumberOfChildren Since this function belongs to a device driver\r
929 only (as opposed to a bus driver), the caller\r
930 environment sets NumberOfChildren to zero, and\r
931 we ignore it.\r
932\r
933 @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).\r
934\r
935**/\r
936\r
937EFI_STATUS\r
938EFIAPI\r
939VirtioBlkDriverBindingStop (\r
940 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
941 IN EFI_HANDLE DeviceHandle,\r
942 IN UINTN NumberOfChildren,\r
943 IN EFI_HANDLE *ChildHandleBuffer\r
944 )\r
945{\r
946 VBLK_DEV *Dev;\r
947 EFI_STATUS Status;\r
948\r
949 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
950\r
951 //\r
952 // If DriverBindingStop() is called with the driver instance still in use,\r
953 // or any of the parameters are invalid, we've caught a bug.\r
954 //\r
955 Status = gBS->UninstallProtocolInterface (DeviceHandle,\r
956 &gEfiBlockIoProtocolGuid, &Dev->BlockIo);\r
957 ASSERT (Status == EFI_SUCCESS);\r
958\r
959 VirtioBlkUninit (Dev);\r
960\r
961 Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet,\r
962 Dev->OriginalPciAttributes, NULL);\r
963\r
964 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,\r
965 This->DriverBindingHandle, DeviceHandle);\r
966\r
967 FreePool (Dev);\r
968\r
969 return EFI_SUCCESS;\r
970}\r
971\r
972\r
973//\r
974// The static object that groups the Supported() (ie. probe), Start() and\r
975// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r
976// C, 10.1 EFI Driver Binding Protocol.\r
977//\r
978STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
979 &VirtioBlkDriverBindingSupported,\r
980 &VirtioBlkDriverBindingStart,\r
981 &VirtioBlkDriverBindingStop,\r
982 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r
983 NULL, // ImageHandle, to be overwritten by\r
984 // EfiLibInstallDriverBindingComponentName2() in VirtioBlkEntryPoint()\r
985 NULL // DriverBindingHandle, ditto\r
986};\r
987\r
988\r
989//\r
990// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r
991// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r
992// in English, for display on standard console devices. This is recommended for\r
993// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's\r
994// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.\r
995//\r
996// Device type names ("Virtio Block Device") are not formatted because the\r
997// driver supports only that device type. Therefore the driver name suffices\r
998// for unambiguous identification.\r
999//\r
1000\r
9de0355b 1001STATIC\r
fd51d759 1002EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
1003 { "eng;en", L"Virtio Block Driver" },\r
1004 { NULL, NULL }\r
1005};\r
1006\r
9de0355b 1007STATIC\r
fd51d759 1008EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
1009\r
1010EFI_STATUS\r
1011EFIAPI\r
1012VirtioBlkGetDriverName (\r
1013 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1014 IN CHAR8 *Language,\r
1015 OUT CHAR16 **DriverName\r
1016 )\r
1017{\r
1018 return LookupUnicodeString2 (\r
1019 Language,\r
1020 This->SupportedLanguages,\r
1021 mDriverNameTable,\r
1022 DriverName,\r
1023 (BOOLEAN)(This == &gComponentName) // Iso639Language\r
1024 );\r
1025}\r
1026\r
1027EFI_STATUS\r
1028EFIAPI\r
1029VirtioBlkGetDeviceName (\r
1030 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1031 IN EFI_HANDLE DeviceHandle,\r
1032 IN EFI_HANDLE ChildHandle,\r
1033 IN CHAR8 *Language,\r
1034 OUT CHAR16 **ControllerName\r
1035 )\r
1036{\r
1037 return EFI_UNSUPPORTED;\r
1038}\r
1039\r
9de0355b 1040STATIC\r
fd51d759 1041EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
1042 &VirtioBlkGetDriverName,\r
1043 &VirtioBlkGetDeviceName,\r
1044 "eng" // SupportedLanguages, ISO 639-2 language codes\r
1045};\r
1046\r
9de0355b 1047STATIC\r
fd51d759 1048EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
1049 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioBlkGetDriverName,\r
1050 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioBlkGetDeviceName,\r
1051 "en" // SupportedLanguages, RFC 4646 language codes\r
1052};\r
1053\r
1054\r
1055//\r
1056// Entry point of this driver.\r
1057//\r
1058EFI_STATUS\r
1059EFIAPI\r
1060VirtioBlkEntryPoint (\r
1061 IN EFI_HANDLE ImageHandle,\r
1062 IN EFI_SYSTEM_TABLE *SystemTable\r
1063 )\r
1064{\r
1065 return EfiLibInstallDriverBindingComponentName2 (\r
1066 ImageHandle,\r
1067 SystemTable,\r
1068 &gDriverBinding,\r
1069 ImageHandle,\r
1070 &gComponentName,\r
1071 &gComponentName2\r
1072 );\r
1073}\r
1074\r