When setting up the list of GOP modes offered on QEMU's stdvga ("VGA") and
QXL ("qxl-vga") video devices, QemuVideoBochsModeSetup() filters those
modes against the available framebuffer size. (Refer to SVN r15288 / git
commit ec88061e.)The current calculation is correct for stdvga, because on stdvga the value returned by VBE_DISPI_INDEX_VIDEO_MEMORY_64K, ie. the full video RAM, is usable for drawing. However, on the QXL card, only an initial portion of the video RAM is suitable for drawing, as compatibility frame buffer. The size of this segment can be read from a register in the QXL ROM bar (bar 2). Beyond this range, the video RAM contains buffers and structures for the QXL guest-host protocol. Without this fix, OVMF offers too large resolutions on the QXL card (up to the full size of the video RAM). If a GOP client selects such a resolution and draws into the video RAM past the compatibility segment, then the guest corrupts its communication structures (which is invalid guest behavior). Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <[email protected]> --- OvmfPkg/QemuVideoDxe/Qemu.h | 3 ++- OvmfPkg/QemuVideoDxe/Driver.c | 3 ++- OvmfPkg/QemuVideoDxe/Initialize.c | 41 +++++++++++++++++++++++++++++++++++---- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/OvmfPkg/QemuVideoDxe/Qemu.h b/OvmfPkg/QemuVideoDxe/Qemu.h index 4bf51c7..52ee20d 100644 --- a/OvmfPkg/QemuVideoDxe/Qemu.h +++ b/OvmfPkg/QemuVideoDxe/Qemu.h @@ -499,7 +499,8 @@ QemuVideoCirrusModeSetup ( EFI_STATUS QemuVideoBochsModeSetup ( - QEMU_VIDEO_PRIVATE_DATA *Private + QEMU_VIDEO_PRIVATE_DATA *Private, + BOOLEAN IsQxl ); VOID diff --git a/OvmfPkg/QemuVideoDxe/Driver.c b/OvmfPkg/QemuVideoDxe/Driver.c index 2194cbe..abe2c9d 100644 --- a/OvmfPkg/QemuVideoDxe/Driver.c +++ b/OvmfPkg/QemuVideoDxe/Driver.c @@ -354,7 +354,8 @@ QemuVideoControllerDriverStart ( break; case QEMU_VIDEO_BOCHS_MMIO: case QEMU_VIDEO_BOCHS: - Status = QemuVideoBochsModeSetup (Private); + Status = QemuVideoBochsModeSetup (Private, + (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS)); break; default: ASSERT (FALSE); diff --git a/OvmfPkg/QemuVideoDxe/Initialize.c b/OvmfPkg/QemuVideoDxe/Initialize.c index a536d47..6111d06 100644 --- a/OvmfPkg/QemuVideoDxe/Initialize.c +++ b/OvmfPkg/QemuVideoDxe/Initialize.c @@ -253,7 +253,8 @@ QEMU_VIDEO_BOCHS_MODES QemuVideoBochsModes[] = { EFI_STATUS QemuVideoBochsModeSetup ( - QEMU_VIDEO_PRIVATE_DATA *Private + QEMU_VIDEO_PRIVATE_DATA *Private, + BOOLEAN IsQxl ) { UINT32 AvailableFbSize; @@ -262,10 +263,42 @@ QemuVideoBochsModeSetup ( QEMU_VIDEO_BOCHS_MODES *VideoMode; // - // fetch available framebuffer size + // Fetch the available framebuffer size. // - AvailableFbSize = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K); - AvailableFbSize *= SIZE_64KB; + // On stdvga, the full memory size returned by the + // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is usable for drawing. + // + // On QXL however, only a leading segment, "surface 0", can be used for + // drawing; the rest of the buffer is used for the QXL guest-host protocol. + // The size of the drawable portion is available from a field in the QXL ROM + // bar. + // + if (IsQxl) { + UINT32 Signature; + UINT32 DrawStart; + + Signature = 0; + DrawStart = 0xFFFFFFFF; + AvailableFbSize = 0; + if (EFI_ERROR ( + Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32, + PCI_BAR_IDX2, 0, 1, &Signature)) || + Signature != SIGNATURE_32 ('Q', 'X', 'R', 'O') || + EFI_ERROR ( + Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32, + PCI_BAR_IDX2, 36, 1, &DrawStart)) || + DrawStart != 0 || + EFI_ERROR ( + Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32, + PCI_BAR_IDX2, 40, 1, &AvailableFbSize))) { + DEBUG ((EFI_D_ERROR, "%a: can't read size of drawable buffer from QXL " + "ROM\n", __FUNCTION__)); + return EFI_NOT_FOUND; + } + } else { + AvailableFbSize = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K); + AvailableFbSize *= SIZE_64KB; + } DEBUG ((EFI_D_VERBOSE, "%a: AvailableFbSize=0x%x\n", __FUNCTION__, AvailableFbSize)); -- 1.8.3.1 ------------------------------------------------------------------------------ _______________________________________________ edk2-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/edk2-devel
