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