1 /** @file
2 
3   Implement the Driver Binding Protocol and the Component Name 2 Protocol for
4   the Virtio GPU hybrid driver.
5 
6   Copyright (C) 2016, Red Hat, Inc.
7 
8   SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10 **/
11 
12 #include <Library/DevicePathLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/PrintLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/UefiLib.h>
17 #include <Protocol/ComponentName2.h>
18 #include <Protocol/DevicePath.h>
19 #include <Protocol/DriverBinding.h>
20 #include <Protocol/PciIo.h>
21 
22 #include "VirtioGpu.h"
23 
24 //
25 // The device path node that describes the Video Output Device Attributes for
26 // the single head (UEFI child handle) that we support.
27 //
28 // The ACPI_DISPLAY_ADR() macro corresponds to Table B-2, section "B.4.2 _DOD"
29 // in the ACPI 3.0b spec, or more recently, to Table B-379, section "B.3.2
30 // _DOD" in the ACPI 6.0 spec.
31 //
32 STATIC CONST ACPI_ADR_DEVICE_PATH mAcpiAdr = {
33   {                                         // Header
34     ACPI_DEVICE_PATH,                       //   Type
35     ACPI_ADR_DP,                            //   SubType
36     { sizeof mAcpiAdr, 0 },                 //   Length
37   },
38   ACPI_DISPLAY_ADR (                        // ADR
39     1,                                      //   DeviceIdScheme: use the ACPI
40                                             //     bit-field definitions
41     0,                                      //   HeadId
42     0,                                      //   NonVgaOutput
43     1,                                      //   BiosCanDetect
44     0,                                      //   VendorInfo
45     ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, //   Type
46     0,                                      //   Port
47     0                                       //   Index
48     )
49 };
50 
51 //
52 // Component Name 2 Protocol implementation.
53 //
54 STATIC CONST EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
55   { "en", L"Virtio GPU Driver" },
56   { NULL, NULL                 }
57 };
58 
59 STATIC
60 EFI_STATUS
61 EFIAPI
VirtioGpuGetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL * This,IN CHAR8 * Language,OUT CHAR16 ** DriverName)62 VirtioGpuGetDriverName (
63   IN  EFI_COMPONENT_NAME2_PROTOCOL *This,
64   IN  CHAR8                        *Language,
65   OUT CHAR16                       **DriverName
66   )
67 {
68   return LookupUnicodeString2 (Language, This->SupportedLanguages,
69            mDriverNameTable, DriverName, FALSE /* Iso639Language */);
70 }
71 
72 STATIC
73 EFI_STATUS
74 EFIAPI
VirtioGpuGetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE ChildHandle OPTIONAL,IN CHAR8 * Language,OUT CHAR16 ** ControllerName)75 VirtioGpuGetControllerName (
76   IN  EFI_COMPONENT_NAME2_PROTOCOL *This,
77   IN  EFI_HANDLE                   ControllerHandle,
78   IN  EFI_HANDLE                   ChildHandle       OPTIONAL,
79   IN  CHAR8                        *Language,
80   OUT CHAR16                       **ControllerName
81   )
82 {
83   EFI_STATUS Status;
84   VGPU_DEV   *VgpuDev;
85 
86   //
87   // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
88   //
89   Status = gBS->OpenProtocol (ControllerHandle, &gEfiCallerIdGuid,
90                   (VOID **)&VgpuDev, gImageHandle, ControllerHandle,
91                   EFI_OPEN_PROTOCOL_GET_PROTOCOL);
92   if (EFI_ERROR (Status)) {
93     return Status;
94   }
95   //
96   // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
97   // keep its Virtio Device Protocol interface open BY_DRIVER.
98   //
99   ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle, gImageHandle,
100                       &gVirtioDeviceProtocolGuid));
101 
102   if (ChildHandle == NULL) {
103     //
104     // The caller is querying the name of the VGPU_DEV controller.
105     //
106     return LookupUnicodeString2 (Language, This->SupportedLanguages,
107              VgpuDev->BusName, ControllerName, FALSE /* Iso639Language */);
108   }
109 
110   //
111   // Otherwise, the caller is looking for the name of the GOP child controller.
112   // Check if it is asking about the GOP child controller that we manage. (The
113   // condition below covers the case when we haven't produced the GOP child
114   // controller yet, or we've destroyed it since.)
115   //
116   if (VgpuDev->Child == NULL || ChildHandle != VgpuDev->Child->GopHandle) {
117     return EFI_UNSUPPORTED;
118   }
119   //
120   // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
121   // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
122   //
123   ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle, ChildHandle,
124                       &gVirtioDeviceProtocolGuid));
125 
126   return LookupUnicodeString2 (Language, This->SupportedLanguages,
127            VgpuDev->Child->GopName, ControllerName,
128            FALSE /* Iso639Language */);
129 }
130 
131 STATIC CONST EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
132   VirtioGpuGetDriverName,
133   VirtioGpuGetControllerName,
134   "en"                       // SupportedLanguages (RFC 4646)
135 };
136 
137 //
138 // Helper functions for the Driver Binding Protocol Implementation.
139 //
140 /**
141   Format the VGPU_DEV controller name, to be looked up and returned by
142   VirtioGpuGetControllerName().
143 
144   @param[in] ControllerHandle  The handle that identifies the VGPU_DEV
145                                controller.
146 
147   @param[in] AgentHandle       The handle of the agent that will attempt to
148                                temporarily open the PciIo protocol. This is the
149                                DriverBindingHandle member of the
150                                EFI_DRIVER_BINDING_PROTOCOL whose Start()
151                                function is calling this function.
152 
153   @param[in] DevicePath        The device path that is installed on
154                                ControllerHandle.
155 
156   @param[out] ControllerName   A dynamically allocated unicode string that
157                                unconditionally says "Virtio GPU Device", with a
158                                PCI Segment:Bus:Device.Function location
159                                optionally appended. The latter part is only
160                                produced if DevicePath contains at least one
161                                PciIo node; in that case, the most specific such
162                                node is used for retrieving the location info.
163                                The caller is responsible for freeing
164                                ControllerName after use.
165 
166   @retval EFI_SUCCESS           ControllerName has been formatted.
167 
168   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for ControllerName.
169 **/
170 STATIC
171 EFI_STATUS
FormatVgpuDevName(IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE AgentHandle,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT CHAR16 ** ControllerName)172 FormatVgpuDevName (
173   IN  EFI_HANDLE               ControllerHandle,
174   IN  EFI_HANDLE               AgentHandle,
175   IN  EFI_DEVICE_PATH_PROTOCOL *DevicePath,
176   OUT CHAR16                   **ControllerName
177   )
178 {
179   EFI_HANDLE          PciIoHandle;
180   EFI_PCI_IO_PROTOCOL *PciIo;
181   UINTN               Segment, Bus, Device, Function;
182   STATIC CONST CHAR16 ControllerNameStem[] = L"Virtio GPU Device";
183   UINTN               ControllerNameSize;
184 
185   if (EFI_ERROR (gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &DevicePath,
186                         &PciIoHandle)) ||
187       EFI_ERROR (gBS->OpenProtocol (PciIoHandle, &gEfiPciIoProtocolGuid,
188                         (VOID **)&PciIo, AgentHandle, ControllerHandle,
189                         EFI_OPEN_PROTOCOL_GET_PROTOCOL)) ||
190       EFI_ERROR (PciIo->GetLocation (PciIo, &Segment, &Bus, &Device,
191                           &Function))) {
192     //
193     // Failed to retrieve location info, return verbatim copy of static string.
194     //
195     *ControllerName = AllocateCopyPool (sizeof ControllerNameStem,
196                         ControllerNameStem);
197     return (*ControllerName == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS;
198   }
199   //
200   // Location info available, format ControllerName dynamically.
201   //
202   ControllerNameSize = sizeof ControllerNameStem + // includes L'\0'
203                        sizeof (CHAR16) * (1 + 4 +  // Segment
204                                           1 + 2 +  // Bus
205                                           1 + 2 +  // Device
206                                           1 + 1    // Function
207                                           );
208   *ControllerName = AllocatePool (ControllerNameSize);
209   if (*ControllerName == NULL) {
210     return EFI_OUT_OF_RESOURCES;
211   }
212 
213   UnicodeSPrintAsciiFormat (*ControllerName, ControllerNameSize,
214     "%s %04x:%02x:%02x.%x", ControllerNameStem, (UINT32)Segment, (UINT32)Bus,
215     (UINT32)Device, (UINT32)Function);
216   return EFI_SUCCESS;
217 }
218 
219 /**
220   Dynamically allocate and initialize the VGPU_GOP child object within an
221   otherwise configured parent VGPU_DEV object.
222 
223   This function adds a BY_CHILD_CONTROLLER reference to ParentBusController's
224   VIRTIO_DEVICE_PROTOCOL interface.
225 
226   @param[in,out] ParentBus        The pre-initialized VGPU_DEV object that the
227                                   newly created VGPU_GOP object will be the
228                                   child of.
229 
230   @param[in] ParentDevicePath     The device path protocol instance that is
231                                   installed on ParentBusController.
232 
233   @param[in] ParentBusController  The UEFI controller handle on which the
234                                   ParentBus VGPU_DEV object and the
235                                   ParentDevicePath device path protocol are
236                                   installed.
237 
238   @param[in] DriverBindingHandle  The DriverBindingHandle member of
239                                   EFI_DRIVER_BINDING_PROTOCOL whose Start()
240                                   function is calling this function. It is
241                                   passed as AgentHandle to gBS->OpenProtocol()
242                                   when creating the BY_CHILD_CONTROLLER
243                                   reference.
244 
245   @retval EFI_SUCCESS           ParentBus->Child has been created and
246                                 populated, and ParentBus->Child->GopHandle now
247                                 references ParentBusController->VirtIo
248                                 BY_CHILD_CONTROLLER.
249 
250   @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
251 
252   @return                       Error codes from underlying functions.
253 **/
254 STATIC
255 EFI_STATUS
InitVgpuGop(IN OUT VGPU_DEV * ParentBus,IN EFI_DEVICE_PATH_PROTOCOL * ParentDevicePath,IN EFI_HANDLE ParentBusController,IN EFI_HANDLE DriverBindingHandle)256 InitVgpuGop (
257   IN OUT VGPU_DEV                 *ParentBus,
258   IN     EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
259   IN     EFI_HANDLE               ParentBusController,
260   IN     EFI_HANDLE               DriverBindingHandle
261   )
262 {
263   VGPU_GOP            *VgpuGop;
264   EFI_STATUS          Status;
265   CHAR16              *ParentBusName;
266   STATIC CONST CHAR16 NameSuffix[] = L" Head #0";
267   UINTN               NameSize;
268   CHAR16              *Name;
269   EFI_TPL             OldTpl;
270   VOID                *ParentVirtIo;
271 
272   VgpuGop = AllocateZeroPool (sizeof *VgpuGop);
273   if (VgpuGop == NULL) {
274     return EFI_OUT_OF_RESOURCES;
275   }
276 
277   VgpuGop->Signature = VGPU_GOP_SIG;
278   VgpuGop->ParentBus = ParentBus;
279 
280   //
281   // Format a human-readable controller name for VGPU_GOP, and stash it for
282   // VirtioGpuGetControllerName() to look up. We simply append NameSuffix to
283   // ParentBus->BusName.
284   //
285   Status = LookupUnicodeString2 ("en", mComponentName2.SupportedLanguages,
286              ParentBus->BusName, &ParentBusName, FALSE /* Iso639Language */);
287   ASSERT_EFI_ERROR (Status);
288   NameSize = StrSize (ParentBusName) - sizeof (CHAR16) + sizeof NameSuffix;
289   Name = AllocatePool (NameSize);
290   if (Name == NULL) {
291     Status = EFI_OUT_OF_RESOURCES;
292     goto FreeVgpuGop;
293   }
294   UnicodeSPrintAsciiFormat (Name, NameSize, "%s%s", ParentBusName, NameSuffix);
295   Status = AddUnicodeString2 ("en", mComponentName2.SupportedLanguages,
296              &VgpuGop->GopName, Name, FALSE /* Iso639Language */);
297   FreePool (Name);
298   if (EFI_ERROR (Status)) {
299     goto FreeVgpuGop;
300   }
301 
302   //
303   // Create the child device path.
304   //
305   VgpuGop->GopDevicePath = AppendDevicePathNode (ParentDevicePath,
306                              &mAcpiAdr.Header);
307   if (VgpuGop->GopDevicePath == NULL) {
308     Status = EFI_OUT_OF_RESOURCES;
309     goto FreeVgpuGopName;
310   }
311 
312   //
313   // Mask protocol notify callbacks until we're done.
314   //
315   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
316 
317   //
318   // Create the child handle with the child device path.
319   //
320   Status = gBS->InstallProtocolInterface (&VgpuGop->GopHandle,
321                   &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
322                   VgpuGop->GopDevicePath);
323   if (EFI_ERROR (Status)) {
324     goto FreeDevicePath;
325   }
326 
327   //
328   // The child handle must present a reference to the parent handle's Virtio
329   // Device Protocol interface.
330   //
331   Status = gBS->OpenProtocol (ParentBusController, &gVirtioDeviceProtocolGuid,
332                   &ParentVirtIo, DriverBindingHandle, VgpuGop->GopHandle,
333                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
334   if (EFI_ERROR (Status)) {
335     goto UninstallDevicePath;
336   }
337   ASSERT (ParentVirtIo == ParentBus->VirtIo);
338 
339   //
340   // Initialize our Graphics Output Protocol.
341   //
342   // Fill in the function members of VgpuGop->Gop from the template, then set
343   // up the rest of the GOP infrastructure by calling SetMode() right now.
344   //
345   CopyMem (&VgpuGop->Gop, &mGopTemplate, sizeof mGopTemplate);
346   Status = VgpuGop->Gop.SetMode (&VgpuGop->Gop, 0);
347   if (EFI_ERROR (Status)) {
348     goto CloseVirtIoByChild;
349   }
350 
351   //
352   // Install the Graphics Output Protocol on the child handle.
353   //
354   Status = gBS->InstallProtocolInterface (&VgpuGop->GopHandle,
355                   &gEfiGraphicsOutputProtocolGuid, EFI_NATIVE_INTERFACE,
356                   &VgpuGop->Gop);
357   if (EFI_ERROR (Status)) {
358     goto UninitGop;
359   }
360 
361   //
362   // We're done.
363   //
364   gBS->RestoreTPL (OldTpl);
365   ParentBus->Child = VgpuGop;
366   return EFI_SUCCESS;
367 
368 UninitGop:
369   ReleaseGopResources (VgpuGop, TRUE /* DisableHead */);
370 
371 CloseVirtIoByChild:
372   gBS->CloseProtocol (ParentBusController, &gVirtioDeviceProtocolGuid,
373     DriverBindingHandle, VgpuGop->GopHandle);
374 
375 UninstallDevicePath:
376   gBS->UninstallProtocolInterface (VgpuGop->GopHandle,
377          &gEfiDevicePathProtocolGuid, VgpuGop->GopDevicePath);
378 
379 FreeDevicePath:
380   gBS->RestoreTPL (OldTpl);
381   FreePool (VgpuGop->GopDevicePath);
382 
383 FreeVgpuGopName:
384   FreeUnicodeStringTable (VgpuGop->GopName);
385 
386 FreeVgpuGop:
387   FreePool (VgpuGop);
388 
389   return Status;
390 }
391 
392 /**
393   Tear down and release the VGPU_GOP child object within the VGPU_DEV parent
394   object.
395 
396   This function removes the BY_CHILD_CONTROLLER reference from
397   ParentBusController's VIRTIO_DEVICE_PROTOCOL interface.
398 
399   @param[in,out] ParentBus        The VGPU_DEV object that the VGPU_GOP child
400                                   object will be removed from.
401 
402   @param[in] ParentBusController  The UEFI controller handle on which the
403                                   ParentBus VGPU_DEV object is installed.
404 
405   @param[in] DriverBindingHandle  The DriverBindingHandle member of
406                                   EFI_DRIVER_BINDING_PROTOCOL whose Stop()
407                                   function is calling this function. It is
408                                   passed as AgentHandle to gBS->CloseProtocol()
409                                   when removing the BY_CHILD_CONTROLLER
410                                   reference.
411 **/
412 STATIC
413 VOID
UninitVgpuGop(IN OUT VGPU_DEV * ParentBus,IN EFI_HANDLE ParentBusController,IN EFI_HANDLE DriverBindingHandle)414 UninitVgpuGop (
415   IN OUT VGPU_DEV   *ParentBus,
416   IN     EFI_HANDLE ParentBusController,
417   IN     EFI_HANDLE DriverBindingHandle
418   )
419 {
420   VGPU_GOP   *VgpuGop;
421   EFI_STATUS Status;
422 
423   VgpuGop = ParentBus->Child;
424   Status = gBS->UninstallProtocolInterface (VgpuGop->GopHandle,
425                   &gEfiGraphicsOutputProtocolGuid, &VgpuGop->Gop);
426   ASSERT_EFI_ERROR (Status);
427 
428   //
429   // Uninitialize VgpuGop->Gop.
430   //
431   ReleaseGopResources (VgpuGop, TRUE /* DisableHead */);
432 
433   Status = gBS->CloseProtocol (ParentBusController, &gVirtioDeviceProtocolGuid,
434                   DriverBindingHandle, VgpuGop->GopHandle);
435   ASSERT_EFI_ERROR (Status);
436 
437   Status = gBS->UninstallProtocolInterface (VgpuGop->GopHandle,
438                   &gEfiDevicePathProtocolGuid, VgpuGop->GopDevicePath);
439   ASSERT_EFI_ERROR (Status);
440 
441   FreePool (VgpuGop->GopDevicePath);
442   FreeUnicodeStringTable (VgpuGop->GopName);
443   FreePool (VgpuGop);
444 
445   ParentBus->Child = NULL;
446 }
447 
448 //
449 // Driver Binding Protocol Implementation.
450 //
451 STATIC
452 EFI_STATUS
453 EFIAPI
VirtioGpuDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)454 VirtioGpuDriverBindingSupported (
455   IN EFI_DRIVER_BINDING_PROTOCOL *This,
456   IN EFI_HANDLE                  ControllerHandle,
457   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
458   )
459 {
460   EFI_STATUS             Status;
461   VIRTIO_DEVICE_PROTOCOL *VirtIo;
462 
463   //
464   // - If RemainingDevicePath is NULL: the caller is interested in creating all
465   //   child handles.
466   // - If RemainingDevicePath points to an end node: the caller is not
467   //   interested in creating any child handle.
468   // - Otherwise, the caller would like to create the one child handle
469   //   specified in RemainingDevicePath. In this case we have to see if the
470   //   requested device path is supportable.
471   //
472   if (RemainingDevicePath != NULL &&
473       !IsDevicePathEnd (RemainingDevicePath) &&
474       (DevicePathNodeLength (RemainingDevicePath) != sizeof mAcpiAdr ||
475        CompareMem (RemainingDevicePath, &mAcpiAdr, sizeof mAcpiAdr) != 0)) {
476     return EFI_UNSUPPORTED;
477   }
478 
479   //
480   // Open the Virtio Device Protocol interface on the controller, BY_DRIVER.
481   //
482   Status = gBS->OpenProtocol (ControllerHandle, &gVirtioDeviceProtocolGuid,
483                   (VOID **)&VirtIo, This->DriverBindingHandle,
484                   ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
485   if (EFI_ERROR (Status)) {
486     //
487     // If this fails, then by default we cannot support ControllerHandle. There
488     // is one exception: we've already bound the device, have not produced any
489     // GOP child controller, and now the caller wants us to produce the child
490     // controller (either specifically or as part of "all children"). That's
491     // allowed.
492     //
493     if (Status == EFI_ALREADY_STARTED) {
494       EFI_STATUS Status2;
495       VGPU_DEV   *VgpuDev;
496 
497       Status2 = gBS->OpenProtocol (ControllerHandle, &gEfiCallerIdGuid,
498                        (VOID **)&VgpuDev, This->DriverBindingHandle,
499                        ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
500       ASSERT_EFI_ERROR (Status2);
501 
502       if (VgpuDev->Child == NULL &&
503           (RemainingDevicePath == NULL ||
504            !IsDevicePathEnd (RemainingDevicePath))) {
505         Status = EFI_SUCCESS;
506       }
507     }
508 
509     return Status;
510   }
511 
512   //
513   // First BY_DRIVER open; check the VirtIo revision and subsystem.
514   //
515   if (VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0) ||
516       VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_GPU_DEVICE) {
517     Status = EFI_UNSUPPORTED;
518     goto CloseVirtIo;
519   }
520 
521   //
522   // We'll need the device path of the VirtIo device both for formatting
523   // VGPU_DEV.BusName and for populating VGPU_GOP.GopDevicePath.
524   //
525   Status = gBS->OpenProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
526                   NULL, This->DriverBindingHandle, ControllerHandle,
527                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
528 
529 CloseVirtIo:
530   gBS->CloseProtocol (ControllerHandle, &gVirtioDeviceProtocolGuid,
531     This->DriverBindingHandle, ControllerHandle);
532 
533   return Status;
534 }
535 
536 STATIC
537 EFI_STATUS
538 EFIAPI
VirtioGpuDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)539 VirtioGpuDriverBindingStart (
540   IN EFI_DRIVER_BINDING_PROTOCOL *This,
541   IN EFI_HANDLE                  ControllerHandle,
542   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
543   )
544 {
545   EFI_STATUS               Status;
546   VIRTIO_DEVICE_PROTOCOL   *VirtIo;
547   BOOLEAN                  VirtIoBoundJustNow;
548   VGPU_DEV                 *VgpuDev;
549   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
550 
551   //
552   // Open the Virtio Device Protocol.
553   //
554   // The result of this operation, combined with the checks in
555   // VirtioGpuDriverBindingSupported(), uniquely tells us whether we are
556   // binding the VirtIo controller on this call (with or without creating child
557   // controllers), or else we're *only* creating child controllers.
558   //
559   Status = gBS->OpenProtocol (ControllerHandle, &gVirtioDeviceProtocolGuid,
560                   (VOID **)&VirtIo, This->DriverBindingHandle,
561                   ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
562   if (EFI_ERROR (Status)) {
563     //
564     // The assertions below are based on the success of
565     // VirtioGpuDriverBindingSupported(): we bound ControllerHandle earlier,
566     // without producing child handles, and now we're producing the GOP child
567     // handle only.
568     //
569     ASSERT (Status == EFI_ALREADY_STARTED);
570 
571     Status = gBS->OpenProtocol (ControllerHandle, &gEfiCallerIdGuid,
572                     (VOID **)&VgpuDev, This->DriverBindingHandle,
573                     ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
574     ASSERT_EFI_ERROR (Status);
575 
576     ASSERT (VgpuDev->Child == NULL);
577     ASSERT (
578       RemainingDevicePath == NULL || !IsDevicePathEnd (RemainingDevicePath));
579 
580     VirtIoBoundJustNow = FALSE;
581   } else {
582     VirtIoBoundJustNow = TRUE;
583 
584     //
585     // Allocate the private structure.
586     //
587     VgpuDev = AllocateZeroPool (sizeof *VgpuDev);
588     if (VgpuDev == NULL) {
589       Status = EFI_OUT_OF_RESOURCES;
590       goto CloseVirtIo;
591     }
592     VgpuDev->VirtIo = VirtIo;
593   }
594 
595   //
596   // Grab the VirtIo controller's device path. This is necessary regardless of
597   // VirtIoBoundJustNow.
598   //
599   Status = gBS->OpenProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
600                   (VOID **)&DevicePath, This->DriverBindingHandle,
601                   ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
602   if (EFI_ERROR (Status)) {
603     goto FreeVgpuDev;
604   }
605 
606   //
607   // Create VGPU_DEV if we've bound the VirtIo controller right now (that is,
608   // if we aren't *only* creating child handles).
609   //
610   if (VirtIoBoundJustNow) {
611     CHAR16 *VgpuDevName;
612 
613     //
614     // Format a human-readable controller name for VGPU_DEV, and stash it for
615     // VirtioGpuGetControllerName() to look up.
616     //
617     Status = FormatVgpuDevName (ControllerHandle, This->DriverBindingHandle,
618                DevicePath, &VgpuDevName);
619     if (EFI_ERROR (Status)) {
620       goto FreeVgpuDev;
621     }
622     Status = AddUnicodeString2 ("en", mComponentName2.SupportedLanguages,
623                &VgpuDev->BusName, VgpuDevName, FALSE /* Iso639Language */);
624     FreePool (VgpuDevName);
625     if (EFI_ERROR (Status)) {
626       goto FreeVgpuDev;
627     }
628 
629     Status = VirtioGpuInit (VgpuDev);
630     if (EFI_ERROR (Status)) {
631       goto FreeVgpuDevBusName;
632     }
633 
634     Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
635                     VirtioGpuExitBoot, VgpuDev /* NotifyContext */,
636                     &VgpuDev->ExitBoot);
637     if (EFI_ERROR (Status)) {
638       goto UninitGpu;
639     }
640 
641     //
642     // Install the VGPU_DEV "protocol interface" on ControllerHandle.
643     //
644     Status = gBS->InstallProtocolInterface (&ControllerHandle,
645                     &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, VgpuDev);
646     if (EFI_ERROR (Status)) {
647       goto CloseExitBoot;
648     }
649 
650     if (RemainingDevicePath != NULL && IsDevicePathEnd (RemainingDevicePath)) {
651       //
652       // No child handle should be produced; we're done.
653       //
654       DEBUG ((EFI_D_INFO, "%a: bound VirtIo=%p without producing GOP\n",
655         __FUNCTION__, (VOID *)VgpuDev->VirtIo));
656       return EFI_SUCCESS;
657     }
658   }
659 
660   //
661   // Below we'll produce our single child handle: the caller requested it
662   // either specifically, or as part of all child handles.
663   //
664   ASSERT (VgpuDev->Child == NULL);
665   ASSERT (
666     RemainingDevicePath == NULL || !IsDevicePathEnd (RemainingDevicePath));
667 
668   Status = InitVgpuGop (VgpuDev, DevicePath, ControllerHandle,
669              This->DriverBindingHandle);
670   if (EFI_ERROR (Status)) {
671     goto UninstallVgpuDev;
672   }
673 
674   //
675   // We're done.
676   //
677   DEBUG ((EFI_D_INFO, "%a: produced GOP %a VirtIo=%p\n", __FUNCTION__,
678     VirtIoBoundJustNow ? "while binding" : "for pre-bound",
679     (VOID *)VgpuDev->VirtIo));
680   return EFI_SUCCESS;
681 
682 UninstallVgpuDev:
683   if (VirtIoBoundJustNow) {
684     gBS->UninstallProtocolInterface (ControllerHandle, &gEfiCallerIdGuid,
685            VgpuDev);
686   }
687 
688 CloseExitBoot:
689   if (VirtIoBoundJustNow) {
690     gBS->CloseEvent (VgpuDev->ExitBoot);
691   }
692 
693 UninitGpu:
694   if (VirtIoBoundJustNow) {
695     VirtioGpuUninit (VgpuDev);
696   }
697 
698 FreeVgpuDevBusName:
699   if (VirtIoBoundJustNow) {
700     FreeUnicodeStringTable (VgpuDev->BusName);
701   }
702 
703 FreeVgpuDev:
704   if (VirtIoBoundJustNow) {
705     FreePool (VgpuDev);
706   }
707 
708 CloseVirtIo:
709   if (VirtIoBoundJustNow) {
710     gBS->CloseProtocol (ControllerHandle, &gVirtioDeviceProtocolGuid,
711       This->DriverBindingHandle, ControllerHandle);
712   }
713 
714   return Status;
715 }
716 
717 STATIC
718 EFI_STATUS
719 EFIAPI
VirtioGpuDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)720 VirtioGpuDriverBindingStop (
721   IN  EFI_DRIVER_BINDING_PROTOCOL *This,
722   IN  EFI_HANDLE                  ControllerHandle,
723   IN  UINTN                       NumberOfChildren,
724   IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
725   )
726 {
727   EFI_STATUS Status;
728   VGPU_DEV   *VgpuDev;
729 
730   //
731   // Look up the VGPU_DEV "protocol interface" on ControllerHandle.
732   //
733   Status = gBS->OpenProtocol (ControllerHandle, &gEfiCallerIdGuid,
734                   (VOID **)&VgpuDev, This->DriverBindingHandle,
735                   ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
736   if (EFI_ERROR (Status)) {
737     return Status;
738   }
739   //
740   // Sanity check: if we found gEfiCallerIdGuid on ControllerHandle, then we
741   // keep its Virtio Device Protocol interface open BY_DRIVER.
742   //
743   ASSERT_EFI_ERROR (EfiTestManagedDevice (ControllerHandle,
744                       This->DriverBindingHandle, &gVirtioDeviceProtocolGuid));
745 
746   switch (NumberOfChildren) {
747   case 0:
748     //
749     // The caller wants us to unbind the VirtIo controller.
750     //
751     if (VgpuDev->Child != NULL) {
752       //
753       // We still have the GOP child.
754       //
755       Status = EFI_DEVICE_ERROR;
756       break;
757     }
758 
759     DEBUG ((EFI_D_INFO, "%a: unbinding GOP-less VirtIo=%p\n", __FUNCTION__,
760       (VOID *)VgpuDev->VirtIo));
761 
762     Status = gBS->UninstallProtocolInterface (ControllerHandle,
763                     &gEfiCallerIdGuid, VgpuDev);
764     ASSERT_EFI_ERROR (Status);
765 
766     Status = gBS->CloseEvent (VgpuDev->ExitBoot);
767     ASSERT_EFI_ERROR (Status);
768 
769     VirtioGpuUninit (VgpuDev);
770     FreeUnicodeStringTable (VgpuDev->BusName);
771     FreePool (VgpuDev);
772 
773     Status = gBS->CloseProtocol (ControllerHandle, &gVirtioDeviceProtocolGuid,
774                     This->DriverBindingHandle, ControllerHandle);
775     ASSERT_EFI_ERROR (Status);
776     break;
777 
778   case 1:
779     //
780     // The caller wants us to destroy our child GOP controller.
781     //
782     if (VgpuDev->Child == NULL ||
783         ChildHandleBuffer[0] != VgpuDev->Child->GopHandle) {
784       //
785       // We have no child controller at the moment, or it differs from the one
786       // the caller wants us to destroy. I.e., we don't own the child
787       // controller passed in.
788       //
789       Status = EFI_DEVICE_ERROR;
790       break;
791     }
792     //
793     // Sanity check: our GOP child controller keeps the VGPU_DEV controller's
794     // Virtio Device Protocol interface open BY_CHILD_CONTROLLER.
795     //
796     ASSERT_EFI_ERROR (EfiTestChildHandle (ControllerHandle,
797                         VgpuDev->Child->GopHandle,
798                         &gVirtioDeviceProtocolGuid));
799 
800     DEBUG ((EFI_D_INFO, "%a: destroying GOP under VirtIo=%p\n", __FUNCTION__,
801       (VOID *)VgpuDev->VirtIo));
802     UninitVgpuGop (VgpuDev, ControllerHandle, This->DriverBindingHandle);
803     break;
804 
805   default:
806     //
807     // Impossible, we never produced more than one child.
808     //
809     Status = EFI_DEVICE_ERROR;
810     break;
811   }
812   return Status;
813 }
814 
815 STATIC EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
816   VirtioGpuDriverBindingSupported,
817   VirtioGpuDriverBindingStart,
818   VirtioGpuDriverBindingStop,
819   0x10,                            // Version
820   NULL,                            // ImageHandle, overwritten in entry point
821   NULL                             // DriverBindingHandle, ditto
822 };
823 
824 //
825 // Entry point of the driver.
826 //
827 EFI_STATUS
828 EFIAPI
VirtioGpuEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)829 VirtioGpuEntryPoint (
830   IN EFI_HANDLE       ImageHandle,
831   IN EFI_SYSTEM_TABLE *SystemTable
832   )
833 {
834   return EfiLibInstallDriverBindingComponentName2 (ImageHandle, SystemTable,
835            &mDriverBinding, ImageHandle, NULL /* ComponentName */,
836            &mComponentName2);
837 }
838