]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Bhyve/BhyveRfbDxe/GopDriver.c
OvmfPkg: Add MicrocodeLib in DSC files.
[mirror_edk2.git] / OvmfPkg / Bhyve / BhyveRfbDxe / GopDriver.c
CommitLineData
656419f9
RC
1/*++ @file\r
2\r
3Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>\r
4Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
5Portions copyright (c) 2010,Apple Inc. All rights reserved.<BR>\r
6\r
7SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include "Gop.h"\r
12#include <IndustryStandard/Acpi.h>\r
13\r
14STATIC VOID\r
15BhyveGetGraphicsMode (\r
16 EFI_PCI_IO_PROTOCOL *PciIo,\r
17 UINT16 *Width,\r
18 UINT16 *Height,\r
19 UINT16 *Depth\r
20 );\r
21\r
22\r
23/**\r
24 Tests to see if this driver supports a given controller. If a child device is provided,\r
25 it further tests to see if this driver supports creating a handle for the specified child device.\r
26\r
27 This function checks to see if the driver specified by This supports the device specified by\r
28 ControllerHandle. Drivers will typically use the device path attached to\r
29 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
30 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
31 may be called many times during platform initialization. In order to reduce boot times, the tests\r
32 performed by this function must be very small, and take as little time as possible to execute. This\r
33 function must not change the state of any hardware devices, and this function must be aware that the\r
34 device specified by ControllerHandle may already be managed by the same driver or a\r
35 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
36 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
37 Because ControllerHandle may have been previously started by the same driver, if a protocol is\r
38 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
39 to guarantee the state of ControllerHandle is not modified by this function.\r
40\r
41 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
42 @param[in] ControllerHandle The handle of the controller to test. This handle\r
43 must support a protocol interface that supplies\r
44 an I/O abstraction to the driver.\r
45 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
46 parameter is ignored by device drivers, and is optional for bus\r
47 drivers. For bus drivers, if this parameter is not NULL, then\r
48 the bus driver must determine if the bus controller specified\r
49 by ControllerHandle and the child controller specified\r
50 by RemainingDevicePath are both supported by this\r
51 bus driver.\r
52\r
53 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
54 RemainingDevicePath is supported by the driver specified by This.\r
55 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
56 RemainingDevicePath is already being managed by the driver\r
57 specified by This.\r
58 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
59 RemainingDevicePath is already being managed by a different\r
60 driver or an application that requires exclusive access.\r
61 Currently not implemented.\r
62 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
63 RemainingDevicePath is not supported by the driver specified by This.\r
64**/\r
65EFI_STATUS\r
66EFIAPI\r
67EmuGopDriverBindingSupported (\r
68 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
69 IN EFI_HANDLE Handle,\r
70 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
71 )\r
72{\r
73 EFI_STATUS Status;\r
74 EFI_PCI_IO_PROTOCOL *PciIo;\r
75 PCI_TYPE00 Pci;\r
76 UINT16 Width, Height, Depth;\r
77\r
78 //\r
79 // Open the IO Abstraction(s) needed to perform the supported test\r
80 //\r
81 Status = gBS->OpenProtocol (\r
82 Handle,\r
83 &gEfiPciIoProtocolGuid,\r
84 (VOID **) &PciIo,\r
85 This->DriverBindingHandle,\r
86 Handle,\r
87 EFI_OPEN_PROTOCOL_BY_DRIVER\r
88 );\r
89 if (EFI_ERROR (Status)) {\r
90 return Status;\r
91 }\r
92\r
93 //\r
94 // See if this is a PCI Framebuffer Controller by looking at the Command register and\r
95 // Class Code Register\r
96 //\r
97 Status = PciIo->Pci.Read (\r
98 PciIo,\r
99 EfiPciIoWidthUint32,\r
100 PCI_BAR_IDX0,\r
101 sizeof (Pci) / sizeof (UINT32),\r
102 &Pci\r
103 );\r
104 if (EFI_ERROR (Status)) {\r
105 Status = EFI_UNSUPPORTED;\r
106 goto Done;\r
107 }\r
108\r
109 Status = EFI_UNSUPPORTED;\r
110 if (Pci.Hdr.VendorId == 0xFB5D && Pci.Hdr.DeviceId == 0x40FB) {\r
111 DEBUG((DEBUG_INFO, "BHYVE framebuffer device detected\n"));\r
112 Status = EFI_SUCCESS;\r
113\r
114 BhyveGetGraphicsMode(PciIo, &Width, &Height, &Depth);\r
115 PcdSet32S (PcdVideoHorizontalResolution, Width);\r
116 PcdSet32S (PcdVideoVerticalResolution, Height);\r
117 }\r
118\r
119Done:\r
120 //\r
121 // Close the PCI I/O Protocol\r
122 //\r
123 gBS->CloseProtocol (\r
124 Handle,\r
125 &gEfiPciIoProtocolGuid,\r
126 This->DriverBindingHandle,\r
127 Handle\r
128 );\r
129\r
130 return Status;\r
131}\r
132\r
133\r
134/**\r
135 Starts a device controller or a bus controller.\r
136\r
137 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
138 As a result, much of the error checking on the parameters to Start() has been moved into this\r
139 common boot service. It is legal to call Start() from other locations,\r
140 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
141 1. ControllerHandle must be a valid EFI_HANDLE.\r
142 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
143 EFI_DEVICE_PATH_PROTOCOL.\r
144 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
145 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
146\r
147 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
148 @param[in] ControllerHandle The handle of the controller to start. This handle\r
149 must support a protocol interface that supplies\r
150 an I/O abstraction to the driver.\r
151 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
152 parameter is ignored by device drivers, and is optional for bus\r
153 drivers. For a bus driver, if this parameter is NULL, then handles\r
154 for all the children of Controller are created by this driver.\r
155 If this parameter is not NULL and the first Device Path Node is\r
156 not the End of Device Path Node, then only the handle for the\r
157 child device specified by the first Device Path Node of\r
158 RemainingDevicePath is created by this driver.\r
159 If the first Device Path Node of RemainingDevicePath is\r
160 the End of Device Path Node, no child handle is created by this\r
161 driver.\r
162\r
163 @retval EFI_SUCCESS The device was started.\r
164 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
165 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
166 @retval Others The driver failded to start the device.\r
167\r
168**/\r
169EFI_STATUS\r
170EFIAPI\r
171EmuGopDriverBindingStart (\r
172 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
173 IN EFI_HANDLE Handle,\r
174 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
175 )\r
176{\r
177 BHYVE_FBUF_MEMREGS Memregs;\r
178 GOP_PRIVATE_DATA *Private;\r
179 EFI_STATUS Status;\r
180 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;\r
181\r
182 //\r
183 // Allocate Private context data for SGO inteface.\r
184 //\r
185 Private = NULL;\r
186 Status = gBS->AllocatePool (\r
187 EfiBootServicesData,\r
188 sizeof (GOP_PRIVATE_DATA),\r
189 (VOID **)&Private\r
190 );\r
191 if (EFI_ERROR (Status)) {\r
192 goto Done;\r
193 }\r
194\r
195 // Set up context record\r
196 //\r
197 Private->Signature = GOP_PRIVATE_DATA_SIGNATURE;\r
198 Private->Handle = Handle;\r
199 Private->ControllerNameTable = NULL;\r
200\r
201 //\r
202 // Open PCI I/O Protocol\r
203 //\r
204 Status = gBS->OpenProtocol (\r
205 Handle,\r
206 &gEfiPciIoProtocolGuid,\r
207 (VOID **) &Private->PciIo,\r
208 This->DriverBindingHandle,\r
209 Handle,\r
210 EFI_OPEN_PROTOCOL_BY_DRIVER\r
211 );\r
212 if (EFI_ERROR (Status)) {\r
213 goto Done;\r
214 }\r
215\r
216 //\r
217 // Check if fbuf mmio BAR is present\r
218 //\r
219 MmioDesc = NULL;\r
220 Status = Private->PciIo->GetBarAttributes (\r
221 Private->PciIo,\r
222 PCI_BAR_IDX0,\r
223 NULL,\r
224 (VOID**) &MmioDesc\r
225 );\r
226 if (EFI_ERROR (Status) ||\r
227 MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
228 DEBUG ((DEBUG_INFO, "BHYVE GOP: No mmio bar\n"));\r
229 } else {\r
230 DEBUG ((DEBUG_INFO, "BHYVE GOP: Using mmio bar @ 0x%lx\n",\r
231 MmioDesc->AddrRangeMin));\r
232 BhyveGetMemregs(Private, &Memregs);\r
233 Private->FbSize = Memregs.FbSize;\r
234 }\r
235 if (MmioDesc != NULL) {\r
236 FreePool (MmioDesc);\r
237 }\r
238 if (EFI_ERROR (Status)) {\r
239 goto Done;\r
240 }\r
241\r
242 //\r
243 // Check if fbuf frame-buffer BAR is present\r
244 //\r
245 MmioDesc = NULL;\r
246 Status = Private->PciIo->GetBarAttributes (\r
247 Private->PciIo,\r
248 PCI_BAR_IDX1,\r
249 NULL,\r
250 (VOID**) &MmioDesc\r
251 );\r
252 if (EFI_ERROR (Status) ||\r
253 MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
254 DEBUG ((DEBUG_INFO, "BHYVE GOP: No frame-buffer bar\n"));\r
255 } else {\r
256 DEBUG ((DEBUG_INFO, "BHYVE GOP: Using frame-buffer bar @ 0x%lx\n",\r
257 MmioDesc->AddrRangeMin));\r
258 Private->FbAddr = MmioDesc->AddrRangeMin;\r
259 // XXX assert BAR is >= size\r
260 }\r
261\r
262 if (MmioDesc != NULL) {\r
263 FreePool (MmioDesc);\r
264 }\r
265 if (EFI_ERROR (Status)) {\r
266 goto Done;\r
267 }\r
268\r
269 DEBUG ((DEBUG_INFO, "BHYVE GOP: Framebuf addr 0x%lx, size %x\n",\r
270 Private->FbAddr, Private->FbSize));\r
271\r
272 Status = EmuGopConstructor (Private);\r
273 if (EFI_ERROR (Status)) {\r
274 goto Done;\r
275 }\r
276\r
277 //\r
278 // Publish the Gop interface to the world\r
279 //\r
280 Status = gBS->InstallMultipleProtocolInterfaces (\r
281 &Private->Handle,\r
282 &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,\r
283 NULL\r
284 );\r
285\r
286 DEBUG((DEBUG_INFO, "BHYVE framebuffer device started\n"));\r
287\r
288 //\r
289 // Install int10 handler\r
290 //\r
291#ifndef CSM_ENABLE\r
292 InstallVbeShim (L"Framebuffer", Private->FbAddr);\r
293#endif\r
294\r
295Done:\r
296 if (EFI_ERROR (Status)) {\r
297 if (Private != NULL) {\r
298 //\r
299 // On Error Free back private data\r
300 //\r
301 if (Private->ControllerNameTable != NULL) {\r
302 FreeUnicodeStringTable (Private->ControllerNameTable);\r
303 }\r
304\r
305 gBS->FreePool (Private);\r
306 }\r
307 }\r
308\r
309 return Status;\r
310}\r
311\r
312\r
313\r
314/**\r
315 Stops a device controller or a bus controller.\r
316\r
317 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
318 As a result, much of the error checking on the parameters to Stop() has been moved\r
319 into this common boot service. It is legal to call Stop() from other locations,\r
320 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
321 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
322 same driver's Start() function.\r
323 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
324 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
325 Start() function, and the Start() function must have called OpenProtocol() on\r
326 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
327\r
328 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
329 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
330 support a bus specific I/O protocol for the driver\r
331 to use to stop the device.\r
332 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
333 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
334 if NumberOfChildren is 0.\r
335\r
336 @retval EFI_SUCCESS The device was stopped.\r
337 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
338\r
339**/\r
340EFI_STATUS\r
341EFIAPI\r
342EmuGopDriverBindingStop (\r
343 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
344 IN EFI_HANDLE Handle,\r
345 IN UINTN NumberOfChildren,\r
346 IN EFI_HANDLE *ChildHandleBuffer\r
347 )\r
348{\r
349 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
350 EFI_STATUS Status;\r
351 GOP_PRIVATE_DATA *Private;\r
352\r
353 DEBUG((DEBUG_INFO, "BHYVE framebuffer device stopping\n"));\r
354\r
355 Status = gBS->OpenProtocol (\r
356 Handle,\r
357 &gEfiGraphicsOutputProtocolGuid,\r
358 (VOID **)&GraphicsOutput,\r
359 This->DriverBindingHandle,\r
360 Handle,\r
361 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
362 );\r
363 if (EFI_ERROR (Status)) {\r
364 //\r
365 // If the GOP interface does not exist the driver is not started\r
366 //\r
367 return EFI_NOT_STARTED;\r
368 }\r
369\r
370 //\r
371 // Get our private context information\r
372 //\r
373 Private = GOP_PRIVATE_DATA_FROM_THIS (GraphicsOutput);\r
374\r
375 //\r
376 // Remove the SGO interface from the system\r
377 //\r
378 Status = gBS->UninstallMultipleProtocolInterfaces (\r
379 Private->Handle,\r
380 &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,\r
381 NULL\r
382 );\r
383 if (!EFI_ERROR (Status)) {\r
384 //\r
385 // Shutdown the hardware\r
386 //\r
387 Status = EmuGopDestructor (Private);\r
388 if (EFI_ERROR (Status)) {\r
389 return EFI_DEVICE_ERROR;\r
390 }\r
391\r
392 gBS->CloseProtocol (\r
393 Handle,\r
394 &gEfiPciIoProtocolGuid,\r
395 This->DriverBindingHandle,\r
396 Private->Handle\r
397 );\r
398\r
399 //\r
400 // Free our instance data\r
401 //\r
402 FreeUnicodeStringTable (Private->ControllerNameTable);\r
403\r
404 gBS->FreePool (Private);\r
405\r
406 }\r
407\r
408 return Status;\r
409}\r
410\r
411\r
412///\r
413/// This protocol provides the services required to determine if a driver supports a given controller.\r
414/// If a controller is supported, then it also provides routines to start and stop the controller.\r
415///\r
416EFI_DRIVER_BINDING_PROTOCOL gEmuGopDriverBinding = {\r
417 EmuGopDriverBindingSupported,\r
418 EmuGopDriverBindingStart,\r
419 EmuGopDriverBindingStop,\r
420 0xa,\r
421 NULL,\r
422 NULL\r
423};\r
424\r
425\r
426\r
427/**\r
428 The user Entry Point for module EmuGop. The user code starts with this function.\r
429\r
430 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
431 @param[in] SystemTable A pointer to the EFI System Table.\r
432\r
433 @retval EFI_SUCCESS The entry point is executed successfully.\r
434 @retval other Some error occurs when executing this entry point.\r
435\r
436**/\r
437EFI_STATUS\r
438EFIAPI\r
439InitializeEmuGop (\r
440 IN EFI_HANDLE ImageHandle,\r
441 IN EFI_SYSTEM_TABLE *SystemTable\r
442 )\r
443{\r
444 EFI_STATUS Status;\r
445\r
446 Status = EfiLibInstallDriverBindingComponentName2 (\r
447 ImageHandle,\r
448 SystemTable,\r
449 &gEmuGopDriverBinding,\r
450 ImageHandle,\r
451 &gEmuGopComponentName,\r
452 &gEmuGopComponentName2\r
453 );\r
454 ASSERT_EFI_ERROR (Status);\r
455\r
456\r
457 return Status;\r
458}\r
459\r
460STATIC VOID\r
461BhyveGetGraphicsMode (\r
462 EFI_PCI_IO_PROTOCOL *PciIo,\r
463 UINT16 *Width,\r
464 UINT16 *Height,\r
465 UINT16 *Depth\r
466 )\r
467{\r
468 BHYVE_FBUF_MEMREGS BhyveRegs;\r
469 UINT64 Offset;\r
470 EFI_STATUS Status;\r
471\r
472\r
473 Offset = (UINT64)&BhyveRegs.Width - (UINT64)&BhyveRegs;\r
474\r
475 Status = PciIo->Mem.Read (\r
476 PciIo,\r
477 EfiPciIoWidthUint16,\r
478 PCI_BAR_IDX0,\r
479 Offset,\r
480 3,\r
481 &BhyveRegs.Width\r
482 );\r
483\r
484 *Width = BhyveRegs.Width;\r
485 *Height = BhyveRegs.Height;\r
486 *Depth = BhyveRegs.Depth;\r
487\r
488 DEBUG ((DEBUG_INFO, "BHYVE Get Graphics Mode: w %d, h %d\n", *Width, *Height));\r
489\r
490 ASSERT_EFI_ERROR (Status);\r
491}\r
492\r
493VOID\r
494BhyveSetGraphicsMode (\r
495 GOP_PRIVATE_DATA *Private,\r
496 UINT16 Width,\r
497 UINT16 Height,\r
498 UINT16 Depth\r
499 )\r
500{\r
501 BHYVE_FBUF_MEMREGS BhyveRegs;\r
502 UINT64 Offset;\r
503 EFI_STATUS Status;\r
504\r
505 DEBUG ((DEBUG_INFO, "BHYVE Set Graphics Mode: w %d, h %d\n", Width, Height));\r
506\r
507 BhyveRegs.Width = Width;\r
508 BhyveRegs.Height = Height;\r
509 BhyveRegs.Depth = Depth;\r
510 Offset = (UINT64)&BhyveRegs.Width - (UINT64)&BhyveRegs;\r
511\r
512 Status = Private->PciIo->Mem.Write (\r
513 Private->PciIo,\r
514 EfiPciIoWidthUint16,\r
515 PCI_BAR_IDX0,\r
516 Offset,\r
517 3,\r
518 &BhyveRegs.Width\r
519 );\r
520 ASSERT_EFI_ERROR (Status);\r
521}\r
522\r
523VOID\r
524BhyveGetMemregs (\r
525 GOP_PRIVATE_DATA *Private,\r
526 BHYVE_FBUF_MEMREGS *Memregs\r
527 )\r
528{\r
529 EFI_STATUS Status;\r
530\r
531 Status = Private->PciIo->Mem.Read (\r
532 Private->PciIo,\r
533 EfiPciIoWidthUint32,\r
534 PCI_BAR_IDX0,\r
535 0,\r
536 3,\r
537 Memregs\r
538 );\r
539 ASSERT_EFI_ERROR (Status);\r
540\r
541 DEBUG ((DEBUG_INFO, "BHYVE Get Memregs, size %d width %d height %d\n",\r
542 Memregs->FbSize, Memregs->Width, Memregs->Height));\r
543}\r