]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/VirtioGpuDxe/Gop.c
CorebootPayloadPkg: Add an option to use HPET timer driver
[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
207 if (ModeNumber >= sizeof mGopResolutions / sizeof mGopResolutions[0]) {\r
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
242 if (ModeNumber >= sizeof mGopResolutions / sizeof mGopResolutions[0]) {\r
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
261 VgpuGop->GopMode.MaxMode = (UINT32)(sizeof mGopResolutions /\r
262 sizeof mGopResolutions[0]);\r
263 VgpuGop->GopMode.Info = &VgpuGop->GopModeInfo;\r
264 VgpuGop->GopMode.SizeOfInfo = sizeof VgpuGop->GopModeInfo;\r
265\r
266 VgpuGop->GopModeInfo.PixelFormat = PixelBltOnly;\r
267\r
268 //\r
269 // This is the first time we create a host side resource.\r
270 //\r
271 NewResourceId = 1;\r
272 } else {\r
273 //\r
274 // We already have an active host side resource. Create the new one without\r
275 // interfering with the current one, so that we can cleanly bail out on\r
276 // error, without disturbing the current graphics mode.\r
277 //\r
278 // The formula below will alternate between IDs 1 and 2.\r
279 //\r
280 NewResourceId = 3 - VgpuGop->ResourceId;\r
281 }\r
282\r
283 //\r
284 // Create the 2D host resource.\r
285 //\r
286 Status = VirtioGpuResourceCreate2d (\r
287 VgpuGop->ParentBus, // VgpuDev\r
288 NewResourceId, // ResourceId\r
289 VirtioGpuFormatB8G8R8X8Unorm, // Format\r
290 mGopResolutions[ModeNumber].Width, // Width\r
291 mGopResolutions[ModeNumber].Height // Height\r
292 );\r
293 if (EFI_ERROR (Status)) {\r
294 return Status;\r
295 }\r
296\r
297 //\r
298 // Allocate guest backing store.\r
299 //\r
300 NewNumberOfBytes = mGopResolutions[ModeNumber].Width *\r
301 mGopResolutions[ModeNumber].Height * sizeof (UINT32);\r
302 NewNumberOfPages = EFI_SIZE_TO_PAGES (NewNumberOfBytes);\r
303 NewBackingStore = AllocatePages (NewNumberOfPages);\r
304 if (NewBackingStore == NULL) {\r
305 Status = EFI_OUT_OF_RESOURCES;\r
306 goto DestroyHostResource;\r
307 }\r
308 //\r
309 // Fill visible part of backing store with black.\r
310 //\r
311 ZeroMem (NewBackingStore, NewNumberOfBytes);\r
312\r
313 //\r
314 // Attach backing store to the host resource.\r
315 //\r
316 Status = VirtioGpuResourceAttachBacking (\r
317 VgpuGop->ParentBus, // VgpuDev\r
318 NewResourceId, // ResourceId\r
319 NewBackingStore, // FirstBackingPage\r
320 NewNumberOfPages // NumberOfPages\r
321 );\r
322 if (EFI_ERROR (Status)) {\r
323 goto FreeBackingStore;\r
324 }\r
325\r
326 //\r
327 // Point head (scanout) #0 to the host resource.\r
328 //\r
329 Status = VirtioGpuSetScanout (\r
330 VgpuGop->ParentBus, // VgpuDev\r
331 0, // X\r
332 0, // Y\r
333 mGopResolutions[ModeNumber].Width, // Width\r
334 mGopResolutions[ModeNumber].Height, // Height\r
335 0, // ScanoutId\r
336 NewResourceId // ResourceId\r
337 );\r
338 if (EFI_ERROR (Status)) {\r
339 goto DetachBackingStore;\r
340 }\r
341\r
342 //\r
343 // If this is not the first (i.e., internal) call, then we have to (a) flush\r
344 // the new resource to head (scanout) #0, after having flipped the latter to\r
345 // the former above, plus (b) release the old resources.\r
346 //\r
347 if (VgpuGop->ResourceId != 0) {\r
348 Status = VirtioGpuResourceFlush (\r
349 VgpuGop->ParentBus, // VgpuDev\r
350 0, // X\r
351 0, // Y\r
352 mGopResolutions[ModeNumber].Width, // Width\r
353 mGopResolutions[ModeNumber].Height, // Height\r
354 NewResourceId // ResourceId\r
355 );\r
356 if (EFI_ERROR (Status)) {\r
357 //\r
358 // Flip head (scanout) #0 back to the current resource. If this fails, we\r
359 // cannot continue, as this error occurs on the error path and is\r
360 // therefore non-recoverable.\r
361 //\r
362 Status2 = VirtioGpuSetScanout (\r
363 VgpuGop->ParentBus, // VgpuDev\r
364 0, // X\r
365 0, // Y\r
366 mGopResolutions[This->Mode->Mode].Width, // Width\r
367 mGopResolutions[This->Mode->Mode].Height, // Height\r
368 0, // ScanoutId\r
369 VgpuGop->ResourceId // ResourceId\r
370 );\r
371 ASSERT_EFI_ERROR (Status2);\r
372 if (EFI_ERROR (Status2)) {\r
373 CpuDeadLoop ();\r
374 }\r
375 goto DetachBackingStore;\r
376 }\r
377\r
378 //\r
379 // Flush successful; release the old resources (without disabling head\r
380 // (scanout) #0).\r
381 //\r
382 ReleaseGopResources (VgpuGop, FALSE /* DisableHead */);\r
383 }\r
384\r
385 //\r
386 // This is either the first (internal) call when we have no old resources\r
387 // yet, or we've changed the mode successfully and released the old\r
388 // resources.\r
389 //\r
390 ASSERT (VgpuGop->ResourceId == 0);\r
391 ASSERT (VgpuGop->BackingStore == NULL);\r
392\r
393 VgpuGop->ResourceId = NewResourceId;\r
394 VgpuGop->BackingStore = NewBackingStore;\r
395 VgpuGop->NumberOfPages = NewNumberOfPages;\r
396\r
397 //\r
398 // Populate Mode and ModeInfo (mutable fields only).\r
399 //\r
400 VgpuGop->GopMode.Mode = ModeNumber;\r
401 VgpuGop->GopModeInfo.HorizontalResolution =\r
402 mGopResolutions[ModeNumber].Width;\r
403 VgpuGop->GopModeInfo.VerticalResolution = mGopResolutions[ModeNumber].Height;\r
404 VgpuGop->GopModeInfo.PixelsPerScanLine = mGopResolutions[ModeNumber].Width;\r
405 return EFI_SUCCESS;\r
406\r
407DetachBackingStore:\r
408 Status2 = VirtioGpuResourceDetachBacking (VgpuGop->ParentBus, NewResourceId);\r
409 ASSERT_EFI_ERROR (Status2);\r
410 if (EFI_ERROR (Status2)) {\r
411 CpuDeadLoop ();\r
412 }\r
413\r
414FreeBackingStore:\r
415 FreePages (NewBackingStore, NewNumberOfPages);\r
416\r
417DestroyHostResource:\r
418 Status2 = VirtioGpuResourceUnref (VgpuGop->ParentBus, NewResourceId);\r
419 ASSERT_EFI_ERROR (Status2);\r
420 if (EFI_ERROR (Status2)) {\r
421 CpuDeadLoop ();\r
422 }\r
423\r
424 return Status;\r
425}\r
426\r
427STATIC\r
428EFI_STATUS\r
429EFIAPI\r
430GopBlt (\r
431 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
432 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL\r
433 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,\r
434 IN UINTN SourceX,\r
435 IN UINTN SourceY,\r
436 IN UINTN DestinationX,\r
437 IN UINTN DestinationY,\r
438 IN UINTN Width,\r
439 IN UINTN Height,\r
440 IN UINTN Delta OPTIONAL\r
441 )\r
442{\r
443 VGPU_GOP *VgpuGop;\r
444 UINT32 CurrentHorizontal;\r
445 UINT32 CurrentVertical;\r
446 UINTN SegmentSize;\r
447 UINTN Y;\r
448 UINTN ResourceOffset;\r
449 EFI_STATUS Status;\r
450\r
451 VgpuGop = VGPU_GOP_FROM_GOP (This);\r
452 CurrentHorizontal = VgpuGop->GopModeInfo.HorizontalResolution;\r
453 CurrentVertical = VgpuGop->GopModeInfo.VerticalResolution;\r
454\r
455 //\r
456 // We can avoid pixel format conversion in the guest because the internal\r
457 // representation of EFI_GRAPHICS_OUTPUT_BLT_PIXEL and that of\r
458 // VirtioGpuFormatB8G8R8X8Unorm are identical.\r
459 //\r
460 SegmentSize = Width * sizeof (UINT32);\r
461\r
462 //\r
463 // Delta is relevant for operations that read a rectangle from, or write a\r
464 // rectangle to, BltBuffer.\r
465 //\r
466 // In these cases, Delta is the stride of BltBuffer, in bytes. If Delta is\r
467 // zero, then Width is the entire width of BltBuffer, and the stride is\r
468 // supposed to be calculated from Width.\r
469 //\r
470 if (BltOperation == EfiBltVideoToBltBuffer ||\r
471 BltOperation == EfiBltBufferToVideo) {\r
472 if (Delta == 0) {\r
473 Delta = SegmentSize;\r
474 }\r
475 }\r
476\r
477 //\r
478 // For operations that write to the display, check if the destination fits\r
479 // onto the display.\r
480 //\r
481 if (BltOperation == EfiBltVideoFill ||\r
482 BltOperation == EfiBltBufferToVideo ||\r
483 BltOperation == EfiBltVideoToVideo) {\r
484 if (DestinationX > CurrentHorizontal ||\r
485 Width > CurrentHorizontal - DestinationX ||\r
486 DestinationY > CurrentVertical ||\r
487 Height > CurrentVertical - DestinationY) {\r
488 return EFI_INVALID_PARAMETER;\r
489 }\r
490 }\r
491\r
492 //\r
493 // For operations that read from the display, check if the source fits onto\r
494 // the display.\r
495 //\r
496 if (BltOperation == EfiBltVideoToBltBuffer ||\r
497 BltOperation == EfiBltVideoToVideo) {\r
498 if (SourceX > CurrentHorizontal ||\r
499 Width > CurrentHorizontal - SourceX ||\r
500 SourceY > CurrentVertical ||\r
501 Height > CurrentVertical - SourceY) {\r
502 return EFI_INVALID_PARAMETER;\r
503 }\r
504 }\r
505\r
506 //\r
507 // Render the request. For requests that do not modify the display, there\r
508 // won't be further steps.\r
509 //\r
510 switch (BltOperation) {\r
511 case EfiBltVideoFill:\r
512 //\r
513 // Write data from the BltBuffer pixel (0, 0) directly to every pixel of\r
514 // the video display rectangle (DestinationX, DestinationY) (DestinationX +\r
515 // Width, DestinationY + Height). Only one pixel will be used from the\r
516 // BltBuffer. Delta is NOT used.\r
517 //\r
518 for (Y = 0; Y < Height; ++Y) {\r
519 SetMem32 (\r
520 VgpuGop->BackingStore +\r
521 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
522 SegmentSize,\r
523 *(UINT32 *)BltBuffer\r
524 );\r
525 }\r
526 break;\r
527\r
528 case EfiBltVideoToBltBuffer:\r
529 //\r
530 // Read data from the video display rectangle (SourceX, SourceY) (SourceX +\r
531 // Width, SourceY + Height) and place it in the BltBuffer rectangle\r
532 // (DestinationX, DestinationY ) (DestinationX + Width, DestinationY +\r
533 // Height). If DestinationX or DestinationY is not zero then Delta must be\r
534 // set to the length in bytes of a row in the BltBuffer.\r
535 //\r
536 for (Y = 0; Y < Height; ++Y) {\r
537 CopyMem (\r
538 (UINT8 *)BltBuffer +\r
539 (DestinationY + Y) * Delta + DestinationX * sizeof *BltBuffer,\r
540 VgpuGop->BackingStore +\r
541 (SourceY + Y) * CurrentHorizontal + SourceX,\r
542 SegmentSize\r
543 );\r
544 }\r
545 return EFI_SUCCESS;\r
546\r
547 case EfiBltBufferToVideo:\r
548 //\r
549 // Write data from the BltBuffer rectangle (SourceX, SourceY) (SourceX +\r
550 // Width, SourceY + Height) directly to the video display rectangle\r
551 // (DestinationX, DestinationY) (DestinationX + Width, DestinationY +\r
552 // Height). If SourceX or SourceY is not zero then Delta must be set to the\r
553 // length in bytes of a row in the BltBuffer.\r
554 //\r
555 for (Y = 0; Y < Height; ++Y) {\r
556 CopyMem (\r
557 VgpuGop->BackingStore +\r
558 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
559 (UINT8 *)BltBuffer +\r
560 (SourceY + Y) * Delta + SourceX * sizeof *BltBuffer,\r
561 SegmentSize\r
562 );\r
563 }\r
564 break;\r
565\r
566 case EfiBltVideoToVideo:\r
567 //\r
568 // Copy from the video display rectangle (SourceX, SourceY) (SourceX +\r
569 // Width, SourceY + Height) to the video display rectangle (DestinationX,\r
570 // DestinationY) (DestinationX + Width, DestinationY + Height). The\r
571 // BltBuffer and Delta are not used in this mode.\r
572 //\r
573 // A single invocation of CopyMem() handles overlap between source and\r
574 // destination (that is, within a single line), but for multiple\r
575 // invocations, we must handle overlaps.\r
576 //\r
577 if (SourceY < DestinationY) {\r
578 Y = Height;\r
579 while (Y > 0) {\r
580 --Y;\r
581 CopyMem (\r
582 VgpuGop->BackingStore +\r
583 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
584 VgpuGop->BackingStore +\r
585 (SourceY + Y) * CurrentHorizontal + SourceX,\r
586 SegmentSize\r
587 );\r
588 }\r
589 } else {\r
590 for (Y = 0; Y < Height; ++Y) {\r
591 CopyMem (\r
592 VgpuGop->BackingStore +\r
593 (DestinationY + Y) * CurrentHorizontal + DestinationX,\r
594 VgpuGop->BackingStore +\r
595 (SourceY + Y) * CurrentHorizontal + SourceX,\r
596 SegmentSize\r
597 );\r
598 }\r
599 }\r
600 break;\r
601\r
602 default:\r
603 return EFI_INVALID_PARAMETER;\r
604 }\r
605\r
606 //\r
607 // For operations that wrote to the display, submit the updated area to the\r
608 // host -- update the host resource from guest memory.\r
609 //\r
610 ResourceOffset = sizeof (UINT32) * (DestinationY * CurrentHorizontal +\r
611 DestinationX);\r
612 Status = VirtioGpuTransferToHost2d (\r
613 VgpuGop->ParentBus, // VgpuDev\r
614 (UINT32)DestinationX, // X\r
615 (UINT32)DestinationY, // Y\r
616 (UINT32)Width, // Width\r
617 (UINT32)Height, // Height\r
618 ResourceOffset, // Offset\r
619 VgpuGop->ResourceId // ResourceId\r
620 );\r
621 if (EFI_ERROR (Status)) {\r
622 return Status;\r
623 }\r
624\r
625 //\r
626 // Flush the updated resource to the display.\r
627 //\r
628 Status = VirtioGpuResourceFlush (\r
629 VgpuGop->ParentBus, // VgpuDev\r
630 (UINT32)DestinationX, // X\r
631 (UINT32)DestinationY, // Y\r
632 (UINT32)Width, // Width\r
633 (UINT32)Height, // Height\r
634 VgpuGop->ResourceId // ResourceId\r
635 );\r
636 return Status;\r
637}\r
638\r
639//\r
640// Template for initializing VGPU_GOP.Gop.\r
641//\r
642CONST EFI_GRAPHICS_OUTPUT_PROTOCOL mGopTemplate = {\r
643 GopQueryMode,\r
644 GopSetMode,\r
645 GopBlt,\r
646 NULL // Mode, to be overwritten in the actual protocol instance\r
647};\r