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