VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.4 KB
Line 
1/* $Id: VBoxVgaGraphicsOutput.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBoxVgaGraphicsOutput.c
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37/*
38 This code is based on:
39
40Copyright (c) 2007, Intel Corporation
41All rights reserved. This program and the accompanying materials
42are licensed and made available under the terms and conditions of the BSD License
43which accompanies this distribution. The full text of the license may be found at
44http://opensource.org/licenses/bsd-license.php
45
46THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
47WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
48
49Module Name:
50
51 UefiVBoxVgaGraphicsOutput.c
52
53Abstract:
54
55 This file produces the graphics abstraction of Graphics Output Protocol. It is called by
56 VBoxVga.c file which deals with the EFI 1.1 driver model.
57 This file just does graphics.
58
59*/
60#include "VBoxVga.h"
61#include <IndustryStandard/Acpi.h>
62
63
64STATIC
65VOID
66VBoxVgaCompleteModeInfo (
67 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info
68 )
69{
70 Info->Version = 0;
71 Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
72 Info->PixelsPerScanLine = Info->HorizontalResolution;
73}
74
75
76STATIC
77EFI_STATUS
78VBoxVgaCompleteModeData (
79 IN VBOX_VGA_PRIVATE_DATA *Private,
80 OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
81 )
82{
83 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
84 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
85
86 Info = Mode->Info;
87 VBoxVgaCompleteModeInfo (Info);
88
89 Private->PciIo->GetBarAttributes (
90 Private->PciIo,
91 Private->BarIndexFB,
92 NULL,
93 (VOID**) &FrameBufDesc
94 );
95
96 DEBUG((DEBUG_INFO, "%a:%d FrameBufferBase:%x\n", __FILE__, __LINE__, FrameBufDesc->AddrRangeMin));
97 Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin;
98 Mode->FrameBufferSize = Info->PixelsPerScanLine * Info->VerticalResolution
99 * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); /* 32bpp only! */
100
101 return EFI_SUCCESS;
102}
103
104
105//
106// Graphics Output Protocol Member Functions
107//
108EFI_STATUS
109EFIAPI
110VBoxVgaGraphicsOutputQueryMode (
111 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
112 IN UINT32 ModeNumber,
113 OUT UINTN *SizeOfInfo,
114 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
115 )
116/*++
117
118Routine Description:
119
120 Graphics Output protocol interface to query video mode
121
122 Arguments:
123 This - Protocol instance pointer.
124 ModeNumber - The mode number to return information on.
125 Info - Caller allocated buffer that returns information about ModeNumber.
126 SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
127
128 Returns:
129 EFI_SUCCESS - Mode information returned.
130 EFI_BUFFER_TOO_SMALL - The Info buffer was too small.
131 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
132 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
133 EFI_INVALID_PARAMETER - One of the input args was NULL.
134
135--*/
136{
137 VBOX_VGA_PRIVATE_DATA *Private;
138
139 Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
140
141 if (Private->HardwareNeedsStarting) {
142 return EFI_NOT_STARTED;
143 }
144
145 if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
146 return EFI_INVALID_PARAMETER;
147 }
148
149 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
150 if (*Info == NULL) {
151 return EFI_OUT_OF_RESOURCES;
152 }
153
154 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
155
156 (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
157 (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution;
158 VBoxVgaCompleteModeInfo (*Info);
159
160 return EFI_SUCCESS;
161}
162
163EFI_STATUS
164EFIAPI
165VBoxVgaGraphicsOutputSetMode (
166 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
167 IN UINT32 ModeNumber
168 )
169/*++
170
171Routine Description:
172
173 Graphics Output protocol interface to set video mode
174
175 Arguments:
176 This - Protocol instance pointer.
177 ModeNumber - The mode number to be set.
178
179 Returns:
180 EFI_SUCCESS - Graphics mode was changed.
181 EFI_DEVICE_ERROR - The device had an error and could not complete the request.
182 EFI_UNSUPPORTED - ModeNumber is not supported by this device.
183
184--*/
185{
186 VBOX_VGA_PRIVATE_DATA *Private;
187 VBOX_VGA_MODE_DATA *ModeData;
188
189 Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
190
191 DEBUG((DEBUG_INFO, "%a:%d mode:%d\n", __FILE__, __LINE__, ModeNumber));
192 if (ModeNumber >= This->Mode->MaxMode) {
193 return EFI_UNSUPPORTED;
194 }
195
196 ModeData = &Private->ModeData[ModeNumber];
197
198 InitializeGraphicsMode (Private, &VBoxVgaVideoModes[ModeData->ModeNumber]);
199
200 This->Mode->Mode = ModeNumber;
201 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
202 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
203 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
204
205 VBoxVgaCompleteModeData (Private, This->Mode);
206
207 Private->HardwareNeedsStarting = FALSE;
208 /* update current mode */
209 Private->CurrentMode = ModeNumber;
210
211 return EFI_SUCCESS;
212}
213
214EFI_STATUS
215EFIAPI
216VBoxVgaGraphicsOutputBlt (
217 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
218 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
219 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
220 IN UINTN SourceX,
221 IN UINTN SourceY,
222 IN UINTN DestinationX,
223 IN UINTN DestinationY,
224 IN UINTN Width,
225 IN UINTN Height,
226 IN UINTN Delta
227 )
228/*++
229
230Routine Description:
231
232 Graphics Output protocol instance to block transfer for CirrusLogic device
233
234Arguments:
235
236 This - Pointer to Graphics Output protocol instance
237 BltBuffer - The data to transfer to screen
238 BltOperation - The operation to perform
239 SourceX - The X coordinate of the source for BltOperation
240 SourceY - The Y coordinate of the source for BltOperation
241 DestinationX - The X coordinate of the destination for BltOperation
242 DestinationY - The Y coordinate of the destination for BltOperation
243 Width - The width of a rectangle in the blt rectangle in pixels
244 Height - The height of a rectangle in the blt rectangle in pixels
245 Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
246 If a Delta of 0 is used, the entire BltBuffer will be operated on.
247 If a subrectangle of the BltBuffer is used, then Delta represents
248 the number of bytes in a row of the BltBuffer.
249
250Returns:
251
252 EFI_INVALID_PARAMETER - Invalid parameter passed in
253 EFI_SUCCESS - Blt operation success
254
255--*/
256{
257 VBOX_VGA_PRIVATE_DATA *Private;
258 EFI_TPL OriginalTPL;
259 UINTN DstY;
260 UINTN SrcY;
261 UINT32 CurrentMode;
262 UINTN ScreenWidth;
263 UINTN ScreenHeight;
264 EFI_STATUS Status;
265
266 Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
267 CurrentMode = This->Mode->Mode;
268 ScreenWidth = Private->ModeData[CurrentMode].HorizontalResolution;
269 ScreenHeight = Private->ModeData[CurrentMode].VerticalResolution;
270
271 if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
272 return EFI_INVALID_PARAMETER;
273 }
274 if (Width == 0 || Height == 0) {
275 return EFI_INVALID_PARAMETER;
276 }
277
278 //
279 // If Delta is zero, then the entire BltBuffer is being used, so Delta
280 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
281 // the number of bytes in each row can be computed.
282 //
283 if (Delta == 0) {
284 Delta = Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
285 }
286 // code below assumes a Delta value in pixels, not bytes
287 Delta /= sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
288
289 //
290 // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
291 // are valid for the operation and the current screen geometry.
292 //
293 if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
294 if (SourceY + Height > ScreenHeight) {
295 return EFI_INVALID_PARAMETER;
296 }
297
298 if (SourceX + Width > ScreenWidth) {
299 return EFI_INVALID_PARAMETER;
300 }
301 }
302 if (BltOperation == EfiBltBufferToVideo || BltOperation == EfiBltVideoToVideo || BltOperation == EfiBltVideoFill) {
303 if (DestinationY + Height > ScreenHeight) {
304 return EFI_INVALID_PARAMETER;
305 }
306
307 if (DestinationX + Width > ScreenWidth) {
308 return EFI_INVALID_PARAMETER;
309 }
310 }
311
312 //
313 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
314 // We would not want a timer based event (Cursor, ...) to come in while we are
315 // doing this operation.
316 //
317 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
318
319 switch (BltOperation) {
320 case EfiBltVideoToBltBuffer:
321 //
322 // Video to BltBuffer: Source is Video, destination is BltBuffer
323 //
324 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY) && BltBuffer; SrcY++, DstY++) {
325 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
326 Status = Private->PciIo->Mem.Read (
327 Private->PciIo,
328 EfiPciIoWidthUint32,
329 Private->BarIndexFB,
330 ((SrcY * ScreenWidth) + SourceX) * 4,
331 Width,
332 BltBuffer + (DstY * Delta) + DestinationX
333 );
334 ASSERT_EFI_ERROR((Status));
335 }
336 break;
337
338 case EfiBltBufferToVideo:
339 //
340 // BltBuffer to Video: Source is BltBuffer, destination is Video
341 //
342 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
343 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
344 Status = Private->PciIo->Mem.Write (
345 Private->PciIo,
346 EfiPciIoWidthUint32,
347 Private->BarIndexFB,
348 ((DstY * ScreenWidth) + DestinationX) * 4,
349 Width,
350 BltBuffer + (SrcY * Delta) + SourceX
351 );
352 ASSERT_EFI_ERROR((Status));
353 }
354 break;
355
356 case EfiBltVideoToVideo:
357 //
358 // Video to Video: Source is Video, destination is Video
359 //
360 if (DestinationY <= SourceY) {
361 // forward copy
362 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
363 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
364 Status = Private->PciIo->CopyMem (
365 Private->PciIo,
366 EfiPciIoWidthUint32,
367 Private->BarIndexFB,
368 ((DstY * ScreenWidth) + DestinationX) * 4,
369 Private->BarIndexFB,
370 ((SrcY * ScreenWidth) + SourceX) * 4,
371 Width
372 );
373 ASSERT_EFI_ERROR((Status));
374 }
375 } else {
376 // reverse copy
377 for (SrcY = SourceY + Height - 1, DstY = DestinationY + Height - 1; SrcY >= SourceY && SrcY <= SourceY + Height - 1; SrcY--, DstY--) {
378 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
379 Status = Private->PciIo->CopyMem (
380 Private->PciIo,
381 EfiPciIoWidthUint32,
382 Private->BarIndexFB,
383 ((DstY * ScreenWidth) + DestinationX) * 4,
384 Private->BarIndexFB,
385 ((SrcY * ScreenWidth) + SourceX) * 4,
386 Width
387 );
388 ASSERT_EFI_ERROR((Status));
389 }
390 }
391 break;
392
393 case EfiBltVideoFill:
394 //
395 // Video Fill: Source is BltBuffer, destination is Video
396 //
397 if (DestinationX == 0 && Width == ScreenWidth) {
398 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
399 Status = Private->PciIo->Mem.Write (
400 Private->PciIo,
401 EfiPciIoWidthFillUint32,
402 Private->BarIndexFB,
403 DestinationY * ScreenWidth * 4,
404 (Width * Height),
405 BltBuffer
406 );
407 ASSERT_EFI_ERROR((Status));
408 } else {
409 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
410 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
411 Status = Private->PciIo->Mem.Write (
412 Private->PciIo,
413 EfiPciIoWidthFillUint32,
414 Private->BarIndexFB,
415 ((DstY * ScreenWidth) + DestinationX) * 4,
416 Width,
417 BltBuffer
418 );
419 ASSERT_EFI_ERROR((Status));
420 }
421 }
422 break;
423
424 default:
425 ASSERT (FALSE);
426 }
427
428 gBS->RestoreTPL (OriginalTPL);
429
430 return EFI_SUCCESS;
431}
432
433EFI_STATUS
434VBoxVgaGraphicsOutputConstructor (
435 VBOX_VGA_PRIVATE_DATA *Private
436 )
437{
438 EFI_STATUS Status;
439 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
440 UINT32 Index;
441 UINT32 HorizontalResolution = 1024;
442 UINT32 VerticalResolution = 768;
443 UINT32 ColorDepth = 32;
444
445 DEBUG((DEBUG_INFO, "%a:%d construct\n", __FILE__, __LINE__));
446
447 GraphicsOutput = &Private->GraphicsOutput;
448 GraphicsOutput->QueryMode = VBoxVgaGraphicsOutputQueryMode;
449 GraphicsOutput->SetMode = VBoxVgaGraphicsOutputSetMode;
450 GraphicsOutput->Blt = VBoxVgaGraphicsOutputBlt;
451
452 //
453 // Initialize the private data
454 //
455 Status = gBS->AllocatePool (
456 EfiBootServicesData,
457 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
458 (VOID **) &Private->GraphicsOutput.Mode
459 );
460 if (EFI_ERROR (Status)) {
461 return Status;
462 }
463 Status = gBS->AllocatePool (
464 EfiBootServicesData,
465 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
466 (VOID **) &Private->GraphicsOutput.Mode->Info
467 );
468 if (EFI_ERROR (Status)) {
469 return Status;
470 }
471 Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;
472 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
473 Private->HardwareNeedsStarting = TRUE;
474
475 //
476 // Initialize the hardware
477 //
478 VBoxVgaGetVmVariable(EFI_INFO_INDEX_HORIZONTAL_RESOLUTION, (CHAR8 *)&HorizontalResolution,
479 sizeof(HorizontalResolution));
480 VBoxVgaGetVmVariable(EFI_INFO_INDEX_VERTICAL_RESOLUTION, (CHAR8 *)&VerticalResolution,
481 sizeof(VerticalResolution));
482 for (Index = 0; Index < Private->MaxMode; Index++)
483 {
484 if ( HorizontalResolution == Private->ModeData[Index].HorizontalResolution
485 && VerticalResolution == Private->ModeData[Index].VerticalResolution
486 && ColorDepth == Private->ModeData[Index].ColorDepth)
487 break;
488 }
489 // not found? try mode number
490 if (Index >= Private->MaxMode)
491 {
492 VBoxVgaGetVmVariable(EFI_INFO_INDEX_GRAPHICS_MODE, (CHAR8 *)&Index, sizeof(Index));
493 // try with mode 2 (usually 1024x768) as a fallback
494 if (Index >= Private->MaxMode)
495 Index = 2;
496 // try with mode 0 (usually 640x480) as a fallback
497 if (Index >= Private->MaxMode)
498 Index = 0;
499 }
500
501 // skip mode setting completely if there is no valid mode
502 if (Index >= Private->MaxMode)
503 return EFI_UNSUPPORTED;
504
505 GraphicsOutput->SetMode (GraphicsOutput, Index);
506
507 DrawLogo (
508 Private,
509 Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,
510 Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution
511 );
512
513 PcdSet32S(PcdVideoHorizontalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution);
514 PcdSet32S(PcdVideoVerticalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution);
515
516 return EFI_SUCCESS;
517}
518
519EFI_STATUS
520VBoxVgaGraphicsOutputDestructor (
521 VBOX_VGA_PRIVATE_DATA *Private
522 )
523/*++
524
525Routine Description:
526
527Arguments:
528
529Returns:
530
531 None
532
533--*/
534{
535 if (Private->GraphicsOutput.Mode != NULL) {
536 if (Private->GraphicsOutput.Mode->Info != NULL) {
537 gBS->FreePool (Private->GraphicsOutput.Mode->Info);
538 }
539 gBS->FreePool (Private->GraphicsOutput.Mode);
540 }
541
542 return EFI_SUCCESS;
543}
544
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use