VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/VirtioGpuDxe/Gop.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 23.1 KB
Line 
1/** @file
2
3 EFI_GRAPHICS_OUTPUT_PROTOCOL member functions for the VirtIo GPU driver.
4
5 Copyright (C) 2016, Red Hat, Inc.
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9**/
10
11#include <Library/MemoryAllocationLib.h>
12#include <Library/PcdLib.h>
13
14#include "VirtioGpu.h"
15
16/**
17 Release guest-side and host-side resources that are related to an initialized
18 VGPU_GOP.Gop.
19
20 param[in,out] VgpuGop The VGPU_GOP object to release resources for.
21
22 On input, the caller is responsible for having called
23 VgpuGop->Gop.SetMode() at least once successfully.
24 (This is equivalent to the requirement that
25 VgpuGop->BackingStore be non-NULL. It is also
26 equivalent to the requirement that VgpuGop->ResourceId
27 be nonzero.)
28
29 On output, resources will be released, and
30 VgpuGop->BackingStore and VgpuGop->ResourceId will be
31 nulled.
32
33 param[in] DisableHead Whether this head (scanout) currently references the
34 resource identified by VgpuGop->ResourceId. Only pass
35 FALSE when VgpuGop->Gop.SetMode() calls this function
36 while switching between modes, and set it to TRUE
37 every other time.
38**/
39VOID
40ReleaseGopResources (
41 IN OUT VGPU_GOP *VgpuGop,
42 IN BOOLEAN DisableHead
43 )
44{
45 EFI_STATUS Status;
46
47 ASSERT (VgpuGop->ResourceId != 0);
48 ASSERT (VgpuGop->BackingStore != NULL);
49
50 //
51 // If any of the following host-side destruction steps fail, we can't get out
52 // of an inconsistent state, so we'll hang. In general errors in object
53 // destruction can hardly be recovered from.
54 //
55 if (DisableHead) {
56 //
57 // Dissociate head (scanout) #0 from the currently used 2D host resource,
58 // by setting ResourceId=0 for it.
59 //
60 Status = VirtioGpuSetScanout (
61 VgpuGop->ParentBus, // VgpuDev
62 0,
63 0,
64 0,
65 0, // X, Y, Width, Height
66 0, // ScanoutId
67 0 // ResourceId
68 );
69 //
70 // HACK BEGINS HERE
71 //
72 // According to the GPU Device section of the VirtIo specification, the
73 // above operation is valid:
74 //
75 // "The driver can use resource_id = 0 to disable a scanout."
76 //
77 // However, in practice QEMU does not allow us to disable head (scanout) #0
78 // -- it rejects the command with response code 0x1202
79 // (VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID). Looking at the QEMU source
80 // code, function virtio_gpu_set_scanout() in "hw/display/virtio-gpu.c",
81 // this appears fully intentional, despite not being documented in the
82 // spec.
83 //
84 // Surprisingly, ignoring the error here, and proceeding to release
85 // host-side resources that presumably underlie head (scanout) #0, work
86 // without any problems -- the driver survives repeated "disconnect" /
87 // "connect -r" commands in the UEFI shell.
88 //
89 // So, for now, let's just suppress the error.
90 //
91 Status = EFI_SUCCESS;
92 //
93 // HACK ENDS HERE
94 //
95
96 ASSERT_EFI_ERROR (Status);
97 if (EFI_ERROR (Status)) {
98 CpuDeadLoop ();
99 }
100 }
101
102 //
103 // Detach backing pages from the currently used 2D host resource.
104 //
105 Status = VirtioGpuResourceDetachBacking (
106 VgpuGop->ParentBus, // VgpuDev
107 VgpuGop->ResourceId // ResourceId
108 );
109 ASSERT_EFI_ERROR (Status);
110 if (EFI_ERROR (Status)) {
111 CpuDeadLoop ();
112 }
113
114 //
115 // Unmap and release backing pages.
116 //
117 VirtioGpuUnmapAndFreeBackingStore (
118 VgpuGop->ParentBus, // VgpuDev
119 VgpuGop->NumberOfPages, // NumberOfPages
120 VgpuGop->BackingStore, // HostAddress
121 VgpuGop->BackingStoreMap // Mapping
122 );
123 VgpuGop->BackingStore = NULL;
124 VgpuGop->NumberOfPages = 0;
125 VgpuGop->BackingStoreMap = NULL;
126
127 //
128 // Destroy the currently used 2D host resource.
129 //
130 Status = VirtioGpuResourceUnref (
131 VgpuGop->ParentBus, // VgpuDev
132 VgpuGop->ResourceId // ResourceId
133 );
134 ASSERT_EFI_ERROR (Status);
135 if (EFI_ERROR (Status)) {
136 CpuDeadLoop ();
137 }
138
139 VgpuGop->ResourceId = 0;
140}
141
142//
143// The resolutions supported by this driver.
144//
145typedef struct {
146 UINT32 Width;
147 UINT32 Height;
148} GOP_RESOLUTION;
149
150STATIC CONST GOP_RESOLUTION mGopResolutions[] = {
151 { 640, 480 },
152 { 800, 480 },
153 { 800, 600 },
154 { 832, 624 },
155 { 960, 640 },
156 { 1024, 600 },
157 { 1024, 768 },
158 { 1152, 864 },
159 { 1152, 870 },
160 { 1280, 720 },
161 { 1280, 760 },
162 { 1280, 768 },
163 { 1280, 800 },
164 { 1280, 960 },
165 { 1280, 1024 },
166 { 1360, 768 },
167 { 1366, 768 },
168 { 1400, 1050 },
169 { 1440, 900 },
170 { 1600, 900 },
171 { 1600, 1200 },
172 { 1680, 1050 },
173 { 1920, 1080 },
174 { 1920, 1200 },
175 { 1920, 1440 },
176 { 2000, 2000 },
177 { 2048, 1536 },
178 { 2048, 2048 },
179 { 2560, 1440 },
180 { 2560, 1600 },
181 { 2560, 2048 },
182 { 2800, 2100 },
183 { 3200, 2400 },
184 { 3840, 2160 },
185 { 4096, 2160 },
186 { 7680, 4320 },
187 { 8192, 4320 },
188};
189
190//
191// Macro for casting VGPU_GOP.Gop to VGPU_GOP.
192//
193#define VGPU_GOP_FROM_GOP(GopPointer) \
194 CR (GopPointer, VGPU_GOP, Gop, VGPU_GOP_SIG)
195
196STATIC
197VOID
198EFIAPI
199GopNativeResolution (
200 IN VGPU_GOP *VgpuGop,
201 OUT UINT32 *XRes,
202 OUT UINT32 *YRes
203 )
204{
205 volatile VIRTIO_GPU_RESP_DISPLAY_INFO DisplayInfo;
206 EFI_STATUS Status;
207 UINTN Index;
208
209 Status = VirtioGpuGetDisplayInfo (VgpuGop->ParentBus, &DisplayInfo);
210 if (Status != EFI_SUCCESS) {
211 return;
212 }
213
214 for (Index = 0; Index < VIRTIO_GPU_MAX_SCANOUTS; Index++) {
215 if (!DisplayInfo.Pmodes[Index].Enabled ||
216 !DisplayInfo.Pmodes[Index].Rectangle.Width ||
217 !DisplayInfo.Pmodes[Index].Rectangle.Height)
218 {
219 continue;
220 }
221
222 DEBUG ((
223 DEBUG_INFO,
224 "%a: #%d: %dx%d\n",
225 __func__,
226 Index,
227 DisplayInfo.Pmodes[Index].Rectangle.Width,
228 DisplayInfo.Pmodes[Index].Rectangle.Height
229 ));
230 if ((*XRes == 0) || (*YRes == 0)) {
231 *XRes = DisplayInfo.Pmodes[Index].Rectangle.Width;
232 *YRes = DisplayInfo.Pmodes[Index].Rectangle.Height;
233 }
234 }
235}
236
237STATIC
238VOID
239EFIAPI
240GopInitialize (
241 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This
242 )
243{
244 VGPU_GOP *VgpuGop;
245 EFI_STATUS Status;
246 UINT32 XRes = 0, YRes = 0, Index;
247
248 VgpuGop = VGPU_GOP_FROM_GOP (This);
249
250 //
251 // Set up the Gop -> GopMode -> GopModeInfo pointer chain, and the other
252 // (nonzero) constant fields.
253 //
254 // No direct framebuffer access is supported, only Blt() is.
255 //
256 VgpuGop->Gop.Mode = &VgpuGop->GopMode;
257
258 VgpuGop->GopMode.MaxMode = (UINT32)(ARRAY_SIZE (mGopResolutions));
259 VgpuGop->GopMode.Info = &VgpuGop->GopModeInfo;
260 VgpuGop->GopMode.SizeOfInfo = sizeof VgpuGop->GopModeInfo;
261
262 VgpuGop->GopModeInfo.PixelFormat = PixelBltOnly;
263
264 //
265 // query host for display resolution
266 //
267 GopNativeResolution (VgpuGop, &XRes, &YRes);
268 if ((XRes < 640) || (YRes < 480)) {
269 /* ignore hint, GraphicsConsoleDxe needs 640x480 or larger */
270 return;
271 }
272
273 if (PcdGet8 (PcdVideoResolutionSource) == 0) {
274 Status = PcdSet32S (PcdVideoHorizontalResolution, XRes);
275 ASSERT_RETURN_ERROR (Status);
276 Status = PcdSet32S (PcdSetupVideoHorizontalResolution, XRes);
277 ASSERT_RETURN_ERROR (Status);
278 Status = PcdSet32S (PcdVideoVerticalResolution, YRes);
279 ASSERT_RETURN_ERROR (Status);
280 Status = PcdSet32S (PcdSetupVideoVerticalResolution, YRes);
281 ASSERT_RETURN_ERROR (Status);
282 Status = PcdSet8S (PcdVideoResolutionSource, 2);
283 ASSERT_RETURN_ERROR (Status);
284 }
285
286 VgpuGop->NativeXRes = XRes;
287 VgpuGop->NativeYRes = YRes;
288 for (Index = 0; Index < ARRAY_SIZE (mGopResolutions); Index++) {
289 if ((mGopResolutions[Index].Width == XRes) &&
290 (mGopResolutions[Index].Height == YRes))
291 {
292 // native resolution already is in mode list
293 return;
294 }
295 }
296
297 // add to mode list
298 VgpuGop->GopMode.MaxMode++;
299}
300
301//
302// EFI_GRAPHICS_OUTPUT_PROTOCOL member functions.
303//
304STATIC
305EFI_STATUS
306EFIAPI
307GopQueryMode (
308 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
309 IN UINT32 ModeNumber,
310 OUT UINTN *SizeOfInfo,
311 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
312 )
313{
314 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *GopModeInfo;
315
316 if ((Info == NULL) ||
317 (SizeOfInfo == NULL) ||
318 (ModeNumber >= This->Mode->MaxMode))
319 {
320 return EFI_INVALID_PARAMETER;
321 }
322
323 GopModeInfo = AllocateZeroPool (sizeof *GopModeInfo);
324 if (GopModeInfo == NULL) {
325 return EFI_OUT_OF_RESOURCES;
326 }
327
328 if (ModeNumber < ARRAY_SIZE (mGopResolutions)) {
329 GopModeInfo->HorizontalResolution = mGopResolutions[ModeNumber].Width;
330 GopModeInfo->VerticalResolution = mGopResolutions[ModeNumber].Height;
331 } else {
332 VGPU_GOP *VgpuGop = VGPU_GOP_FROM_GOP (This);
333 GopModeInfo->HorizontalResolution = VgpuGop->NativeXRes;
334 GopModeInfo->VerticalResolution = VgpuGop->NativeYRes;
335 }
336
337 GopModeInfo->PixelFormat = PixelBltOnly;
338 GopModeInfo->PixelsPerScanLine = GopModeInfo->HorizontalResolution;
339
340 *SizeOfInfo = sizeof *GopModeInfo;
341 *Info = GopModeInfo;
342 return EFI_SUCCESS;
343}
344
345STATIC
346EFI_STATUS
347EFIAPI
348GopSetMode (
349 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
350 IN UINT32 ModeNumber
351 )
352{
353 VGPU_GOP *VgpuGop;
354 UINT32 NewResourceId;
355 UINTN NewNumberOfBytes;
356 UINTN NewNumberOfPages;
357 VOID *NewBackingStore;
358 EFI_PHYSICAL_ADDRESS NewBackingStoreDeviceAddress;
359 VOID *NewBackingStoreMap;
360 UINTN SizeOfInfo;
361 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *GopModeInfo;
362
363 EFI_STATUS Status;
364 EFI_STATUS Status2;
365
366 if (!This->Mode) {
367 // SetMode() call in InitVgpuGop() triggers this.
368 GopInitialize (This);
369 }
370
371 Status = GopQueryMode (This, ModeNumber, &SizeOfInfo, &GopModeInfo);
372 if (Status != EFI_SUCCESS) {
373 return Status;
374 }
375
376 VgpuGop = VGPU_GOP_FROM_GOP (This);
377
378 //
379 // Distinguish the first (internal) call from the other (protocol consumer)
380 // calls.
381 //
382 if (VgpuGop->ResourceId == 0) {
383 //
384 // This is the first time we create a host side resource.
385 //
386 NewResourceId = 1;
387 } else {
388 //
389 // We already have an active host side resource. Create the new one without
390 // interfering with the current one, so that we can cleanly bail out on
391 // error, without disturbing the current graphics mode.
392 //
393 // The formula below will alternate between IDs 1 and 2.
394 //
395 NewResourceId = 3 - VgpuGop->ResourceId;
396 }
397
398 //
399 // Create the 2D host resource.
400 //
401 Status = VirtioGpuResourceCreate2d (
402 VgpuGop->ParentBus, // VgpuDev
403 NewResourceId, // ResourceId
404 VirtioGpuFormatB8G8R8X8Unorm, // Format
405 GopModeInfo->HorizontalResolution, // Width
406 GopModeInfo->VerticalResolution // Height
407 );
408 if (EFI_ERROR (Status)) {
409 return Status;
410 }
411
412 //
413 // Allocate, zero and map guest backing store, for bus master common buffer
414 // operation.
415 //
416 NewNumberOfBytes = GopModeInfo->HorizontalResolution *
417 GopModeInfo->VerticalResolution * sizeof (UINT32);
418 NewNumberOfPages = EFI_SIZE_TO_PAGES (NewNumberOfBytes);
419 Status = VirtioGpuAllocateZeroAndMapBackingStore (
420 VgpuGop->ParentBus, // VgpuDev
421 NewNumberOfPages, // NumberOfPages
422 &NewBackingStore, // HostAddress
423 &NewBackingStoreDeviceAddress, // DeviceAddress
424 &NewBackingStoreMap // Mapping
425 );
426 if (EFI_ERROR (Status)) {
427 goto DestroyHostResource;
428 }
429
430 //
431 // Attach backing store to the host resource.
432 //
433 Status = VirtioGpuResourceAttachBacking (
434 VgpuGop->ParentBus, // VgpuDev
435 NewResourceId, // ResourceId
436 NewBackingStoreDeviceAddress, // BackingStoreDeviceAddress
437 NewNumberOfPages // NumberOfPages
438 );
439 if (EFI_ERROR (Status)) {
440 goto UnmapAndFreeBackingStore;
441 }
442
443 //
444 // Point head (scanout) #0 to the host resource.
445 //
446 Status = VirtioGpuSetScanout (
447 VgpuGop->ParentBus, // VgpuDev
448 0, // X
449 0, // Y
450 GopModeInfo->HorizontalResolution, // Width
451 GopModeInfo->VerticalResolution, // Height
452 0, // ScanoutId
453 NewResourceId // ResourceId
454 );
455 if (EFI_ERROR (Status)) {
456 goto DetachBackingStore;
457 }
458
459 //
460 // If this is not the first (i.e., internal) call, then we have to (a) flush
461 // the new resource to head (scanout) #0, after having flipped the latter to
462 // the former above, plus (b) release the old resources.
463 //
464 if (VgpuGop->ResourceId != 0) {
465 Status = VirtioGpuResourceFlush (
466 VgpuGop->ParentBus, // VgpuDev
467 0, // X
468 0, // Y
469 GopModeInfo->HorizontalResolution, // Width
470 GopModeInfo->VerticalResolution, // Height
471 NewResourceId // ResourceId
472 );
473 if (EFI_ERROR (Status)) {
474 //
475 // Flip head (scanout) #0 back to the current resource. If this fails, we
476 // cannot continue, as this error occurs on the error path and is
477 // therefore non-recoverable.
478 //
479 Status2 = VirtioGpuSetScanout (
480 VgpuGop->ParentBus, // VgpuDev
481 0, // X
482 0, // Y
483 VgpuGop->GopModeInfo.HorizontalResolution, // Width
484 VgpuGop->GopModeInfo.VerticalResolution, // Height
485 0, // ScanoutId
486 VgpuGop->ResourceId // ResourceId
487 );
488 ASSERT_EFI_ERROR (Status2);
489 if (EFI_ERROR (Status2)) {
490 CpuDeadLoop ();
491 }
492
493 goto DetachBackingStore;
494 }
495
496 //
497 // Flush successful; release the old resources (without disabling head
498 // (scanout) #0).
499 //
500 ReleaseGopResources (VgpuGop, FALSE /* DisableHead */);
501 }
502
503 //
504 // This is either the first (internal) call when we have no old resources
505 // yet, or we've changed the mode successfully and released the old
506 // resources.
507 //
508 ASSERT (VgpuGop->ResourceId == 0);
509 ASSERT (VgpuGop->BackingStore == NULL);
510
511 VgpuGop->ResourceId = NewResourceId;
512 VgpuGop->BackingStore = NewBackingStore;
513 VgpuGop->NumberOfPages = NewNumberOfPages;
514 VgpuGop->BackingStoreMap = NewBackingStoreMap;
515
516 //
517 // Populate Mode and ModeInfo (mutable fields only).
518 //
519 VgpuGop->GopMode.Mode = ModeNumber;
520 CopyMem (&VgpuGop->GopModeInfo, GopModeInfo, sizeof VgpuGop->GopModeInfo);
521 FreePool (GopModeInfo);
522 return EFI_SUCCESS;
523
524DetachBackingStore:
525 Status2 = VirtioGpuResourceDetachBacking (VgpuGop->ParentBus, NewResourceId);
526 ASSERT_EFI_ERROR (Status2);
527 if (EFI_ERROR (Status2)) {
528 CpuDeadLoop ();
529 }
530
531UnmapAndFreeBackingStore:
532 VirtioGpuUnmapAndFreeBackingStore (
533 VgpuGop->ParentBus, // VgpuDev
534 NewNumberOfPages, // NumberOfPages
535 NewBackingStore, // HostAddress
536 NewBackingStoreMap // Mapping
537 );
538
539DestroyHostResource:
540 Status2 = VirtioGpuResourceUnref (VgpuGop->ParentBus, NewResourceId);
541 ASSERT_EFI_ERROR (Status2);
542 if (EFI_ERROR (Status2)) {
543 CpuDeadLoop ();
544 }
545
546 FreePool (GopModeInfo);
547 return Status;
548}
549
550STATIC
551EFI_STATUS
552EFIAPI
553GopBlt (
554 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
555 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL,
556 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
557 IN UINTN SourceX,
558 IN UINTN SourceY,
559 IN UINTN DestinationX,
560 IN UINTN DestinationY,
561 IN UINTN Width,
562 IN UINTN Height,
563 IN UINTN Delta OPTIONAL
564 )
565{
566 VGPU_GOP *VgpuGop;
567 UINT32 CurrentHorizontal;
568 UINT32 CurrentVertical;
569 UINTN SegmentSize;
570 UINTN Y;
571 UINTN ResourceOffset;
572 EFI_STATUS Status;
573
574 VgpuGop = VGPU_GOP_FROM_GOP (This);
575 CurrentHorizontal = VgpuGop->GopModeInfo.HorizontalResolution;
576 CurrentVertical = VgpuGop->GopModeInfo.VerticalResolution;
577
578 //
579 // We can avoid pixel format conversion in the guest because the internal
580 // representation of EFI_GRAPHICS_OUTPUT_BLT_PIXEL and that of
581 // VirtioGpuFormatB8G8R8X8Unorm are identical.
582 //
583 SegmentSize = Width * sizeof (UINT32);
584
585 //
586 // Delta is relevant for operations that read a rectangle from, or write a
587 // rectangle to, BltBuffer.
588 //
589 // In these cases, Delta is the stride of BltBuffer, in bytes. If Delta is
590 // zero, then Width is the entire width of BltBuffer, and the stride is
591 // supposed to be calculated from Width.
592 //
593 if ((BltOperation == EfiBltVideoToBltBuffer) ||
594 (BltOperation == EfiBltBufferToVideo))
595 {
596 if (Delta == 0) {
597 Delta = SegmentSize;
598 }
599 }
600
601 //
602 // For operations that write to the display, check if the destination fits
603 // onto the display.
604 //
605 if ((BltOperation == EfiBltVideoFill) ||
606 (BltOperation == EfiBltBufferToVideo) ||
607 (BltOperation == EfiBltVideoToVideo))
608 {
609 if ((DestinationX > CurrentHorizontal) ||
610 (Width > CurrentHorizontal - DestinationX) ||
611 (DestinationY > CurrentVertical) ||
612 (Height > CurrentVertical - DestinationY))
613 {
614 return EFI_INVALID_PARAMETER;
615 }
616 }
617
618 //
619 // For operations that read from the display, check if the source fits onto
620 // the display.
621 //
622 if ((BltOperation == EfiBltVideoToBltBuffer) ||
623 (BltOperation == EfiBltVideoToVideo))
624 {
625 if ((SourceX > CurrentHorizontal) ||
626 (Width > CurrentHorizontal - SourceX) ||
627 (SourceY > CurrentVertical) ||
628 (Height > CurrentVertical - SourceY))
629 {
630 return EFI_INVALID_PARAMETER;
631 }
632 }
633
634 //
635 // Render the request. For requests that do not modify the display, there
636 // won't be further steps.
637 //
638 switch (BltOperation) {
639 case EfiBltVideoFill:
640 //
641 // Write data from the BltBuffer pixel (0, 0) directly to every pixel of
642 // the video display rectangle (DestinationX, DestinationY) (DestinationX +
643 // Width, DestinationY + Height). Only one pixel will be used from the
644 // BltBuffer. Delta is NOT used.
645 //
646 for (Y = 0; Y < Height; ++Y) {
647 SetMem32 (
648 VgpuGop->BackingStore +
649 (DestinationY + Y) * CurrentHorizontal + DestinationX,
650 SegmentSize,
651 *(UINT32 *)BltBuffer
652 );
653 }
654
655 break;
656
657 case EfiBltVideoToBltBuffer:
658 //
659 // Read data from the video display rectangle (SourceX, SourceY) (SourceX +
660 // Width, SourceY + Height) and place it in the BltBuffer rectangle
661 // (DestinationX, DestinationY ) (DestinationX + Width, DestinationY +
662 // Height). If DestinationX or DestinationY is not zero then Delta must be
663 // set to the length in bytes of a row in the BltBuffer.
664 //
665 for (Y = 0; Y < Height; ++Y) {
666 CopyMem (
667 (UINT8 *)BltBuffer +
668 (DestinationY + Y) * Delta + DestinationX * sizeof *BltBuffer,
669 VgpuGop->BackingStore +
670 (SourceY + Y) * CurrentHorizontal + SourceX,
671 SegmentSize
672 );
673 }
674
675 return EFI_SUCCESS;
676
677 case EfiBltBufferToVideo:
678 //
679 // Write data from the BltBuffer rectangle (SourceX, SourceY) (SourceX +
680 // Width, SourceY + Height) directly to the video display rectangle
681 // (DestinationX, DestinationY) (DestinationX + Width, DestinationY +
682 // Height). If SourceX or SourceY is not zero then Delta must be set to the
683 // length in bytes of a row in the BltBuffer.
684 //
685 for (Y = 0; Y < Height; ++Y) {
686 CopyMem (
687 VgpuGop->BackingStore +
688 (DestinationY + Y) * CurrentHorizontal + DestinationX,
689 (UINT8 *)BltBuffer +
690 (SourceY + Y) * Delta + SourceX * sizeof *BltBuffer,
691 SegmentSize
692 );
693 }
694
695 break;
696
697 case EfiBltVideoToVideo:
698 //
699 // Copy from the video display rectangle (SourceX, SourceY) (SourceX +
700 // Width, SourceY + Height) to the video display rectangle (DestinationX,
701 // DestinationY) (DestinationX + Width, DestinationY + Height). The
702 // BltBuffer and Delta are not used in this mode.
703 //
704 // A single invocation of CopyMem() handles overlap between source and
705 // destination (that is, within a single line), but for multiple
706 // invocations, we must handle overlaps.
707 //
708 if (SourceY < DestinationY) {
709 Y = Height;
710 while (Y > 0) {
711 --Y;
712 CopyMem (
713 VgpuGop->BackingStore +
714 (DestinationY + Y) * CurrentHorizontal + DestinationX,
715 VgpuGop->BackingStore +
716 (SourceY + Y) * CurrentHorizontal + SourceX,
717 SegmentSize
718 );
719 }
720 } else {
721 for (Y = 0; Y < Height; ++Y) {
722 CopyMem (
723 VgpuGop->BackingStore +
724 (DestinationY + Y) * CurrentHorizontal + DestinationX,
725 VgpuGop->BackingStore +
726 (SourceY + Y) * CurrentHorizontal + SourceX,
727 SegmentSize
728 );
729 }
730 }
731
732 break;
733
734 default:
735 return EFI_INVALID_PARAMETER;
736 }
737
738 //
739 // For operations that wrote to the display, submit the updated area to the
740 // host -- update the host resource from guest memory.
741 //
742 ResourceOffset = sizeof (UINT32) * (DestinationY * CurrentHorizontal +
743 DestinationX);
744 Status = VirtioGpuTransferToHost2d (
745 VgpuGop->ParentBus, // VgpuDev
746 (UINT32)DestinationX, // X
747 (UINT32)DestinationY, // Y
748 (UINT32)Width, // Width
749 (UINT32)Height, // Height
750 ResourceOffset, // Offset
751 VgpuGop->ResourceId // ResourceId
752 );
753 if (EFI_ERROR (Status)) {
754 return Status;
755 }
756
757 //
758 // Flush the updated resource to the display.
759 //
760 Status = VirtioGpuResourceFlush (
761 VgpuGop->ParentBus, // VgpuDev
762 (UINT32)DestinationX, // X
763 (UINT32)DestinationY, // Y
764 (UINT32)Width, // Width
765 (UINT32)Height, // Height
766 VgpuGop->ResourceId // ResourceId
767 );
768 return Status;
769}
770
771//
772// Template for initializing VGPU_GOP.Gop.
773//
774CONST EFI_GRAPHICS_OUTPUT_PROTOCOL mGopTemplate = {
775 GopQueryMode,
776 GopSetMode,
777 GopBlt,
778 NULL // Mode, to be overwritten in the actual protocol instance
779};
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