diff --git a/OvmfPkg/QemuVideoDxe/Driver.c b/OvmfPkg/QemuVideoDxe/Driver.c index 2194cbef44..17bd4cc2cc 100644 --- a/OvmfPkg/QemuVideoDxe/Driver.c +++ b/OvmfPkg/QemuVideoDxe/Driver.c @@ -173,6 +173,7 @@ QemuVideoControllerDriverStart ( EFI_TPL OldTpl; EFI_STATUS Status; QEMU_VIDEO_PRIVATE_DATA *Private; + BOOLEAN IsQxl; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; ACPI_ADR_DEVICE_PATH AcpiDeviceNode; PCI_TYPE00 Pci; @@ -234,6 +235,12 @@ QemuVideoControllerDriverStart ( } Private->Variant = Card->Variant; + // + // IsQxl is based on the detected Card->Variant, which at a later point might + // not match Private->Variant. + // + IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS); + // // Save original PCI attributes // @@ -354,7 +361,7 @@ QemuVideoControllerDriverStart ( break; case QEMU_VIDEO_BOCHS_MMIO: case QEMU_VIDEO_BOCHS: - Status = QemuVideoBochsModeSetup (Private); + Status = QemuVideoBochsModeSetup (Private, IsQxl); break; default: ASSERT (FALSE); diff --git a/OvmfPkg/QemuVideoDxe/Initialize.c b/OvmfPkg/QemuVideoDxe/Initialize.c index a536d47bbb..9e0c3aa09f 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,48 @@ 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; + // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the + // drawable framebuffer. Up to and including qemu-2.1 however it used to + // return the size of PCI BAR 0 (ie. the full video RAM size). + // + // On stdvga the two concepts coincide with each other; the full memory size + // is usable for drawing. + // + // On QXL however, only a leading segment, "surface 0", can be used for + // drawing; the rest of the video memory is used for the QXL guest-host + // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of + // "surface 0", but since it doesn't (up to and including qemu-2.1), we + // retrieve the size of the drawable portion from a field in the QXL ROM BAR, + // where it is also available. + // + 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)); diff --git a/OvmfPkg/QemuVideoDxe/Qemu.h b/OvmfPkg/QemuVideoDxe/Qemu.h index 4bf51c7150..52ee20d8ba 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