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