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