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