3 Implement the Driver Binding Protocol and the Component Name 2 Protocol for
4 the Virtio GPU hybrid driver.
6 Copyright (C) 2016, Red Hat, Inc.
8 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DevicePathLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/PrintLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiLib.h>
24 #include <Protocol/ComponentName2.h>
25 #include <Protocol/DevicePath.h>
26 #include <Protocol/DriverBinding.h>
27 #include <Protocol/PciIo.h>
29 #include "VirtioGpu.h"
32 // The device path node that describes the Video Output Device Attributes for
33 // the single head (UEFI child handle) that we support.
35 // The ACPI_DISPLAY_ADR() macro corresponds to Table B-2, section "B.4.2 _DOD"
36 // in the ACPI 3.0b spec, or more recently, to Table B-379, section "B.3.2
37 // _DOD" in the ACPI 6.0 spec.
39 STATIC CONST ACPI_ADR_DEVICE_PATH mAcpiAdr
= {
41 ACPI_DEVICE_PATH
, // Type
42 ACPI_ADR_DP
, // SubType
43 { sizeof mAcpiAdr
, 0 }, // Length
45 ACPI_DISPLAY_ADR ( // ADR
46 1, // DeviceIdScheme: use the ACPI
47 // bit-field definitions
52 ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL
, // Type
59 // Component Name 2 Protocol implementation.
61 STATIC CONST EFI_UNICODE_STRING_TABLE mDriverNameTable
[] = {
62 { "en", L
"Virtio GPU Driver" },
69 VirtioGpuGetDriverName (
70 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
72 OUT CHAR16
**DriverName
75 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
76 mDriverNameTable
, DriverName
, FALSE
/* Iso639Language */);
82 VirtioGpuGetControllerName (
83 IN EFI_COMPONENT_NAME2_PROTOCOL
*This
,
84 IN EFI_HANDLE ControllerHandle
,
85 IN EFI_HANDLE ChildHandle OPTIONAL
,
87 OUT CHAR16
**ControllerName
94 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
96 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
97 (VOID
**)&VgpuDev
, gImageHandle
, ControllerHandle
,
98 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
99 if (EFI_ERROR (Status
)) {
103 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
104 // keep its Virtio Device Protocol interface open BY_DRIVER.
106 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
, gImageHandle
,
107 &gVirtioDeviceProtocolGuid
));
109 if (ChildHandle
== NULL
) {
111 // The caller is querying the name of the VGPU_DEV controller.
113 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
114 VgpuDev
->BusName
, ControllerName
, FALSE
/* Iso639Language */);
118 // Otherwise, the caller is looking for the name of the GOP child controller.
119 // Check if it is asking about the GOP child controller that we manage. (The
120 // condition below covers the case when we haven't produced the GOP child
121 // controller yet, or we've destroyed it since.)
123 if (VgpuDev
->Child
== NULL
|| ChildHandle
!= VgpuDev
->Child
->GopHandle
) {
124 return EFI_UNSUPPORTED
;
127 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
128 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
130 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
, ChildHandle
,
131 &gVirtioDeviceProtocolGuid
));
133 return LookupUnicodeString2 (Language
, This
->SupportedLanguages
,
134 VgpuDev
->Child
->GopName
, ControllerName
,
135 FALSE
/* Iso639Language */);
138 STATIC CONST EFI_COMPONENT_NAME2_PROTOCOL mComponentName2
= {
139 VirtioGpuGetDriverName
,
140 VirtioGpuGetControllerName
,
141 "en" // SupportedLanguages (RFC 4646)
145 // Helper functions for the Driver Binding Protocol Implementation.
148 Format the VGPU_DEV controller name, to be looked up and returned by
149 VirtioGpuGetControllerName().
151 @param[in] ControllerHandle The handle that identifies the VGPU_DEV
154 @param[in] AgentHandle The handle of the agent that will attempt to
155 temporarily open the PciIo protocol. This is the
156 DriverBindingHandle member of the
157 EFI_DRIVER_BINDING_PROTOCOL whose Start()
158 function is calling this function.
160 @param[in] DevicePath The device path that is installed on
163 @param[out] ControllerName A dynamically allocated unicode string that
164 unconditionally says "Virtio GPU Device", with a
165 PCI Segment:Bus:Device.Function location
166 optionally appended. The latter part is only
167 produced if DevicePath contains at least one
168 PciIo node; in that case, the most specific such
169 node is used for retrieving the location info.
170 The caller is responsible for freeing
171 ControllerName after use.
173 @retval EFI_SUCCESS ControllerName has been formatted.
175 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for ControllerName.
180 IN EFI_HANDLE ControllerHandle
,
181 IN EFI_HANDLE AgentHandle
,
182 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
183 OUT CHAR16
**ControllerName
186 EFI_HANDLE PciIoHandle
;
187 EFI_PCI_IO_PROTOCOL
*PciIo
;
188 UINTN Segment
, Bus
, Device
, Function
;
189 STATIC CONST CHAR16 ControllerNameStem
[] = L
"Virtio GPU Device";
190 UINTN ControllerNameSize
;
192 if (EFI_ERROR (gBS
->LocateDevicePath (&gEfiPciIoProtocolGuid
, &DevicePath
,
194 EFI_ERROR (gBS
->OpenProtocol (PciIoHandle
, &gEfiPciIoProtocolGuid
,
195 (VOID
**)&PciIo
, AgentHandle
, ControllerHandle
,
196 EFI_OPEN_PROTOCOL_GET_PROTOCOL
)) ||
197 EFI_ERROR (PciIo
->GetLocation (PciIo
, &Segment
, &Bus
, &Device
,
200 // Failed to retrieve location info, return verbatim copy of static string.
202 *ControllerName
= AllocateCopyPool (sizeof ControllerNameStem
,
204 return (*ControllerName
== NULL
) ? EFI_OUT_OF_RESOURCES
: EFI_SUCCESS
;
207 // Location info available, format ControllerName dynamically.
209 ControllerNameSize
= sizeof ControllerNameStem
+ // includes L'\0'
210 sizeof (CHAR16
) * (1 + 4 + // Segment
215 *ControllerName
= AllocatePool (ControllerNameSize
);
216 if (*ControllerName
== NULL
) {
217 return EFI_OUT_OF_RESOURCES
;
220 UnicodeSPrintAsciiFormat (*ControllerName
, ControllerNameSize
,
221 "%s %04x:%02x:%02x.%x", ControllerNameStem
, (UINT32
)Segment
, (UINT32
)Bus
,
222 (UINT32
)Device
, (UINT32
)Function
);
227 Dynamically allocate and initialize the VGPU_GOP child object within an
228 otherwise configured parent VGPU_DEV object.
230 This function adds a BY_CHILD_CONTROLLER reference to ParentBusController's
231 VIRTIO_DEVICE_PROTOCOL interface.
233 @param[in,out] ParentBus The pre-initialized VGPU_DEV object that the
234 newly created VGPU_GOP object will be the
237 @param[in] ParentDevicePath The device path protocol instance that is
238 installed on ParentBusController.
240 @param[in] ParentBusController The UEFI controller handle on which the
241 ParentBus VGPU_DEV object and the
242 ParentDevicePath device path protocol are
245 @param[in] DriverBindingHandle The DriverBindingHandle member of
246 EFI_DRIVER_BINDING_PROTOCOL whose Start()
247 function is calling this function. It is
248 passed as AgentHandle to gBS->OpenProtocol()
249 when creating the BY_CHILD_CONTROLLER
252 @retval EFI_SUCCESS ParentBus->Child has been created and
253 populated, and ParentBus->Child->GopHandle now
254 references ParentBusController->VirtIo
257 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
259 @return Error codes from underlying functions.
264 IN OUT VGPU_DEV
*ParentBus
,
265 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
266 IN EFI_HANDLE ParentBusController
,
267 IN EFI_HANDLE DriverBindingHandle
272 CHAR16
*ParentBusName
;
273 STATIC CONST CHAR16 NameSuffix
[] = L
" Head #0";
279 VgpuGop
= AllocateZeroPool (sizeof *VgpuGop
);
280 if (VgpuGop
== NULL
) {
281 return EFI_OUT_OF_RESOURCES
;
284 VgpuGop
->Signature
= VGPU_GOP_SIG
;
285 VgpuGop
->ParentBus
= ParentBus
;
288 // Format a human-readable controller name for VGPU_GOP, and stash it for
289 // VirtioGpuGetControllerName() to look up. We simply append NameSuffix to
290 // ParentBus->BusName.
292 Status
= LookupUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
293 ParentBus
->BusName
, &ParentBusName
, FALSE
/* Iso639Language */);
294 ASSERT_EFI_ERROR (Status
);
295 NameSize
= StrSize (ParentBusName
) - sizeof (CHAR16
) + sizeof NameSuffix
;
296 Name
= AllocatePool (NameSize
);
298 Status
= EFI_OUT_OF_RESOURCES
;
301 UnicodeSPrintAsciiFormat (Name
, NameSize
, "%s%s", ParentBusName
, NameSuffix
);
302 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
303 &VgpuGop
->GopName
, Name
, FALSE
/* Iso639Language */);
305 if (EFI_ERROR (Status
)) {
310 // Create the child device path.
312 VgpuGop
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
,
314 if (VgpuGop
->GopDevicePath
== NULL
) {
315 Status
= EFI_OUT_OF_RESOURCES
;
316 goto FreeVgpuGopName
;
320 // Mask protocol notify callbacks until we're done.
322 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
325 // Create the child handle with the child device path.
327 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
328 &gEfiDevicePathProtocolGuid
, EFI_NATIVE_INTERFACE
,
329 VgpuGop
->GopDevicePath
);
330 if (EFI_ERROR (Status
)) {
335 // The child handle must present a reference to the parent handle's Virtio
336 // Device Protocol interface.
338 Status
= gBS
->OpenProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
339 &ParentVirtIo
, DriverBindingHandle
, VgpuGop
->GopHandle
,
340 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
341 if (EFI_ERROR (Status
)) {
342 goto UninstallDevicePath
;
344 ASSERT (ParentVirtIo
== ParentBus
->VirtIo
);
347 // Initialize our Graphics Output Protocol.
349 // Fill in the function members of VgpuGop->Gop from the template, then set
350 // up the rest of the GOP infrastructure by calling SetMode() right now.
352 CopyMem (&VgpuGop
->Gop
, &mGopTemplate
, sizeof mGopTemplate
);
353 Status
= VgpuGop
->Gop
.SetMode (&VgpuGop
->Gop
, 0);
354 if (EFI_ERROR (Status
)) {
355 goto CloseVirtIoByChild
;
359 // Install the Graphics Output Protocol on the child handle.
361 Status
= gBS
->InstallProtocolInterface (&VgpuGop
->GopHandle
,
362 &gEfiGraphicsOutputProtocolGuid
, EFI_NATIVE_INTERFACE
,
364 if (EFI_ERROR (Status
)) {
371 gBS
->RestoreTPL (OldTpl
);
372 ParentBus
->Child
= VgpuGop
;
376 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
379 gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
380 DriverBindingHandle
, VgpuGop
->GopHandle
);
383 gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
384 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
387 gBS
->RestoreTPL (OldTpl
);
388 FreePool (VgpuGop
->GopDevicePath
);
391 FreeUnicodeStringTable (VgpuGop
->GopName
);
400 Tear down and release the VGPU_GOP child object within the VGPU_DEV parent
403 This function removes the BY_CHILD_CONTROLLER reference from
404 ParentBusController's VIRTIO_DEVICE_PROTOCOL interface.
406 @param[in,out] ParentBus The VGPU_DEV object that the VGPU_GOP child
407 object will be removed from.
409 @param[in] ParentBusController The UEFI controller handle on which the
410 ParentBus VGPU_DEV object is installed.
412 @param[in] DriverBindingHandle The DriverBindingHandle member of
413 EFI_DRIVER_BINDING_PROTOCOL whose Stop()
414 function is calling this function. It is
415 passed as AgentHandle to gBS->CloseProtocol()
416 when removing the BY_CHILD_CONTROLLER
422 IN OUT VGPU_DEV
*ParentBus
,
423 IN EFI_HANDLE ParentBusController
,
424 IN EFI_HANDLE DriverBindingHandle
430 VgpuGop
= ParentBus
->Child
;
431 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
432 &gEfiGraphicsOutputProtocolGuid
, &VgpuGop
->Gop
);
433 ASSERT_EFI_ERROR (Status
);
436 // Uninitialize VgpuGop->Gop.
438 ReleaseGopResources (VgpuGop
, TRUE
/* DisableHead */);
440 Status
= gBS
->CloseProtocol (ParentBusController
, &gVirtioDeviceProtocolGuid
,
441 DriverBindingHandle
, VgpuGop
->GopHandle
);
442 ASSERT_EFI_ERROR (Status
);
444 Status
= gBS
->UninstallProtocolInterface (VgpuGop
->GopHandle
,
445 &gEfiDevicePathProtocolGuid
, VgpuGop
->GopDevicePath
);
446 ASSERT_EFI_ERROR (Status
);
448 FreePool (VgpuGop
->GopDevicePath
);
449 FreeUnicodeStringTable (VgpuGop
->GopName
);
452 ParentBus
->Child
= NULL
;
456 // Driver Binding Protocol Implementation.
461 VirtioGpuDriverBindingSupported (
462 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
463 IN EFI_HANDLE ControllerHandle
,
464 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
468 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
471 // - If RemainingDevicePath is NULL: the caller is interested in creating all
473 // - If RemainingDevicePath points to an end node: the caller is not
474 // interested in creating any child handle.
475 // - Otherwise, the caller would like to create the one child handle
476 // specified in RemainingDevicePath. In this case we have to see if the
477 // requested device path is supportable.
479 if (RemainingDevicePath
!= NULL
&&
480 !IsDevicePathEnd (RemainingDevicePath
) &&
481 (DevicePathNodeLength (RemainingDevicePath
) != sizeof mAcpiAdr
||
482 CompareMem (RemainingDevicePath
, &mAcpiAdr
, sizeof mAcpiAdr
) != 0)) {
483 return EFI_UNSUPPORTED
;
487 // Open the Virtio Device Protocol interface on the controller, BY_DRIVER.
489 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
490 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
491 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
492 if (EFI_ERROR (Status
)) {
494 // If this fails, then by default we cannot support ControllerHandle. There
495 // is one exception: we've already bound the device, have not produced any
496 // GOP child controller, and now the caller wants us to produce the child
497 // controller (either specifically or as part of "all children"). That's
500 if (Status
== EFI_ALREADY_STARTED
) {
504 Status2
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
505 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
506 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
507 ASSERT_EFI_ERROR (Status2
);
509 if (VgpuDev
->Child
== NULL
&&
510 (RemainingDevicePath
== NULL
||
511 !IsDevicePathEnd (RemainingDevicePath
))) {
512 Status
= EFI_SUCCESS
;
520 // First BY_DRIVER open; check the VirtIo revision and subsystem.
522 if (VirtIo
->Revision
< VIRTIO_SPEC_REVISION (1, 0, 0) ||
523 VirtIo
->SubSystemDeviceId
!= VIRTIO_SUBSYSTEM_GPU_DEVICE
) {
524 Status
= EFI_UNSUPPORTED
;
529 // We'll need the device path of the VirtIo device both for formatting
530 // VGPU_DEV.BusName and for populating VGPU_GOP.GopDevicePath.
532 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
533 NULL
, This
->DriverBindingHandle
, ControllerHandle
,
534 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
537 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
538 This
->DriverBindingHandle
, ControllerHandle
);
546 VirtioGpuDriverBindingStart (
547 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
548 IN EFI_HANDLE ControllerHandle
,
549 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
553 VIRTIO_DEVICE_PROTOCOL
*VirtIo
;
554 BOOLEAN VirtIoBoundJustNow
;
556 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
559 // Open the Virtio Device Protocol.
561 // The result of this operation, combined with the checks in
562 // VirtioGpuDriverBindingSupported(), uniquely tells us whether we are
563 // binding the VirtIo controller on this call (with or without creating child
564 // controllers), or else we're *only* creating child controllers.
566 Status
= gBS
->OpenProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
567 (VOID
**)&VirtIo
, This
->DriverBindingHandle
,
568 ControllerHandle
, EFI_OPEN_PROTOCOL_BY_DRIVER
);
569 if (EFI_ERROR (Status
)) {
571 // The assertions below are based on the success of
572 // VirtioGpuDriverBindingSupported(): we bound ControllerHandle earlier,
573 // without producing child handles, and now we're producing the GOP child
576 ASSERT (Status
== EFI_ALREADY_STARTED
);
578 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
579 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
580 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
581 ASSERT_EFI_ERROR (Status
);
583 ASSERT (VgpuDev
->Child
== NULL
);
585 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
587 VirtIoBoundJustNow
= FALSE
;
589 VirtIoBoundJustNow
= TRUE
;
592 // Allocate the private structure.
594 VgpuDev
= AllocateZeroPool (sizeof *VgpuDev
);
595 if (VgpuDev
== NULL
) {
596 Status
= EFI_OUT_OF_RESOURCES
;
599 VgpuDev
->VirtIo
= VirtIo
;
603 // Grab the VirtIo controller's device path. This is necessary regardless of
604 // VirtIoBoundJustNow.
606 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
607 (VOID
**)&DevicePath
, This
->DriverBindingHandle
,
608 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
609 if (EFI_ERROR (Status
)) {
614 // Create VGPU_DEV if we've bound the VirtIo controller right now (that is,
615 // if we aren't *only* creating child handles).
617 if (VirtIoBoundJustNow
) {
621 // Format a human-readable controller name for VGPU_DEV, and stash it for
622 // VirtioGpuGetControllerName() to look up.
624 Status
= FormatVgpuDevName (ControllerHandle
, This
->DriverBindingHandle
,
625 DevicePath
, &VgpuDevName
);
626 if (EFI_ERROR (Status
)) {
629 Status
= AddUnicodeString2 ("en", mComponentName2
.SupportedLanguages
,
630 &VgpuDev
->BusName
, VgpuDevName
, FALSE
/* Iso639Language */);
631 FreePool (VgpuDevName
);
632 if (EFI_ERROR (Status
)) {
636 Status
= VirtioGpuInit (VgpuDev
);
637 if (EFI_ERROR (Status
)) {
638 goto FreeVgpuDevBusName
;
641 Status
= gBS
->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES
, TPL_CALLBACK
,
642 VirtioGpuExitBoot
, VgpuDev
/* NotifyContext */,
644 if (EFI_ERROR (Status
)) {
649 // Install the VGPU_DEV "protocol interface" on ControllerHandle.
651 Status
= gBS
->InstallProtocolInterface (&ControllerHandle
,
652 &gEfiCallerIdGuid
, EFI_NATIVE_INTERFACE
, VgpuDev
);
653 if (EFI_ERROR (Status
)) {
657 if (RemainingDevicePath
!= NULL
&& IsDevicePathEnd (RemainingDevicePath
)) {
659 // No child handle should be produced; we're done.
661 DEBUG ((EFI_D_INFO
, "%a: bound VirtIo=%p without producing GOP\n",
662 __FUNCTION__
, (VOID
*)VgpuDev
->VirtIo
));
668 // Below we'll produce our single child handle: the caller requested it
669 // either specifically, or as part of all child handles.
671 ASSERT (VgpuDev
->Child
== NULL
);
673 RemainingDevicePath
== NULL
|| !IsDevicePathEnd (RemainingDevicePath
));
675 Status
= InitVgpuGop (VgpuDev
, DevicePath
, ControllerHandle
,
676 This
->DriverBindingHandle
);
677 if (EFI_ERROR (Status
)) {
678 goto UninstallVgpuDev
;
684 DEBUG ((EFI_D_INFO
, "%a: produced GOP %a VirtIo=%p\n", __FUNCTION__
,
685 VirtIoBoundJustNow
? "while binding" : "for pre-bound",
686 (VOID
*)VgpuDev
->VirtIo
));
690 if (VirtIoBoundJustNow
) {
691 gBS
->UninstallProtocolInterface (ControllerHandle
, &gEfiCallerIdGuid
,
696 if (VirtIoBoundJustNow
) {
697 gBS
->CloseEvent (VgpuDev
->ExitBoot
);
701 if (VirtIoBoundJustNow
) {
702 VirtioGpuUninit (VgpuDev
);
706 if (VirtIoBoundJustNow
) {
707 FreeUnicodeStringTable (VgpuDev
->BusName
);
711 if (VirtIoBoundJustNow
) {
716 if (VirtIoBoundJustNow
) {
717 gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
718 This
->DriverBindingHandle
, ControllerHandle
);
727 VirtioGpuDriverBindingStop (
728 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
729 IN EFI_HANDLE ControllerHandle
,
730 IN UINTN NumberOfChildren
,
731 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
738 // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
740 Status
= gBS
->OpenProtocol (ControllerHandle
, &gEfiCallerIdGuid
,
741 (VOID
**)&VgpuDev
, This
->DriverBindingHandle
,
742 ControllerHandle
, EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
743 if (EFI_ERROR (Status
)) {
747 // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
748 // keep its Virtio Device Protocol interface open BY_DRIVER.
750 ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle
,
751 This
->DriverBindingHandle
, &gVirtioDeviceProtocolGuid
));
753 switch (NumberOfChildren
) {
756 // The caller wants us to unbind the VirtIo controller.
758 if (VgpuDev
->Child
!= NULL
) {
760 // We still have the GOP child.
762 Status
= EFI_DEVICE_ERROR
;
766 DEBUG ((EFI_D_INFO
, "%a: unbinding GOP-less VirtIo=%p\n", __FUNCTION__
,
767 (VOID
*)VgpuDev
->VirtIo
));
769 Status
= gBS
->UninstallProtocolInterface (ControllerHandle
,
770 &gEfiCallerIdGuid
, VgpuDev
);
771 ASSERT_EFI_ERROR (Status
);
773 Status
= gBS
->CloseEvent (VgpuDev
->ExitBoot
);
774 ASSERT_EFI_ERROR (Status
);
776 VirtioGpuUninit (VgpuDev
);
777 FreeUnicodeStringTable (VgpuDev
->BusName
);
780 Status
= gBS
->CloseProtocol (ControllerHandle
, &gVirtioDeviceProtocolGuid
,
781 This
->DriverBindingHandle
, ControllerHandle
);
782 ASSERT_EFI_ERROR (Status
);
787 // The caller wants us to destroy our child GOP controller.
789 if (VgpuDev
->Child
== NULL
||
790 ChildHandleBuffer
[0] != VgpuDev
->Child
->GopHandle
) {
792 // We have no child controller at the moment, or it differs from the one
793 // the caller wants us to destroy. I.e., we don't own the child
794 // controller passed in.
796 Status
= EFI_DEVICE_ERROR
;
800 // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
801 // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
803 ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle
,
804 VgpuDev
->Child
->GopHandle
,
805 &gVirtioDeviceProtocolGuid
));
807 DEBUG ((EFI_D_INFO
, "%a: destroying GOP under VirtIo=%p\n", __FUNCTION__
,
808 (VOID
*)VgpuDev
->VirtIo
));
809 UninitVgpuGop (VgpuDev
, ControllerHandle
, This
->DriverBindingHandle
);
814 // Impossible, we never produced more than one child.
816 Status
= EFI_DEVICE_ERROR
;
822 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
823 VirtioGpuDriverBindingSupported
,
824 VirtioGpuDriverBindingStart
,
825 VirtioGpuDriverBindingStop
,
827 NULL
, // ImageHandle, overwritten in entry point
828 NULL
// DriverBindingHandle, ditto
832 // Entry point of the driver.
836 VirtioGpuEntryPoint (
837 IN EFI_HANDLE ImageHandle
,
838 IN EFI_SYSTEM_TABLE
*SystemTable
841 return EfiLibInstallDriverBindingComponentName2 (ImageHandle
, SystemTable
,
842 &mDriverBinding
, ImageHandle
, NULL
/* ComponentName */,