]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/VirtioGpuDxe/Commands.c
OvmfPkg/AcpiPlatformDxe: catch theoretical nullptr deref in Xen code
[mirror_edk2.git] / OvmfPkg / VirtioGpuDxe / Commands.c
1 /** @file
2
3 VirtIo GPU initialization, and commands (primitives) for the GPU device.
4
5 Copyright (C) 2016, Red Hat, Inc.
6 Copyright (c) 2017, AMD Inc, All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include <Library/VirtioLib.h>
13
14 #include "VirtioGpu.h"
15
16 /**
17 Configure the VirtIo GPU device that underlies VgpuDev.
18
19 @param[in,out] VgpuDev The VGPU_DEV object to set up VirtIo messaging for.
20 On input, the caller is responsible for having
21 initialized VgpuDev->VirtIo. On output, VgpuDev->Ring
22 has been initialized, and synchronous VirtIo GPU
23 commands (primitives) can be submitted to the device.
24
25 @retval EFI_SUCCESS VirtIo GPU configuration successful.
26
27 @retval EFI_UNSUPPORTED The host-side configuration of the VirtIo GPU is not
28 supported by this driver.
29
30 @retval Error codes from underlying functions.
31 **/
32 EFI_STATUS
33 VirtioGpuInit (
34 IN OUT VGPU_DEV *VgpuDev
35 )
36 {
37 UINT8 NextDevStat;
38 EFI_STATUS Status;
39 UINT64 Features;
40 UINT16 QueueSize;
41 UINT64 RingBaseShift;
42
43 //
44 // Execute virtio-v1.0-cs04, 3.1.1 Driver Requirements: Device
45 // Initialization.
46 //
47 // 1. Reset the device.
48 //
49 NextDevStat = 0;
50 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
51 if (EFI_ERROR (Status)) {
52 goto Failed;
53 }
54
55 //
56 // 2. Set the ACKNOWLEDGE status bit [...]
57 //
58 NextDevStat |= VSTAT_ACK;
59 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
60 if (EFI_ERROR (Status)) {
61 goto Failed;
62 }
63
64 //
65 // 3. Set the DRIVER status bit [...]
66 //
67 NextDevStat |= VSTAT_DRIVER;
68 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
69 if (EFI_ERROR (Status)) {
70 goto Failed;
71 }
72
73 //
74 // 4. Read device feature bits...
75 //
76 Status = VgpuDev->VirtIo->GetDeviceFeatures (VgpuDev->VirtIo, &Features);
77 if (EFI_ERROR (Status)) {
78 goto Failed;
79 }
80 if ((Features & VIRTIO_F_VERSION_1) == 0) {
81 Status = EFI_UNSUPPORTED;
82 goto Failed;
83 }
84 //
85 // We only want the most basic 2D features.
86 //
87 Features &= VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM;
88
89 //
90 // ... and write the subset of feature bits understood by the [...] driver to
91 // the device. [...]
92 // 5. Set the FEATURES_OK status bit.
93 // 6. Re-read device status to ensure the FEATURES_OK bit is still set [...]
94 //
95 Status = Virtio10WriteFeatures (VgpuDev->VirtIo, Features, &NextDevStat);
96 if (EFI_ERROR (Status)) {
97 goto Failed;
98 }
99
100 //
101 // 7. Perform device-specific setup, including discovery of virtqueues for
102 // the device [...]
103 //
104 Status = VgpuDev->VirtIo->SetQueueSel (VgpuDev->VirtIo,
105 VIRTIO_GPU_CONTROL_QUEUE);
106 if (EFI_ERROR (Status)) {
107 goto Failed;
108 }
109 Status = VgpuDev->VirtIo->GetQueueNumMax (VgpuDev->VirtIo, &QueueSize);
110 if (EFI_ERROR (Status)) {
111 goto Failed;
112 }
113
114 //
115 // We implement each VirtIo GPU command that we use with two descriptors:
116 // request, response.
117 //
118 if (QueueSize < 2) {
119 Status = EFI_UNSUPPORTED;
120 goto Failed;
121 }
122
123 //
124 // [...] population of virtqueues [...]
125 //
126 Status = VirtioRingInit (VgpuDev->VirtIo, QueueSize, &VgpuDev->Ring);
127 if (EFI_ERROR (Status)) {
128 goto Failed;
129 }
130 //
131 // If anything fails from here on, we have to release the ring.
132 //
133 Status = VirtioRingMap (
134 VgpuDev->VirtIo,
135 &VgpuDev->Ring,
136 &RingBaseShift,
137 &VgpuDev->RingMap
138 );
139 if (EFI_ERROR (Status)) {
140 goto ReleaseQueue;
141 }
142 //
143 // If anything fails from here on, we have to unmap the ring.
144 //
145 Status = VgpuDev->VirtIo->SetQueueAddress (
146 VgpuDev->VirtIo,
147 &VgpuDev->Ring,
148 RingBaseShift
149 );
150 if (EFI_ERROR (Status)) {
151 goto UnmapQueue;
152 }
153
154 //
155 // 8. Set the DRIVER_OK status bit.
156 //
157 NextDevStat |= VSTAT_DRIVER_OK;
158 Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
159 if (EFI_ERROR (Status)) {
160 goto UnmapQueue;
161 }
162
163 return EFI_SUCCESS;
164
165 UnmapQueue:
166 VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, VgpuDev->RingMap);
167
168 ReleaseQueue:
169 VirtioRingUninit (VgpuDev->VirtIo, &VgpuDev->Ring);
170
171 Failed:
172 //
173 // If any of these steps go irrecoverably wrong, the driver SHOULD set the
174 // FAILED status bit to indicate that it has given up on the device (it can
175 // reset the device later to restart if desired). [...]
176 //
177 // VirtIo access failure here should not mask the original error.
178 //
179 NextDevStat |= VSTAT_FAILED;
180 VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat);
181
182 return Status;
183 }
184
185 /**
186 De-configure the VirtIo GPU device that underlies VgpuDev.
187
188 @param[in,out] VgpuDev The VGPU_DEV object to tear down VirtIo messaging
189 for. On input, the caller is responsible for having
190 called VirtioGpuInit(). On output, VgpuDev->Ring has
191 been uninitialized; VirtIo GPU commands (primitives)
192 can no longer be submitted to the device.
193 **/
194 VOID
195 VirtioGpuUninit (
196 IN OUT VGPU_DEV *VgpuDev
197 )
198 {
199 //
200 // Resetting the VirtIo device makes it release its resources and forget its
201 // configuration.
202 //
203 VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);
204 VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, VgpuDev->RingMap);
205 VirtioRingUninit (VgpuDev->VirtIo, &VgpuDev->Ring);
206 }
207
208 /**
209 Allocate, zero and map memory, for bus master common buffer operation, to be
210 attached as backing store to a host-side VirtIo GPU resource.
211
212 @param[in] VgpuDev The VGPU_DEV object that represents the VirtIo GPU
213 device.
214
215 @param[in] NumberOfPages The number of whole pages to allocate and map.
216
217 @param[out] HostAddress The system memory address of the allocated area.
218
219 @param[out] DeviceAddress The bus master device address of the allocated
220 area. The VirtIo GPU device may be programmed to
221 access the allocated area through DeviceAddress;
222 DeviceAddress is to be passed to the
223 VirtioGpuResourceAttachBacking() function, as the
224 BackingStoreDeviceAddress parameter.
225
226 @param[out] Mapping A resulting token to pass to
227 VirtioGpuUnmapAndFreeBackingStore().
228
229 @retval EFI_SUCCESS The requested number of pages has been allocated, zeroed
230 and mapped.
231
232 @return Status codes propagated from
233 VgpuDev->VirtIo->AllocateSharedPages() and
234 VirtioMapAllBytesInSharedBuffer().
235 **/
236 EFI_STATUS
237 VirtioGpuAllocateZeroAndMapBackingStore (
238 IN VGPU_DEV *VgpuDev,
239 IN UINTN NumberOfPages,
240 OUT VOID **HostAddress,
241 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
242 OUT VOID **Mapping
243 )
244 {
245 EFI_STATUS Status;
246 VOID *NewHostAddress;
247
248 Status = VgpuDev->VirtIo->AllocateSharedPages (
249 VgpuDev->VirtIo,
250 NumberOfPages,
251 &NewHostAddress
252 );
253 if (EFI_ERROR (Status)) {
254 return Status;
255 }
256
257 //
258 // Avoid exposing stale data to the device even temporarily: zero the area
259 // before mapping it.
260 //
261 ZeroMem (NewHostAddress, EFI_PAGES_TO_SIZE (NumberOfPages));
262
263 Status = VirtioMapAllBytesInSharedBuffer (
264 VgpuDev->VirtIo, // VirtIo
265 VirtioOperationBusMasterCommonBuffer, // Operation
266 NewHostAddress, // HostAddress
267 EFI_PAGES_TO_SIZE (NumberOfPages), // NumberOfBytes
268 DeviceAddress, // DeviceAddress
269 Mapping // Mapping
270 );
271 if (EFI_ERROR (Status)) {
272 goto FreeSharedPages;
273 }
274
275 *HostAddress = NewHostAddress;
276 return EFI_SUCCESS;
277
278 FreeSharedPages:
279 VgpuDev->VirtIo->FreeSharedPages (
280 VgpuDev->VirtIo,
281 NumberOfPages,
282 NewHostAddress
283 );
284 return Status;
285 }
286
287 /**
288 Unmap and free memory originally allocated and mapped with
289 VirtioGpuAllocateZeroAndMapBackingStore().
290
291 If the memory allocated and mapped with
292 VirtioGpuAllocateZeroAndMapBackingStore() was attached to a host-side VirtIo
293 GPU resource with VirtioGpuResourceAttachBacking(), then the caller is
294 responsible for detaching the backing store from the same resource, with
295 VirtioGpuResourceDetachBacking(), before calling this function.
296
297 @param[in] VgpuDev The VGPU_DEV object that represents the VirtIo GPU
298 device.
299
300 @param[in] NumberOfPages The NumberOfPages parameter originally passed to
301 VirtioGpuAllocateZeroAndMapBackingStore().
302
303 @param[in] HostAddress The HostAddress value originally output by
304 VirtioGpuAllocateZeroAndMapBackingStore().
305
306 @param[in] Mapping The token that was originally output by
307 VirtioGpuAllocateZeroAndMapBackingStore().
308 **/
309 VOID
310 VirtioGpuUnmapAndFreeBackingStore (
311 IN VGPU_DEV *VgpuDev,
312 IN UINTN NumberOfPages,
313 IN VOID *HostAddress,
314 IN VOID *Mapping
315 )
316 {
317 VgpuDev->VirtIo->UnmapSharedBuffer (
318 VgpuDev->VirtIo,
319 Mapping
320 );
321 VgpuDev->VirtIo->FreeSharedPages (
322 VgpuDev->VirtIo,
323 NumberOfPages,
324 HostAddress
325 );
326 }
327
328 /**
329 EFI_EVENT_NOTIFY function for the VGPU_DEV.ExitBoot event. It resets the
330 VirtIo device, causing it to release its resources and to forget its
331 configuration.
332
333 This function may only be called (that is, VGPU_DEV.ExitBoot may only be
334 signaled) after VirtioGpuInit() returns and before VirtioGpuUninit() is
335 called.
336
337 @param[in] Event Event whose notification function is being invoked.
338
339 @param[in] Context Pointer to the associated VGPU_DEV object.
340 **/
341 VOID
342 EFIAPI
343 VirtioGpuExitBoot (
344 IN EFI_EVENT Event,
345 IN VOID *Context
346 )
347 {
348 VGPU_DEV *VgpuDev;
349
350 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
351 VgpuDev = Context;
352 VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0);
353 }
354
355 /**
356 Internal utility function that sends a request to the VirtIo GPU device
357 model, awaits the answer from the host, and returns a status.
358
359 @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo GPU
360 device. The caller is responsible to have
361 successfully invoked VirtioGpuInit() on VgpuDev
362 previously, while VirtioGpuUninit() must not have
363 been called on VgpuDev.
364
365 @param[in] RequestType The type of the request. The caller is responsible
366 for providing a VirtioGpuCmd* RequestType which, on
367 success, elicits a VirtioGpuRespOkNodata response
368 from the host.
369
370 @param[in] Fence Whether to enable fencing for this request. Fencing
371 forces the host to complete the command before
372 producing a response. If Fence is TRUE, then
373 VgpuDev->FenceId is consumed, and incremented.
374
375 @param[in,out] Header Pointer to the caller-allocated request object. The
376 request must start with VIRTIO_GPU_CONTROL_HEADER.
377 This function overwrites all fields of Header before
378 submitting the request to the host:
379
380 - it sets Type from RequestType,
381
382 - it sets Flags and FenceId based on Fence,
383
384 - it zeroes CtxId and Padding.
385
386 @param[in] RequestSize Size of the entire caller-allocated request object,
387 including the leading VIRTIO_GPU_CONTROL_HEADER.
388
389 @retval EFI_SUCCESS Operation successful.
390
391 @retval EFI_DEVICE_ERROR The host rejected the request. The host error
392 code has been logged on the EFI_D_ERROR level.
393
394 @return Codes for unexpected errors in VirtIo
395 messaging, or request/response
396 mapping/unmapping.
397 **/
398 STATIC
399 EFI_STATUS
400 VirtioGpuSendCommand (
401 IN OUT VGPU_DEV *VgpuDev,
402 IN VIRTIO_GPU_CONTROL_TYPE RequestType,
403 IN BOOLEAN Fence,
404 IN OUT volatile VIRTIO_GPU_CONTROL_HEADER *Header,
405 IN UINTN RequestSize
406 )
407 {
408 DESC_INDICES Indices;
409 volatile VIRTIO_GPU_CONTROL_HEADER Response;
410 EFI_STATUS Status;
411 UINT32 ResponseSize;
412 EFI_PHYSICAL_ADDRESS RequestDeviceAddress;
413 VOID *RequestMap;
414 EFI_PHYSICAL_ADDRESS ResponseDeviceAddress;
415 VOID *ResponseMap;
416
417 //
418 // Initialize Header.
419 //
420 Header->Type = RequestType;
421 if (Fence) {
422 Header->Flags = VIRTIO_GPU_FLAG_FENCE;
423 Header->FenceId = VgpuDev->FenceId++;
424 } else {
425 Header->Flags = 0;
426 Header->FenceId = 0;
427 }
428 Header->CtxId = 0;
429 Header->Padding = 0;
430
431 ASSERT (RequestSize >= sizeof *Header);
432 ASSERT (RequestSize <= MAX_UINT32);
433
434 //
435 // Map request and response to bus master device addresses.
436 //
437 Status = VirtioMapAllBytesInSharedBuffer (
438 VgpuDev->VirtIo,
439 VirtioOperationBusMasterRead,
440 (VOID *)Header,
441 RequestSize,
442 &RequestDeviceAddress,
443 &RequestMap
444 );
445 if (EFI_ERROR (Status)) {
446 return Status;
447 }
448 Status = VirtioMapAllBytesInSharedBuffer (
449 VgpuDev->VirtIo,
450 VirtioOperationBusMasterWrite,
451 (VOID *)&Response,
452 sizeof Response,
453 &ResponseDeviceAddress,
454 &ResponseMap
455 );
456 if (EFI_ERROR (Status)) {
457 goto UnmapRequest;
458 }
459
460 //
461 // Compose the descriptor chain.
462 //
463 VirtioPrepare (&VgpuDev->Ring, &Indices);
464 VirtioAppendDesc (
465 &VgpuDev->Ring,
466 RequestDeviceAddress,
467 (UINT32)RequestSize,
468 VRING_DESC_F_NEXT,
469 &Indices
470 );
471 VirtioAppendDesc (
472 &VgpuDev->Ring,
473 ResponseDeviceAddress,
474 (UINT32)sizeof Response,
475 VRING_DESC_F_WRITE,
476 &Indices
477 );
478
479 //
480 // Send the command.
481 //
482 Status = VirtioFlush (VgpuDev->VirtIo, VIRTIO_GPU_CONTROL_QUEUE,
483 &VgpuDev->Ring, &Indices, &ResponseSize);
484 if (EFI_ERROR (Status)) {
485 goto UnmapResponse;
486 }
487
488 //
489 // Verify response size.
490 //
491 if (ResponseSize != sizeof Response) {
492 DEBUG ((EFI_D_ERROR, "%a: malformed response to Request=0x%x\n",
493 __FUNCTION__, (UINT32)RequestType));
494 Status = EFI_PROTOCOL_ERROR;
495 goto UnmapResponse;
496 }
497
498 //
499 // Unmap response and request, in reverse order of mapping. On error, the
500 // respective mapping is invalidated anyway, only the data may not have been
501 // committed to system memory (in case of VirtioOperationBusMasterWrite).
502 //
503 Status = VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, ResponseMap);
504 if (EFI_ERROR (Status)) {
505 goto UnmapRequest;
506 }
507 Status = VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, RequestMap);
508 if (EFI_ERROR (Status)) {
509 return Status;
510 }
511
512 //
513 // Parse the response.
514 //
515 if (Response.Type == VirtioGpuRespOkNodata) {
516 return EFI_SUCCESS;
517 }
518
519 DEBUG ((EFI_D_ERROR, "%a: Request=0x%x Response=0x%x\n", __FUNCTION__,
520 (UINT32)RequestType, Response.Type));
521 return EFI_DEVICE_ERROR;
522
523 UnmapResponse:
524 VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, ResponseMap);
525
526 UnmapRequest:
527 VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, RequestMap);
528
529 return Status;
530 }
531
532 /**
533 The following functions send requests to the VirtIo GPU device model, await
534 the answer from the host, and return a status. They share the following
535 interface details:
536
537 @param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo GPU
538 device. The caller is responsible to have
539 successfully invoked VirtioGpuInit() on VgpuDev
540 previously, while VirtioGpuUninit() must not have
541 been called on VgpuDev.
542
543 @retval EFI_INVALID_PARAMETER Invalid command-specific parameters were
544 detected by this driver.
545
546 @retval EFI_SUCCESS Operation successful.
547
548 @retval EFI_DEVICE_ERROR The host rejected the request. The host error
549 code has been logged on the EFI_D_ERROR level.
550
551 @return Codes for unexpected errors in VirtIo
552 messaging.
553
554 For the command-specific parameters, please consult the GPU Device section of
555 the VirtIo 1.0 specification (see references in
556 "OvmfPkg/Include/IndustryStandard/VirtioGpu.h").
557 **/
558 EFI_STATUS
559 VirtioGpuResourceCreate2d (
560 IN OUT VGPU_DEV *VgpuDev,
561 IN UINT32 ResourceId,
562 IN VIRTIO_GPU_FORMATS Format,
563 IN UINT32 Width,
564 IN UINT32 Height
565 )
566 {
567 volatile VIRTIO_GPU_RESOURCE_CREATE_2D Request;
568
569 if (ResourceId == 0) {
570 return EFI_INVALID_PARAMETER;
571 }
572
573 Request.ResourceId = ResourceId;
574 Request.Format = (UINT32)Format;
575 Request.Width = Width;
576 Request.Height = Height;
577
578 return VirtioGpuSendCommand (
579 VgpuDev,
580 VirtioGpuCmdResourceCreate2d,
581 FALSE, // Fence
582 &Request.Header,
583 sizeof Request
584 );
585 }
586
587 EFI_STATUS
588 VirtioGpuResourceUnref (
589 IN OUT VGPU_DEV *VgpuDev,
590 IN UINT32 ResourceId
591 )
592 {
593 volatile VIRTIO_GPU_RESOURCE_UNREF Request;
594
595 if (ResourceId == 0) {
596 return EFI_INVALID_PARAMETER;
597 }
598
599 Request.ResourceId = ResourceId;
600 Request.Padding = 0;
601
602 return VirtioGpuSendCommand (
603 VgpuDev,
604 VirtioGpuCmdResourceUnref,
605 FALSE, // Fence
606 &Request.Header,
607 sizeof Request
608 );
609 }
610
611 EFI_STATUS
612 VirtioGpuResourceAttachBacking (
613 IN OUT VGPU_DEV *VgpuDev,
614 IN UINT32 ResourceId,
615 IN EFI_PHYSICAL_ADDRESS BackingStoreDeviceAddress,
616 IN UINTN NumberOfPages
617 )
618 {
619 volatile VIRTIO_GPU_RESOURCE_ATTACH_BACKING Request;
620
621 if (ResourceId == 0) {
622 return EFI_INVALID_PARAMETER;
623 }
624
625 Request.ResourceId = ResourceId;
626 Request.NrEntries = 1;
627 Request.Entry.Addr = BackingStoreDeviceAddress;
628 Request.Entry.Length = (UINT32)EFI_PAGES_TO_SIZE (NumberOfPages);
629 Request.Entry.Padding = 0;
630
631 return VirtioGpuSendCommand (
632 VgpuDev,
633 VirtioGpuCmdResourceAttachBacking,
634 FALSE, // Fence
635 &Request.Header,
636 sizeof Request
637 );
638 }
639
640 EFI_STATUS
641 VirtioGpuResourceDetachBacking (
642 IN OUT VGPU_DEV *VgpuDev,
643 IN UINT32 ResourceId
644 )
645 {
646 volatile VIRTIO_GPU_RESOURCE_DETACH_BACKING Request;
647
648 if (ResourceId == 0) {
649 return EFI_INVALID_PARAMETER;
650 }
651
652 Request.ResourceId = ResourceId;
653 Request.Padding = 0;
654
655 //
656 // In this case, we set Fence to TRUE, because after this function returns,
657 // the caller might reasonably want to repurpose the backing pages
658 // immediately. Thus we should ensure that the host releases all references
659 // to the backing pages before we return.
660 //
661 return VirtioGpuSendCommand (
662 VgpuDev,
663 VirtioGpuCmdResourceDetachBacking,
664 TRUE, // Fence
665 &Request.Header,
666 sizeof Request
667 );
668 }
669
670 EFI_STATUS
671 VirtioGpuSetScanout (
672 IN OUT VGPU_DEV *VgpuDev,
673 IN UINT32 X,
674 IN UINT32 Y,
675 IN UINT32 Width,
676 IN UINT32 Height,
677 IN UINT32 ScanoutId,
678 IN UINT32 ResourceId
679 )
680 {
681 volatile VIRTIO_GPU_SET_SCANOUT Request;
682
683 //
684 // Unlike for most other commands, ResourceId=0 is valid; it
685 // is used to disable a scanout.
686 //
687 Request.Rectangle.X = X;
688 Request.Rectangle.Y = Y;
689 Request.Rectangle.Width = Width;
690 Request.Rectangle.Height = Height;
691 Request.ScanoutId = ScanoutId;
692 Request.ResourceId = ResourceId;
693
694 return VirtioGpuSendCommand (
695 VgpuDev,
696 VirtioGpuCmdSetScanout,
697 FALSE, // Fence
698 &Request.Header,
699 sizeof Request
700 );
701 }
702
703 EFI_STATUS
704 VirtioGpuTransferToHost2d (
705 IN OUT VGPU_DEV *VgpuDev,
706 IN UINT32 X,
707 IN UINT32 Y,
708 IN UINT32 Width,
709 IN UINT32 Height,
710 IN UINT64 Offset,
711 IN UINT32 ResourceId
712 )
713 {
714 volatile VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D Request;
715
716 if (ResourceId == 0) {
717 return EFI_INVALID_PARAMETER;
718 }
719
720 Request.Rectangle.X = X;
721 Request.Rectangle.Y = Y;
722 Request.Rectangle.Width = Width;
723 Request.Rectangle.Height = Height;
724 Request.Offset = Offset;
725 Request.ResourceId = ResourceId;
726 Request.Padding = 0;
727
728 return VirtioGpuSendCommand (
729 VgpuDev,
730 VirtioGpuCmdTransferToHost2d,
731 FALSE, // Fence
732 &Request.Header,
733 sizeof Request
734 );
735 }
736
737 EFI_STATUS
738 VirtioGpuResourceFlush (
739 IN OUT VGPU_DEV *VgpuDev,
740 IN UINT32 X,
741 IN UINT32 Y,
742 IN UINT32 Width,
743 IN UINT32 Height,
744 IN UINT32 ResourceId
745 )
746 {
747 volatile VIRTIO_GPU_RESOURCE_FLUSH Request;
748
749 if (ResourceId == 0) {
750 return EFI_INVALID_PARAMETER;
751 }
752
753 Request.Rectangle.X = X;
754 Request.Rectangle.Y = Y;
755 Request.Rectangle.Width = Width;
756 Request.Rectangle.Height = Height;
757 Request.ResourceId = ResourceId;
758 Request.Padding = 0;
759
760 return VirtioGpuSendCommand (
761 VgpuDev,
762 VirtioGpuCmdResourceFlush,
763 FALSE, // Fence
764 &Request.Header,
765 sizeof Request
766 );
767 }