]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/VirtioBlkDxe/VirtioBlk.c
OvmfPkg/VirtioBlkDxe: Check the return status of unmap data buffer
[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
ea8314e4 263 EFI_STATUS UnmapStatus;\r
fd51d759 264\r
265 BlockSize = Dev->BlockIoMedia.BlockSize;\r
266\r
267 //\r
268 // ensured by VirtioBlkInit()\r
269 //\r
270 ASSERT (BlockSize > 0);\r
271 ASSERT (BlockSize % 512 == 0);\r
272\r
273 //\r
274 // ensured by contract above, plus VerifyReadWriteRequest()\r
275 //\r
276 ASSERT (BufferSize % BlockSize == 0);\r
277\r
278 //\r
279 // Prepare virtio-blk request header, setting zero size for flush.\r
280 // IO Priority is homogeneously 0.\r
281 //\r
282 Request.Type = RequestIsWrite ?\r
283 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :\r
284 VIRTIO_BLK_T_IN;\r
285 Request.IoPrio = 0;\r
389b5518 286 Request.Sector = MultU64x32(Lba, BlockSize / 512);\r
fd51d759 287\r
3540f2ce
BS
288 //\r
289 // Host status is bi-directional (we preset with a value and expect the\r
290 // device to update it). Allocate a host status buffer which can be mapped\r
291 // to access equally by both processor and the device.\r
292 //\r
293 Status = Dev->VirtIo->AllocateSharedPages (\r
294 Dev->VirtIo,\r
295 EFI_SIZE_TO_PAGES (sizeof *HostStatus),\r
296 &HostStatusBuffer\r
297 );\r
298 if (EFI_ERROR (Status)) {\r
299 return EFI_DEVICE_ERROR;\r
300 }\r
301\r
302 HostStatus = HostStatusBuffer;\r
303\r
304 //\r
305 // Map virtio-blk request header (must be done after request header is\r
306 // populated)\r
307 //\r
308 Status = VirtioMapAllBytesInSharedBuffer (\r
309 Dev->VirtIo,\r
310 VirtioOperationBusMasterRead,\r
311 (VOID *) &Request,\r
312 sizeof Request,\r
313 &RequestDeviceAddress,\r
314 &RequestMapping\r
315 );\r
316 if (EFI_ERROR (Status)) {\r
317 Status = EFI_DEVICE_ERROR;\r
318 goto FreeHostStatusBuffer;\r
319 }\r
320\r
321 //\r
322 // Map data buffer\r
323 //\r
324 if (BufferSize > 0) {\r
325 Status = VirtioMapAllBytesInSharedBuffer (\r
326 Dev->VirtIo,\r
327 (RequestIsWrite ?\r
328 VirtioOperationBusMasterRead :\r
329 VirtioOperationBusMasterWrite),\r
330 (VOID *) Buffer,\r
331 BufferSize,\r
332 &BufferDeviceAddress,\r
333 &BufferMapping\r
334 );\r
335 if (EFI_ERROR (Status)) {\r
336 Status = EFI_DEVICE_ERROR;\r
337 goto UnmapRequestBuffer;\r
338 }\r
339 }\r
fd51d759 340\r
341 //\r
342 // preset a host status for ourselves that we do not accept as success\r
343 //\r
3540f2ce
BS
344 *HostStatus = VIRTIO_BLK_S_IOERR;\r
345\r
346 //\r
347 // Map the Status Buffer with VirtioOperationBusMasterCommonBuffer so that\r
348 // both processor and device can access it.\r
349 //\r
350 Status = VirtioMapAllBytesInSharedBuffer (\r
351 Dev->VirtIo,\r
352 VirtioOperationBusMasterCommonBuffer,\r
353 HostStatusBuffer,\r
354 sizeof *HostStatus,\r
355 &HostStatusDeviceAddress,\r
356 &StatusMapping\r
357 );\r
358 if (EFI_ERROR (Status)) {\r
359 Status = EFI_DEVICE_ERROR;\r
360 goto UnmapDataBuffer;\r
361 }\r
362\r
363 VirtioPrepare (&Dev->Ring, &Indices);\r
fd51d759 364\r
365 //\r
366 // ensured by VirtioBlkInit() -- this predicate, in combination with the\r
367 // lock-step progress, ensures we don't have to track free descriptors.\r
368 //\r
369 ASSERT (Dev->Ring.QueueSize >= 3);\r
370\r
fd51d759 371 //\r
372 // virtio-blk header in first desc\r
373 //\r
3540f2ce
BS
374 VirtioAppendDesc (\r
375 &Dev->Ring,\r
376 RequestDeviceAddress,\r
377 sizeof Request,\r
378 VRING_DESC_F_NEXT,\r
379 &Indices\r
380 );\r
fd51d759 381\r
382 //\r
383 // data buffer for read/write in second desc\r
384 //\r
385 if (BufferSize > 0) {\r
386 //\r
387 // From virtio-0.9.5, 2.3.2 Descriptor Table:\r
388 // "no descriptor chain may be more than 2^32 bytes long in total".\r
389 //\r
390 // The predicate is ensured by the call contract above (for flush), or\r
391 // VerifyReadWriteRequest() (for read/write). It also implies that\r
392 // converting BufferSize to UINT32 will not truncate it.\r
393 //\r
394 ASSERT (BufferSize <= SIZE_1GB);\r
395\r
396 //\r
397 // VRING_DESC_F_WRITE is interpreted from the host's point of view.\r
398 //\r
3540f2ce
BS
399 VirtioAppendDesc (\r
400 &Dev->Ring,\r
401 BufferDeviceAddress,\r
402 (UINT32) BufferSize,\r
fd51d759 403 VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),\r
3540f2ce
BS
404 &Indices\r
405 );\r
fd51d759 406 }\r
407\r
408 //\r
409 // host status in last (second or third) desc\r
410 //\r
3540f2ce
BS
411 VirtioAppendDesc (\r
412 &Dev->Ring,\r
413 HostStatusDeviceAddress,\r
414 sizeof *HostStatus,\r
415 VRING_DESC_F_WRITE,\r
416 &Indices\r
417 );\r
fd51d759 418\r
419 //\r
e371e7e5 420 // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
fd51d759 421 //\r
8bc951a2
LE
422 if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices,\r
423 NULL) == EFI_SUCCESS &&\r
3540f2ce
BS
424 *HostStatus == VIRTIO_BLK_S_OK) {\r
425 Status = EFI_SUCCESS;\r
426 } else {\r
427 Status = EFI_DEVICE_ERROR;\r
fd51d759 428 }\r
429\r
3540f2ce
BS
430 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);\r
431\r
432UnmapDataBuffer:\r
433 if (BufferSize > 0) {\r
ea8314e4
BS
434 UnmapStatus = Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping);\r
435 if (EFI_ERROR (UnmapStatus) && !RequestIsWrite && !EFI_ERROR (Status)) {\r
436 //\r
437 // Data from the bus master may not reach the caller; fail the request.\r
438 //\r
439 Status = EFI_DEVICE_ERROR;\r
440 }\r
3540f2ce
BS
441 }\r
442\r
443UnmapRequestBuffer:\r
444 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);\r
445\r
446FreeHostStatusBuffer:\r
447 Dev->VirtIo->FreeSharedPages (\r
448 Dev->VirtIo,\r
449 EFI_SIZE_TO_PAGES (sizeof *HostStatus),\r
450 HostStatusBuffer\r
451 );\r
452\r
453 return Status;\r
fd51d759 454}\r
455\r
456\r
457/**\r
458\r
459 ReadBlocks() operation for virtio-blk.\r
460\r
461 See\r
462 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
463 Protocol, EFI_BLOCK_IO_PROTOCOL.ReadBlocks().\r
464 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.2. ReadBlocks() and\r
465 ReadBlocksEx() Implementation.\r
466\r
467 Parameter checks and conformant return values are implemented in\r
468 VerifyReadWriteRequest() and SynchronousRequest().\r
469\r
470 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,\r
471 successfully.\r
472\r
473**/\r
474\r
475EFI_STATUS\r
476EFIAPI\r
477VirtioBlkReadBlocks (\r
478 IN EFI_BLOCK_IO_PROTOCOL *This,\r
479 IN UINT32 MediaId,\r
480 IN EFI_LBA Lba,\r
481 IN UINTN BufferSize,\r
482 OUT VOID *Buffer\r
483 )\r
484{\r
485 VBLK_DEV *Dev;\r
486 EFI_STATUS Status;\r
487\r
488 if (BufferSize == 0) {\r
489 return EFI_SUCCESS;\r
490 }\r
491\r
492 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
493 Status = VerifyReadWriteRequest (\r
494 &Dev->BlockIoMedia,\r
495 Lba,\r
496 BufferSize,\r
497 FALSE // RequestIsWrite\r
498 );\r
499 if (EFI_ERROR (Status)) {\r
500 return Status;\r
501 }\r
502\r
503 return SynchronousRequest (\r
504 Dev,\r
505 Lba,\r
506 BufferSize,\r
507 Buffer,\r
508 FALSE // RequestIsWrite\r
509 );\r
510}\r
511\r
512/**\r
513\r
514 WriteBlocks() operation for virtio-blk.\r
515\r
516 See\r
517 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
518 Protocol, EFI_BLOCK_IO_PROTOCOL.WriteBlocks().\r
519 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.3 WriteBlocks() and\r
520 WriteBlockEx() Implementation.\r
521\r
522 Parameter checks and conformant return values are implemented in\r
523 VerifyReadWriteRequest() and SynchronousRequest().\r
524\r
525 A zero BufferSize doesn't seem to be prohibited, so do nothing in that case,\r
526 successfully.\r
527\r
528**/\r
529\r
530EFI_STATUS\r
531EFIAPI\r
532VirtioBlkWriteBlocks (\r
533 IN EFI_BLOCK_IO_PROTOCOL *This,\r
534 IN UINT32 MediaId,\r
535 IN EFI_LBA Lba,\r
536 IN UINTN BufferSize,\r
537 IN VOID *Buffer\r
538 )\r
539{\r
540 VBLK_DEV *Dev;\r
541 EFI_STATUS Status;\r
542\r
543 if (BufferSize == 0) {\r
544 return EFI_SUCCESS;\r
545 }\r
546\r
547 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
548 Status = VerifyReadWriteRequest (\r
549 &Dev->BlockIoMedia,\r
550 Lba,\r
551 BufferSize,\r
552 TRUE // RequestIsWrite\r
553 );\r
554 if (EFI_ERROR (Status)) {\r
555 return Status;\r
556 }\r
557\r
558 return SynchronousRequest (\r
559 Dev,\r
560 Lba,\r
561 BufferSize,\r
562 Buffer,\r
563 TRUE // RequestIsWrite\r
564 );\r
565}\r
566\r
567\r
568/**\r
569\r
570 FlushBlocks() operation for virtio-blk.\r
571\r
572 See\r
573 - UEFI Spec 2.3.1 + Errata C, 12.8 EFI Block I/O Protocol, 12.8 EFI Block I/O\r
574 Protocol, EFI_BLOCK_IO_PROTOCOL.FlushBlocks().\r
575 - Driver Writer's Guide for UEFI 2.3.1 v1.01, 24.2.4 FlushBlocks() and\r
576 FlushBlocksEx() Implementation.\r
577\r
578 If the underlying virtio-blk device doesn't support flushing (ie.\r
579 write-caching), then this function should not be called by higher layers,\r
580 according to EFI_BLOCK_IO_MEDIA characteristics set in VirtioBlkInit().\r
581 Should they do nonetheless, we do nothing, successfully.\r
582\r
583**/\r
584\r
585EFI_STATUS\r
586EFIAPI\r
587VirtioBlkFlushBlocks (\r
588 IN EFI_BLOCK_IO_PROTOCOL *This\r
589 )\r
590{\r
591 VBLK_DEV *Dev;\r
592\r
593 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
594 return Dev->BlockIoMedia.WriteCaching ?\r
595 SynchronousRequest (\r
596 Dev,\r
597 0, // Lba\r
598 0, // BufferSize\r
599 NULL, // Buffer\r
600 TRUE // RequestIsWrite\r
601 ) :\r
602 EFI_SUCCESS;\r
603}\r
604\r
605\r
606/**\r
607\r
608 Device probe function for this driver.\r
609\r
610 The DXE core calls this function for any given device in order to see if the\r
611 driver can drive the device.\r
612\r
613 Specs relevant in the general sense:\r
614\r
615 - UEFI Spec 2.3.1 + Errata C:\r
616 - 6.3 Protocol Handler Services -- for accessing the underlying device\r
617 - 10.1 EFI Driver Binding Protocol -- for exporting ourselves\r
618\r
619 - Driver Writer's Guide for UEFI 2.3.1 v1.01:\r
620 - 5.1.3.4 OpenProtocol() and CloseProtocol() -- for accessing the\r
621 underlying device\r
622 - 9 Driver Binding Protocol -- for exporting ourselves\r
623\r
fd51d759 624 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
625 incorporating this driver (independently of\r
626 any device).\r
627\r
628 @param[in] DeviceHandle The device to probe.\r
629\r
630 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r
631\r
632\r
633 @retval EFI_SUCCESS The driver supports the device being probed.\r
634\r
56f65ed8 635 @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support\r
fd51d759 636 the device.\r
637\r
638 @return Error codes from the OpenProtocol() boot service or\r
56f65ed8 639 the VirtIo protocol.\r
fd51d759 640\r
641**/\r
642\r
643EFI_STATUS\r
644EFIAPI\r
645VirtioBlkDriverBindingSupported (\r
646 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
647 IN EFI_HANDLE DeviceHandle,\r
648 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
649 )\r
650{\r
651 EFI_STATUS Status;\r
56f65ed8 652 VIRTIO_DEVICE_PROTOCOL *VirtIo;\r
fd51d759 653\r
654 //\r
56f65ed8 655 // Attempt to open the device with the VirtIo set of interfaces. On success,\r
21479c3c
LE
656 // the protocol is "instantiated" for the VirtIo device. Covers duplicate\r
657 // open attempts (EFI_ALREADY_STARTED).\r
fd51d759 658 //\r
659 Status = gBS->OpenProtocol (\r
660 DeviceHandle, // candidate device\r
56f65ed8
OM
661 &gVirtioDeviceProtocolGuid, // for generic VirtIo access\r
662 (VOID **)&VirtIo, // handle to instantiate\r
fd51d759 663 This->DriverBindingHandle, // requestor driver identity\r
664 DeviceHandle, // ControllerHandle, according to\r
665 // the UEFI Driver Model\r
56f65ed8 666 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to\r
fd51d759 667 // the device; to be released\r
668 );\r
669 if (EFI_ERROR (Status)) {\r
670 return Status;\r
671 }\r
672\r
56f65ed8
OM
673 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {\r
674 Status = EFI_UNSUPPORTED;\r
fd51d759 675 }\r
676\r
677 //\r
56f65ed8 678 // We needed VirtIo access only transitorily, to see whether we support the\r
fd51d759 679 // device or not.\r
680 //\r
56f65ed8 681 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
fd51d759 682 This->DriverBindingHandle, DeviceHandle);\r
683 return Status;\r
684}\r
685\r
686\r
fd51d759 687/**\r
688\r
689 Set up all BlockIo and virtio-blk aspects of this driver for the specified\r
690 device.\r
691\r
692 @param[in out] Dev The driver instance to configure. The caller is\r
56f65ed8
OM
693 responsible for Dev->VirtIo's validity (ie. working IO\r
694 access to the underlying virtio-blk device).\r
fd51d759 695\r
696 @retval EFI_SUCCESS Setup complete.\r
697\r
698 @retval EFI_UNSUPPORTED The driver is unable to work with the virtio ring or\r
699 virtio-blk attributes the host provides.\r
700\r
701 @return Error codes from VirtioRingInit() or\r
19165130
BS
702 VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE or\r
703 VirtioRingMap().\r
fd51d759 704\r
705**/\r
706\r
707STATIC\r
708EFI_STATUS\r
709EFIAPI\r
710VirtioBlkInit (\r
711 IN OUT VBLK_DEV *Dev\r
712 )\r
713{\r
714 UINT8 NextDevStat;\r
715 EFI_STATUS Status;\r
716\r
bc8fde6f 717 UINT64 Features;\r
fd51d759 718 UINT64 NumSectors;\r
719 UINT32 BlockSize;\r
6476804e
LE
720 UINT8 PhysicalBlockExp;\r
721 UINT8 AlignmentOffset;\r
722 UINT32 OptIoSize;\r
fd51d759 723 UINT16 QueueSize;\r
19165130 724 UINT64 RingBaseShift;\r
fd51d759 725\r
6476804e
LE
726 PhysicalBlockExp = 0;\r
727 AlignmentOffset = 0;\r
728 OptIoSize = 0;\r
729\r
fd51d759 730 //\r
731 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.\r
732 //\r
733 NextDevStat = 0; // step 1 -- reset device\r
56f65ed8 734 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
fd51d759 735 if (EFI_ERROR (Status)) {\r
736 goto Failed;\r
737 }\r
738\r
739 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence\r
56f65ed8 740 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
fd51d759 741 if (EFI_ERROR (Status)) {\r
742 goto Failed;\r
743 }\r
744\r
745 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it\r
56f65ed8
OM
746 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
747 if (EFI_ERROR (Status)) {\r
748 goto Failed;\r
749 }\r
750\r
751 //\r
752 // Set Page Size - MMIO VirtIo Specific\r
753 //\r
754 Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);\r
fd51d759 755 if (EFI_ERROR (Status)) {\r
756 goto Failed;\r
757 }\r
758\r
759 //\r
760 // step 4a -- retrieve and validate features\r
761 //\r
56f65ed8 762 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);\r
fd51d759 763 if (EFI_ERROR (Status)) {\r
764 goto Failed;\r
765 }\r
56f65ed8
OM
766\r
767 Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);\r
fd51d759 768 if (EFI_ERROR (Status)) {\r
769 goto Failed;\r
770 }\r
771 if (NumSectors == 0) {\r
772 Status = EFI_UNSUPPORTED;\r
773 goto Failed;\r
774 }\r
775\r
776 if (Features & VIRTIO_BLK_F_BLK_SIZE) {\r
56f65ed8 777 Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);\r
fd51d759 778 if (EFI_ERROR (Status)) {\r
779 goto Failed;\r
780 }\r
781 if (BlockSize == 0 || BlockSize % 512 != 0 ||\r
2f03f796 782 ModU64x32 (NumSectors, BlockSize / 512) != 0) {\r
fd51d759 783 //\r
784 // We can only handle a logical block consisting of whole sectors,\r
785 // and only a disk composed of whole logical blocks.\r
786 //\r
787 Status = EFI_UNSUPPORTED;\r
788 goto Failed;\r
789 }\r
790 }\r
791 else {\r
792 BlockSize = 512;\r
793 }\r
794\r
6476804e
LE
795 if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
796 Status = VIRTIO_CFG_READ (Dev, Topology.PhysicalBlockExp,\r
797 &PhysicalBlockExp);\r
798 if (EFI_ERROR (Status)) {\r
799 goto Failed;\r
800 }\r
801 if (PhysicalBlockExp >= 32) {\r
802 Status = EFI_UNSUPPORTED;\r
803 goto Failed;\r
804 }\r
805\r
806 Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);\r
807 if (EFI_ERROR (Status)) {\r
808 goto Failed;\r
809 }\r
810\r
811 Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);\r
812 if (EFI_ERROR (Status)) {\r
813 goto Failed;\r
814 }\r
815 }\r
816\r
cbad8e4c 817 Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |\r
dd4205f8
BS
818 VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |\r
819 VIRTIO_F_IOMMU_PLATFORM;\r
cbad8e4c
LE
820\r
821 //\r
822 // In virtio-1.0, feature negotiation is expected to complete before queue\r
823 // discovery, and the device can also reject the selected set of features.\r
824 //\r
825 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
826 Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);\r
827 if (EFI_ERROR (Status)) {\r
828 goto Failed;\r
829 }\r
830 }\r
831\r
fd51d759 832 //\r
833 // step 4b -- allocate virtqueue\r
834 //\r
56f65ed8 835 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);\r
fd51d759 836 if (EFI_ERROR (Status)) {\r
837 goto Failed;\r
838 }\r
56f65ed8 839 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);\r
fd51d759 840 if (EFI_ERROR (Status)) {\r
841 goto Failed;\r
842 }\r
843 if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors\r
844 Status = EFI_UNSUPPORTED;\r
845 goto Failed;\r
846 }\r
847\r
fc2c1543 848 Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);\r
fd51d759 849 if (EFI_ERROR (Status)) {\r
850 goto Failed;\r
851 }\r
852\r
19165130
BS
853 //\r
854 // If anything fails from here on, we must release the ring resources\r
855 //\r
856 Status = VirtioRingMap (\r
857 Dev->VirtIo,\r
858 &Dev->Ring,\r
859 &RingBaseShift,\r
860 &Dev->RingMap\r
861 );\r
862 if (EFI_ERROR (Status)) {\r
863 goto ReleaseQueue;\r
864 }\r
865\r
fd51d759 866 //\r
56f65ed8 867 // Additional steps for MMIO: align the queue appropriately, and set the\r
19165130 868 // size. If anything fails from here on, we must unmap the ring resources.\r
fd51d759 869 //\r
56f65ed8 870 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);\r
fd51d759 871 if (EFI_ERROR (Status)) {\r
19165130 872 goto UnmapQueue;\r
fd51d759 873 }\r
874\r
56f65ed8
OM
875 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);\r
876 if (EFI_ERROR (Status)) {\r
19165130 877 goto UnmapQueue;\r
56f65ed8
OM
878 }\r
879\r
880 //\r
881 // step 4c -- Report GPFN (guest-physical frame number) of queue.\r
882 //\r
19165130
BS
883 Status = Dev->VirtIo->SetQueueAddress (\r
884 Dev->VirtIo,\r
885 &Dev->Ring,\r
886 RingBaseShift\r
887 );\r
56f65ed8 888 if (EFI_ERROR (Status)) {\r
19165130 889 goto UnmapQueue;\r
56f65ed8
OM
890 }\r
891\r
892\r
fd51d759 893 //\r
0c2a4860 894 // step 5 -- Report understood features.\r
fd51d759 895 //\r
cbad8e4c 896 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
dd4205f8 897 Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);\r
cbad8e4c
LE
898 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);\r
899 if (EFI_ERROR (Status)) {\r
19165130 900 goto UnmapQueue;\r
cbad8e4c 901 }\r
fd51d759 902 }\r
903\r
904 //\r
905 // step 6 -- initialization complete\r
906 //\r
907 NextDevStat |= VSTAT_DRIVER_OK;\r
56f65ed8 908 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
fd51d759 909 if (EFI_ERROR (Status)) {\r
19165130 910 goto UnmapQueue;\r
fd51d759 911 }\r
912\r
913 //\r
6476804e
LE
914 // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI\r
915 // Block I/O Protocol.\r
fd51d759 916 //\r
917 Dev->BlockIo.Revision = 0;\r
918 Dev->BlockIo.Media = &Dev->BlockIoMedia;\r
919 Dev->BlockIo.Reset = &VirtioBlkReset;\r
920 Dev->BlockIo.ReadBlocks = &VirtioBlkReadBlocks;\r
921 Dev->BlockIo.WriteBlocks = &VirtioBlkWriteBlocks;\r
922 Dev->BlockIo.FlushBlocks = &VirtioBlkFlushBlocks;\r
923 Dev->BlockIoMedia.MediaId = 0;\r
924 Dev->BlockIoMedia.RemovableMedia = FALSE;\r
925 Dev->BlockIoMedia.MediaPresent = TRUE;\r
926 Dev->BlockIoMedia.LogicalPartition = FALSE;\r
c4046161
JJ
927 Dev->BlockIoMedia.ReadOnly = (BOOLEAN) ((Features & VIRTIO_BLK_F_RO) != 0);\r
928 Dev->BlockIoMedia.WriteCaching = (BOOLEAN) ((Features & VIRTIO_BLK_F_FLUSH) != 0);\r
fd51d759 929 Dev->BlockIoMedia.BlockSize = BlockSize;\r
930 Dev->BlockIoMedia.IoAlign = 0;\r
2f03f796 931 Dev->BlockIoMedia.LastBlock = DivU64x32 (NumSectors,\r
932 BlockSize / 512) - 1;\r
6476804e 933\r
957914ee
LE
934 DEBUG ((DEBUG_INFO, "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",\r
935 __FUNCTION__, Dev->BlockIoMedia.BlockSize,\r
936 Dev->BlockIoMedia.LastBlock + 1));\r
937\r
6476804e
LE
938 if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
939 Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;\r
940\r
941 Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;\r
942 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;\r
943 Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;\r
957914ee
LE
944\r
945 DEBUG ((DEBUG_INFO, "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",\r
946 __FUNCTION__, Dev->BlockIoMedia.LowestAlignedLba,\r
947 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock));\r
948 DEBUG ((DEBUG_INFO, "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",\r
949 __FUNCTION__, Dev->BlockIoMedia.OptimalTransferLengthGranularity));\r
6476804e 950 }\r
fd51d759 951 return EFI_SUCCESS;\r
952\r
19165130
BS
953UnmapQueue:\r
954 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
955\r
fd51d759 956ReleaseQueue:\r
fc2c1543 957 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
fd51d759 958\r
959Failed:\r
960 //\r
961 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device\r
56f65ed8 962 // Status. VirtIo access failure here should not mask the original error.\r
fd51d759 963 //\r
964 NextDevStat |= VSTAT_FAILED;\r
56f65ed8 965 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
fd51d759 966\r
967 return Status; // reached only via Failed above\r
968}\r
969\r
970\r
971/**\r
972\r
973 Uninitialize the internals of a virtio-blk device that has been successfully\r
974 set up with VirtioBlkInit().\r
975\r
976 @param[in out] Dev The device to clean up.\r
977\r
978**/\r
979\r
980STATIC\r
981VOID\r
982EFIAPI\r
983VirtioBlkUninit (\r
984 IN OUT VBLK_DEV *Dev\r
985 )\r
986{\r
987 //\r
988 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When\r
989 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from\r
990 // the old comms area.\r
991 //\r
56f65ed8 992 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
fd51d759 993\r
19165130 994 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
fc2c1543 995 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
fd51d759 996\r
997 SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00);\r
998 SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);\r
999}\r
1000\r
1001\r
fcb636ea
LE
1002/**\r
1003\r
1004 Event notification function enqueued by ExitBootServices().\r
1005\r
1006 @param[in] Event Event whose notification function is being invoked.\r
1007\r
1008 @param[in] Context Pointer to the VBLK_DEV structure.\r
1009\r
1010**/\r
1011\r
1012STATIC\r
1013VOID\r
1014EFIAPI\r
1015VirtioBlkExitBoot (\r
1016 IN EFI_EVENT Event,\r
1017 IN VOID *Context\r
1018 )\r
1019{\r
1020 VBLK_DEV *Dev;\r
1021\r
1022 //\r
1023 // Reset the device. This causes the hypervisor to forget about the virtio\r
1024 // ring.\r
1025 //\r
1026 // We allocated said ring in EfiBootServicesData type memory, and code\r
1027 // executing after ExitBootServices() is permitted to overwrite it.\r
1028 //\r
1029 Dev = Context;\r
1030 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
19165130
BS
1031\r
1032 //\r
1033 // Unmap the ring buffer so that hypervisor will not be able to get\r
1034 // readable data after device is reset.\r
1035 //\r
1036 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
fcb636ea
LE
1037}\r
1038\r
fd51d759 1039/**\r
1040\r
1041 After we've pronounced support for a specific device in\r
1042 DriverBindingSupported(), we start managing said device (passed in by the\r
694673c9 1043 Driver Execution Environment) with the following service.\r
fd51d759 1044\r
1045 See DriverBindingSupported() for specification references.\r
1046\r
1047 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
1048 incorporating this driver (independently of\r
1049 any device).\r
1050\r
1051 @param[in] DeviceHandle The supported device to drive.\r
1052\r
1053 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.\r
1054\r
1055\r
1056 @retval EFI_SUCCESS Driver instance has been created and\r
56f65ed8 1057 initialized for the virtio-blk device, it\r
694673c9 1058 is now accessible via EFI_BLOCK_IO_PROTOCOL.\r
fd51d759 1059\r
1060 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
1061\r
1062 @return Error codes from the OpenProtocol() boot\r
56f65ed8 1063 service, the VirtIo protocol, VirtioBlkInit(),\r
fd51d759 1064 or the InstallProtocolInterface() boot service.\r
1065\r
1066**/\r
1067\r
1068EFI_STATUS\r
1069EFIAPI\r
1070VirtioBlkDriverBindingStart (\r
1071 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1072 IN EFI_HANDLE DeviceHandle,\r
1073 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1074 )\r
1075{\r
1076 VBLK_DEV *Dev;\r
1077 EFI_STATUS Status;\r
1078\r
1079 Dev = (VBLK_DEV *) AllocateZeroPool (sizeof *Dev);\r
1080 if (Dev == NULL) {\r
1081 return EFI_OUT_OF_RESOURCES;\r
1082 }\r
1083\r
56f65ed8
OM
1084 Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
1085 (VOID **)&Dev->VirtIo, This->DriverBindingHandle,\r
fd51d759 1086 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);\r
1087 if (EFI_ERROR (Status)) {\r
1088 goto FreeVirtioBlk;\r
1089 }\r
1090\r
1091 //\r
56f65ed8 1092 // VirtIo access granted, configure virtio-blk device.\r
fd51d759 1093 //\r
1094 Status = VirtioBlkInit (Dev);\r
1095 if (EFI_ERROR (Status)) {\r
56f65ed8 1096 goto CloseVirtIo;\r
fd51d759 1097 }\r
1098\r
fcb636ea
LE
1099 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
1100 &VirtioBlkExitBoot, Dev, &Dev->ExitBoot);\r
1101 if (EFI_ERROR (Status)) {\r
1102 goto UninitDev;\r
1103 }\r
1104\r
fd51d759 1105 //\r
1106 // Setup complete, attempt to export the driver instance's BlockIo interface.\r
1107 //\r
1108 Dev->Signature = VBLK_SIG;\r
1109 Status = gBS->InstallProtocolInterface (&DeviceHandle,\r
1110 &gEfiBlockIoProtocolGuid, EFI_NATIVE_INTERFACE,\r
1111 &Dev->BlockIo);\r
1112 if (EFI_ERROR (Status)) {\r
fcb636ea 1113 goto CloseExitBoot;\r
fd51d759 1114 }\r
1115\r
1116 return EFI_SUCCESS;\r
1117\r
fcb636ea
LE
1118CloseExitBoot:\r
1119 gBS->CloseEvent (Dev->ExitBoot);\r
1120\r
fd51d759 1121UninitDev:\r
1122 VirtioBlkUninit (Dev);\r
1123\r
56f65ed8
OM
1124CloseVirtIo:\r
1125 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
fd51d759 1126 This->DriverBindingHandle, DeviceHandle);\r
1127\r
1128FreeVirtioBlk:\r
1129 FreePool (Dev);\r
1130\r
1131 return Status;\r
1132}\r
1133\r
1134\r
1135/**\r
1136\r
1137 Stop driving a virtio-blk device and remove its BlockIo interface.\r
1138\r
1139 This function replays the success path of DriverBindingStart() in reverse.\r
1140 The host side virtio-blk device is reset, so that the OS boot loader or the\r
1141 OS may reinitialize it.\r
1142\r
1143 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object\r
1144 incorporating this driver (independently of any\r
1145 device).\r
1146\r
1147 @param[in] DeviceHandle Stop driving this device.\r
1148\r
1149 @param[in] NumberOfChildren Since this function belongs to a device driver\r
1150 only (as opposed to a bus driver), the caller\r
1151 environment sets NumberOfChildren to zero, and\r
1152 we ignore it.\r
1153\r
1154 @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).\r
1155\r
1156**/\r
1157\r
1158EFI_STATUS\r
1159EFIAPI\r
1160VirtioBlkDriverBindingStop (\r
1161 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1162 IN EFI_HANDLE DeviceHandle,\r
1163 IN UINTN NumberOfChildren,\r
1164 IN EFI_HANDLE *ChildHandleBuffer\r
1165 )\r
1166{\r
c8c2e4d6 1167 EFI_STATUS Status;\r
1168 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
1169 VBLK_DEV *Dev;\r
fd51d759 1170\r
c8c2e4d6 1171 Status = gBS->OpenProtocol (\r
1172 DeviceHandle, // candidate device\r
1173 &gEfiBlockIoProtocolGuid, // retrieve the BlockIo iface\r
1174 (VOID **)&BlockIo, // target pointer\r
1175 This->DriverBindingHandle, // requestor driver identity\r
1176 DeviceHandle, // requesting lookup for dev.\r
1177 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added\r
1178 );\r
1179 if (EFI_ERROR (Status)) {\r
1180 return Status;\r
1181 }\r
1182\r
1183 Dev = VIRTIO_BLK_FROM_BLOCK_IO (BlockIo);\r
fd51d759 1184\r
1185 //\r
c8c2e4d6 1186 // Handle Stop() requests for in-use driver instances gracefully.\r
fd51d759 1187 //\r
1188 Status = gBS->UninstallProtocolInterface (DeviceHandle,\r
1189 &gEfiBlockIoProtocolGuid, &Dev->BlockIo);\r
c8c2e4d6 1190 if (EFI_ERROR (Status)) {\r
1191 return Status;\r
1192 }\r
fd51d759 1193\r
fcb636ea
LE
1194 gBS->CloseEvent (Dev->ExitBoot);\r
1195\r
fd51d759 1196 VirtioBlkUninit (Dev);\r
1197\r
56f65ed8 1198 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
fd51d759 1199 This->DriverBindingHandle, DeviceHandle);\r
1200\r
1201 FreePool (Dev);\r
1202\r
1203 return EFI_SUCCESS;\r
1204}\r
1205\r
1206\r
1207//\r
1208// The static object that groups the Supported() (ie. probe), Start() and\r
1209// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata\r
1210// C, 10.1 EFI Driver Binding Protocol.\r
1211//\r
1212STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
1213 &VirtioBlkDriverBindingSupported,\r
1214 &VirtioBlkDriverBindingStart,\r
1215 &VirtioBlkDriverBindingStop,\r
1216 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers\r
1217 NULL, // ImageHandle, to be overwritten by\r
1218 // EfiLibInstallDriverBindingComponentName2() in VirtioBlkEntryPoint()\r
1219 NULL // DriverBindingHandle, ditto\r
1220};\r
1221\r
1222\r
1223//\r
1224// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and\r
1225// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name\r
1226// in English, for display on standard console devices. This is recommended for\r
1227// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's\r
1228// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.\r
1229//\r
1230// Device type names ("Virtio Block Device") are not formatted because the\r
1231// driver supports only that device type. Therefore the driver name suffices\r
1232// for unambiguous identification.\r
1233//\r
1234\r
9de0355b 1235STATIC\r
fd51d759 1236EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
1237 { "eng;en", L"Virtio Block Driver" },\r
1238 { NULL, NULL }\r
1239};\r
1240\r
9de0355b 1241STATIC\r
fd51d759 1242EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
1243\r
1244EFI_STATUS\r
1245EFIAPI\r
1246VirtioBlkGetDriverName (\r
1247 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1248 IN CHAR8 *Language,\r
1249 OUT CHAR16 **DriverName\r
1250 )\r
1251{\r
1252 return LookupUnicodeString2 (\r
1253 Language,\r
1254 This->SupportedLanguages,\r
1255 mDriverNameTable,\r
1256 DriverName,\r
1257 (BOOLEAN)(This == &gComponentName) // Iso639Language\r
1258 );\r
1259}\r
1260\r
1261EFI_STATUS\r
1262EFIAPI\r
1263VirtioBlkGetDeviceName (\r
1264 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1265 IN EFI_HANDLE DeviceHandle,\r
1266 IN EFI_HANDLE ChildHandle,\r
1267 IN CHAR8 *Language,\r
1268 OUT CHAR16 **ControllerName\r
1269 )\r
1270{\r
1271 return EFI_UNSUPPORTED;\r
1272}\r
1273\r
9de0355b 1274STATIC\r
fd51d759 1275EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
1276 &VirtioBlkGetDriverName,\r
1277 &VirtioBlkGetDeviceName,\r
1278 "eng" // SupportedLanguages, ISO 639-2 language codes\r
1279};\r
1280\r
9de0355b 1281STATIC\r
fd51d759 1282EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
1283 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioBlkGetDriverName,\r
1284 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioBlkGetDeviceName,\r
1285 "en" // SupportedLanguages, RFC 4646 language codes\r
1286};\r
1287\r
1288\r
1289//\r
1290// Entry point of this driver.\r
1291//\r
1292EFI_STATUS\r
1293EFIAPI\r
1294VirtioBlkEntryPoint (\r
1295 IN EFI_HANDLE ImageHandle,\r
1296 IN EFI_SYSTEM_TABLE *SystemTable\r
1297 )\r
1298{\r
1299 return EfiLibInstallDriverBindingComponentName2 (\r
1300 ImageHandle,\r
1301 SystemTable,\r
1302 &gDriverBinding,\r
1303 ImageHandle,\r
1304 &gComponentName,\r
1305 &gComponentName2\r
1306 );\r
1307}\r
1308\r