VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.9 KB
Line 
1/* $Id: VBoxVgaUgaDraw.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBoxVgaUgaDraw.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
40 This file produces the graphics abstraction of UGA Draw. It is called by
41 VBoxVga.c file which deals with the EFI 1.1 driver model.
42 This file just does graphics.
43
44 Copyright (c) 2006, Intel Corporation
45 All rights reserved. This program and the accompanying materials
46 are licensed and made available under the terms and conditions of the BSD License
47 which accompanies this distribution. The full text of the license may be found at
48 http://opensource.org/licenses/bsd-license.php
49
50 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
51 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
52
53*/
54
55#include "VBoxVga.h"
56
57//
58// UGA Draw Protocol Member Functions
59//
60EFI_STATUS
61EFIAPI
62VBoxVgaUgaDrawGetMode (
63 IN EFI_UGA_DRAW_PROTOCOL *This,
64 OUT UINT32 *HorizontalResolution,
65 OUT UINT32 *VerticalResolution,
66 OUT UINT32 *ColorDepth,
67 OUT UINT32 *RefreshRate
68 )
69{
70 VBOX_VGA_PRIVATE_DATA *Private;
71
72 Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
73
74 if (Private->HardwareNeedsStarting) {
75 return EFI_NOT_STARTED;
76 }
77
78 if ((HorizontalResolution == NULL) ||
79 (VerticalResolution == NULL) ||
80 (ColorDepth == NULL) ||
81 (RefreshRate == NULL)) {
82 return EFI_INVALID_PARAMETER;
83 }
84
85 *HorizontalResolution = Private->ModeData[Private->CurrentMode].HorizontalResolution;
86 *VerticalResolution = Private->ModeData[Private->CurrentMode].VerticalResolution;
87 *ColorDepth = Private->ModeData[Private->CurrentMode].ColorDepth;
88 *RefreshRate = Private->ModeData[Private->CurrentMode].RefreshRate;
89 return EFI_SUCCESS;
90}
91
92EFI_STATUS
93EFIAPI
94VBoxVgaUgaDrawSetMode (
95 IN EFI_UGA_DRAW_PROTOCOL *This,
96 IN UINT32 HorizontalResolution,
97 IN UINT32 VerticalResolution,
98 IN UINT32 ColorDepth,
99 IN UINT32 RefreshRate
100 )
101{
102 VBOX_VGA_PRIVATE_DATA *Private;
103 UINTN Index;
104
105 DEBUG((DEBUG_INFO, "%a:%d VIDEO: %dx%d %d bpp\n", __FILE__, __LINE__, HorizontalResolution, VerticalResolution, ColorDepth));
106 Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
107
108 for (Index = 0; Index < Private->MaxMode; Index++) {
109
110 if (HorizontalResolution != Private->ModeData[Index].HorizontalResolution) {
111 continue;
112 }
113
114 if (VerticalResolution != Private->ModeData[Index].VerticalResolution) {
115 continue;
116 }
117
118 if (ColorDepth != Private->ModeData[Index].ColorDepth) {
119 continue;
120 }
121
122#if 0
123 if (RefreshRate != Private->ModeData[Index].RefreshRate) {
124 continue;
125 }
126#endif
127
128 InitializeGraphicsMode (Private, &VBoxVgaVideoModes[Private->ModeData[Index].ModeNumber]);
129
130 Private->CurrentMode = Index;
131
132 Private->HardwareNeedsStarting = FALSE;
133
134 /* update current mode */
135 Private->CurrentMode = Index;
136 return EFI_SUCCESS;
137 }
138
139 return EFI_NOT_FOUND;
140}
141
142EFI_STATUS
143EFIAPI
144VBoxVgaUgaDrawBlt (
145 IN EFI_UGA_DRAW_PROTOCOL *This,
146 IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
147 IN EFI_UGA_BLT_OPERATION BltOperation,
148 IN UINTN SourceX,
149 IN UINTN SourceY,
150 IN UINTN DestinationX,
151 IN UINTN DestinationY,
152 IN UINTN Width,
153 IN UINTN Height,
154 IN UINTN Delta
155 )
156{
157 VBOX_VGA_PRIVATE_DATA *Private;
158 EFI_TPL OriginalTPL;
159 UINTN DstY;
160 UINTN SrcY;
161 UINTN ScreenWidth;
162 UINTN ScreenHeight;
163 EFI_STATUS Status;
164
165 Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
166 ScreenWidth = Private->ModeData[Private->CurrentMode].HorizontalResolution;
167 ScreenHeight = Private->ModeData[Private->CurrentMode].VerticalResolution;
168
169 if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) {
170 return EFI_INVALID_PARAMETER;
171 }
172
173 if (Width == 0 || Height == 0) {
174 return EFI_INVALID_PARAMETER;
175 }
176
177 //
178 // If Delta is zero, then the entire BltBuffer is being used, so Delta
179 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
180 // the number of bytes in each row can be computed.
181 //
182 if (Delta == 0) {
183 Delta = Width * sizeof (EFI_UGA_PIXEL);
184 }
185 // code below assumes a Delta value in pixels, not bytes
186 Delta /= sizeof (EFI_UGA_PIXEL);
187
188 //
189 // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
190 // are valid for the operation and the current screen geometry.
191 //
192 if (BltOperation == EfiUgaVideoToBltBuffer || BltOperation == EfiUgaVideoToVideo) {
193 if (SourceY + Height > ScreenHeight) {
194 return EFI_INVALID_PARAMETER;
195 }
196
197 if (SourceX + Width > ScreenWidth) {
198 return EFI_INVALID_PARAMETER;
199 }
200 }
201 if (BltOperation == EfiUgaBltBufferToVideo || BltOperation == EfiUgaVideoToVideo || BltOperation == EfiUgaVideoFill) {
202 if (DestinationY + Height > ScreenHeight) {
203 return EFI_INVALID_PARAMETER;
204 }
205
206 if (DestinationX + Width > ScreenWidth) {
207 return EFI_INVALID_PARAMETER;
208 }
209 }
210
211 //
212 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
213 // We would not want a timer based event (Cursor, ...) to come in while we are
214 // doing this operation.
215 //
216 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
217
218 switch (BltOperation) {
219 case EfiUgaVideoToBltBuffer:
220 //
221 // Video to BltBuffer: Source is Video, destination is BltBuffer
222 //
223 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
224 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
225 Status = Private->PciIo->Mem.Read (
226 Private->PciIo,
227 EfiPciIoWidthUint32,
228 Private->BarIndexFB,
229 ((SrcY * ScreenWidth) + SourceX) * 4,
230 Width,
231 BltBuffer + (DstY * Delta) + DestinationX
232 );
233 ASSERT_EFI_ERROR((Status));
234 }
235 break;
236
237 case EfiUgaBltBufferToVideo:
238 //
239 // BltBuffer to Video: Source is BltBuffer, destination is Video
240 //
241 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
242 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
243 Status = Private->PciIo->Mem.Write (
244 Private->PciIo,
245 EfiPciIoWidthUint32,
246 Private->BarIndexFB,
247 ((DstY * ScreenWidth) + DestinationX) * 4,
248 Width,
249 BltBuffer + (SrcY * Delta) + SourceX
250 );
251 ASSERT_EFI_ERROR((Status));
252 }
253 break;
254
255 case EfiUgaVideoToVideo:
256 //
257 // Video to Video: Source is Video, destination is Video
258 //
259 if (DestinationY <= SourceY) {
260 // forward copy
261 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
262 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
263 Status = Private->PciIo->CopyMem (
264 Private->PciIo,
265 EfiPciIoWidthUint32,
266 Private->BarIndexFB,
267 ((DstY * ScreenWidth) + DestinationX) * 4,
268 Private->BarIndexFB,
269 ((SrcY * ScreenWidth) + SourceX) * 4,
270 Width
271 );
272 ASSERT_EFI_ERROR((Status));
273 }
274 } else {
275 // reverse copy
276 for (SrcY = SourceY + Height - 1, DstY = DestinationY + Height - 1; SrcY >= SourceY && SrcY <= SourceY + Height - 1; SrcY--, DstY--) {
277 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
278 Status = Private->PciIo->CopyMem (
279 Private->PciIo,
280 EfiPciIoWidthUint32,
281 Private->BarIndexFB,
282 ((DstY * ScreenWidth) + DestinationX) * 4,
283 Private->BarIndexFB,
284 ((SrcY * ScreenWidth) + SourceX) * 4,
285 Width
286 );
287 ASSERT_EFI_ERROR((Status));
288 }
289 }
290 break;
291
292 case EfiUgaVideoFill:
293 //
294 // Video Fill: Source is BltBuffer, destination is Video
295 //
296 if (DestinationX == 0 && Width == ScreenWidth) {
297 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_UGA_PIXEL
298 Status = Private->PciIo->Mem.Write (
299 Private->PciIo,
300 EfiPciIoWidthFillUint32,
301 Private->BarIndexFB,
302 DestinationY * ScreenWidth * 4,
303 (Width * Height),
304 BltBuffer
305 );
306 ASSERT_EFI_ERROR((Status));
307 } else {
308 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
309 /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_UGA_PIXEL
310 Private->PciIo->Mem.Write (
311 Private->PciIo,
312 EfiPciIoWidthFillUint32,
313 Private->BarIndexFB,
314 ((DstY * ScreenWidth) + DestinationX) * 4,
315 Width,
316 BltBuffer
317 );
318 }
319 }
320 break;
321
322 default:
323 ASSERT (FALSE);
324 }
325
326 gBS->RestoreTPL (OriginalTPL);
327
328 return EFI_SUCCESS;
329}
330
331//
332// Construction and Destruction functions
333//
334EFI_STATUS
335VBoxVgaUgaDrawConstructor (
336 VBOX_VGA_PRIVATE_DATA *Private
337 )
338{
339 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
340 UINT32 Index;
341 UINT32 HorizontalResolution = 1024;
342 UINT32 VerticalResolution = 768;
343 UINT32 ColorDepth = 32;
344
345 //
346 // Fill in Private->UgaDraw protocol
347 //
348 UgaDraw = &Private->UgaDraw;
349
350 UgaDraw->GetMode = VBoxVgaUgaDrawGetMode;
351 UgaDraw->SetMode = VBoxVgaUgaDrawSetMode;
352 UgaDraw->Blt = VBoxVgaUgaDrawBlt;
353
354 //
355 // Initialize the private data
356 //
357 Private->CurrentMode = 0;
358 Private->HardwareNeedsStarting = TRUE;
359
360 //
361 // Initialize the hardware
362 //
363 VBoxVgaGetVmVariable(EFI_INFO_INDEX_HORIZONTAL_RESOLUTION, (CHAR8 *)&HorizontalResolution,
364 sizeof(HorizontalResolution));
365 VBoxVgaGetVmVariable(EFI_INFO_INDEX_VERTICAL_RESOLUTION, (CHAR8 *)&VerticalResolution,
366 sizeof(VerticalResolution));
367 for (Index = 0; Index < Private->MaxMode; Index++)
368 {
369 if ( HorizontalResolution == Private->ModeData[Index].HorizontalResolution
370 && VerticalResolution == Private->ModeData[Index].VerticalResolution
371 && ColorDepth == Private->ModeData[Index].ColorDepth)
372 break;
373 }
374 // not found? try mode number
375 if (Index >= Private->MaxMode)
376 {
377 VBoxVgaGetVmVariable(EFI_INFO_INDEX_GRAPHICS_MODE, (CHAR8 *)&Index, sizeof(Index));
378 // try with mode 2 (usually 1024x768) as a fallback
379 if (Index >= Private->MaxMode)
380 Index = 2;
381 // try with mode 0 (usually 640x480) as a fallback
382 if (Index >= Private->MaxMode)
383 Index = 0;
384
385 // get the resolution from the mode if valid
386 if (Index < Private->MaxMode)
387 {
388 HorizontalResolution = Private->ModeData[Index].HorizontalResolution;
389 VerticalResolution = Private->ModeData[Index].VerticalResolution;
390 ColorDepth = Private->ModeData[Index].ColorDepth;
391 }
392 }
393
394 // skip mode setting completely if there is no valid mode
395 if (Index >= Private->MaxMode)
396 return EFI_UNSUPPORTED;
397
398 UgaDraw->SetMode (
399 UgaDraw,
400 HorizontalResolution,
401 VerticalResolution,
402 ColorDepth,
403 60
404 );
405
406 DrawLogo (
407 Private,
408 Private->ModeData[Private->CurrentMode].HorizontalResolution,
409 Private->ModeData[Private->CurrentMode].VerticalResolution
410 );
411
412 PcdSet32S(PcdVideoHorizontalResolution, HorizontalResolution);
413 PcdSet32S(PcdVideoVerticalResolution, VerticalResolution);
414
415 return EFI_SUCCESS;
416}
417
Note: See TracBrowser for help on using the repository browser.

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