TianoCore EDK2 master
Loading...
Searching...
No Matches
VirtioPciDevice.c
Go to the documentation of this file.
1
16#include <Library/DebugLib.h>
19#include <Library/UefiLib.h>
20
21#include "VirtioPciDevice.h"
22
23STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = {
24 0, // Revision
25 0, // SubSystemDeviceId
26 VirtioPciGetDeviceFeatures, // GetDeviceFeatures
27 VirtioPciSetGuestFeatures, // SetGuestFeatures
28 VirtioPciSetQueueAddress, // SetQueueAddress
29 VirtioPciSetQueueSel, // SetQueueSel
30 VirtioPciSetQueueNotify, // SetQueueNotify
31 VirtioPciSetQueueAlignment, // SetQueueAlignment
32 VirtioPciSetPageSize, // SetPageSize
33 VirtioPciGetQueueSize, // GetQueueNumMax
34 VirtioPciSetQueueSize, // SetQueueNum
35 VirtioPciGetDeviceStatus, // GetDeviceStatus
36 VirtioPciSetDeviceStatus, // SetDeviceStatus
37 VirtioPciDeviceWrite, // WriteDevice
38 VirtioPciDeviceRead, // ReadDevice
39 VirtioPciAllocateSharedPages, // AllocateSharedPages
40 VirtioPciFreeSharedPages, // FreeSharedPages
41 VirtioPciMapSharedBuffer, // MapSharedBuffer
42 VirtioPciUnmapSharedBuffer, // UnmapSharedBuffer
43};
44
68EFIAPI
71 IN UINTN FieldOffset,
72 IN UINTN FieldSize,
73 IN UINTN BufferSize,
74 OUT VOID *Buffer
75 )
76{
77 UINTN Count;
80
81 ASSERT (FieldSize == BufferSize);
82
83 PciIo = Dev->PciIo;
84 Count = 1;
85
86 switch (FieldSize) {
87 case 1:
88 Width = EfiPciIoWidthUint8;
89 break;
90
91 case 2:
92 Width = EfiPciIoWidthUint16;
93 break;
94
95 case 8:
96 //
97 // The 64bit PCI I/O is broken down into two 32bit reads to prevent
98 // any alignment or width issues.
99 // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():
100 //
101 // The I/O operations are carried out exactly as requested. The caller
102 // is responsible for any alignment and I/O width issues which the
103 // bus, device, platform, or type of I/O might require. For example on
104 // some platforms, width requests of EfiPciIoWidthUint64 do not work.
105 //
106 Count = 2;
107
108 //
109 // fall through
110 //
111 case 4:
112 Width = EfiPciIoWidthUint32;
113 break;
114
115 default:
116 ASSERT (FALSE);
117 return EFI_INVALID_PARAMETER;
118 }
119
120 return PciIo->Io.Read (
121 PciIo,
122 Width,
123 PCI_BAR_IDX0,
124 FieldOffset,
125 Count,
126 Buffer
127 );
128}
129
151EFIAPI
154 IN UINTN FieldOffset,
155 IN UINTN FieldSize,
156 IN UINT64 Value
157 )
158{
159 UINTN Count;
161 EFI_PCI_IO_PROTOCOL *PciIo;
162
163 PciIo = Dev->PciIo;
164 Count = 1;
165
166 switch (FieldSize) {
167 case 1:
168 Width = EfiPciIoWidthUint8;
169 break;
170
171 case 2:
172 Width = EfiPciIoWidthUint16;
173 break;
174
175 case 8:
176 //
177 // The 64bit PCI I/O is broken down into two 32bit writes to prevent
178 // any alignment or width issues.
179 // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():
180 //
181 // The I/O operations are carried out exactly as requested. The caller
182 // is responsible for any alignment and I/O width issues which the
183 // bus, device, platform, or type of I/O might require. For example on
184 // some platforms, width requests of EfiPciIoWidthUint64 do not work
185 //
186 Count = Count * 2;
187
188 //
189 // fall through
190 //
191 case 4:
192 Width = EfiPciIoWidthUint32;
193 break;
194
195 default:
196 ASSERT (FALSE);
197 return EFI_INVALID_PARAMETER;
198 }
199
200 return PciIo->Io.Write (
201 PciIo,
202 Width,
203 PCI_BAR_IDX0,
204 FieldOffset,
205 Count,
206 &Value
207 );
208}
209
235STATIC
237EFIAPI
240 IN EFI_HANDLE DeviceHandle,
241 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
242 )
243{
244 EFI_STATUS Status;
245 EFI_PCI_IO_PROTOCOL *PciIo;
246 PCI_TYPE00 Pci;
247
248 //
249 // Attempt to open the device with the PciIo set of interfaces. On success,
250 // the protocol is "instantiated" for the PCI device. Covers duplicate open
251 // attempts (EFI_ALREADY_STARTED).
252 //
253 Status = gBS->OpenProtocol (
254 DeviceHandle, // candidate device
255 &gEfiPciIoProtocolGuid, // for generic PCI access
256 (VOID **)&PciIo, // handle to instantiate
257 This->DriverBindingHandle, // requestor driver identity
258 DeviceHandle, // ControllerHandle, according to
259 // the UEFI Driver Model
260 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to
261 // the device; to be released
262 );
263 if (EFI_ERROR (Status)) {
264 return Status;
265 }
266
267 //
268 // Read entire PCI configuration header for more extensive check ahead.
269 //
270 Status = PciIo->Pci.Read (
271 PciIo, // (protocol, device)
272 // handle
273 EfiPciIoWidthUint32, // access width & copy
274 // mode
275 0, // Offset
276 sizeof Pci / sizeof (UINT32), // Count
277 &Pci // target buffer
278 );
279
280 if (Status == EFI_SUCCESS) {
281 //
282 // virtio-0.9.5, 2.1 PCI Discovery
283 //
284 if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) &&
285 (Pci.Hdr.DeviceId >= 0x1000) &&
286 (Pci.Hdr.DeviceId <= 0x103F) &&
287 (Pci.Hdr.RevisionID == 0x00))
288 {
289 Status = EFI_SUCCESS;
290 } else {
291 Status = EFI_UNSUPPORTED;
292 }
293 }
294
295 //
296 // We needed PCI IO access only transitorily, to see whether we support the
297 // device or not.
298 //
299 gBS->CloseProtocol (
300 DeviceHandle,
301 &gEfiPciIoProtocolGuid,
302 This->DriverBindingHandle,
303 DeviceHandle
304 );
305
306 return Status;
307}
308
325STATIC
327EFIAPI
329 IN OUT VIRTIO_PCI_DEVICE *Device
330 )
331{
332 EFI_STATUS Status;
333 EFI_PCI_IO_PROTOCOL *PciIo;
334 PCI_TYPE00 Pci;
335
336 ASSERT (Device != NULL);
337 PciIo = Device->PciIo;
338 ASSERT (PciIo != NULL);
339 ASSERT (PciIo->Pci.Read != NULL);
340
341 Status = PciIo->Pci.Read (
342 PciIo, // (protocol, device)
343 // handle
344 EfiPciIoWidthUint32, // access width & copy
345 // mode
346 0, // Offset
347 sizeof (Pci) / sizeof (UINT32), // Count
348 &Pci // target buffer
349 );
350 if (EFI_ERROR (Status)) {
351 return Status;
352 }
353
354 //
355 // Copy protocol template
356 //
357 CopyMem (
358 &Device->VirtioDevice,
359 &mDeviceProtocolTemplate,
361 );
362
363 //
364 // Initialize the protocol interface attributes
365 //
366 Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);
367 Device->VirtioDevice.SubSystemDeviceId = Pci.Device.SubsystemID;
368
369 //
370 // Note: We don't support the MSI-X capability. If we did,
371 // the offset would become 24 after enabling MSI-X.
372 //
373 Device->DeviceSpecificConfigurationOffset =
374 VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;
375
376 return EFI_SUCCESS;
377}
378
387STATIC
388VOID
389EFIAPI
391 IN OUT VIRTIO_PCI_DEVICE *Device
392 )
393{
394 // Note: This function mirrors VirtioPciInit() that does not allocate any
395 // resources - there's nothing to free here.
396}
397
426STATIC
428EFIAPI
431 IN EFI_HANDLE DeviceHandle,
432 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
433 )
434{
435 VIRTIO_PCI_DEVICE *Device;
436 EFI_STATUS Status;
437
438 Device = (VIRTIO_PCI_DEVICE *)AllocateZeroPool (sizeof *Device);
439 if (Device == NULL) {
440 return EFI_OUT_OF_RESOURCES;
441 }
442
443 Status = gBS->OpenProtocol (
444 DeviceHandle,
445 &gEfiPciIoProtocolGuid,
446 (VOID **)&Device->PciIo,
447 This->DriverBindingHandle,
448 DeviceHandle,
449 EFI_OPEN_PROTOCOL_BY_DRIVER
450 );
451 if (EFI_ERROR (Status)) {
452 goto FreeVirtioPci;
453 }
454
455 //
456 // We must retain and ultimately restore the original PCI attributes of the
457 // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /
458 // 18.3.2 Start() and Stop().
459 //
460 // The third parameter ("Attributes", input) is ignored by the Get operation.
461 // The fourth parameter ("Result", output) is ignored by the Enable and Set
462 // operations.
463 //
464 // For virtio-pci we only need IO space access.
465 //
466 Status = Device->PciIo->Attributes (
467 Device->PciIo,
469 0,
470 &Device->OriginalPciAttributes
471 );
472 if (EFI_ERROR (Status)) {
473 goto ClosePciIo;
474 }
475
476 Status = Device->PciIo->Attributes (
477 Device->PciIo,
481 NULL
482 );
483 if (EFI_ERROR (Status)) {
484 goto ClosePciIo;
485 }
486
487 //
488 // PCI IO access granted, configure protocol instance
489 //
490
491 Status = VirtioPciInit (Device);
492 if (EFI_ERROR (Status)) {
493 goto RestorePciAttributes;
494 }
495
496 //
497 // Setup complete, attempt to export the driver instance's VirtioDevice
498 // interface.
499 //
500 Device->Signature = VIRTIO_PCI_DEVICE_SIGNATURE;
501 Status = gBS->InstallProtocolInterface (
502 &DeviceHandle,
503 &gVirtioDeviceProtocolGuid,
505 &Device->VirtioDevice
506 );
507 if (EFI_ERROR (Status)) {
508 goto UninitDev;
509 }
510
511 return EFI_SUCCESS;
512
513UninitDev:
514 VirtioPciUninit (Device);
515
516RestorePciAttributes:
517 Device->PciIo->Attributes (
518 Device->PciIo,
520 Device->OriginalPciAttributes,
521 NULL
522 );
523
524ClosePciIo:
525 gBS->CloseProtocol (
526 DeviceHandle,
527 &gEfiPciIoProtocolGuid,
528 This->DriverBindingHandle,
529 DeviceHandle
530 );
531
532FreeVirtioPci:
533 FreePool (Device);
534
535 return Status;
536}
537
563STATIC
565EFIAPI
568 IN EFI_HANDLE DeviceHandle,
569 IN UINTN NumberOfChildren,
570 IN EFI_HANDLE *ChildHandleBuffer
571 )
572{
573 EFI_STATUS Status;
574 VIRTIO_DEVICE_PROTOCOL *VirtioDevice;
575 VIRTIO_PCI_DEVICE *Device;
576
577 Status = gBS->OpenProtocol (
578 DeviceHandle, // candidate device
579 &gVirtioDeviceProtocolGuid, // retrieve the VirtIo iface
580 (VOID **)&VirtioDevice, // target pointer
581 This->DriverBindingHandle, // requestor driver identity
582 DeviceHandle, // requesting lookup for dev.
583 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added
584 );
585 if (EFI_ERROR (Status)) {
586 return Status;
587 }
588
589 Device = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);
590
591 //
592 // Handle Stop() requests for in-use driver instances gracefully.
593 //
594 Status = gBS->UninstallProtocolInterface (
595 DeviceHandle,
596 &gVirtioDeviceProtocolGuid,
597 &Device->VirtioDevice
598 );
599 if (EFI_ERROR (Status)) {
600 return Status;
601 }
602
603 VirtioPciUninit (Device);
604
605 Device->PciIo->Attributes (
606 Device->PciIo,
608 Device->OriginalPciAttributes,
609 NULL
610 );
611
612 Status = gBS->CloseProtocol (
613 DeviceHandle,
614 &gEfiPciIoProtocolGuid,
615 This->DriverBindingHandle,
616 DeviceHandle
617 );
618
619 FreePool (Device);
620
621 return Status;
622}
623
624//
625// The static object that groups the Supported() (ie. probe), Start() and
626// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
627// C, 10.1 EFI Driver Binding Protocol.
628//
629STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
633 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
634 NULL, // ImageHandle, to be overwritten by
635 // EfiLibInstallDriverBindingComponentName2() in VirtioPciEntryPoint()
636 NULL // DriverBindingHandle, ditto
637};
638
639//
640// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
641// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
642// in English, for display on standard console devices. This is recommended for
643// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
644// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
645//
646STATIC
647EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
648 { "eng;en", L"Virtio PCI Driver" },
649 { NULL, NULL }
650};
651
652STATIC
653EFI_COMPONENT_NAME_PROTOCOL gComponentName;
654
656EFIAPI
657VirtioPciGetDriverName (
659 IN CHAR8 *Language,
660 OUT CHAR16 **DriverName
661 )
662{
663 return LookupUnicodeString2 (
664 Language,
665 This->SupportedLanguages,
666 mDriverNameTable,
667 DriverName,
668 (BOOLEAN)(This == &gComponentName) // Iso639Language
669 );
670}
671
673EFIAPI
674VirtioPciGetDeviceName (
676 IN EFI_HANDLE DeviceHandle,
677 IN EFI_HANDLE ChildHandle,
678 IN CHAR8 *Language,
679 OUT CHAR16 **ControllerName
680 )
681{
682 return EFI_UNSUPPORTED;
683}
684
685STATIC
686EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
687 &VirtioPciGetDriverName,
688 &VirtioPciGetDeviceName,
689 "eng" // SupportedLanguages, ISO 639-2 language codes
690};
691
692STATIC
693EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
694 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioPciGetDriverName,
695 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioPciGetDeviceName,
696 "en" // SupportedLanguages, RFC 4646 language codes
697};
698
699//
700// Entry point of this driver.
701//
703EFIAPI
704VirtioPciDeviceEntryPoint (
705 IN EFI_HANDLE ImageHandle,
706 IN EFI_SYSTEM_TABLE *SystemTable
707 )
708{
710 ImageHandle,
711 SystemTable,
712 &gDriverBinding,
713 ImageHandle,
714 &gComponentName,
715 &gComponentName2
716 );
717}
UINT64 UINTN
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 STATIC
Definition: Base.h:264
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
EFI_PCI_IO_PROTOCOL_WIDTH
Definition: PciIo.h:28
@ 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
#define EFI_PCI_IO_ATTRIBUTE_IO
Enable the I/O decode bit in the PCI Config Header.
Definition: PciIo.h:57
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)
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
STATIC EFI_STATUS EFIAPI VirtioPciDeviceBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer)
STATIC VOID EFIAPI VirtioPciUninit(IN OUT VIRTIO_PCI_DEVICE *Device)
EFI_STATUS EFIAPI VirtioPciIoRead(IN VIRTIO_PCI_DEVICE *Dev, IN UINTN FieldOffset, IN UINTN FieldSize, IN UINTN BufferSize, OUT VOID *Buffer)
EFI_STATUS EFIAPI VirtioPciIoWrite(IN VIRTIO_PCI_DEVICE *Dev, IN UINTN FieldOffset, IN UINTN FieldSize, IN UINT64 Value)
STATIC EFI_STATUS EFIAPI VirtioPciInit(IN OUT VIRTIO_PCI_DEVICE *Device)
STATIC EFI_STATUS EFIAPI VirtioPciDeviceBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
STATIC EFI_STATUS EFIAPI VirtioPciDeviceBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE DeviceHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
EFI_STATUS EFIAPI VirtioPciDeviceWrite(IN VIRTIO_DEVICE_PROTOCOL *This, IN UINTN FieldOffset, IN UINTN FieldSize, IN UINT64 Value)
EFI_STATUS EFIAPI VirtioPciDeviceRead(IN VIRTIO_DEVICE_PROTOCOL *This, IN UINTN FieldOffset, IN UINTN FieldSize, IN UINTN BufferSize, OUT VOID *Buffer)
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