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