]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Virtio10Dxe/Virtio10.c
OvmfPkg/Virtio10Dxe: convert to PciCapLib
[mirror_edk2.git] / OvmfPkg / Virtio10Dxe / Virtio10.c
1 /** @file
2 A non-transitional driver for VirtIo 1.0 PCI devices.
3
4 Copyright (C) 2016, Red Hat, Inc.
5 Copyright (C) 2017, AMD Inc, All rights reserved.<BR>
6
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 **/
15
16 #include <IndustryStandard/Pci.h>
17 #include <IndustryStandard/Virtio.h>
18 #include <Protocol/PciIo.h>
19 #include <Protocol/PciRootBridgeIo.h>
20 #include <Protocol/VirtioDevice.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/DebugLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/PciCapLib.h>
25 #include <Library/PciCapPciIoLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Library/UefiLib.h>
28
29 #include "Virtio10.h"
30
31
32 //
33 // Utility functions
34 //
35
36 /**
37 Transfer data between the caller and a register in a virtio-1.0 register
38 block.
39
40 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents
41 the device.
42
43 @param[in] Config The "fat pointer" structure that identifies the
44 register block to access.
45
46 @param[in] Write TRUE if the register should be written, FALSE if
47 the register should be read.
48
49 @param[in] FieldOffset The offset of the register within the register
50 block.
51
52 @param[in] FieldSize The size of the register within the register
53 block. Can be one of 1, 2, 4 and 8. Accesses to
54 8-byte registers are broken up into two 4-byte
55 accesses.
56
57 @param[in,out] Buffer When Write is TRUE, the register is written with
58 data from Buffer. When Write is FALSE, the caller
59 receives the register value into Buffer.
60
61 @retval EFI_SUCCESS Register access successful.
62
63 @retval EFI_INVALID_PARAMETER The register block pointed-to by Config
64 doesn't exist; or FieldOffset and FieldSize
65 would overflow the register block; or
66 FieldSize is invalid.
67
68 @return Error codes from
69 EFI_PCI_IO_PROTOCOL.(Io|Mem).(Read|Write)
70 member functions.
71 **/
72 STATIC
73 EFI_STATUS
74 Virtio10Transfer (
75 IN EFI_PCI_IO_PROTOCOL *PciIo,
76 IN VIRTIO_1_0_CONFIG *Config,
77 IN BOOLEAN Write,
78 IN UINTN FieldOffset,
79 IN UINTN FieldSize,
80 IN OUT VOID *Buffer
81 )
82 {
83 UINTN Count;
84 EFI_PCI_IO_PROTOCOL_WIDTH Width;
85 EFI_PCI_IO_PROTOCOL_ACCESS *BarType;
86 EFI_PCI_IO_PROTOCOL_IO_MEM Access;
87
88 if (!Config->Exists ||
89 FieldSize > Config->Length ||
90 FieldOffset > Config->Length - FieldSize) {
91 return EFI_INVALID_PARAMETER;
92 }
93
94 Count = 1;
95 switch (FieldSize) {
96 case 1:
97 Width = EfiPciIoWidthUint8;
98 break;
99
100 case 2:
101 Width = EfiPciIoWidthUint16;
102 break;
103
104 case 8:
105 Count = 2;
106 //
107 // fall through
108 //
109
110 case 4:
111 Width = EfiPciIoWidthUint32;
112 break;
113
114 default:
115 return EFI_INVALID_PARAMETER;
116 }
117
118 BarType = (Config->BarType == Virtio10BarTypeMem) ? &PciIo->Mem : &PciIo->Io;
119 Access = Write ? BarType->Write : BarType->Read;
120
121 return Access (PciIo, Width, Config->Bar, Config->Offset + FieldOffset,
122 Count, Buffer);
123 }
124
125
126 /**
127 Determine if a PCI BAR is IO or MMIO.
128
129 @param[in] PciIo The EFI_PCI_IO_PROTOCOL instance that represents the
130 device.
131
132 @param[in] BarIndex The number of the BAR whose type the caller is
133 interested in.
134
135 @param[out] BarType On output, a VIRTIO_1_0_BAR_TYPE value that gives the
136 type of the BAR.
137
138 @retval EFI_SUCCESS The BAR type has been recognized and stored in
139 BarType.
140
141 @retval EFI_UNSUPPORTED The BAR type couldn't be identified.
142
143 @return Error codes from
144 EFI_PCI_IO_PROTOCOL.GetBarAttributes().
145 **/
146 STATIC
147 EFI_STATUS
148 GetBarType (
149 IN EFI_PCI_IO_PROTOCOL *PciIo,
150 IN UINT8 BarIndex,
151 OUT VIRTIO_1_0_BAR_TYPE *BarType
152 )
153 {
154 EFI_STATUS Status;
155 VOID *Resources;
156
157 Status = PciIo->GetBarAttributes (PciIo, BarIndex, NULL, &Resources);
158 if (EFI_ERROR (Status)) {
159 return Status;
160 }
161
162 Status = EFI_UNSUPPORTED;
163
164 if (*(UINT8 *)Resources == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) {
165 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
166
167 Descriptor = Resources;
168 switch (Descriptor->ResType) {
169 case ACPI_ADDRESS_SPACE_TYPE_MEM:
170 *BarType = Virtio10BarTypeMem;
171 Status = EFI_SUCCESS;
172 break;
173
174 case ACPI_ADDRESS_SPACE_TYPE_IO:
175 *BarType = Virtio10BarTypeIo;
176 Status = EFI_SUCCESS;
177 break;
178
179 default:
180 break;
181 }
182 }
183
184 FreePool (Resources);
185 return Status;
186 }
187
188
189 /*
190 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
191 locations of the interesting virtio-1.0 register blocks.
192
193 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies
194 the device. On input, the caller is responsible
195 that the Device->PciIo member be live, and that
196 the CommonConfig, NotifyConfig,
197 NotifyOffsetMultiplier and SpecificConfig
198 members be zeroed. On output, said members
199 will have been updated from the PCI
200 capabilities found.
201
202 @retval EFI_SUCCESS Traversal successful.
203
204 @return Error codes from PciCapPciIoLib, PciCapLib, and the
205 GetBarType() helper function.
206 */
207 STATIC
208 EFI_STATUS
209 ParseCapabilities (
210 IN OUT VIRTIO_1_0_DEV *Device
211 )
212 {
213 EFI_STATUS Status;
214 PCI_CAP_DEV *PciDevice;
215 PCI_CAP_LIST *CapList;
216 UINT16 VendorInstance;
217 PCI_CAP *VendorCap;
218
219 Status = PciCapPciIoDeviceInit (Device->PciIo, &PciDevice);
220 if (EFI_ERROR (Status)) {
221 return Status;
222 }
223 Status = PciCapListInit (PciDevice, &CapList);
224 if (EFI_ERROR (Status)) {
225 goto UninitPciDevice;
226 }
227
228 for (VendorInstance = 0;
229 !EFI_ERROR (PciCapListFindCap (CapList, PciCapNormal,
230 EFI_PCI_CAPABILITY_ID_VENDOR, VendorInstance,
231 &VendorCap));
232 VendorInstance++) {
233 UINT8 CapLen;
234 VIRTIO_PCI_CAP VirtIoCap;
235 VIRTIO_1_0_CONFIG *ParsedConfig;
236
237 //
238 // Big enough to accommodate a VIRTIO_PCI_CAP structure?
239 //
240 Status = PciCapRead (PciDevice, VendorCap,
241 OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length), &CapLen,
242 sizeof CapLen);
243 if (EFI_ERROR (Status)) {
244 goto UninitCapList;
245 }
246 if (CapLen < sizeof VirtIoCap) {
247 //
248 // Too small, move to next.
249 //
250 continue;
251 }
252
253 //
254 // Read interesting part of capability.
255 //
256 Status = PciCapRead (PciDevice, VendorCap, 0, &VirtIoCap, sizeof VirtIoCap);
257 if (EFI_ERROR (Status)) {
258 goto UninitCapList;
259 }
260
261 switch (VirtIoCap.ConfigType) {
262 case VIRTIO_PCI_CAP_COMMON_CFG:
263 ParsedConfig = &Device->CommonConfig;
264 break;
265 case VIRTIO_PCI_CAP_NOTIFY_CFG:
266 ParsedConfig = &Device->NotifyConfig;
267 break;
268 case VIRTIO_PCI_CAP_DEVICE_CFG:
269 ParsedConfig = &Device->SpecificConfig;
270 break;
271 default:
272 //
273 // Capability is not interesting.
274 //
275 continue;
276 }
277
278 //
279 // Save the location of the register block into ParsedConfig.
280 //
281 Status = GetBarType (Device->PciIo, VirtIoCap.Bar, &ParsedConfig->BarType);
282 if (EFI_ERROR (Status)) {
283 goto UninitCapList;
284 }
285 ParsedConfig->Bar = VirtIoCap.Bar;
286 ParsedConfig->Offset = VirtIoCap.Offset;
287 ParsedConfig->Length = VirtIoCap.Length;
288
289 if (VirtIoCap.ConfigType == VIRTIO_PCI_CAP_NOTIFY_CFG) {
290 //
291 // This capability has an additional field called NotifyOffsetMultiplier;
292 // parse it too.
293 //
294 if (CapLen < sizeof VirtIoCap + sizeof Device->NotifyOffsetMultiplier) {
295 //
296 // Too small, move to next.
297 //
298 continue;
299 }
300
301 Status = PciCapRead (PciDevice, VendorCap, sizeof VirtIoCap,
302 &Device->NotifyOffsetMultiplier,
303 sizeof Device->NotifyOffsetMultiplier);
304 if (EFI_ERROR (Status)) {
305 goto UninitCapList;
306 }
307 }
308
309 //
310 // Capability parsed successfully.
311 //
312 ParsedConfig->Exists = TRUE;
313 }
314
315 ASSERT_EFI_ERROR (Status);
316
317 UninitCapList:
318 PciCapListUninit (CapList);
319
320 UninitPciDevice:
321 PciCapPciIoDeviceUninit (PciDevice);
322
323 return Status;
324 }
325
326
327 /**
328 Accumulate the BAR type of a virtio-1.0 register block into a UINT64
329 attribute map, such that the latter is suitable for enabling IO / MMIO
330 decoding with EFI_PCI_IO_PROTOCOL.Attributes().
331
332 @param[in] Config The "fat pointer" structure that identifies the
333 register block. It is allowed for the register
334 block not to exist.
335
336 @param[in,out] Attributes On output, if the register block exists,
337 EFI_PCI_IO_ATTRIBUTE_MEMORY or
338 EFI_PCI_IO_ATTRIBUTE_IO is OR-ed into Attributes,
339 according to the register block's BAR type.
340 **/
341 STATIC
342 VOID
343 UpdateAttributes (
344 IN VIRTIO_1_0_CONFIG *Config,
345 IN OUT UINT64 *Attributes
346 )
347 {
348 if (Config->Exists) {
349 *Attributes |= (Config->BarType == Virtio10BarTypeMem) ?
350 EFI_PCI_IO_ATTRIBUTE_MEMORY:
351 EFI_PCI_IO_ATTRIBUTE_IO;
352 }
353 }
354
355
356 //
357 // VIRTIO_DEVICE_PROTOCOL member functions
358 //
359
360 STATIC
361 EFI_STATUS
362 EFIAPI
363 Virtio10GetDeviceFeatures (
364 IN VIRTIO_DEVICE_PROTOCOL *This,
365 OUT UINT64 *DeviceFeatures
366 )
367 {
368 VIRTIO_1_0_DEV *Dev;
369 UINT32 Selector;
370 UINT32 Features32[2];
371
372 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
373
374 for (Selector = 0; Selector < 2; ++Selector) {
375 EFI_STATUS Status;
376
377 //
378 // Select the low or high half of the features.
379 //
380 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
381 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeatureSelect),
382 sizeof Selector, &Selector);
383 if (EFI_ERROR (Status)) {
384 return Status;
385 }
386
387 //
388 // Fetch that half.
389 //
390 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
391 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeature),
392 sizeof Features32[Selector], &Features32[Selector]);
393 if (EFI_ERROR (Status)) {
394 return Status;
395 }
396 }
397
398 *DeviceFeatures = LShiftU64 (Features32[1], 32) | Features32[0];
399 return EFI_SUCCESS;
400 }
401
402
403 STATIC
404 EFI_STATUS
405 EFIAPI
406 Virtio10SetGuestFeatures (
407 IN VIRTIO_DEVICE_PROTOCOL *This,
408 IN UINT64 Features
409 )
410 {
411 VIRTIO_1_0_DEV *Dev;
412 UINT32 Selector;
413 UINT32 Features32[2];
414
415 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
416
417 Features32[0] = (UINT32)Features;
418 Features32[1] = (UINT32)RShiftU64 (Features, 32);
419
420 for (Selector = 0; Selector < 2; ++Selector) {
421 EFI_STATUS Status;
422
423 //
424 // Select the low or high half of the features.
425 //
426 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
427 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeatureSelect),
428 sizeof Selector, &Selector);
429 if (EFI_ERROR (Status)) {
430 return Status;
431 }
432
433 //
434 // Write that half.
435 //
436 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
437 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeature),
438 sizeof Features32[Selector], &Features32[Selector]);
439 if (EFI_ERROR (Status)) {
440 return Status;
441 }
442 }
443
444 return EFI_SUCCESS;
445 }
446
447
448 STATIC
449 EFI_STATUS
450 EFIAPI
451 Virtio10SetQueueAddress (
452 IN VIRTIO_DEVICE_PROTOCOL *This,
453 IN VRING *Ring,
454 IN UINT64 RingBaseShift
455 )
456 {
457 VIRTIO_1_0_DEV *Dev;
458 EFI_STATUS Status;
459 UINT64 Address;
460 UINT16 Enable;
461
462 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
463
464 Address = (UINTN)Ring->Desc;
465 Address += RingBaseShift;
466 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
467 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueDesc),
468 sizeof Address, &Address);
469 if (EFI_ERROR (Status)) {
470 return Status;
471 }
472
473 Address = (UINTN)Ring->Avail.Flags;
474 Address += RingBaseShift;
475 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
476 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueAvail),
477 sizeof Address, &Address);
478 if (EFI_ERROR (Status)) {
479 return Status;
480 }
481
482 Address = (UINTN)Ring->Used.Flags;
483 Address += RingBaseShift;
484 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
485 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueUsed),
486 sizeof Address, &Address);
487 if (EFI_ERROR (Status)) {
488 return Status;
489 }
490
491 Enable = 1;
492 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
493 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueEnable),
494 sizeof Enable, &Enable);
495 return Status;
496 }
497
498
499 STATIC
500 EFI_STATUS
501 EFIAPI
502 Virtio10SetQueueSel (
503 IN VIRTIO_DEVICE_PROTOCOL *This,
504 IN UINT16 Index
505 )
506 {
507 VIRTIO_1_0_DEV *Dev;
508 EFI_STATUS Status;
509
510 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
511
512 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
513 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
514 sizeof Index, &Index);
515 return Status;
516 }
517
518
519 STATIC
520 EFI_STATUS
521 EFIAPI
522 Virtio10SetQueueNotify (
523 IN VIRTIO_DEVICE_PROTOCOL *This,
524 IN UINT16 Index
525 )
526 {
527 VIRTIO_1_0_DEV *Dev;
528 EFI_STATUS Status;
529 UINT16 SavedQueueSelect;
530 UINT16 NotifyOffset;
531
532 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
533
534 //
535 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
536 // to stash & restore the current queue selector around it.
537 //
538 // So, start with saving the current queue selector.
539 //
540 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
541 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
542 sizeof SavedQueueSelect, &SavedQueueSelect);
543 if (EFI_ERROR (Status)) {
544 return Status;
545 }
546
547 //
548 // Select the requested queue.
549 //
550 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
551 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
552 sizeof Index, &Index);
553 if (EFI_ERROR (Status)) {
554 return Status;
555 }
556
557 //
558 // Read the QueueNotifyOff field.
559 //
560 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
561 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueNotifyOff),
562 sizeof NotifyOffset, &NotifyOffset);
563 if (EFI_ERROR (Status)) {
564 return Status;
565 }
566
567 //
568 // Re-select the original queue.
569 //
570 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
571 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
572 sizeof SavedQueueSelect, &SavedQueueSelect);
573 if (EFI_ERROR (Status)) {
574 return Status;
575 }
576
577 //
578 // We can now kick the queue.
579 //
580 Status = Virtio10Transfer (Dev->PciIo, &Dev->NotifyConfig, TRUE,
581 NotifyOffset * Dev->NotifyOffsetMultiplier,
582 sizeof Index, &Index);
583 return Status;
584 }
585
586
587 STATIC
588 EFI_STATUS
589 EFIAPI
590 Virtio10SetQueueAlign (
591 IN VIRTIO_DEVICE_PROTOCOL *This,
592 IN UINT32 Alignment
593 )
594 {
595 return (Alignment == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
596 }
597
598
599 STATIC
600 EFI_STATUS
601 EFIAPI
602 Virtio10SetPageSize (
603 IN VIRTIO_DEVICE_PROTOCOL *This,
604 IN UINT32 PageSize
605 )
606 {
607 return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
608 }
609
610
611 STATIC
612 EFI_STATUS
613 EFIAPI
614 Virtio10GetQueueNumMax (
615 IN VIRTIO_DEVICE_PROTOCOL *This,
616 OUT UINT16 *QueueNumMax
617 )
618 {
619 VIRTIO_1_0_DEV *Dev;
620 EFI_STATUS Status;
621
622 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
623
624 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
625 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSize),
626 sizeof *QueueNumMax, QueueNumMax);
627 return Status;
628 }
629
630
631 STATIC
632 EFI_STATUS
633 EFIAPI
634 Virtio10SetQueueNum (
635 IN VIRTIO_DEVICE_PROTOCOL *This,
636 IN UINT16 QueueSize
637 )
638 {
639 EFI_STATUS Status;
640 UINT16 CurrentSize;
641
642 //
643 // This member function is required for VirtIo MMIO, and a no-op in
644 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
645 // member to reduce memory consumption, but none of our drivers do. So
646 // just check that they set the size that is already in effect.
647 //
648 Status = Virtio10GetQueueNumMax (This, &CurrentSize);
649 if (EFI_ERROR (Status)) {
650 return Status;
651 }
652 return (CurrentSize == QueueSize) ? EFI_SUCCESS : EFI_UNSUPPORTED;
653 }
654
655
656 STATIC
657 EFI_STATUS
658 EFIAPI
659 Virtio10GetDeviceStatus (
660 IN VIRTIO_DEVICE_PROTOCOL *This,
661 OUT UINT8 *DeviceStatus
662 )
663 {
664 VIRTIO_1_0_DEV *Dev;
665 EFI_STATUS Status;
666
667 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
668
669 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, FALSE,
670 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
671 sizeof *DeviceStatus, DeviceStatus);
672 return Status;
673 }
674
675
676 STATIC
677 EFI_STATUS
678 EFIAPI
679 Virtio10SetDeviceStatus (
680 IN VIRTIO_DEVICE_PROTOCOL *This,
681 IN UINT8 DeviceStatus
682 )
683 {
684 VIRTIO_1_0_DEV *Dev;
685 EFI_STATUS Status;
686
687 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
688
689 Status = Virtio10Transfer (Dev->PciIo, &Dev->CommonConfig, TRUE,
690 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
691 sizeof DeviceStatus, &DeviceStatus);
692 return Status;
693 }
694
695
696 STATIC
697 EFI_STATUS
698 EFIAPI
699 Virtio10WriteDevice (
700 IN VIRTIO_DEVICE_PROTOCOL *This,
701 IN UINTN FieldOffset,
702 IN UINTN FieldSize,
703 IN UINT64 Value
704 )
705 {
706 VIRTIO_1_0_DEV *Dev;
707 EFI_STATUS Status;
708
709 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
710
711 Status = Virtio10Transfer (Dev->PciIo, &Dev->SpecificConfig, TRUE,
712 FieldOffset, FieldSize, &Value);
713 return Status;
714 }
715
716
717 STATIC
718 EFI_STATUS
719 EFIAPI
720 Virtio10ReadDevice (
721 IN VIRTIO_DEVICE_PROTOCOL *This,
722 IN UINTN FieldOffset,
723 IN UINTN FieldSize,
724 IN UINTN BufferSize,
725 OUT VOID *Buffer
726 )
727 {
728 VIRTIO_1_0_DEV *Dev;
729 EFI_STATUS Status;
730
731 if (FieldSize != BufferSize) {
732 return EFI_INVALID_PARAMETER;
733 }
734
735 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
736
737 Status = Virtio10Transfer (Dev->PciIo, &Dev->SpecificConfig, FALSE,
738 FieldOffset, FieldSize, Buffer);
739 return Status;
740 }
741
742 STATIC
743 EFI_STATUS
744 EFIAPI
745 Virtio10AllocateSharedPages (
746 IN VIRTIO_DEVICE_PROTOCOL *This,
747 IN UINTN Pages,
748 IN OUT VOID **HostAddress
749 )
750 {
751 VIRTIO_1_0_DEV *Dev;
752 EFI_STATUS Status;
753
754 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
755
756 Status = Dev->PciIo->AllocateBuffer (
757 Dev->PciIo,
758 AllocateAnyPages,
759 EfiBootServicesData,
760 Pages,
761 HostAddress,
762 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
763 );
764 return Status;
765 }
766
767 STATIC
768 VOID
769 EFIAPI
770 Virtio10FreeSharedPages (
771 IN VIRTIO_DEVICE_PROTOCOL *This,
772 IN UINTN Pages,
773 IN VOID *HostAddress
774 )
775 {
776 VIRTIO_1_0_DEV *Dev;
777
778 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
779
780 Dev->PciIo->FreeBuffer (
781 Dev->PciIo,
782 Pages,
783 HostAddress
784 );
785 }
786
787 STATIC
788 EFI_STATUS
789 EFIAPI
790 Virtio10MapSharedBuffer (
791 IN VIRTIO_DEVICE_PROTOCOL *This,
792 IN VIRTIO_MAP_OPERATION Operation,
793 IN VOID *HostAddress,
794 IN OUT UINTN *NumberOfBytes,
795 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
796 OUT VOID **Mapping
797 )
798 {
799 EFI_STATUS Status;
800 VIRTIO_1_0_DEV *Dev;
801 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;
802
803 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
804
805 //
806 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
807 //
808 switch (Operation) {
809 case VirtioOperationBusMasterRead:
810 PciIoOperation = EfiPciIoOperationBusMasterRead;
811 break;
812 case VirtioOperationBusMasterWrite:
813 PciIoOperation = EfiPciIoOperationBusMasterWrite;
814 break;
815 case VirtioOperationBusMasterCommonBuffer:
816 PciIoOperation = EfiPciIoOperationBusMasterCommonBuffer;
817 break;
818 default:
819 return EFI_INVALID_PARAMETER;
820 }
821
822 Status = Dev->PciIo->Map (
823 Dev->PciIo,
824 PciIoOperation,
825 HostAddress,
826 NumberOfBytes,
827 DeviceAddress,
828 Mapping
829 );
830 return Status;
831 }
832
833 STATIC
834 EFI_STATUS
835 EFIAPI
836 Virtio10UnmapSharedBuffer (
837 IN VIRTIO_DEVICE_PROTOCOL *This,
838 IN VOID *Mapping
839 )
840 {
841 EFI_STATUS Status;
842 VIRTIO_1_0_DEV *Dev;
843
844 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
845
846 Status = Dev->PciIo->Unmap (
847 Dev->PciIo,
848 Mapping
849 );
850
851 return Status;
852 }
853
854 STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = {
855 VIRTIO_SPEC_REVISION (1, 0, 0),
856 0, // SubSystemDeviceId, filled in dynamically
857 Virtio10GetDeviceFeatures,
858 Virtio10SetGuestFeatures,
859 Virtio10SetQueueAddress,
860 Virtio10SetQueueSel,
861 Virtio10SetQueueNotify,
862 Virtio10SetQueueAlign,
863 Virtio10SetPageSize,
864 Virtio10GetQueueNumMax,
865 Virtio10SetQueueNum,
866 Virtio10GetDeviceStatus,
867 Virtio10SetDeviceStatus,
868 Virtio10WriteDevice,
869 Virtio10ReadDevice,
870 Virtio10AllocateSharedPages,
871 Virtio10FreeSharedPages,
872 Virtio10MapSharedBuffer,
873 Virtio10UnmapSharedBuffer
874 };
875
876
877 //
878 // EFI_DRIVER_BINDING_PROTOCOL member functions
879 //
880
881 STATIC
882 EFI_STATUS
883 EFIAPI
884 Virtio10BindingSupported (
885 IN EFI_DRIVER_BINDING_PROTOCOL *This,
886 IN EFI_HANDLE DeviceHandle,
887 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
888 )
889 {
890 EFI_STATUS Status;
891 EFI_PCI_IO_PROTOCOL *PciIo;
892 PCI_TYPE00 Pci;
893
894 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
895 (VOID **)&PciIo, This->DriverBindingHandle,
896 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
897 if (EFI_ERROR (Status)) {
898 return Status;
899 }
900
901 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,
902 sizeof Pci / sizeof (UINT32), &Pci);
903 if (EFI_ERROR (Status)) {
904 goto CloseProtocol;
905 }
906
907 Status = EFI_UNSUPPORTED;
908 //
909 // Recognize non-transitional modern devices. Also, we'll have to parse the
910 // PCI capability list, so make sure the CapabilityPtr field will be valid.
911 //
912 if (Pci.Hdr.VendorId == VIRTIO_VENDOR_ID &&
913 Pci.Hdr.DeviceId >= 0x1040 &&
914 Pci.Hdr.DeviceId <= 0x107F &&
915 Pci.Hdr.RevisionID >= 0x01 &&
916 Pci.Device.SubsystemID >= 0x40 &&
917 (Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
918 //
919 // The virtio-vga device is special. It can be driven both as a VGA device
920 // with a linear framebuffer, and through its underlying, modern,
921 // virtio-gpu-pci device, which has no linear framebuffer itself. For
922 // compatibility with guest OSes that insist on inheriting a linear
923 // framebuffer from the firmware, we should leave virtio-vga to
924 // QemuVideoDxe, and support only virtio-gpu-pci here.
925 //
926 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
927 // former has device class PCI_CLASS_DISPLAY_VGA.
928 //
929 if (Pci.Hdr.DeviceId != 0x1050 || !IS_PCI_VGA (&Pci)) {
930 Status = EFI_SUCCESS;
931 }
932 }
933
934 CloseProtocol:
935 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
936 This->DriverBindingHandle, DeviceHandle);
937
938 return Status;
939 }
940
941
942 STATIC
943 EFI_STATUS
944 EFIAPI
945 Virtio10BindingStart (
946 IN EFI_DRIVER_BINDING_PROTOCOL *This,
947 IN EFI_HANDLE DeviceHandle,
948 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
949 )
950 {
951 VIRTIO_1_0_DEV *Device;
952 EFI_STATUS Status;
953 PCI_TYPE00 Pci;
954 UINT64 SetAttributes;
955
956 Device = AllocateZeroPool (sizeof *Device);
957 if (Device == NULL) {
958 return EFI_OUT_OF_RESOURCES;
959 }
960
961 Device->Signature = VIRTIO_1_0_SIGNATURE;
962 CopyMem (&Device->VirtIo, &mVirtIoTemplate, sizeof mVirtIoTemplate);
963
964 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
965 (VOID **)&Device->PciIo, This->DriverBindingHandle,
966 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
967 if (EFI_ERROR (Status)) {
968 goto FreeDevice;
969 }
970
971 Status = Device->PciIo->Pci.Read (Device->PciIo, EfiPciIoWidthUint32, 0,
972 sizeof Pci / sizeof (UINT32), &Pci);
973 if (EFI_ERROR (Status)) {
974 goto ClosePciIo;
975 }
976
977 Device->VirtIo.SubSystemDeviceId = Pci.Hdr.DeviceId - 0x1040;
978
979 Status = ParseCapabilities (Device);
980 if (EFI_ERROR (Status)) {
981 goto ClosePciIo;
982 }
983
984 Status = Device->PciIo->Attributes (Device->PciIo,
985 EfiPciIoAttributeOperationGet, 0,
986 &Device->OriginalPciAttributes);
987 if (EFI_ERROR (Status)) {
988 goto ClosePciIo;
989 }
990
991 SetAttributes = (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |
992 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
993 UpdateAttributes (&Device->CommonConfig, &SetAttributes);
994 UpdateAttributes (&Device->NotifyConfig, &SetAttributes);
995 UpdateAttributes (&Device->SpecificConfig, &SetAttributes);
996 Status = Device->PciIo->Attributes (Device->PciIo,
997 EfiPciIoAttributeOperationEnable, SetAttributes,
998 NULL);
999 if (EFI_ERROR (Status)) {
1000 goto ClosePciIo;
1001 }
1002
1003 Status = gBS->InstallProtocolInterface (&DeviceHandle,
1004 &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,
1005 &Device->VirtIo);
1006 if (EFI_ERROR (Status)) {
1007 goto RestorePciAttributes;
1008 }
1009
1010 return EFI_SUCCESS;
1011
1012 RestorePciAttributes:
1013 Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
1014 Device->OriginalPciAttributes, NULL);
1015
1016 ClosePciIo:
1017 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
1018 This->DriverBindingHandle, DeviceHandle);
1019
1020 FreeDevice:
1021 FreePool (Device);
1022
1023 return Status;
1024 }
1025
1026
1027 STATIC
1028 EFI_STATUS
1029 EFIAPI
1030 Virtio10BindingStop (
1031 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1032 IN EFI_HANDLE DeviceHandle,
1033 IN UINTN NumberOfChildren,
1034 IN EFI_HANDLE *ChildHandleBuffer
1035 )
1036 {
1037 EFI_STATUS Status;
1038 VIRTIO_DEVICE_PROTOCOL *VirtIo;
1039 VIRTIO_1_0_DEV *Device;
1040
1041 Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1042 (VOID **)&VirtIo, This->DriverBindingHandle,
1043 DeviceHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
1044 if (EFI_ERROR (Status)) {
1045 return Status;
1046 }
1047
1048 Device = VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo);
1049
1050 Status = gBS->UninstallProtocolInterface (DeviceHandle,
1051 &gVirtioDeviceProtocolGuid, &Device->VirtIo);
1052 if (EFI_ERROR (Status)) {
1053 return Status;
1054 }
1055
1056 Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
1057 Device->OriginalPciAttributes, NULL);
1058 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
1059 This->DriverBindingHandle, DeviceHandle);
1060 FreePool (Device);
1061
1062 return EFI_SUCCESS;
1063 }
1064
1065
1066 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
1067 &Virtio10BindingSupported,
1068 &Virtio10BindingStart,
1069 &Virtio10BindingStop,
1070 0x10, // Version
1071 NULL, // ImageHandle, to be overwritten
1072 NULL // DriverBindingHandle, to be overwritten
1073 };
1074
1075
1076 //
1077 // EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1078 // implementations
1079 //
1080
1081 STATIC
1082 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1083 { "eng;en", L"Virtio 1.0 PCI Driver" },
1084 { NULL, NULL }
1085 };
1086
1087 STATIC
1088 EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1089
1090 STATIC
1091 EFI_STATUS
1092 EFIAPI
1093 Virtio10GetDriverName (
1094 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1095 IN CHAR8 *Language,
1096 OUT CHAR16 **DriverName
1097 )
1098 {
1099 return LookupUnicodeString2 (
1100 Language,
1101 This->SupportedLanguages,
1102 mDriverNameTable,
1103 DriverName,
1104 (BOOLEAN)(This == &mComponentName) // Iso639Language
1105 );
1106 }
1107
1108 STATIC
1109 EFI_STATUS
1110 EFIAPI
1111 Virtio10GetDeviceName (
1112 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1113 IN EFI_HANDLE DeviceHandle,
1114 IN EFI_HANDLE ChildHandle,
1115 IN CHAR8 *Language,
1116 OUT CHAR16 **ControllerName
1117 )
1118 {
1119 return EFI_UNSUPPORTED;
1120 }
1121
1122 STATIC
1123 EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1124 &Virtio10GetDriverName,
1125 &Virtio10GetDeviceName,
1126 "eng"
1127 };
1128
1129 STATIC
1130 EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
1131 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &Virtio10GetDriverName,
1132 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &Virtio10GetDeviceName,
1133 "en"
1134 };
1135
1136
1137 //
1138 // Entry point of this driver
1139 //
1140
1141 EFI_STATUS
1142 EFIAPI
1143 Virtio10EntryPoint (
1144 IN EFI_HANDLE ImageHandle,
1145 IN EFI_SYSTEM_TABLE *SystemTable
1146 )
1147 {
1148 return EfiLibInstallDriverBindingComponentName2 (
1149 ImageHandle,
1150 SystemTable,
1151 &mDriverBinding,
1152 ImageHandle,
1153 &mComponentName,
1154 &mComponentName2
1155 );
1156 }