1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057 |
- /** @file
- Implement the Driver Binding Protocol and the Component Name 2 Protocol for
- the Virtio GPU hybrid driver.
- Copyright (C) 2016, Red Hat, Inc.
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Library/DevicePathLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/PrintLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/UefiLib.h>
- #include <Protocol/ComponentName2.h>
- #include <Protocol/DevicePath.h>
- #include <Protocol/DriverBinding.h>
- #include <Protocol/PciIo.h>
- #include "VirtioGpu.h"
- //
- // The device path node that describes the Video Output Device Attributes for
- // the single head (UEFI child handle) that we support.
- //
- // The ACPI_DISPLAY_ADR() macro corresponds to Table B-2, section "B.4.2 _DOD"
- // in the ACPI 3.0b spec, or more recently, to Table B-379, section "B.3.2
- // _DOD" in the ACPI 6.0 spec.
- //
- STATIC CONST ACPI_ADR_DEVICE_PATH mAcpiAdr = {
- { // Header
- ACPI_DEVICE_PATH, // Type
- ACPI_ADR_DP, // SubType
- { sizeof mAcpiAdr, 0 }, // Length
- },
- ACPI_DISPLAY_ADR (
- // ADR
- 1, // DeviceIdScheme: use the ACPI
- // bit-field definitions
- 0, // HeadId
- 0, // NonVgaOutput
- 1, // BiosCanDetect
- 0, // VendorInfo
- ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, // Type
- 0, // Port
- 0 // Index
- )
- };
- //
- // Component Name 2 Protocol implementation.
- //
- STATIC CONST EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
- { "en", L"Virtio GPU Driver" },
- { NULL, NULL }
- };
- STATIC
- EFI_STATUS
- EFIAPI
- VirtioGpuGetDriverName (
- IN EFI_COMPONENT_NAME2_PROTOCOL *This,
- IN CHAR8 *Language,
- OUT CHAR16 **DriverName
- )
- {
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- mDriverNameTable,
- DriverName,
- FALSE /* Iso639Language */
- );
- }
- STATIC
- EFI_STATUS
- EFIAPI
- VirtioGpuGetControllerName (
- IN EFI_COMPONENT_NAME2_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE ChildHandle OPTIONAL,
- IN CHAR8 *Language,
- OUT CHAR16 **ControllerName
- )
- {
- EFI_STATUS Status;
- VGPU_DEV *VgpuDev;
- //
- // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiCallerIdGuid,
- (VOID **)&VgpuDev,
- gImageHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
- // keep its Virtio Device Protocol interface open BY_DRIVER.
- //
- ASSERT_EFI_ERROR (
- EfiTestManagedDevice (
- ControllerHandle,
- gImageHandle,
- &gVirtioDeviceProtocolGuid
- )
- );
- if (ChildHandle == NULL) {
- //
- // The caller is querying the name of the VGPU_DEV controller.
- //
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- VgpuDev->BusName,
- ControllerName,
- FALSE /* Iso639Language */
- );
- }
- //
- // Otherwise, the caller is looking for the name of the GOP child controller.
- // Check if it is asking about the GOP child controller that we manage. (The
- // condition below covers the case when we haven't produced the GOP child
- // controller yet, or we've destroyed it since.)
- //
- if ((VgpuDev->Child == NULL) || (ChildHandle != VgpuDev->Child->GopHandle)) {
- return EFI_UNSUPPORTED;
- }
- //
- // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
- // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
- //
- ASSERT_EFI_ERROR (
- EfiTestChildHandle (
- ControllerHandle,
- ChildHandle,
- &gVirtioDeviceProtocolGuid
- )
- );
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- VgpuDev->Child->GopName,
- ControllerName,
- FALSE /* Iso639Language */
- );
- }
- STATIC CONST EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
- VirtioGpuGetDriverName,
- VirtioGpuGetControllerName,
- "en" // SupportedLanguages (RFC 4646)
- };
- //
- // Helper functions for the Driver Binding Protocol Implementation.
- //
- /**
- Format the VGPU_DEV controller name, to be looked up and returned by
- VirtioGpuGetControllerName().
- @param[in] ControllerHandle The handle that identifies the VGPU_DEV
- controller.
- @param[in] AgentHandle The handle of the agent that will attempt to
- temporarily open the PciIo protocol. This is the
- DriverBindingHandle member of the
- EFI_DRIVER_BINDING_PROTOCOL whose Start()
- function is calling this function.
- @param[in] DevicePath The device path that is installed on
- ControllerHandle.
- @param[out] ControllerName A dynamically allocated unicode string that
- unconditionally says "Virtio GPU Device", with a
- PCI Segment:Bus:Device.Function location
- optionally appended. The latter part is only
- produced if DevicePath contains at least one
- PciIo node; in that case, the most specific such
- node is used for retrieving the location info.
- The caller is responsible for freeing
- ControllerName after use.
- @retval EFI_SUCCESS ControllerName has been formatted.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for ControllerName.
- **/
- STATIC
- EFI_STATUS
- FormatVgpuDevName (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE AgentHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT CHAR16 **ControllerName
- )
- {
- EFI_HANDLE PciIoHandle;
- EFI_PCI_IO_PROTOCOL *PciIo;
- UINTN Segment, Bus, Device, Function;
- STATIC CONST CHAR16 ControllerNameStem[] = L"Virtio GPU Device";
- UINTN ControllerNameSize;
- if (EFI_ERROR (
- gBS->LocateDevicePath (
- &gEfiPciIoProtocolGuid,
- &DevicePath,
- &PciIoHandle
- )
- ) ||
- EFI_ERROR (
- gBS->OpenProtocol (
- PciIoHandle,
- &gEfiPciIoProtocolGuid,
- (VOID **)&PciIo,
- AgentHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- )
- ) ||
- EFI_ERROR (
- PciIo->GetLocation (
- PciIo,
- &Segment,
- &Bus,
- &Device,
- &Function
- )
- ))
- {
- //
- // Failed to retrieve location info, return verbatim copy of static string.
- //
- *ControllerName = AllocateCopyPool (
- sizeof ControllerNameStem,
- ControllerNameStem
- );
- return (*ControllerName == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS;
- }
- //
- // Location info available, format ControllerName dynamically.
- //
- ControllerNameSize = sizeof ControllerNameStem + // includes L'\0'
- sizeof (CHAR16) * (1 + 4 + // Segment
- 1 + 2 + // Bus
- 1 + 2 + // Device
- 1 + 1 // Function
- );
- *ControllerName = AllocatePool (ControllerNameSize);
- if (*ControllerName == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- UnicodeSPrintAsciiFormat (
- *ControllerName,
- ControllerNameSize,
- "%s %04x:%02x:%02x.%x",
- ControllerNameStem,
- (UINT32)Segment,
- (UINT32)Bus,
- (UINT32)Device,
- (UINT32)Function
- );
- return EFI_SUCCESS;
- }
- /**
- Dynamically allocate and initialize the VGPU_GOP child object within an
- otherwise configured parent VGPU_DEV object.
- This function adds a BY_CHILD_CONTROLLER reference to ParentBusController's
- VIRTIO_DEVICE_PROTOCOL interface.
- @param[in,out] ParentBus The pre-initialized VGPU_DEV object that the
- newly created VGPU_GOP object will be the
- child of.
- @param[in] ParentDevicePath The device path protocol instance that is
- installed on ParentBusController.
- @param[in] ParentBusController The UEFI controller handle on which the
- ParentBus VGPU_DEV object and the
- ParentDevicePath device path protocol are
- installed.
- @param[in] DriverBindingHandle The DriverBindingHandle member of
- EFI_DRIVER_BINDING_PROTOCOL whose Start()
- function is calling this function. It is
- passed as AgentHandle to gBS->OpenProtocol()
- when creating the BY_CHILD_CONTROLLER
- reference.
- @retval EFI_SUCCESS ParentBus->Child has been created and
- populated, and ParentBus->Child->GopHandle now
- references ParentBusController->VirtIo
- BY_CHILD_CONTROLLER.
- @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
- @return Error codes from underlying functions.
- **/
- STATIC
- EFI_STATUS
- InitVgpuGop (
- IN OUT VGPU_DEV *ParentBus,
- IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
- IN EFI_HANDLE ParentBusController,
- IN EFI_HANDLE DriverBindingHandle
- )
- {
- VGPU_GOP *VgpuGop;
- EFI_STATUS Status;
- CHAR16 *ParentBusName;
- STATIC CONST CHAR16 NameSuffix[] = L" Head #0";
- UINTN NameSize;
- CHAR16 *Name;
- EFI_TPL OldTpl;
- VOID *ParentVirtIo;
- VgpuGop = AllocateZeroPool (sizeof *VgpuGop);
- if (VgpuGop == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- VgpuGop->Signature = VGPU_GOP_SIG;
- VgpuGop->ParentBus = ParentBus;
- //
- // Format a human-readable controller name for VGPU_GOP, and stash it for
- // VirtioGpuGetControllerName() to look up. We simply append NameSuffix to
- // ParentBus->BusName.
- //
- Status = LookupUnicodeString2 (
- "en",
- mComponentName2.SupportedLanguages,
- ParentBus->BusName,
- &ParentBusName,
- FALSE /* Iso639Language */
- );
- ASSERT_EFI_ERROR (Status);
- NameSize = StrSize (ParentBusName) - sizeof (CHAR16) + sizeof NameSuffix;
- Name = AllocatePool (NameSize);
- if (Name == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto FreeVgpuGop;
- }
- UnicodeSPrintAsciiFormat (Name, NameSize, "%s%s", ParentBusName, NameSuffix);
- Status = AddUnicodeString2 (
- "en",
- mComponentName2.SupportedLanguages,
- &VgpuGop->GopName,
- Name,
- FALSE /* Iso639Language */
- );
- FreePool (Name);
- if (EFI_ERROR (Status)) {
- goto FreeVgpuGop;
- }
- //
- // Create the child device path.
- //
- VgpuGop->GopDevicePath = AppendDevicePathNode (
- ParentDevicePath,
- &mAcpiAdr.Header
- );
- if (VgpuGop->GopDevicePath == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto FreeVgpuGopName;
- }
- //
- // Mask protocol notify callbacks until we're done.
- //
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- //
- // Create the child handle with the child device path.
- //
- Status = gBS->InstallProtocolInterface (
- &VgpuGop->GopHandle,
- &gEfiDevicePathProtocolGuid,
- EFI_NATIVE_INTERFACE,
- VgpuGop->GopDevicePath
- );
- if (EFI_ERROR (Status)) {
- goto FreeDevicePath;
- }
- //
- // The child handle must present a reference to the parent handle's Virtio
- // Device Protocol interface.
- //
- Status = gBS->OpenProtocol (
- ParentBusController,
- &gVirtioDeviceProtocolGuid,
- &ParentVirtIo,
- DriverBindingHandle,
- VgpuGop->GopHandle,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- if (EFI_ERROR (Status)) {
- goto UninstallDevicePath;
- }
- ASSERT (ParentVirtIo == ParentBus->VirtIo);
- //
- // Initialize our Graphics Output Protocol.
- //
- // Fill in the function members of VgpuGop->Gop from the template, then set
- // up the rest of the GOP infrastructure by calling SetMode() right now.
- //
- CopyMem (&VgpuGop->Gop, &mGopTemplate, sizeof mGopTemplate);
- Status = VgpuGop->Gop.SetMode (&VgpuGop->Gop, 0);
- if (EFI_ERROR (Status)) {
- goto CloseVirtIoByChild;
- }
- //
- // Install the Graphics Output Protocol on the child handle.
- //
- Status = gBS->InstallProtocolInterface (
- &VgpuGop->GopHandle,
- &gEfiGraphicsOutputProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &VgpuGop->Gop
- );
- if (EFI_ERROR (Status)) {
- goto UninitGop;
- }
- //
- // We're done.
- //
- gBS->RestoreTPL (OldTpl);
- ParentBus->Child = VgpuGop;
- return EFI_SUCCESS;
- UninitGop:
- ReleaseGopResources (VgpuGop, TRUE /* DisableHead */);
- CloseVirtIoByChild:
- gBS->CloseProtocol (
- ParentBusController,
- &gVirtioDeviceProtocolGuid,
- DriverBindingHandle,
- VgpuGop->GopHandle
- );
- UninstallDevicePath:
- gBS->UninstallProtocolInterface (
- VgpuGop->GopHandle,
- &gEfiDevicePathProtocolGuid,
- VgpuGop->GopDevicePath
- );
- FreeDevicePath:
- gBS->RestoreTPL (OldTpl);
- FreePool (VgpuGop->GopDevicePath);
- FreeVgpuGopName:
- FreeUnicodeStringTable (VgpuGop->GopName);
- FreeVgpuGop:
- FreePool (VgpuGop);
- return Status;
- }
- /**
- Tear down and release the VGPU_GOP child object within the VGPU_DEV parent
- object.
- This function removes the BY_CHILD_CONTROLLER reference from
- ParentBusController's VIRTIO_DEVICE_PROTOCOL interface.
- @param[in,out] ParentBus The VGPU_DEV object that the VGPU_GOP child
- object will be removed from.
- @param[in] ParentBusController The UEFI controller handle on which the
- ParentBus VGPU_DEV object is installed.
- @param[in] DriverBindingHandle The DriverBindingHandle member of
- EFI_DRIVER_BINDING_PROTOCOL whose Stop()
- function is calling this function. It is
- passed as AgentHandle to gBS->CloseProtocol()
- when removing the BY_CHILD_CONTROLLER
- reference.
- **/
- STATIC
- VOID
- UninitVgpuGop (
- IN OUT VGPU_DEV *ParentBus,
- IN EFI_HANDLE ParentBusController,
- IN EFI_HANDLE DriverBindingHandle
- )
- {
- VGPU_GOP *VgpuGop;
- EFI_STATUS Status;
- VgpuGop = ParentBus->Child;
- Status = gBS->UninstallProtocolInterface (
- VgpuGop->GopHandle,
- &gEfiGraphicsOutputProtocolGuid,
- &VgpuGop->Gop
- );
- ASSERT_EFI_ERROR (Status);
- //
- // Uninitialize VgpuGop->Gop.
- //
- ReleaseGopResources (VgpuGop, TRUE /* DisableHead */);
- Status = gBS->CloseProtocol (
- ParentBusController,
- &gVirtioDeviceProtocolGuid,
- DriverBindingHandle,
- VgpuGop->GopHandle
- );
- ASSERT_EFI_ERROR (Status);
- Status = gBS->UninstallProtocolInterface (
- VgpuGop->GopHandle,
- &gEfiDevicePathProtocolGuid,
- VgpuGop->GopDevicePath
- );
- ASSERT_EFI_ERROR (Status);
- FreePool (VgpuGop->GopDevicePath);
- FreeUnicodeStringTable (VgpuGop->GopName);
- FreePool (VgpuGop);
- ParentBus->Child = NULL;
- }
- //
- // Driver Binding Protocol Implementation.
- //
- STATIC
- EFI_STATUS
- EFIAPI
- VirtioGpuDriverBindingSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- VIRTIO_DEVICE_PROTOCOL *VirtIo;
- //
- // - If RemainingDevicePath is NULL: the caller is interested in creating all
- // child handles.
- // - If RemainingDevicePath points to an end node: the caller is not
- // interested in creating any child handle.
- // - Otherwise, the caller would like to create the one child handle
- // specified in RemainingDevicePath. In this case we have to see if the
- // requested device path is supportable.
- //
- if ((RemainingDevicePath != NULL) &&
- !IsDevicePathEnd (RemainingDevicePath) &&
- ((DevicePathNodeLength (RemainingDevicePath) != sizeof mAcpiAdr) ||
- (CompareMem (RemainingDevicePath, &mAcpiAdr, sizeof mAcpiAdr) != 0)))
- {
- return EFI_UNSUPPORTED;
- }
- //
- // Open the Virtio Device Protocol interface on the controller, BY_DRIVER.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gVirtioDeviceProtocolGuid,
- (VOID **)&VirtIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- //
- // If this fails, then by default we cannot support ControllerHandle. There
- // is one exception: we've already bound the device, have not produced any
- // GOP child controller, and now the caller wants us to produce the child
- // controller (either specifically or as part of "all children"). That's
- // allowed.
- //
- if (Status == EFI_ALREADY_STARTED) {
- EFI_STATUS Status2;
- VGPU_DEV *VgpuDev;
- Status2 = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiCallerIdGuid,
- (VOID **)&VgpuDev,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- ASSERT_EFI_ERROR (Status2);
- if ((VgpuDev->Child == NULL) &&
- ((RemainingDevicePath == NULL) ||
- !IsDevicePathEnd (RemainingDevicePath)))
- {
- Status = EFI_SUCCESS;
- }
- }
- return Status;
- }
- //
- // First BY_DRIVER open; check the VirtIo revision and subsystem.
- //
- if ((VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ||
- (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_GPU_DEVICE))
- {
- Status = EFI_UNSUPPORTED;
- goto CloseVirtIo;
- }
- //
- // We'll need the device path of the VirtIo device both for formatting
- // VGPU_DEV.BusName and for populating VGPU_GOP.GopDevicePath.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- NULL,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL
- );
- CloseVirtIo:
- gBS->CloseProtocol (
- ControllerHandle,
- &gVirtioDeviceProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- return Status;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- VirtioGpuDriverBindingStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- VIRTIO_DEVICE_PROTOCOL *VirtIo;
- BOOLEAN VirtIoBoundJustNow;
- VGPU_DEV *VgpuDev;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- //
- // Open the Virtio Device Protocol.
- //
- // The result of this operation, combined with the checks in
- // VirtioGpuDriverBindingSupported(), uniquely tells us whether we are
- // binding the VirtIo controller on this call (with or without creating child
- // controllers), or else we're *only* creating child controllers.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gVirtioDeviceProtocolGuid,
- (VOID **)&VirtIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- //
- // The assertions below are based on the success of
- // VirtioGpuDriverBindingSupported(): we bound ControllerHandle earlier,
- // without producing child handles, and now we're producing the GOP child
- // handle only.
- //
- ASSERT (Status == EFI_ALREADY_STARTED);
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiCallerIdGuid,
- (VOID **)&VgpuDev,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- ASSERT_EFI_ERROR (Status);
- ASSERT (VgpuDev->Child == NULL);
- ASSERT (
- RemainingDevicePath == NULL || !IsDevicePathEnd (RemainingDevicePath)
- );
- VirtIoBoundJustNow = FALSE;
- } else {
- VirtIoBoundJustNow = TRUE;
- //
- // Allocate the private structure.
- //
- VgpuDev = AllocateZeroPool (sizeof *VgpuDev);
- if (VgpuDev == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CloseVirtIo;
- }
- VgpuDev->VirtIo = VirtIo;
- }
- //
- // Grab the VirtIo controller's device path. This is necessary regardless of
- // VirtIoBoundJustNow.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&DevicePath,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- goto FreeVgpuDev;
- }
- //
- // Create VGPU_DEV if we've bound the VirtIo controller right now (that is,
- // if we aren't *only* creating child handles).
- //
- if (VirtIoBoundJustNow) {
- CHAR16 *VgpuDevName;
- //
- // Format a human-readable controller name for VGPU_DEV, and stash it for
- // VirtioGpuGetControllerName() to look up.
- //
- Status = FormatVgpuDevName (
- ControllerHandle,
- This->DriverBindingHandle,
- DevicePath,
- &VgpuDevName
- );
- if (EFI_ERROR (Status)) {
- goto FreeVgpuDev;
- }
- Status = AddUnicodeString2 (
- "en",
- mComponentName2.SupportedLanguages,
- &VgpuDev->BusName,
- VgpuDevName,
- FALSE /* Iso639Language */
- );
- FreePool (VgpuDevName);
- if (EFI_ERROR (Status)) {
- goto FreeVgpuDev;
- }
- Status = VirtioGpuInit (VgpuDev);
- if (EFI_ERROR (Status)) {
- goto FreeVgpuDevBusName;
- }
- Status = gBS->CreateEvent (
- EVT_SIGNAL_EXIT_BOOT_SERVICES,
- TPL_CALLBACK,
- VirtioGpuExitBoot,
- VgpuDev /* NotifyContext */,
- &VgpuDev->ExitBoot
- );
- if (EFI_ERROR (Status)) {
- goto UninitGpu;
- }
- //
- // Install the VGPU_DEV "protocol interface" on ControllerHandle.
- //
- Status = gBS->InstallProtocolInterface (
- &ControllerHandle,
- &gEfiCallerIdGuid,
- EFI_NATIVE_INTERFACE,
- VgpuDev
- );
- if (EFI_ERROR (Status)) {
- goto CloseExitBoot;
- }
- if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
- //
- // No child handle should be produced; we're done.
- //
- DEBUG ((
- DEBUG_INFO,
- "%a: bound VirtIo=%p without producing GOP\n",
- __FUNCTION__,
- (VOID *)VgpuDev->VirtIo
- ));
- return EFI_SUCCESS;
- }
- }
- //
- // Below we'll produce our single child handle: the caller requested it
- // either specifically, or as part of all child handles.
- //
- ASSERT (VgpuDev->Child == NULL);
- ASSERT (
- RemainingDevicePath == NULL || !IsDevicePathEnd (RemainingDevicePath)
- );
- Status = InitVgpuGop (
- VgpuDev,
- DevicePath,
- ControllerHandle,
- This->DriverBindingHandle
- );
- if (EFI_ERROR (Status)) {
- goto UninstallVgpuDev;
- }
- //
- // We're done.
- //
- DEBUG ((
- DEBUG_INFO,
- "%a: produced GOP %a VirtIo=%p\n",
- __FUNCTION__,
- VirtIoBoundJustNow ? "while binding" : "for pre-bound",
- (VOID *)VgpuDev->VirtIo
- ));
- return EFI_SUCCESS;
- UninstallVgpuDev:
- if (VirtIoBoundJustNow) {
- gBS->UninstallProtocolInterface (
- ControllerHandle,
- &gEfiCallerIdGuid,
- VgpuDev
- );
- }
- CloseExitBoot:
- if (VirtIoBoundJustNow) {
- gBS->CloseEvent (VgpuDev->ExitBoot);
- }
- UninitGpu:
- if (VirtIoBoundJustNow) {
- VirtioGpuUninit (VgpuDev);
- }
- FreeVgpuDevBusName:
- if (VirtIoBoundJustNow) {
- FreeUnicodeStringTable (VgpuDev->BusName);
- }
- FreeVgpuDev:
- if (VirtIoBoundJustNow) {
- FreePool (VgpuDev);
- }
- CloseVirtIo:
- if (VirtIoBoundJustNow) {
- gBS->CloseProtocol (
- ControllerHandle,
- &gVirtioDeviceProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- }
- return Status;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- VirtioGpuDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
- )
- {
- EFI_STATUS Status;
- VGPU_DEV *VgpuDev;
- //
- // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
- //
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiCallerIdGuid,
- (VOID **)&VgpuDev,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
- // keep its Virtio Device Protocol interface open BY_DRIVER.
- //
- ASSERT_EFI_ERROR (
- EfiTestManagedDevice (
- ControllerHandle,
- This->DriverBindingHandle,
- &gVirtioDeviceProtocolGuid
- )
- );
- switch (NumberOfChildren) {
- case 0:
- //
- // The caller wants us to unbind the VirtIo controller.
- //
- if (VgpuDev->Child != NULL) {
- //
- // We still have the GOP child.
- //
- Status = EFI_DEVICE_ERROR;
- break;
- }
- DEBUG ((
- DEBUG_INFO,
- "%a: unbinding GOP-less VirtIo=%p\n",
- __FUNCTION__,
- (VOID *)VgpuDev->VirtIo
- ));
- Status = gBS->UninstallProtocolInterface (
- ControllerHandle,
- &gEfiCallerIdGuid,
- VgpuDev
- );
- ASSERT_EFI_ERROR (Status);
- Status = gBS->CloseEvent (VgpuDev->ExitBoot);
- ASSERT_EFI_ERROR (Status);
- VirtioGpuUninit (VgpuDev);
- FreeUnicodeStringTable (VgpuDev->BusName);
- FreePool (VgpuDev);
- Status = gBS->CloseProtocol (
- ControllerHandle,
- &gVirtioDeviceProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- ASSERT_EFI_ERROR (Status);
- break;
- case 1:
- //
- // The caller wants us to destroy our child GOP controller.
- //
- if ((VgpuDev->Child == NULL) ||
- (ChildHandleBuffer[0] != VgpuDev->Child->GopHandle))
- {
- //
- // We have no child controller at the moment, or it differs from the one
- // the caller wants us to destroy. I.e., we don't own the child
- // controller passed in.
- //
- Status = EFI_DEVICE_ERROR;
- break;
- }
- //
- // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
- // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
- //
- ASSERT_EFI_ERROR (
- EfiTestChildHandle (
- ControllerHandle,
- VgpuDev->Child->GopHandle,
- &gVirtioDeviceProtocolGuid
- )
- );
- DEBUG ((
- DEBUG_INFO,
- "%a: destroying GOP under VirtIo=%p\n",
- __FUNCTION__,
- (VOID *)VgpuDev->VirtIo
- ));
- UninitVgpuGop (VgpuDev, ControllerHandle, This->DriverBindingHandle);
- break;
- default:
- //
- // Impossible, we never produced more than one child.
- //
- Status = EFI_DEVICE_ERROR;
- break;
- }
- return Status;
- }
- STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
- VirtioGpuDriverBindingSupported,
- VirtioGpuDriverBindingStart,
- VirtioGpuDriverBindingStop,
- 0x10, // Version
- NULL, // ImageHandle, overwritten in entry point
- NULL // DriverBindingHandle, ditto
- };
- //
- // Entry point of the driver.
- //
- EFI_STATUS
- EFIAPI
- VirtioGpuEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- return EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &mDriverBinding,
- ImageHandle,
- NULL /* ComponentName */,
- &mComponentName2
- );
- }
|