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