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