TianoCore EDK2 master
Loading...
Searching...
No Matches
Virtio10.c
Go to the documentation of this file.
1
12#include <Protocol/PciIo.h>
16#include <Library/DebugLib.h>
18#include <Library/PciCapLib.h>
21#include <Library/UefiLib.h>
22
23#include "Virtio10.h"
24
25//
26// Utility functions
27//
28
69 IN VIRTIO_1_0_CONFIG *Config,
70 IN BOOLEAN Write,
71 IN UINTN FieldOffset,
72 IN UINTN FieldSize,
73 IN OUT VOID *Buffer
74 )
75{
76 UINTN Count;
80
81 if (!Config->Exists ||
82 (FieldSize > Config->Length) ||
83 (FieldOffset > Config->Length - FieldSize))
84 {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 Count = 1;
89 switch (FieldSize) {
90 case 1:
91 Width = EfiPciIoWidthUint8;
92 break;
93
94 case 2:
95 Width = EfiPciIoWidthUint16;
96 break;
97
98 case 8:
99 Count = 2;
100 //
101 // fall through
102 //
103
104 case 4:
105 Width = EfiPciIoWidthUint32;
106 break;
107
108 default:
109 return EFI_INVALID_PARAMETER;
110 }
111
112 BarType = (Config->BarType == Virtio10BarTypeMem) ? &PciIo->Mem : &PciIo->Io;
113 Access = Write ? BarType->Write : BarType->Read;
114
115 return Access (
116 PciIo,
117 Width,
118 Config->Bar,
119 Config->Offset + FieldOffset,
120 Count,
121 Buffer
122 );
123}
124
145STATIC
148 IN EFI_PCI_IO_PROTOCOL *PciIo,
149 IN UINT8 BarIndex,
150 OUT VIRTIO_1_0_BAR_TYPE *BarType
151 )
152{
153 EFI_STATUS Status;
154 VOID *Resources;
155
156 Status = PciIo->GetBarAttributes (PciIo, BarIndex, NULL, &Resources);
157 if (EFI_ERROR (Status)) {
158 return Status;
159 }
160
161 Status = EFI_UNSUPPORTED;
162
163 if (*(UINT8 *)Resources == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) {
165
166 Descriptor = Resources;
167 switch (Descriptor->ResType) {
168 case ACPI_ADDRESS_SPACE_TYPE_MEM:
169 *BarType = Virtio10BarTypeMem;
170 Status = EFI_SUCCESS;
171 break;
172
173 case ACPI_ADDRESS_SPACE_TYPE_IO:
174 *BarType = Virtio10BarTypeIo;
175 Status = EFI_SUCCESS;
176 break;
177
178 default:
179 break;
180 }
181 }
182
183 FreePool (Resources);
184 return Status;
185}
186
187/*
188 Traverse the PCI capabilities list of a virtio-1.0 device, and capture the
189 locations of the interesting virtio-1.0 register blocks.
190
191 @param[in,out] Device The VIRTIO_1_0_DEV structure that identifies
192 the device. On input, the caller is responsible
193 that the Device->PciIo member be live, and that
194 the CommonConfig, NotifyConfig,
195 NotifyOffsetMultiplier and SpecificConfig
196 members be zeroed. On output, said members
197 will have been updated from the PCI
198 capabilities found.
199
200 @retval EFI_SUCCESS Traversal successful.
201
202 @return Error codes from PciCapPciIoLib, PciCapLib, and the
203 GetBarType() helper function.
204*/
205STATIC
207ParseCapabilities (
208 IN OUT VIRTIO_1_0_DEV *Device
209 )
210{
211 EFI_STATUS Status;
212 PCI_CAP_DEV *PciDevice;
213 PCI_CAP_LIST *CapList;
214 UINT16 VendorInstance;
215 PCI_CAP *VendorCap;
216
217 Status = PciCapPciIoDeviceInit (Device->PciIo, &PciDevice);
218 if (EFI_ERROR (Status)) {
219 return Status;
220 }
221
222 Status = PciCapListInit (PciDevice, &CapList);
223 if (EFI_ERROR (Status)) {
224 goto UninitPciDevice;
225 }
226
227 for (VendorInstance = 0;
228 !EFI_ERROR (
230 CapList,
231 PciCapNormal,
232 EFI_PCI_CAPABILITY_ID_VENDOR,
233 VendorInstance,
234 &VendorCap
235 )
236 );
237 VendorInstance++)
238 {
239 UINT8 CapLen;
240 VIRTIO_PCI_CAP VirtIoCap;
241 VIRTIO_1_0_CONFIG *ParsedConfig;
242
243 //
244 // Big enough to accommodate a VIRTIO_PCI_CAP structure?
245 //
246 Status = PciCapRead (
247 PciDevice,
248 VendorCap,
250 &CapLen,
251 sizeof CapLen
252 );
253 if (EFI_ERROR (Status)) {
254 goto UninitCapList;
255 }
256
257 if (CapLen < sizeof VirtIoCap) {
258 //
259 // Too small, move to next.
260 //
261 continue;
262 }
263
264 //
265 // Read interesting part of capability.
266 //
267 Status = PciCapRead (PciDevice, VendorCap, 0, &VirtIoCap, sizeof VirtIoCap);
268 if (EFI_ERROR (Status)) {
269 goto UninitCapList;
270 }
271
272 switch (VirtIoCap.ConfigType) {
273 case VIRTIO_PCI_CAP_COMMON_CFG:
274 ParsedConfig = &Device->CommonConfig;
275 break;
276 case VIRTIO_PCI_CAP_NOTIFY_CFG:
277 ParsedConfig = &Device->NotifyConfig;
278 break;
279 case VIRTIO_PCI_CAP_DEVICE_CFG:
280 ParsedConfig = &Device->SpecificConfig;
281 break;
282 default:
283 //
284 // Capability is not interesting.
285 //
286 continue;
287 }
288
289 //
290 // Save the location of the register block into ParsedConfig.
291 //
292 Status = GetBarType (Device->PciIo, VirtIoCap.Bar, &ParsedConfig->BarType);
293 if (EFI_ERROR (Status)) {
294 goto UninitCapList;
295 }
296
297 ParsedConfig->Bar = VirtIoCap.Bar;
298 ParsedConfig->Offset = VirtIoCap.Offset;
299 ParsedConfig->Length = VirtIoCap.Length;
300
301 if (VirtIoCap.ConfigType == VIRTIO_PCI_CAP_NOTIFY_CFG) {
302 //
303 // This capability has an additional field called NotifyOffsetMultiplier;
304 // parse it too.
305 //
306 if (CapLen < sizeof VirtIoCap + sizeof Device->NotifyOffsetMultiplier) {
307 //
308 // Too small, move to next.
309 //
310 continue;
311 }
312
313 Status = PciCapRead (
314 PciDevice,
315 VendorCap,
316 sizeof VirtIoCap,
317 &Device->NotifyOffsetMultiplier,
318 sizeof Device->NotifyOffsetMultiplier
319 );
320 if (EFI_ERROR (Status)) {
321 goto UninitCapList;
322 }
323 }
324
325 //
326 // Capability parsed successfully.
327 //
328 ParsedConfig->Exists = TRUE;
329 }
330
331 ASSERT_EFI_ERROR (Status);
332
333UninitCapList:
334 PciCapListUninit (CapList);
335
336UninitPciDevice:
337 PciCapPciIoDeviceUninit (PciDevice);
338
339 return Status;
340}
341
356STATIC
357VOID
359 IN VIRTIO_1_0_CONFIG *Config,
360 IN OUT UINT64 *Attributes
361 )
362{
363 if (Config->Exists) {
364 *Attributes |= (Config->BarType == Virtio10BarTypeMem) ?
367 }
368}
369
370//
371// VIRTIO_DEVICE_PROTOCOL member functions
372//
373
374STATIC
376EFIAPI
377Virtio10GetDeviceFeatures (
379 OUT UINT64 *DeviceFeatures
380 )
381{
382 VIRTIO_1_0_DEV *Dev;
383 UINT32 Selector;
384 UINT32 Features32[2];
385
386 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
387
388 for (Selector = 0; Selector < 2; ++Selector) {
389 EFI_STATUS Status;
390
391 //
392 // Select the low or high half of the features.
393 //
394 Status = Virtio10Transfer (
395 Dev->PciIo,
396 &Dev->CommonConfig,
397 TRUE,
398 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeatureSelect),
399 sizeof Selector,
400 &Selector
401 );
402 if (EFI_ERROR (Status)) {
403 return Status;
404 }
405
406 //
407 // Fetch that half.
408 //
409 Status = Virtio10Transfer (
410 Dev->PciIo,
411 &Dev->CommonConfig,
412 FALSE,
413 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceFeature),
414 sizeof Features32[Selector],
415 &Features32[Selector]
416 );
417 if (EFI_ERROR (Status)) {
418 return Status;
419 }
420 }
421
422 *DeviceFeatures = LShiftU64 (Features32[1], 32) | Features32[0];
423 return EFI_SUCCESS;
424}
425
426STATIC
428EFIAPI
429Virtio10SetGuestFeatures (
431 IN UINT64 Features
432 )
433{
434 VIRTIO_1_0_DEV *Dev;
435 UINT32 Selector;
436 UINT32 Features32[2];
437
438 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
439
440 Features32[0] = (UINT32)Features;
441 Features32[1] = (UINT32)RShiftU64 (Features, 32);
442
443 for (Selector = 0; Selector < 2; ++Selector) {
444 EFI_STATUS Status;
445
446 //
447 // Select the low or high half of the features.
448 //
449 Status = Virtio10Transfer (
450 Dev->PciIo,
451 &Dev->CommonConfig,
452 TRUE,
453 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeatureSelect),
454 sizeof Selector,
455 &Selector
456 );
457 if (EFI_ERROR (Status)) {
458 return Status;
459 }
460
461 //
462 // Write that half.
463 //
464 Status = Virtio10Transfer (
465 Dev->PciIo,
466 &Dev->CommonConfig,
467 TRUE,
468 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DriverFeature),
469 sizeof Features32[Selector],
470 &Features32[Selector]
471 );
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475 }
476
477 return EFI_SUCCESS;
478}
479
480STATIC
482EFIAPI
483Virtio10SetQueueAddress (
485 IN VRING *Ring,
486 IN UINT64 RingBaseShift
487 )
488{
489 VIRTIO_1_0_DEV *Dev;
490 EFI_STATUS Status;
491 UINT64 Address;
492 UINT16 Enable;
493
494 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
495
496 Address = (UINTN)Ring->Desc;
497 Address += RingBaseShift;
498 Status = Virtio10Transfer (
499 Dev->PciIo,
500 &Dev->CommonConfig,
501 TRUE,
502 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueDesc),
503 sizeof Address,
504 &Address
505 );
506 if (EFI_ERROR (Status)) {
507 return Status;
508 }
509
510 Address = (UINTN)Ring->Avail.Flags;
511 Address += RingBaseShift;
512 Status = Virtio10Transfer (
513 Dev->PciIo,
514 &Dev->CommonConfig,
515 TRUE,
516 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueAvail),
517 sizeof Address,
518 &Address
519 );
520 if (EFI_ERROR (Status)) {
521 return Status;
522 }
523
524 Address = (UINTN)Ring->Used.Flags;
525 Address += RingBaseShift;
526 Status = Virtio10Transfer (
527 Dev->PciIo,
528 &Dev->CommonConfig,
529 TRUE,
530 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueUsed),
531 sizeof Address,
532 &Address
533 );
534 if (EFI_ERROR (Status)) {
535 return Status;
536 }
537
538 Enable = 1;
539 Status = Virtio10Transfer (
540 Dev->PciIo,
541 &Dev->CommonConfig,
542 TRUE,
543 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueEnable),
544 sizeof Enable,
545 &Enable
546 );
547 return Status;
548}
549
550STATIC
552EFIAPI
553Virtio10SetQueueSel (
555 IN UINT16 Index
556 )
557{
558 VIRTIO_1_0_DEV *Dev;
559 EFI_STATUS Status;
560
561 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
562
563 Status = Virtio10Transfer (
564 Dev->PciIo,
565 &Dev->CommonConfig,
566 TRUE,
567 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
568 sizeof Index,
569 &Index
570 );
571 return Status;
572}
573
574STATIC
576EFIAPI
577Virtio10SetQueueNotify (
579 IN UINT16 Index
580 )
581{
582 VIRTIO_1_0_DEV *Dev;
583 EFI_STATUS Status;
584 UINT16 SavedQueueSelect;
585 UINT16 NotifyOffset;
586
587 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
588
589 //
590 // Read NotifyOffset first. NotifyOffset is queue specific, so we have
591 // to stash & restore the current queue selector around it.
592 //
593 // So, start with saving the current queue selector.
594 //
595 Status = Virtio10Transfer (
596 Dev->PciIo,
597 &Dev->CommonConfig,
598 FALSE,
599 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
600 sizeof SavedQueueSelect,
601 &SavedQueueSelect
602 );
603 if (EFI_ERROR (Status)) {
604 return Status;
605 }
606
607 //
608 // Select the requested queue.
609 //
610 Status = Virtio10Transfer (
611 Dev->PciIo,
612 &Dev->CommonConfig,
613 TRUE,
614 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
615 sizeof Index,
616 &Index
617 );
618 if (EFI_ERROR (Status)) {
619 return Status;
620 }
621
622 //
623 // Read the QueueNotifyOff field.
624 //
625 Status = Virtio10Transfer (
626 Dev->PciIo,
627 &Dev->CommonConfig,
628 FALSE,
629 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueNotifyOff),
630 sizeof NotifyOffset,
631 &NotifyOffset
632 );
633 if (EFI_ERROR (Status)) {
634 return Status;
635 }
636
637 //
638 // Re-select the original queue.
639 //
640 Status = Virtio10Transfer (
641 Dev->PciIo,
642 &Dev->CommonConfig,
643 TRUE,
644 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSelect),
645 sizeof SavedQueueSelect,
646 &SavedQueueSelect
647 );
648 if (EFI_ERROR (Status)) {
649 return Status;
650 }
651
652 //
653 // We can now kick the queue.
654 //
655 Status = Virtio10Transfer (
656 Dev->PciIo,
657 &Dev->NotifyConfig,
658 TRUE,
659 NotifyOffset * Dev->NotifyOffsetMultiplier,
660 sizeof Index,
661 &Index
662 );
663 return Status;
664}
665
666STATIC
668EFIAPI
669Virtio10SetQueueAlign (
671 IN UINT32 Alignment
672 )
673{
674 return (Alignment == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
675}
676
677STATIC
679EFIAPI
680Virtio10SetPageSize (
682 IN UINT32 PageSize
683 )
684{
685 return (PageSize == EFI_PAGE_SIZE) ? EFI_SUCCESS : EFI_UNSUPPORTED;
686}
687
688STATIC
690EFIAPI
691Virtio10GetQueueNumMax (
693 OUT UINT16 *QueueNumMax
694 )
695{
696 VIRTIO_1_0_DEV *Dev;
697 EFI_STATUS Status;
698
699 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
700
701 Status = Virtio10Transfer (
702 Dev->PciIo,
703 &Dev->CommonConfig,
704 FALSE,
705 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, QueueSize),
706 sizeof *QueueNumMax,
707 QueueNumMax
708 );
709 return Status;
710}
711
712STATIC
714EFIAPI
715Virtio10SetQueueNum (
717 IN UINT16 QueueSize
718 )
719{
720 EFI_STATUS Status;
721 UINT16 CurrentSize;
722
723 //
724 // This member function is required for VirtIo MMIO, and a no-op in
725 // VirtIo PCI 0.9.5. In VirtIo 1.0, drivers can theoretically use this
726 // member to reduce memory consumption, but none of our drivers do. So
727 // just check that they set the size that is already in effect.
728 //
729 Status = Virtio10GetQueueNumMax (This, &CurrentSize);
730 if (EFI_ERROR (Status)) {
731 return Status;
732 }
733
734 return (CurrentSize == QueueSize) ? EFI_SUCCESS : EFI_UNSUPPORTED;
735}
736
737STATIC
739EFIAPI
740Virtio10GetDeviceStatus (
742 OUT UINT8 *DeviceStatus
743 )
744{
745 VIRTIO_1_0_DEV *Dev;
746 EFI_STATUS Status;
747
748 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
749
750 Status = Virtio10Transfer (
751 Dev->PciIo,
752 &Dev->CommonConfig,
753 FALSE,
754 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
755 sizeof *DeviceStatus,
756 DeviceStatus
757 );
758 return Status;
759}
760
761STATIC
763EFIAPI
764Virtio10SetDeviceStatus (
766 IN UINT8 DeviceStatus
767 )
768{
769 VIRTIO_1_0_DEV *Dev;
770 EFI_STATUS Status;
771
772 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
773
774 Status = Virtio10Transfer (
775 Dev->PciIo,
776 &Dev->CommonConfig,
777 TRUE,
778 OFFSET_OF (VIRTIO_PCI_COMMON_CFG, DeviceStatus),
779 sizeof DeviceStatus,
780 &DeviceStatus
781 );
782 return Status;
783}
784
785STATIC
787EFIAPI
788Virtio10WriteDevice (
790 IN UINTN FieldOffset,
791 IN UINTN FieldSize,
792 IN UINT64 Value
793 )
794{
795 VIRTIO_1_0_DEV *Dev;
796 EFI_STATUS Status;
797
798 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
799
800 Status = Virtio10Transfer (
801 Dev->PciIo,
802 &Dev->SpecificConfig,
803 TRUE,
804 FieldOffset,
805 FieldSize,
806 &Value
807 );
808 return Status;
809}
810
811STATIC
813EFIAPI
814Virtio10ReadDevice (
816 IN UINTN FieldOffset,
817 IN UINTN FieldSize,
818 IN UINTN BufferSize,
819 OUT VOID *Buffer
820 )
821{
822 VIRTIO_1_0_DEV *Dev;
823 EFI_STATUS Status;
824
825 if (FieldSize != BufferSize) {
826 return EFI_INVALID_PARAMETER;
827 }
828
829 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
830
831 Status = Virtio10Transfer (
832 Dev->PciIo,
833 &Dev->SpecificConfig,
834 FALSE,
835 FieldOffset,
836 FieldSize,
837 Buffer
838 );
839 return Status;
840}
841
842STATIC
844EFIAPI
845Virtio10AllocateSharedPages (
847 IN UINTN Pages,
848 IN OUT VOID **HostAddress
849 )
850{
851 VIRTIO_1_0_DEV *Dev;
852 EFI_STATUS Status;
853
854 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
855
856 Status = Dev->PciIo->AllocateBuffer (
857 Dev->PciIo,
860 Pages,
861 HostAddress,
862 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
863 );
864 return Status;
865}
866
867STATIC
868VOID
869EFIAPI
870Virtio10FreeSharedPages (
872 IN UINTN Pages,
873 IN VOID *HostAddress
874 )
875{
876 VIRTIO_1_0_DEV *Dev;
877
878 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
879
880 Dev->PciIo->FreeBuffer (
881 Dev->PciIo,
882 Pages,
883 HostAddress
884 );
885}
886
887STATIC
889EFIAPI
890Virtio10MapSharedBuffer (
892 IN VIRTIO_MAP_OPERATION Operation,
893 IN VOID *HostAddress,
894 IN OUT UINTN *NumberOfBytes,
895 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
896 OUT VOID **Mapping
897 )
898{
899 EFI_STATUS Status;
900 VIRTIO_1_0_DEV *Dev;
901 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;
902
903 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
904
905 //
906 // Map VIRTIO_MAP_OPERATION to EFI_PCI_IO_PROTOCOL_OPERATION
907 //
908 switch (Operation) {
909 case VirtioOperationBusMasterRead:
910 PciIoOperation = EfiPciIoOperationBusMasterRead;
911 break;
912 case VirtioOperationBusMasterWrite:
913 PciIoOperation = EfiPciIoOperationBusMasterWrite;
914 break;
915 case VirtioOperationBusMasterCommonBuffer:
917 break;
918 default:
919 return EFI_INVALID_PARAMETER;
920 }
921
922 Status = Dev->PciIo->Map (
923 Dev->PciIo,
924 PciIoOperation,
925 HostAddress,
926 NumberOfBytes,
927 DeviceAddress,
928 Mapping
929 );
930 return Status;
931}
932
933STATIC
935EFIAPI
936Virtio10UnmapSharedBuffer (
938 IN VOID *Mapping
939 )
940{
941 EFI_STATUS Status;
942 VIRTIO_1_0_DEV *Dev;
943
944 Dev = VIRTIO_1_0_FROM_VIRTIO_DEVICE (This);
945
946 Status = Dev->PciIo->Unmap (
947 Dev->PciIo,
948 Mapping
949 );
950
951 return Status;
952}
953
954STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = {
955 VIRTIO_SPEC_REVISION (1, 0, 0),
956 0, // SubSystemDeviceId, filled in dynamically
957 Virtio10GetDeviceFeatures,
958 Virtio10SetGuestFeatures,
959 Virtio10SetQueueAddress,
960 Virtio10SetQueueSel,
961 Virtio10SetQueueNotify,
962 Virtio10SetQueueAlign,
963 Virtio10SetPageSize,
964 Virtio10GetQueueNumMax,
965 Virtio10SetQueueNum,
966 Virtio10GetDeviceStatus,
967 Virtio10SetDeviceStatus,
968 Virtio10WriteDevice,
969 Virtio10ReadDevice,
970 Virtio10AllocateSharedPages,
971 Virtio10FreeSharedPages,
972 Virtio10MapSharedBuffer,
973 Virtio10UnmapSharedBuffer
974};
975
976//
977// EFI_DRIVER_BINDING_PROTOCOL member functions
978//
979
980STATIC
982EFIAPI
983Virtio10BindingSupported (
985 IN EFI_HANDLE DeviceHandle,
986 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
987 )
988{
989 EFI_STATUS Status;
990 EFI_PCI_IO_PROTOCOL *PciIo;
991 PCI_TYPE00 Pci;
992
993 Status = gBS->OpenProtocol (
994 DeviceHandle,
995 &gEfiPciIoProtocolGuid,
996 (VOID **)&PciIo,
997 This->DriverBindingHandle,
998 DeviceHandle,
999 EFI_OPEN_PROTOCOL_BY_DRIVER
1000 );
1001 if (EFI_ERROR (Status)) {
1002 return Status;
1003 }
1004
1005 Status = PciIo->Pci.Read (
1006 PciIo,
1007 EfiPciIoWidthUint32,
1008 0,
1009 sizeof Pci / sizeof (UINT32),
1010 &Pci
1011 );
1012 if (EFI_ERROR (Status)) {
1013 goto CloseProtocol;
1014 }
1015
1016 Status = EFI_UNSUPPORTED;
1017 //
1018 // Recognize non-transitional modern devices. Also, we'll have to parse the
1019 // PCI capability list, so make sure the CapabilityPtr field will be valid.
1020 //
1021 if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) &&
1022 (Pci.Hdr.DeviceId >= 0x1040) &&
1023 (Pci.Hdr.DeviceId <= 0x107F) &&
1024 (Pci.Hdr.RevisionID >= 0x01) &&
1025 (Pci.Device.SubsystemID >= 0x40) &&
1026 ((Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0))
1027 {
1028 //
1029 // The virtio-vga device is special. It can be driven both as a VGA device
1030 // with a linear framebuffer, and through its underlying, modern,
1031 // virtio-gpu-pci device, which has no linear framebuffer itself. For
1032 // compatibility with guest OSes that insist on inheriting a linear
1033 // framebuffer from the firmware, we should leave virtio-vga to
1034 // QemuVideoDxe, and support only virtio-gpu-pci here.
1035 //
1036 // Both virtio-vga and virtio-gpu-pci have DeviceId 0x1050, but only the
1037 // former has device class PCI_CLASS_DISPLAY_VGA.
1038 //
1039 if ((Pci.Hdr.DeviceId != 0x1050) || !IS_PCI_VGA (&Pci)) {
1040 Status = EFI_SUCCESS;
1041 }
1042 }
1043
1044CloseProtocol:
1045 gBS->CloseProtocol (
1046 DeviceHandle,
1047 &gEfiPciIoProtocolGuid,
1048 This->DriverBindingHandle,
1049 DeviceHandle
1050 );
1051
1052 return Status;
1053}
1054
1055STATIC
1057EFIAPI
1058Virtio10BindingStart (
1060 IN EFI_HANDLE DeviceHandle,
1061 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1062 )
1063{
1064 VIRTIO_1_0_DEV *Device;
1065 EFI_STATUS Status;
1066 PCI_TYPE00 Pci;
1067 UINT64 SetAttributes;
1068
1069 Device = AllocateZeroPool (sizeof *Device);
1070 if (Device == NULL) {
1071 return EFI_OUT_OF_RESOURCES;
1072 }
1073
1074 Device->Signature = VIRTIO_1_0_SIGNATURE;
1075 CopyMem (&Device->VirtIo, &mVirtIoTemplate, sizeof mVirtIoTemplate);
1076
1077 Status = gBS->OpenProtocol (
1078 DeviceHandle,
1079 &gEfiPciIoProtocolGuid,
1080 (VOID **)&Device->PciIo,
1081 This->DriverBindingHandle,
1082 DeviceHandle,
1083 EFI_OPEN_PROTOCOL_BY_DRIVER
1084 );
1085 if (EFI_ERROR (Status)) {
1086 goto FreeDevice;
1087 }
1088
1089 Status = Device->PciIo->Pci.Read (
1090 Device->PciIo,
1091 EfiPciIoWidthUint32,
1092 0,
1093 sizeof Pci / sizeof (UINT32),
1094 &Pci
1095 );
1096 if (EFI_ERROR (Status)) {
1097 goto ClosePciIo;
1098 }
1099
1100 Device->VirtIo.SubSystemDeviceId = Pci.Hdr.DeviceId - 0x1040;
1101
1102 Status = ParseCapabilities (Device);
1103 if (EFI_ERROR (Status)) {
1104 goto ClosePciIo;
1105 }
1106
1107 Status = Device->PciIo->Attributes (
1108 Device->PciIo,
1110 0,
1111 &Device->OriginalPciAttributes
1112 );
1113 if (EFI_ERROR (Status)) {
1114 goto ClosePciIo;
1115 }
1116
1117 SetAttributes = (EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |
1119 UpdateAttributes (&Device->CommonConfig, &SetAttributes);
1120 UpdateAttributes (&Device->NotifyConfig, &SetAttributes);
1121 UpdateAttributes (&Device->SpecificConfig, &SetAttributes);
1122 Status = Device->PciIo->Attributes (
1123 Device->PciIo,
1125 SetAttributes,
1126 NULL
1127 );
1128 if (EFI_ERROR (Status)) {
1129 goto ClosePciIo;
1130 }
1131
1132 Status = gBS->InstallProtocolInterface (
1133 &DeviceHandle,
1134 &gVirtioDeviceProtocolGuid,
1136 &Device->VirtIo
1137 );
1138 if (EFI_ERROR (Status)) {
1139 goto RestorePciAttributes;
1140 }
1141
1142 return EFI_SUCCESS;
1143
1144RestorePciAttributes:
1145 Device->PciIo->Attributes (
1146 Device->PciIo,
1148 Device->OriginalPciAttributes,
1149 NULL
1150 );
1151
1152ClosePciIo:
1153 gBS->CloseProtocol (
1154 DeviceHandle,
1155 &gEfiPciIoProtocolGuid,
1156 This->DriverBindingHandle,
1157 DeviceHandle
1158 );
1159
1160FreeDevice:
1161 FreePool (Device);
1162
1163 return Status;
1164}
1165
1166STATIC
1168EFIAPI
1169Virtio10BindingStop (
1171 IN EFI_HANDLE DeviceHandle,
1172 IN UINTN NumberOfChildren,
1173 IN EFI_HANDLE *ChildHandleBuffer
1174 )
1175{
1176 EFI_STATUS Status;
1177 VIRTIO_DEVICE_PROTOCOL *VirtIo;
1178 VIRTIO_1_0_DEV *Device;
1179
1180 Status = gBS->OpenProtocol (
1181 DeviceHandle,
1182 &gVirtioDeviceProtocolGuid,
1183 (VOID **)&VirtIo,
1184 This->DriverBindingHandle,
1185 DeviceHandle,
1186 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1187 );
1188 if (EFI_ERROR (Status)) {
1189 return Status;
1190 }
1191
1192 Device = VIRTIO_1_0_FROM_VIRTIO_DEVICE (VirtIo);
1193
1194 Status = gBS->UninstallProtocolInterface (
1195 DeviceHandle,
1196 &gVirtioDeviceProtocolGuid,
1197 &Device->VirtIo
1198 );
1199 if (EFI_ERROR (Status)) {
1200 return Status;
1201 }
1202
1203 Device->PciIo->Attributes (
1204 Device->PciIo,
1206 Device->OriginalPciAttributes,
1207 NULL
1208 );
1209 gBS->CloseProtocol (
1210 DeviceHandle,
1211 &gEfiPciIoProtocolGuid,
1212 This->DriverBindingHandle,
1213 DeviceHandle
1214 );
1215 FreePool (Device);
1216
1217 return EFI_SUCCESS;
1218}
1219
1220STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
1221 &Virtio10BindingSupported,
1222 &Virtio10BindingStart,
1223 &Virtio10BindingStop,
1224 0x10, // Version
1225 NULL, // ImageHandle, to be overwritten
1226 NULL // DriverBindingHandle, to be overwritten
1227};
1228
1229//
1230// EFI_COMPONENT_NAME_PROTOCOL and EFI_COMPONENT_NAME2_PROTOCOL
1231// implementations
1232//
1233
1234STATIC
1235EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1236 { "eng;en", L"Virtio 1.0 PCI Driver" },
1237 { NULL, NULL }
1238};
1239
1240STATIC
1241EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1242
1243STATIC
1245EFIAPI
1246Virtio10GetDriverName (
1248 IN CHAR8 *Language,
1249 OUT CHAR16 **DriverName
1250 )
1251{
1252 return LookupUnicodeString2 (
1253 Language,
1254 This->SupportedLanguages,
1255 mDriverNameTable,
1256 DriverName,
1257 (BOOLEAN)(This == &mComponentName) // Iso639Language
1258 );
1259}
1260
1261STATIC
1263EFIAPI
1264Virtio10GetDeviceName (
1266 IN EFI_HANDLE DeviceHandle,
1267 IN EFI_HANDLE ChildHandle,
1268 IN CHAR8 *Language,
1269 OUT CHAR16 **ControllerName
1270 )
1271{
1272 return EFI_UNSUPPORTED;
1273}
1274
1275STATIC
1276EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1277 &Virtio10GetDriverName,
1278 &Virtio10GetDeviceName,
1279 "eng"
1280};
1281
1282STATIC
1283EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
1284 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&Virtio10GetDriverName,
1285 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&Virtio10GetDeviceName,
1286 "en"
1287};
1288
1289//
1290// Entry point of this driver
1291//
1292
1294EFIAPI
1295Virtio10EntryPoint (
1296 IN EFI_HANDLE ImageHandle,
1297 IN EFI_SYSTEM_TABLE *SystemTable
1298 )
1299{
1301 ImageHandle,
1302 SystemTable,
1303 &mDriverBinding,
1304 ImageHandle,
1305 &mComponentName,
1306 &mComponentName2
1307 );
1308}
UINT64 UINTN
PACKED struct @100 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
EFI_STATUS(EFIAPI * EFI_COMPONENT_NAME2_GET_DRIVER_NAME)(IN EFI_COMPONENT_NAME2_PROTOCOL *This, IN CHAR8 *Language, OUT CHAR16 **DriverName)
EFI_STATUS(EFIAPI * EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)(IN EFI_COMPONENT_NAME2_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, OUT CHAR16 **ControllerName)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
EFI_PCI_IO_PROTOCOL_WIDTH
Definition: PciIo.h:28
#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
Clear for PCI controllers that can not genrate a DAC.
Definition: PciIo.h:64
@ EfiPciIoAttributeOperationGet
Definition: PciIo.h:103
@ EfiPciIoAttributeOperationEnable
Definition: PciIo.h:111
@ EfiPciIoAttributeOperationSet
Definition: PciIo.h:107
#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
Enable the DMA bit in the PCI Config Header.
Definition: PciIo.h:59
EFI_PCI_IO_PROTOCOL_OPERATION
Definition: PciIo.h:77
@ EfiPciIoOperationBusMasterWrite
Definition: PciIo.h:85
@ EfiPciIoOperationBusMasterRead
Definition: PciIo.h:81
@ EfiPciIoOperationBusMasterCommonBuffer
Definition: PciIo.h:90
#define EFI_PCI_IO_ATTRIBUTE_MEMORY
Enable the Memory decode bit in the PCI Config Header.
Definition: PciIo.h:58
#define EFI_PCI_IO_ATTRIBUTE_IO
Enable the I/O decode bit in the PCI Config Header.
Definition: PciIo.h:57
EFI_STATUS(EFIAPI * EFI_PCI_IO_PROTOCOL_IO_MEM)(IN EFI_PCI_IO_PROTOCOL *This, IN EFI_PCI_IO_PROTOCOL_WIDTH Width, IN UINT8 BarIndex, IN UINT64 Offset, IN UINTN Count, IN OUT VOID *Buffer)
Definition: PciIo.h:180
#define IS_PCI_VGA(_p)
Definition: Pci22.h:360
#define EFI_PCI_STATUS_CAPABILITY
0x0010
Definition: Pci22.h:629
VOID EFIAPI PciCapListUninit(IN PCI_CAP_LIST *CapList)
RETURN_STATUS EFIAPI PciCapListInit(IN PCI_CAP_DEV *PciDevice, OUT PCI_CAP_LIST **CapList)
RETURN_STATUS EFIAPI PciCapRead(IN PCI_CAP_DEV *PciDevice, IN PCI_CAP *Cap, IN UINT16 SourceOffsetInCap, OUT VOID *DestinationBuffer, IN UINT16 Size)
RETURN_STATUS EFIAPI PciCapListFindCap(IN PCI_CAP_LIST *CapList, IN PCI_CAP_DOMAIN Domain, IN UINT16 CapId, IN UINT16 Instance, OUT PCI_CAP **Cap OPTIONAL)
VOID EFIAPI PciCapPciIoDeviceUninit(IN PCI_CAP_DEV *PciDevice)
EFI_STATUS EFIAPI PciCapPciIoDeviceInit(IN EFI_PCI_IO_PROTOCOL *PciIo, OUT PCI_CAP_DEV **PciDevice)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI LookupUnicodeString2(IN CONST CHAR8 *Language, IN CONST CHAR8 *SupportedLanguages, IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable, OUT CHAR16 **UnicodeString, IN BOOLEAN Iso639Language)
Definition: UefiLib.c:801
EFI_STATUS EFIAPI EfiLibInstallDriverBindingComponentName2(IN CONST EFI_HANDLE ImageHandle, IN CONST EFI_SYSTEM_TABLE *SystemTable, IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, IN EFI_HANDLE DriverBindingHandle, IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName OPTIONAL, IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL)
@ EfiBootServicesData
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
@ AllocateAnyPages
Definition: UefiSpec.h:33
STATIC VOID UpdateAttributes(IN VIRTIO_1_0_CONFIG *Config, IN OUT UINT64 *Attributes)
Definition: Virtio10.c:358
STATIC EFI_STATUS Virtio10Transfer(IN EFI_PCI_IO_PROTOCOL *PciIo, IN VIRTIO_1_0_CONFIG *Config, IN BOOLEAN Write, IN UINTN FieldOffset, IN UINTN FieldSize, IN OUT VOID *Buffer)
Definition: Virtio10.c:67
STATIC EFI_STATUS GetBarType(IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINT8 BarIndex, OUT VIRTIO_1_0_BAR_TYPE *BarType)
Definition: Virtio10.c:147
EFI_PCI_IO_PROTOCOL_IO_MEM Write
Definition: PciIo.h:197
EFI_PCI_IO_PROTOCOL_IO_MEM Read
Definition: PciIo.h:193
EFI_PCI_IO_PROTOCOL_CONFIG Read
Definition: PciIo.h:232