VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/Bhyve/BhyveRfbDxe/GopDriver.c

Last change on this file was 105670, checked in by vboxsync, 9 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 18.1 KB
Line 
1/*++ @file
2
3Copyright (c) 2020, Rebecca Cran <[email protected]>
4Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
5Portions copyright (c) 2010,Apple Inc. All rights reserved.<BR>
6
7SPDX-License-Identifier: BSD-2-Clause-Patent
8
9**/
10
11#include "Gop.h"
12#include <IndustryStandard/Acpi.h>
13
14STATIC VOID
15BhyveGetGraphicsMode (
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**/
64EFI_STATUS
65EFIAPI
66EmuGopDriverBindingSupported (
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
118Done:
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**/
167EFI_STATUS
168EFIAPI
169EmuGopDriverBindingStart (
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 InstallVbeShim (L"Framebuffer", Private->FbAddr);
306
307Done:
308 if (EFI_ERROR (Status)) {
309 if (Private != NULL) {
310 //
311 // On Error Free back private data
312 //
313 if (Private->ControllerNameTable != NULL) {
314 FreeUnicodeStringTable (Private->ControllerNameTable);
315 }
316
317 gBS->FreePool (Private);
318 }
319 }
320
321 return Status;
322}
323
324/**
325 Stops a device controller or a bus controller.
326
327 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
328 As a result, much of the error checking on the parameters to Stop() has been moved
329 into this common boot service. It is legal to call Stop() from other locations,
330 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
331 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
332 same driver's Start() function.
333 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
334 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
335 Start() function, and the Start() function must have called OpenProtocol() on
336 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
337
338 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
339 @param[in] ControllerHandle A handle to the device being stopped. The handle must
340 support a bus specific I/O protocol for the driver
341 to use to stop the device.
342 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
343 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
344 if NumberOfChildren is 0.
345
346 @retval EFI_SUCCESS The device was stopped.
347 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
348
349**/
350EFI_STATUS
351EFIAPI
352EmuGopDriverBindingStop (
353 IN EFI_DRIVER_BINDING_PROTOCOL *This,
354 IN EFI_HANDLE Handle,
355 IN UINTN NumberOfChildren,
356 IN EFI_HANDLE *ChildHandleBuffer
357 )
358{
359 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
360 EFI_STATUS Status;
361 GOP_PRIVATE_DATA *Private;
362
363 DEBUG ((DEBUG_INFO, "BHYVE framebuffer device stopping\n"));
364
365 Status = gBS->OpenProtocol (
366 Handle,
367 &gEfiGraphicsOutputProtocolGuid,
368 (VOID **)&GraphicsOutput,
369 This->DriverBindingHandle,
370 Handle,
371 EFI_OPEN_PROTOCOL_GET_PROTOCOL
372 );
373 if (EFI_ERROR (Status)) {
374 //
375 // If the GOP interface does not exist the driver is not started
376 //
377 return EFI_NOT_STARTED;
378 }
379
380 //
381 // Get our private context information
382 //
383 Private = GOP_PRIVATE_DATA_FROM_THIS (GraphicsOutput);
384
385 //
386 // Remove the SGO interface from the system
387 //
388 Status = gBS->UninstallMultipleProtocolInterfaces (
389 Private->Handle,
390 &gEfiGraphicsOutputProtocolGuid,
391 &Private->GraphicsOutput,
392 NULL
393 );
394 if (!EFI_ERROR (Status)) {
395 //
396 // Shutdown the hardware
397 //
398 Status = EmuGopDestructor (Private);
399 if (EFI_ERROR (Status)) {
400 return EFI_DEVICE_ERROR;
401 }
402
403 gBS->CloseProtocol (
404 Handle,
405 &gEfiPciIoProtocolGuid,
406 This->DriverBindingHandle,
407 Private->Handle
408 );
409
410 //
411 // Free our instance data
412 //
413 FreeUnicodeStringTable (Private->ControllerNameTable);
414
415 gBS->FreePool (Private);
416 }
417
418 return Status;
419}
420
421///
422/// This protocol provides the services required to determine if a driver supports a given controller.
423/// If a controller is supported, then it also provides routines to start and stop the controller.
424///
425EFI_DRIVER_BINDING_PROTOCOL gEmuGopDriverBinding = {
426 EmuGopDriverBindingSupported,
427 EmuGopDriverBindingStart,
428 EmuGopDriverBindingStop,
429 0xa,
430 NULL,
431 NULL
432};
433
434/**
435 The user Entry Point for module EmuGop. The user code starts with this function.
436
437 @param[in] ImageHandle The firmware allocated handle for the EFI image.
438 @param[in] SystemTable A pointer to the EFI System Table.
439
440 @retval EFI_SUCCESS The entry point is executed successfully.
441 @retval other Some error occurs when executing this entry point.
442
443**/
444EFI_STATUS
445EFIAPI
446InitializeEmuGop (
447 IN EFI_HANDLE ImageHandle,
448 IN EFI_SYSTEM_TABLE *SystemTable
449 )
450{
451 EFI_STATUS Status;
452
453 Status = EfiLibInstallDriverBindingComponentName2 (
454 ImageHandle,
455 SystemTable,
456 &gEmuGopDriverBinding,
457 ImageHandle,
458 &gEmuGopComponentName,
459 &gEmuGopComponentName2
460 );
461 ASSERT_EFI_ERROR (Status);
462
463 return Status;
464}
465
466STATIC VOID
467BhyveGetGraphicsMode (
468 EFI_PCI_IO_PROTOCOL *PciIo,
469 UINT16 *Width,
470 UINT16 *Height,
471 UINT16 *Depth
472 )
473{
474 BHYVE_FBUF_MEMREGS BhyveRegs;
475 UINT64 Offset;
476 EFI_STATUS Status;
477
478 Offset = (UINT64)&BhyveRegs.Width - (UINT64)&BhyveRegs;
479
480 Status = PciIo->Mem.Read (
481 PciIo,
482 EfiPciIoWidthUint16,
483 PCI_BAR_IDX0,
484 Offset,
485 3,
486 &BhyveRegs.Width
487 );
488
489 *Width = BhyveRegs.Width;
490 *Height = BhyveRegs.Height;
491 *Depth = BhyveRegs.Depth;
492
493 DEBUG ((DEBUG_INFO, "BHYVE Get Graphics Mode: w %d, h %d\n", *Width, *Height));
494
495 ASSERT_EFI_ERROR (Status);
496}
497
498VOID
499BhyveSetGraphicsMode (
500 GOP_PRIVATE_DATA *Private,
501 UINT16 Width,
502 UINT16 Height,
503 UINT16 Depth
504 )
505{
506 BHYVE_FBUF_MEMREGS BhyveRegs;
507 UINT64 Offset;
508 EFI_STATUS Status;
509
510 DEBUG ((DEBUG_INFO, "BHYVE Set Graphics Mode: w %d, h %d\n", Width, Height));
511
512 BhyveRegs.Width = Width;
513 BhyveRegs.Height = Height;
514 BhyveRegs.Depth = Depth;
515 Offset = (UINT64)&BhyveRegs.Width - (UINT64)&BhyveRegs;
516
517 Status = Private->PciIo->Mem.Write (
518 Private->PciIo,
519 EfiPciIoWidthUint16,
520 PCI_BAR_IDX0,
521 Offset,
522 3,
523 &BhyveRegs.Width
524 );
525 ASSERT_EFI_ERROR (Status);
526}
527
528VOID
529BhyveGetMemregs (
530 GOP_PRIVATE_DATA *Private,
531 BHYVE_FBUF_MEMREGS *Memregs
532 )
533{
534 EFI_STATUS Status;
535
536 Status = Private->PciIo->Mem.Read (
537 Private->PciIo,
538 EfiPciIoWidthUint32,
539 PCI_BAR_IDX0,
540 0,
541 3,
542 Memregs
543 );
544 ASSERT_EFI_ERROR (Status);
545
546 DEBUG ((
547 DEBUG_INFO,
548 "BHYVE Get Memregs, size %d width %d height %d\n",
549 Memregs->FbSize,
550 Memregs->Width,
551 Memregs->Height
552 ));
553}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette