DriverBinding.c 31 KB

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