]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - OvmfPkg/VirtioBlkDxe/VirtioBlk.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / VirtioBlkDxe / VirtioBlk.c
... / ...
CommitLineData
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
14 Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>\r
15 Copyright (c) 2017, AMD Inc, All rights reserved.<BR>\r
16\r
17 SPDX-License-Identifier: BSD-2-Clause-Patent\r
18\r
19**/\r
20\r
21#include <IndustryStandard/VirtioBlk.h>\r
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
27#include <Library/VirtioLib.h>\r
28\r
29#include "VirtioBlk.h"\r
30\r
31/**\r
32\r
33 Convenience macros to read and write region 0 IO space elements of the\r
34 virtio-blk device, for configuration purposes.\r
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
40 @param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space\r
41 we're accessing. Dev->VirtIo must be valid.\r
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
54 @return Status code returned by Virtio->WriteDevice() /\r
55 Virtio->ReadDevice().\r
56\r
57**/\r
58\r
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
64 ))\r
65\r
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
72 ))\r
73\r
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
82 IN EFI_BLOCK_IO_PROTOCOL *This,\r
83 IN BOOLEAN ExtendedVerification\r
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
145 IN EFI_BLOCK_IO_MEDIA *Media,\r
146 IN EFI_LBA Lba,\r
147 IN UINTN PositiveBufferSize,\r
148 IN BOOLEAN RequestIsWrite\r
149 )\r
150{\r
151 UINTN BlockCount;\r
152\r
153 ASSERT (PositiveBufferSize > 0);\r
154\r
155 if ((PositiveBufferSize > SIZE_1GB) ||\r
156 (PositiveBufferSize % Media->BlockSize > 0))\r
157 {\r
158 return EFI_BAD_BUFFER_SIZE;\r
159 }\r
160\r
161 BlockCount = PositiveBufferSize / Media->BlockSize;\r
162\r
163 //\r
164 // Avoid unsigned wraparound on either side in the second comparison.\r
165 //\r
166 if ((Lba > Media->LastBlock) || (BlockCount - 1 > Media->LastBlock - Lba)) {\r
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
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
225 @retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or\r
226 unable to parse host response, or host response\r
227 is not VIRTIO_BLK_S_OK or failed to map Buffer\r
228 for a bus master operation.\r
229\r
230**/\r
231STATIC\r
232EFI_STATUS\r
233EFIAPI\r
234SynchronousRequest (\r
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
240 )\r
241{\r
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
255\r
256 BlockSize = Dev->BlockIoMedia.BlockSize;\r
257\r
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
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
280 Request.Type = RequestIsWrite ?\r
281 (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) :\r
282 VIRTIO_BLK_T_IN;\r
283 Request.IoPrio = 0;\r
284 Request.Sector = MultU64x32 (Lba, BlockSize / 512);\r
285\r
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
309 (VOID *)&Request,\r
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
328 (VOID *)Buffer,\r
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
338\r
339 //\r
340 // preset a host status for ourselves that we do not accept as success\r
341 //\r
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
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
369 //\r
370 // virtio-blk header in first desc\r
371 //\r
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
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
397 VirtioAppendDesc (\r
398 &Dev->Ring,\r
399 BufferDeviceAddress,\r
400 (UINT32)BufferSize,\r
401 VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),\r
402 &Indices\r
403 );\r
404 }\r
405\r
406 //\r
407 // host status in last (second or third) desc\r
408 //\r
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
416\r
417 //\r
418 // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
419 //\r
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
429 Status = EFI_SUCCESS;\r
430 } else {\r
431 Status = EFI_DEVICE_ERROR;\r
432 }\r
433\r
434 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);\r
435\r
436UnmapDataBuffer:\r
437 if (BufferSize > 0) {\r
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
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
458}\r
459\r
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
477EFI_STATUS\r
478EFIAPI\r
479VirtioBlkReadBlocks (\r
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
485 )\r
486{\r
487 VBLK_DEV *Dev;\r
488 EFI_STATUS Status;\r
489\r
490 if (BufferSize == 0) {\r
491 return EFI_SUCCESS;\r
492 }\r
493\r
494 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
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
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 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
584EFI_STATUS\r
585EFIAPI\r
586VirtioBlkFlushBlocks (\r
587 IN EFI_BLOCK_IO_PROTOCOL *This\r
588 )\r
589{\r
590 VBLK_DEV *Dev;\r
591\r
592 Dev = VIRTIO_BLK_FROM_BLOCK_IO (This);\r
593 return Dev->BlockIoMedia.WriteCaching ?\r
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
602}\r
603\r
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
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
633 @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support\r
634 the device.\r
635\r
636 @return Error codes from the OpenProtocol() boot service or\r
637 the VirtIo protocol.\r
638\r
639**/\r
640EFI_STATUS\r
641EFIAPI\r
642VirtioBlkDriverBindingSupported (\r
643 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
644 IN EFI_HANDLE DeviceHandle,\r
645 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
646 )\r
647{\r
648 EFI_STATUS Status;\r
649 VIRTIO_DEVICE_PROTOCOL *VirtIo;\r
650\r
651 //\r
652 // Attempt to open the device with the VirtIo set of interfaces. On success,\r
653 // the protocol is "instantiated" for the VirtIo device. Covers duplicate\r
654 // open attempts (EFI_ALREADY_STARTED).\r
655 //\r
656 Status = gBS->OpenProtocol (\r
657 DeviceHandle, // candidate device\r
658 &gVirtioDeviceProtocolGuid, // for generic VirtIo access\r
659 (VOID **)&VirtIo, // handle to instantiate\r
660 This->DriverBindingHandle, // requestor driver identity\r
661 DeviceHandle, // ControllerHandle, according to\r
662 // the UEFI Driver Model\r
663 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to\r
664 // the device; to be released\r
665 );\r
666 if (EFI_ERROR (Status)) {\r
667 return Status;\r
668 }\r
669\r
670 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) {\r
671 Status = EFI_UNSUPPORTED;\r
672 }\r
673\r
674 //\r
675 // We needed VirtIo access only transitorily, to see whether we support the\r
676 // device or not.\r
677 //\r
678 gBS->CloseProtocol (\r
679 DeviceHandle,\r
680 &gVirtioDeviceProtocolGuid,\r
681 This->DriverBindingHandle,\r
682 DeviceHandle\r
683 );\r
684 return Status;\r
685}\r
686\r
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
693 responsible for Dev->VirtIo's validity (ie. working IO\r
694 access to the underlying virtio-blk device).\r
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
702 VIRTIO_CFG_READ() / VIRTIO_CFG_WRITE or\r
703 VirtioRingMap().\r
704\r
705**/\r
706STATIC\r
707EFI_STATUS\r
708EFIAPI\r
709VirtioBlkInit (\r
710 IN OUT VBLK_DEV *Dev\r
711 )\r
712{\r
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
724\r
725 PhysicalBlockExp = 0;\r
726 AlignmentOffset = 0;\r
727 OptIoSize = 0;\r
728\r
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
733 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
734 if (EFI_ERROR (Status)) {\r
735 goto Failed;\r
736 }\r
737\r
738 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence\r
739 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
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
745 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
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
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
761 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);\r
762 if (EFI_ERROR (Status)) {\r
763 goto Failed;\r
764 }\r
765\r
766 Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);\r
767 if (EFI_ERROR (Status)) {\r
768 goto Failed;\r
769 }\r
770\r
771 if (NumSectors == 0) {\r
772 Status = EFI_UNSUPPORTED;\r
773 goto Failed;\r
774 }\r
775\r
776 if (Features & VIRTIO_BLK_F_BLK_SIZE) {\r
777 Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);\r
778 if (EFI_ERROR (Status)) {\r
779 goto Failed;\r
780 }\r
781\r
782 if ((BlockSize == 0) || (BlockSize % 512 != 0) ||\r
783 (ModU64x32 (NumSectors, BlockSize / 512) != 0))\r
784 {\r
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
792 } else {\r
793 BlockSize = 512;\r
794 }\r
795\r
796 if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
797 Status = VIRTIO_CFG_READ (\r
798 Dev,\r
799 Topology.PhysicalBlockExp,\r
800 &PhysicalBlockExp\r
801 );\r
802 if (EFI_ERROR (Status)) {\r
803 goto Failed;\r
804 }\r
805\r
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
822 Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |\r
823 VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |\r
824 VIRTIO_F_IOMMU_PLATFORM;\r
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
837 //\r
838 // step 4b -- allocate virtqueue\r
839 //\r
840 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);\r
841 if (EFI_ERROR (Status)) {\r
842 goto Failed;\r
843 }\r
844\r
845 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);\r
846 if (EFI_ERROR (Status)) {\r
847 goto Failed;\r
848 }\r
849\r
850 if (QueueSize < 3) {\r
851 // SynchronousRequest() uses at most three descriptors\r
852 Status = EFI_UNSUPPORTED;\r
853 goto Failed;\r
854 }\r
855\r
856 Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);\r
857 if (EFI_ERROR (Status)) {\r
858 goto Failed;\r
859 }\r
860\r
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
874 //\r
875 // Additional steps for MMIO: align the queue appropriately, and set the\r
876 // size. If anything fails from here on, we must unmap the ring resources.\r
877 //\r
878 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);\r
879 if (EFI_ERROR (Status)) {\r
880 goto UnmapQueue;\r
881 }\r
882\r
883 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);\r
884 if (EFI_ERROR (Status)) {\r
885 goto UnmapQueue;\r
886 }\r
887\r
888 //\r
889 // step 4c -- Report GPFN (guest-physical frame number) of queue.\r
890 //\r
891 Status = Dev->VirtIo->SetQueueAddress (\r
892 Dev->VirtIo,\r
893 &Dev->Ring,\r
894 RingBaseShift\r
895 );\r
896 if (EFI_ERROR (Status)) {\r
897 goto UnmapQueue;\r
898 }\r
899\r
900 //\r
901 // step 5 -- Report understood features.\r
902 //\r
903 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
904 Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);\r
905 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);\r
906 if (EFI_ERROR (Status)) {\r
907 goto UnmapQueue;\r
908 }\r
909 }\r
910\r
911 //\r
912 // step 6 -- initialization complete\r
913 //\r
914 NextDevStat |= VSTAT_DRIVER_OK;\r
915 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
916 if (EFI_ERROR (Status)) {\r
917 goto UnmapQueue;\r
918 }\r
919\r
920 //\r
921 // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI\r
922 // Block I/O Protocol.\r
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
934 Dev->BlockIoMedia.ReadOnly = (BOOLEAN)((Features & VIRTIO_BLK_F_RO) != 0);\r
935 Dev->BlockIoMedia.WriteCaching = (BOOLEAN)((Features & VIRTIO_BLK_F_FLUSH) != 0);\r
936 Dev->BlockIoMedia.BlockSize = BlockSize;\r
937 Dev->BlockIoMedia.IoAlign = 0;\r
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
950\r
951 if (Features & VIRTIO_BLK_F_TOPOLOGY) {\r
952 Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;\r
953\r
954 Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;\r
955 Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;\r
956 Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;\r
957\r
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
971 }\r
972\r
973 return EFI_SUCCESS;\r
974\r
975UnmapQueue:\r
976 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
977\r
978ReleaseQueue:\r
979 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
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
984 // Status. VirtIo access failure here should not mask the original error.\r
985 //\r
986 NextDevStat |= VSTAT_FAILED;\r
987 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);\r
988\r
989 return Status; // reached only via Failed above\r
990}\r
991\r
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
1000STATIC\r
1001VOID\r
1002EFIAPI\r
1003VirtioBlkUninit (\r
1004 IN OUT VBLK_DEV *Dev\r
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
1012 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
1013\r
1014 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);\r
1015 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
1016\r
1017 SetMem (&Dev->BlockIo, sizeof Dev->BlockIo, 0x00);\r
1018 SetMem (&Dev->BlockIoMedia, sizeof Dev->BlockIoMedia, 0x00);\r
1019}\r
1020\r
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
1030STATIC\r
1031VOID\r
1032EFIAPI\r
1033VirtioBlkExitBoot (\r
1034 IN EFI_EVENT Event,\r
1035 IN VOID *Context\r
1036 )\r
1037{\r
1038 VBLK_DEV *Dev;\r
1039\r
1040 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));\r
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
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
1056 Driver Execution Environment) with the following service.\r
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
1070 initialized for the virtio-blk device, it\r
1071 is now accessible via EFI_BLOCK_IO_PROTOCOL.\r
1072\r
1073 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
1074\r
1075 @return Error codes from the OpenProtocol() boot\r
1076 service, the VirtIo protocol, VirtioBlkInit(),\r
1077 or the InstallProtocolInterface() boot service.\r
1078\r
1079**/\r
1080EFI_STATUS\r
1081EFIAPI\r
1082VirtioBlkDriverBindingStart (\r
1083 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1084 IN EFI_HANDLE DeviceHandle,\r
1085 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1086 )\r
1087{\r
1088 VBLK_DEV *Dev;\r
1089 EFI_STATUS Status;\r
1090\r
1091 Dev = (VBLK_DEV *)AllocateZeroPool (sizeof *Dev);\r
1092 if (Dev == NULL) {\r
1093 return EFI_OUT_OF_RESOURCES;\r
1094 }\r
1095\r
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
1104 if (EFI_ERROR (Status)) {\r
1105 goto FreeVirtioBlk;\r
1106 }\r
1107\r
1108 //\r
1109 // VirtIo access granted, configure virtio-blk device.\r
1110 //\r
1111 Status = VirtioBlkInit (Dev);\r
1112 if (EFI_ERROR (Status)) {\r
1113 goto CloseVirtIo;\r
1114 }\r
1115\r
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
1123 if (EFI_ERROR (Status)) {\r
1124 goto UninitDev;\r
1125 }\r
1126\r
1127 //\r
1128 // Setup complete, attempt to export the driver instance's BlockIo interface.\r
1129 //\r
1130 Dev->Signature = VBLK_SIG;\r
1131 Status = gBS->InstallProtocolInterface (\r
1132 &DeviceHandle,\r
1133 &gEfiBlockIoProtocolGuid,\r
1134 EFI_NATIVE_INTERFACE,\r
1135 &Dev->BlockIo\r
1136 );\r
1137 if (EFI_ERROR (Status)) {\r
1138 goto CloseExitBoot;\r
1139 }\r
1140\r
1141 return EFI_SUCCESS;\r
1142\r
1143CloseExitBoot:\r
1144 gBS->CloseEvent (Dev->ExitBoot);\r
1145\r
1146UninitDev:\r
1147 VirtioBlkUninit (Dev);\r
1148\r
1149CloseVirtIo:\r
1150 gBS->CloseProtocol (\r
1151 DeviceHandle,\r
1152 &gVirtioDeviceProtocolGuid,\r
1153 This->DriverBindingHandle,\r
1154 DeviceHandle\r
1155 );\r
1156\r
1157FreeVirtioBlk:\r
1158 FreePool (Dev);\r
1159\r
1160 return Status;\r
1161}\r
1162\r
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
1185EFI_STATUS\r
1186EFIAPI\r
1187VirtioBlkDriverBindingStop (\r
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
1192 )\r
1193{\r
1194 EFI_STATUS Status;\r
1195 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
1196 VBLK_DEV *Dev;\r
1197\r
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
1211\r
1212 //\r
1213 // Handle Stop() requests for in-use driver instances gracefully.\r
1214 //\r
1215 Status = gBS->UninstallProtocolInterface (\r
1216 DeviceHandle,\r
1217 &gEfiBlockIoProtocolGuid,\r
1218 &Dev->BlockIo\r
1219 );\r
1220 if (EFI_ERROR (Status)) {\r
1221 return Status;\r
1222 }\r
1223\r
1224 gBS->CloseEvent (Dev->ExitBoot);\r
1225\r
1226 VirtioBlkUninit (Dev);\r
1227\r
1228 gBS->CloseProtocol (\r
1229 DeviceHandle,\r
1230 &gVirtioDeviceProtocolGuid,\r
1231 This->DriverBindingHandle,\r
1232 DeviceHandle\r
1233 );\r
1234\r
1235 FreePool (Dev);\r
1236\r
1237 return EFI_SUCCESS;\r
1238}\r
1239\r
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
1245STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {\r
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
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
1267STATIC\r
1268EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
1269 { "eng;en", L"Virtio Block Driver" },\r
1270 { NULL, NULL }\r
1271};\r
1272\r
1273STATIC\r
1274EFI_COMPONENT_NAME_PROTOCOL gComponentName;\r
1275\r
1276EFI_STATUS\r
1277EFIAPI\r
1278VirtioBlkGetDriverName (\r
1279 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
1280 IN CHAR8 *Language,\r
1281 OUT CHAR16 **DriverName\r
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
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
1301 )\r
1302{\r
1303 return EFI_UNSUPPORTED;\r
1304}\r
1305\r
1306STATIC\r
1307EFI_COMPONENT_NAME_PROTOCOL gComponentName = {\r
1308 &VirtioBlkGetDriverName,\r
1309 &VirtioBlkGetDeviceName,\r
1310 "eng" // SupportedLanguages, ISO 639-2 language codes\r
1311};\r
1312\r
1313STATIC\r
1314EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {\r
1315 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioBlkGetDriverName,\r
1316 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioBlkGetDeviceName,\r
1317 "en" // SupportedLanguages, RFC 4646 language codes\r
1318};\r
1319\r
1320//\r
1321// Entry point of this driver.\r
1322//\r
1323EFI_STATUS\r
1324EFIAPI\r
1325VirtioBlkEntryPoint (\r
1326 IN EFI_HANDLE ImageHandle,\r
1327 IN EFI_SYSTEM_TABLE *SystemTable\r
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