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