/** @file | |
VirtIo GPU initialization, and commands (primitives) for the GPU device. | |
Copyright (C) 2016, Red Hat, Inc. | |
Copyright (c) 2017, AMD Inc, All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Library/VirtioLib.h> | |
#include "VirtioGpu.h" | |
/** | |
Configure the VirtIo GPU device that underlies VgpuDev. | |
@param[in,out] VgpuDev The VGPU_DEV object to set up VirtIo messaging for. | |
On input, the caller is responsible for having | |
initialized VgpuDev->VirtIo. On output, VgpuDev->Ring | |
has been initialized, and synchronous VirtIo GPU | |
commands (primitives) can be submitted to the device. | |
@retval EFI_SUCCESS VirtIo GPU configuration successful. | |
@retval EFI_UNSUPPORTED The host-side configuration of the VirtIo GPU is not | |
supported by this driver. | |
@retval Error codes from underlying functions. | |
**/ | |
EFI_STATUS | |
VirtioGpuInit ( | |
IN OUT VGPU_DEV *VgpuDev | |
) | |
{ | |
UINT8 NextDevStat; | |
EFI_STATUS Status; | |
UINT64 Features; | |
UINT16 QueueSize; | |
UINT64 RingBaseShift; | |
// | |
// Execute virtio-v1.0-cs04, 3.1.1 Driver Requirements: Device | |
// Initialization. | |
// | |
// 1. Reset the device. | |
// | |
NextDevStat = 0; | |
Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
// | |
// 2. Set the ACKNOWLEDGE status bit [...] | |
// | |
NextDevStat |= VSTAT_ACK; | |
Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
// | |
// 3. Set the DRIVER status bit [...] | |
// | |
NextDevStat |= VSTAT_DRIVER; | |
Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
// | |
// 4. Read device feature bits... | |
// | |
Status = VgpuDev->VirtIo->GetDeviceFeatures (VgpuDev->VirtIo, &Features); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
if ((Features & VIRTIO_F_VERSION_1) == 0) { | |
Status = EFI_UNSUPPORTED; | |
goto Failed; | |
} | |
// | |
// We only want the most basic 2D features. | |
// | |
Features &= VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM; | |
// | |
// ... and write the subset of feature bits understood by the [...] driver to | |
// the device. [...] | |
// 5. Set the FEATURES_OK status bit. | |
// 6. Re-read device status to ensure the FEATURES_OK bit is still set [...] | |
// | |
Status = Virtio10WriteFeatures (VgpuDev->VirtIo, Features, &NextDevStat); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
// | |
// 7. Perform device-specific setup, including discovery of virtqueues for | |
// the device [...] | |
// | |
Status = VgpuDev->VirtIo->SetQueueSel ( | |
VgpuDev->VirtIo, | |
VIRTIO_GPU_CONTROL_QUEUE | |
); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
Status = VgpuDev->VirtIo->GetQueueNumMax (VgpuDev->VirtIo, &QueueSize); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
// | |
// We implement each VirtIo GPU command that we use with two descriptors: | |
// request, response. | |
// | |
if (QueueSize < 2) { | |
Status = EFI_UNSUPPORTED; | |
goto Failed; | |
} | |
// | |
// [...] population of virtqueues [...] | |
// | |
Status = VirtioRingInit (VgpuDev->VirtIo, QueueSize, &VgpuDev->Ring); | |
if (EFI_ERROR (Status)) { | |
goto Failed; | |
} | |
// | |
// If anything fails from here on, we have to release the ring. | |
// | |
Status = VirtioRingMap ( | |
VgpuDev->VirtIo, | |
&VgpuDev->Ring, | |
&RingBaseShift, | |
&VgpuDev->RingMap | |
); | |
if (EFI_ERROR (Status)) { | |
goto ReleaseQueue; | |
} | |
// | |
// If anything fails from here on, we have to unmap the ring. | |
// | |
Status = VgpuDev->VirtIo->SetQueueAddress ( | |
VgpuDev->VirtIo, | |
&VgpuDev->Ring, | |
RingBaseShift | |
); | |
if (EFI_ERROR (Status)) { | |
goto UnmapQueue; | |
} | |
// | |
// 8. Set the DRIVER_OK status bit. | |
// | |
NextDevStat |= VSTAT_DRIVER_OK; | |
Status = VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat); | |
if (EFI_ERROR (Status)) { | |
goto UnmapQueue; | |
} | |
return EFI_SUCCESS; | |
UnmapQueue: | |
VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, VgpuDev->RingMap); | |
ReleaseQueue: | |
VirtioRingUninit (VgpuDev->VirtIo, &VgpuDev->Ring); | |
Failed: | |
// | |
// If any of these steps go irrecoverably wrong, the driver SHOULD set the | |
// FAILED status bit to indicate that it has given up on the device (it can | |
// reset the device later to restart if desired). [...] | |
// | |
// VirtIo access failure here should not mask the original error. | |
// | |
NextDevStat |= VSTAT_FAILED; | |
VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, NextDevStat); | |
return Status; | |
} | |
/** | |
De-configure the VirtIo GPU device that underlies VgpuDev. | |
@param[in,out] VgpuDev The VGPU_DEV object to tear down VirtIo messaging | |
for. On input, the caller is responsible for having | |
called VirtioGpuInit(). On output, VgpuDev->Ring has | |
been uninitialized; VirtIo GPU commands (primitives) | |
can no longer be submitted to the device. | |
**/ | |
VOID | |
VirtioGpuUninit ( | |
IN OUT VGPU_DEV *VgpuDev | |
) | |
{ | |
// | |
// Resetting the VirtIo device makes it release its resources and forget its | |
// configuration. | |
// | |
VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0); | |
VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, VgpuDev->RingMap); | |
VirtioRingUninit (VgpuDev->VirtIo, &VgpuDev->Ring); | |
} | |
/** | |
Allocate, zero and map memory, for bus master common buffer operation, to be | |
attached as backing store to a host-side VirtIo GPU resource. | |
@param[in] VgpuDev The VGPU_DEV object that represents the VirtIo GPU | |
device. | |
@param[in] NumberOfPages The number of whole pages to allocate and map. | |
@param[out] HostAddress The system memory address of the allocated area. | |
@param[out] DeviceAddress The bus master device address of the allocated | |
area. The VirtIo GPU device may be programmed to | |
access the allocated area through DeviceAddress; | |
DeviceAddress is to be passed to the | |
VirtioGpuResourceAttachBacking() function, as the | |
BackingStoreDeviceAddress parameter. | |
@param[out] Mapping A resulting token to pass to | |
VirtioGpuUnmapAndFreeBackingStore(). | |
@retval EFI_SUCCESS The requested number of pages has been allocated, zeroed | |
and mapped. | |
@return Status codes propagated from | |
VgpuDev->VirtIo->AllocateSharedPages() and | |
VirtioMapAllBytesInSharedBuffer(). | |
**/ | |
EFI_STATUS | |
VirtioGpuAllocateZeroAndMapBackingStore ( | |
IN VGPU_DEV *VgpuDev, | |
IN UINTN NumberOfPages, | |
OUT VOID **HostAddress, | |
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
OUT VOID **Mapping | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *NewHostAddress; | |
Status = VgpuDev->VirtIo->AllocateSharedPages ( | |
VgpuDev->VirtIo, | |
NumberOfPages, | |
&NewHostAddress | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Avoid exposing stale data to the device even temporarily: zero the area | |
// before mapping it. | |
// | |
ZeroMem (NewHostAddress, EFI_PAGES_TO_SIZE (NumberOfPages)); | |
Status = VirtioMapAllBytesInSharedBuffer ( | |
VgpuDev->VirtIo, // VirtIo | |
VirtioOperationBusMasterCommonBuffer, // Operation | |
NewHostAddress, // HostAddress | |
EFI_PAGES_TO_SIZE (NumberOfPages), // NumberOfBytes | |
DeviceAddress, // DeviceAddress | |
Mapping // Mapping | |
); | |
if (EFI_ERROR (Status)) { | |
goto FreeSharedPages; | |
} | |
*HostAddress = NewHostAddress; | |
return EFI_SUCCESS; | |
FreeSharedPages: | |
VgpuDev->VirtIo->FreeSharedPages ( | |
VgpuDev->VirtIo, | |
NumberOfPages, | |
NewHostAddress | |
); | |
return Status; | |
} | |
/** | |
Unmap and free memory originally allocated and mapped with | |
VirtioGpuAllocateZeroAndMapBackingStore(). | |
If the memory allocated and mapped with | |
VirtioGpuAllocateZeroAndMapBackingStore() was attached to a host-side VirtIo | |
GPU resource with VirtioGpuResourceAttachBacking(), then the caller is | |
responsible for detaching the backing store from the same resource, with | |
VirtioGpuResourceDetachBacking(), before calling this function. | |
@param[in] VgpuDev The VGPU_DEV object that represents the VirtIo GPU | |
device. | |
@param[in] NumberOfPages The NumberOfPages parameter originally passed to | |
VirtioGpuAllocateZeroAndMapBackingStore(). | |
@param[in] HostAddress The HostAddress value originally output by | |
VirtioGpuAllocateZeroAndMapBackingStore(). | |
@param[in] Mapping The token that was originally output by | |
VirtioGpuAllocateZeroAndMapBackingStore(). | |
**/ | |
VOID | |
VirtioGpuUnmapAndFreeBackingStore ( | |
IN VGPU_DEV *VgpuDev, | |
IN UINTN NumberOfPages, | |
IN VOID *HostAddress, | |
IN VOID *Mapping | |
) | |
{ | |
VgpuDev->VirtIo->UnmapSharedBuffer ( | |
VgpuDev->VirtIo, | |
Mapping | |
); | |
VgpuDev->VirtIo->FreeSharedPages ( | |
VgpuDev->VirtIo, | |
NumberOfPages, | |
HostAddress | |
); | |
} | |
/** | |
EFI_EVENT_NOTIFY function for the VGPU_DEV.ExitBoot event. It resets the | |
VirtIo device, causing it to release its resources and to forget its | |
configuration. | |
This function may only be called (that is, VGPU_DEV.ExitBoot may only be | |
signaled) after VirtioGpuInit() returns and before VirtioGpuUninit() is | |
called. | |
@param[in] Event Event whose notification function is being invoked. | |
@param[in] Context Pointer to the associated VGPU_DEV object. | |
**/ | |
VOID | |
EFIAPI | |
VirtioGpuExitBoot ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
VGPU_DEV *VgpuDev; | |
DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __func__, Context)); | |
VgpuDev = Context; | |
VgpuDev->VirtIo->SetDeviceStatus (VgpuDev->VirtIo, 0); | |
} | |
/** | |
Internal utility function that sends a request to the VirtIo GPU device | |
model, awaits the answer from the host, and returns a status. | |
@param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo GPU | |
device. The caller is responsible to have | |
successfully invoked VirtioGpuInit() on VgpuDev | |
previously, while VirtioGpuUninit() must not have | |
been called on VgpuDev. | |
@param[in] RequestType The type of the request. The caller is responsible | |
for providing a VirtioGpuCmd* RequestType which, on | |
success, elicits a VirtioGpuRespOkNodata response | |
from the host. | |
@param[in] Fence Whether to enable fencing for this request. Fencing | |
forces the host to complete the command before | |
producing a response. If Fence is TRUE, then | |
VgpuDev->FenceId is consumed, and incremented. | |
@param[in,out] Header Pointer to the caller-allocated request object. The | |
request must start with VIRTIO_GPU_CONTROL_HEADER. | |
This function overwrites all fields of Header before | |
submitting the request to the host: | |
- it sets Type from RequestType, | |
- it sets Flags and FenceId based on Fence, | |
- it zeroes CtxId and Padding. | |
@param[in] RequestSize Size of the entire caller-allocated request object, | |
including the leading VIRTIO_GPU_CONTROL_HEADER. | |
@param[in] ResponseType The type of the response (VirtioGpuResp*). | |
@param[in,out] Response Pointer to the caller-allocated response object. The | |
request must start with VIRTIO_GPU_CONTROL_HEADER. | |
@param[in] ResponseSize Size of the entire caller-allocated response object, | |
including the leading VIRTIO_GPU_CONTROL_HEADER. | |
@retval EFI_SUCCESS Operation successful. | |
@retval EFI_DEVICE_ERROR The host rejected the request. The host error | |
code has been logged on the DEBUG_ERROR level. | |
@return Codes for unexpected errors in VirtIo | |
messaging, or request/response | |
mapping/unmapping. | |
**/ | |
STATIC | |
EFI_STATUS | |
VirtioGpuSendCommandWithReply ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN VIRTIO_GPU_CONTROL_TYPE RequestType, | |
IN BOOLEAN Fence, | |
IN OUT volatile VIRTIO_GPU_CONTROL_HEADER *Header, | |
IN UINTN RequestSize, | |
IN VIRTIO_GPU_CONTROL_TYPE ResponseType, | |
IN OUT volatile VIRTIO_GPU_CONTROL_HEADER *Response, | |
IN UINTN ResponseSize | |
) | |
{ | |
DESC_INDICES Indices; | |
EFI_STATUS Status; | |
UINT32 ResponseSizeRet; | |
EFI_PHYSICAL_ADDRESS RequestDeviceAddress; | |
VOID *RequestMap; | |
EFI_PHYSICAL_ADDRESS ResponseDeviceAddress; | |
VOID *ResponseMap; | |
// | |
// Initialize Header. | |
// | |
Header->Type = RequestType; | |
if (Fence) { | |
Header->Flags = VIRTIO_GPU_FLAG_FENCE; | |
Header->FenceId = VgpuDev->FenceId++; | |
} else { | |
Header->Flags = 0; | |
Header->FenceId = 0; | |
} | |
Header->CtxId = 0; | |
Header->Padding = 0; | |
ASSERT (RequestSize >= sizeof *Header); | |
ASSERT (RequestSize <= MAX_UINT32); | |
// | |
// Map request and response to bus master device addresses. | |
// | |
Status = VirtioMapAllBytesInSharedBuffer ( | |
VgpuDev->VirtIo, | |
VirtioOperationBusMasterRead, | |
(VOID *)Header, | |
RequestSize, | |
&RequestDeviceAddress, | |
&RequestMap | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = VirtioMapAllBytesInSharedBuffer ( | |
VgpuDev->VirtIo, | |
VirtioOperationBusMasterWrite, | |
(VOID *)Response, | |
ResponseSize, | |
&ResponseDeviceAddress, | |
&ResponseMap | |
); | |
if (EFI_ERROR (Status)) { | |
goto UnmapRequest; | |
} | |
// | |
// Compose the descriptor chain. | |
// | |
VirtioPrepare (&VgpuDev->Ring, &Indices); | |
VirtioAppendDesc ( | |
&VgpuDev->Ring, | |
RequestDeviceAddress, | |
(UINT32)RequestSize, | |
VRING_DESC_F_NEXT, | |
&Indices | |
); | |
VirtioAppendDesc ( | |
&VgpuDev->Ring, | |
ResponseDeviceAddress, | |
(UINT32)ResponseSize, | |
VRING_DESC_F_WRITE, | |
&Indices | |
); | |
// | |
// Send the command. | |
// | |
Status = VirtioFlush ( | |
VgpuDev->VirtIo, | |
VIRTIO_GPU_CONTROL_QUEUE, | |
&VgpuDev->Ring, | |
&Indices, | |
&ResponseSizeRet | |
); | |
if (EFI_ERROR (Status)) { | |
goto UnmapResponse; | |
} | |
// | |
// Verify response size. | |
// | |
if (ResponseSize != ResponseSizeRet) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: malformed response to Request=0x%x\n", | |
__func__, | |
(UINT32)RequestType | |
)); | |
Status = EFI_PROTOCOL_ERROR; | |
goto UnmapResponse; | |
} | |
// | |
// Unmap response and request, in reverse order of mapping. On error, the | |
// respective mapping is invalidated anyway, only the data may not have been | |
// committed to system memory (in case of VirtioOperationBusMasterWrite). | |
// | |
Status = VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, ResponseMap); | |
if (EFI_ERROR (Status)) { | |
goto UnmapRequest; | |
} | |
Status = VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, RequestMap); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Parse the response. | |
// | |
if (Response->Type == (UINT32)ResponseType) { | |
return EFI_SUCCESS; | |
} | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Request=0x%x Response=0x%x (expected 0x%x)\n", | |
__func__, | |
(UINT32)RequestType, | |
Response->Type, | |
ResponseType | |
)); | |
return EFI_DEVICE_ERROR; | |
UnmapResponse: | |
VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, ResponseMap); | |
UnmapRequest: | |
VgpuDev->VirtIo->UnmapSharedBuffer (VgpuDev->VirtIo, RequestMap); | |
return Status; | |
} | |
/** | |
Simplified version of VirtioGpuSendCommandWithReply() for commands | |
which do not send back any data. | |
**/ | |
STATIC | |
EFI_STATUS | |
VirtioGpuSendCommand ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN VIRTIO_GPU_CONTROL_TYPE RequestType, | |
IN BOOLEAN Fence, | |
IN OUT volatile VIRTIO_GPU_CONTROL_HEADER *Header, | |
IN UINTN RequestSize | |
) | |
{ | |
volatile VIRTIO_GPU_CONTROL_HEADER Response; | |
return VirtioGpuSendCommandWithReply ( | |
VgpuDev, | |
RequestType, | |
Fence, | |
Header, | |
RequestSize, | |
VirtioGpuRespOkNodata, | |
&Response, | |
sizeof (Response) | |
); | |
} | |
/** | |
The following functions send requests to the VirtIo GPU device model, await | |
the answer from the host, and return a status. They share the following | |
interface details: | |
@param[in,out] VgpuDev The VGPU_DEV object that represents the VirtIo GPU | |
device. The caller is responsible to have | |
successfully invoked VirtioGpuInit() on VgpuDev | |
previously, while VirtioGpuUninit() must not have | |
been called on VgpuDev. | |
@retval EFI_INVALID_PARAMETER Invalid command-specific parameters were | |
detected by this driver. | |
@retval EFI_SUCCESS Operation successful. | |
@retval EFI_DEVICE_ERROR The host rejected the request. The host error | |
code has been logged on the DEBUG_ERROR level. | |
@return Codes for unexpected errors in VirtIo | |
messaging. | |
For the command-specific parameters, please consult the GPU Device section of | |
the VirtIo 1.0 specification (see references in | |
"OvmfPkg/Include/IndustryStandard/VirtioGpu.h"). | |
**/ | |
EFI_STATUS | |
VirtioGpuResourceCreate2d ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN UINT32 ResourceId, | |
IN VIRTIO_GPU_FORMATS Format, | |
IN UINT32 Width, | |
IN UINT32 Height | |
) | |
{ | |
volatile VIRTIO_GPU_RESOURCE_CREATE_2D Request; | |
if (ResourceId == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Request.ResourceId = ResourceId; | |
Request.Format = (UINT32)Format; | |
Request.Width = Width; | |
Request.Height = Height; | |
return VirtioGpuSendCommand ( | |
VgpuDev, | |
VirtioGpuCmdResourceCreate2d, | |
FALSE, // Fence | |
&Request.Header, | |
sizeof Request | |
); | |
} | |
EFI_STATUS | |
VirtioGpuResourceUnref ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN UINT32 ResourceId | |
) | |
{ | |
volatile VIRTIO_GPU_RESOURCE_UNREF Request; | |
if (ResourceId == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Request.ResourceId = ResourceId; | |
Request.Padding = 0; | |
return VirtioGpuSendCommand ( | |
VgpuDev, | |
VirtioGpuCmdResourceUnref, | |
FALSE, // Fence | |
&Request.Header, | |
sizeof Request | |
); | |
} | |
EFI_STATUS | |
VirtioGpuResourceAttachBacking ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN UINT32 ResourceId, | |
IN EFI_PHYSICAL_ADDRESS BackingStoreDeviceAddress, | |
IN UINTN NumberOfPages | |
) | |
{ | |
volatile VIRTIO_GPU_RESOURCE_ATTACH_BACKING Request; | |
if (ResourceId == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Request.ResourceId = ResourceId; | |
Request.NrEntries = 1; | |
Request.Entry.Addr = BackingStoreDeviceAddress; | |
Request.Entry.Length = (UINT32)EFI_PAGES_TO_SIZE (NumberOfPages); | |
Request.Entry.Padding = 0; | |
return VirtioGpuSendCommand ( | |
VgpuDev, | |
VirtioGpuCmdResourceAttachBacking, | |
FALSE, // Fence | |
&Request.Header, | |
sizeof Request | |
); | |
} | |
EFI_STATUS | |
VirtioGpuResourceDetachBacking ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN UINT32 ResourceId | |
) | |
{ | |
volatile VIRTIO_GPU_RESOURCE_DETACH_BACKING Request; | |
if (ResourceId == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Request.ResourceId = ResourceId; | |
Request.Padding = 0; | |
// | |
// In this case, we set Fence to TRUE, because after this function returns, | |
// the caller might reasonably want to repurpose the backing pages | |
// immediately. Thus we should ensure that the host releases all references | |
// to the backing pages before we return. | |
// | |
return VirtioGpuSendCommand ( | |
VgpuDev, | |
VirtioGpuCmdResourceDetachBacking, | |
TRUE, // Fence | |
&Request.Header, | |
sizeof Request | |
); | |
} | |
EFI_STATUS | |
VirtioGpuSetScanout ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN UINT32 X, | |
IN UINT32 Y, | |
IN UINT32 Width, | |
IN UINT32 Height, | |
IN UINT32 ScanoutId, | |
IN UINT32 ResourceId | |
) | |
{ | |
volatile VIRTIO_GPU_SET_SCANOUT Request; | |
// | |
// Unlike for most other commands, ResourceId=0 is valid; it | |
// is used to disable a scanout. | |
// | |
Request.Rectangle.X = X; | |
Request.Rectangle.Y = Y; | |
Request.Rectangle.Width = Width; | |
Request.Rectangle.Height = Height; | |
Request.ScanoutId = ScanoutId; | |
Request.ResourceId = ResourceId; | |
return VirtioGpuSendCommand ( | |
VgpuDev, | |
VirtioGpuCmdSetScanout, | |
FALSE, // Fence | |
&Request.Header, | |
sizeof Request | |
); | |
} | |
EFI_STATUS | |
VirtioGpuTransferToHost2d ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN UINT32 X, | |
IN UINT32 Y, | |
IN UINT32 Width, | |
IN UINT32 Height, | |
IN UINT64 Offset, | |
IN UINT32 ResourceId | |
) | |
{ | |
volatile VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D Request; | |
if (ResourceId == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Request.Rectangle.X = X; | |
Request.Rectangle.Y = Y; | |
Request.Rectangle.Width = Width; | |
Request.Rectangle.Height = Height; | |
Request.Offset = Offset; | |
Request.ResourceId = ResourceId; | |
Request.Padding = 0; | |
return VirtioGpuSendCommand ( | |
VgpuDev, | |
VirtioGpuCmdTransferToHost2d, | |
FALSE, // Fence | |
&Request.Header, | |
sizeof Request | |
); | |
} | |
EFI_STATUS | |
VirtioGpuResourceFlush ( | |
IN OUT VGPU_DEV *VgpuDev, | |
IN UINT32 X, | |
IN UINT32 Y, | |
IN UINT32 Width, | |
IN UINT32 Height, | |
IN UINT32 ResourceId | |
) | |
{ | |
volatile VIRTIO_GPU_RESOURCE_FLUSH Request; | |
if (ResourceId == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Request.Rectangle.X = X; | |
Request.Rectangle.Y = Y; | |
Request.Rectangle.Width = Width; | |
Request.Rectangle.Height = Height; | |
Request.ResourceId = ResourceId; | |
Request.Padding = 0; | |
return VirtioGpuSendCommand ( | |
VgpuDev, | |
VirtioGpuCmdResourceFlush, | |
FALSE, // Fence | |
&Request.Header, | |
sizeof Request | |
); | |
} | |
EFI_STATUS | |
VirtioGpuGetDisplayInfo ( | |
IN OUT VGPU_DEV *VgpuDev, | |
volatile VIRTIO_GPU_RESP_DISPLAY_INFO *Response | |
) | |
{ | |
volatile VIRTIO_GPU_CONTROL_HEADER Request; | |
return VirtioGpuSendCommandWithReply ( | |
VgpuDev, | |
VirtioGpuCmdGetDisplayInfo, | |
FALSE, // Fence | |
&Request, | |
sizeof Request, | |
VirtioGpuRespOkDisplayInfo, | |
&Response->Header, | |
sizeof *Response | |
); | |
} |