diff mbox

[edk2] OvmfPkg: QemuVideoDxe: fix querying of QXL's drawable buffer size

Message ID 1408201311-16898-1-git-send-email-lersek@redhat.com
State New
Headers show

Commit Message

Laszlo Ersek Aug. 16, 2014, 3:01 p.m. UTC
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 <lersek@redhat.com>
---
 OvmfPkg/QemuVideoDxe/Qemu.h       |  3 ++-
 OvmfPkg/QemuVideoDxe/Driver.c     |  3 ++-
 OvmfPkg/QemuVideoDxe/Initialize.c | 41 +++++++++++++++++++++++++++++++++++----
 3 files changed, 41 insertions(+), 6 deletions(-)

Comments

Gerd Hoffmann Aug. 25, 2014, 12:43 p.m. UTC | #1
Hi,

> 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.

Value returned by VBE_DISPI_INDEX_VIDEO_MEMORY_64K being wrong is a qemu
bug.  We have releases with the bug in the wild though, so adding this
as (temporary?) workaround is sensible IMO.  The comment should be
updated saying so though.

cheers,
  Gerd



------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
Laszlo Ersek Aug. 25, 2014, 9:21 p.m. UTC | #2
On 08/25/14 14:43, Gerd Hoffmann wrote:
>   Hi,
> 
>> 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.
> 
> Value returned by VBE_DISPI_INDEX_VIDEO_MEMORY_64K being wrong is a qemu
> bug.  We have releases with the bug in the wild though, so adding this
> as (temporary?) workaround is sensible IMO.  The comment should be
> updated saying so though.

Thanks for the review!

If the workaround is stable in your opinion (ie. it can be relied upon
even after the qemu problem with VBE_DISPI_INDEX_VIDEO_MEMORY_64K is
fixed), then I'd probably leave it in, even in the long term.

Jordan, is it enough if I only reword the commit message below, or do
you want me to resubmit the patch?

-------------------------
OvmfPkg: QemuVideoDxe: work around misreported QXL framebuffer size

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 VBE_DISPI_INDEX_VIDEO_MEMORY_64K register of both stdvga and QXL is
supposed to report the size of the drawable, VGA-compatibility
framebuffer. Instead, up to and including qemu-2.1, this register
actually reports the full video RAM (PCI BAR 0) size.

In case of stdvga, this happens to be correct, because on that card the
full PCI BAR 0 is usable for drawing; there is no difference between
"drawable framebuffer size" and "video RAM (PCI BAR 0) size".

However, on the QXL card, only an initial portion of the video RAM is
suitable for drawing, as compatibility framebuffer; and the value
currently reported by VBE_DISPI_INDEX_VIDEO_MEMORY_64K overshoots the
valid size. Beyond the drawable range, the video RAM contains buffers
and structures for the QXL guest-host protocol.

Luckily, the size of the drawable QXL framebuffer can also be read from
a register in the QXL ROM BAR (PCI BAR 2), so let's retrieve it from
there.

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 <lersek@redhat.com>
-------------------------

Thanks,
Laszlo


------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
Jordan Justen Aug. 25, 2014, 9:42 p.m. UTC | #3
On Mon, Aug 25, 2014 at 2:21 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> On 08/25/14 14:43, Gerd Hoffmann wrote:
>>   Hi,
>>
>>> 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.
>>
>> Value returned by VBE_DISPI_INDEX_VIDEO_MEMORY_64K being wrong is a qemu
>> bug.  We have releases with the bug in the wild though, so adding this
>> as (temporary?) workaround is sensible IMO.  The comment should be
>> updated saying so though.
>
> Thanks for the review!
>
> If the workaround is stable in your opinion (ie. it can be relied upon
> even after the qemu problem with VBE_DISPI_INDEX_VIDEO_MEMORY_64K is
> fixed), then I'd probably leave it in, even in the long term.
>
> Jordan, is it enough if I only reword the commit message below, or do
> you want me to resubmit the patch?

Why not use Private->Variant, rather than 'IsQxl'?

-Jordan

> -------------------------
> OvmfPkg: QemuVideoDxe: work around misreported QXL framebuffer size
>
> 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 VBE_DISPI_INDEX_VIDEO_MEMORY_64K register of both stdvga and QXL is
> supposed to report the size of the drawable, VGA-compatibility
> framebuffer. Instead, up to and including qemu-2.1, this register
> actually reports the full video RAM (PCI BAR 0) size.
>
> In case of stdvga, this happens to be correct, because on that card the
> full PCI BAR 0 is usable for drawing; there is no difference between
> "drawable framebuffer size" and "video RAM (PCI BAR 0) size".
>
> However, on the QXL card, only an initial portion of the video RAM is
> suitable for drawing, as compatibility framebuffer; and the value
> currently reported by VBE_DISPI_INDEX_VIDEO_MEMORY_64K overshoots the
> valid size. Beyond the drawable range, the video RAM contains buffers
> and structures for the QXL guest-host protocol.
>
> Luckily, the size of the drawable QXL framebuffer can also be read from
> a register in the QXL ROM BAR (PCI BAR 2), so let's retrieve it from
> there.
>
> 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 <lersek@redhat.com>
> -------------------------
>
> Thanks,
> Laszlo
>
>
> ------------------------------------------------------------------------------
> Slashdot TV.
> Video for Nerds.  Stuff that matters.
> http://tv.slashdot.org/
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/edk2-devel

------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
Laszlo Ersek Aug. 25, 2014, 9:56 p.m. UTC | #4
On 08/25/14 23:42, Jordan Justen wrote:
> On Mon, Aug 25, 2014 at 2:21 PM, Laszlo Ersek <lersek@redhat.com>
> wrote:
>> On 08/25/14 14:43, Gerd Hoffmann wrote:
>>>   Hi,
>>>
>>>> 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.
>>>
>>> Value returned by VBE_DISPI_INDEX_VIDEO_MEMORY_64K being wrong is a
>>> qemu bug.  We have releases with the bug in the wild though, so
>>> adding this as (temporary?) workaround is sensible IMO.  The comment
>>> should be updated saying so though.
>>
>> Thanks for the review!
>>
>> If the workaround is stable in your opinion (ie. it can be relied
>> upon even after the qemu problem with
>> VBE_DISPI_INDEX_VIDEO_MEMORY_64K is fixed), then I'd probably leave
>> it in, even in the long term.
>>
>> Jordan, is it enough if I only reword the commit message below, or do
>> you want me to resubmit the patch?
>
> Why not use Private->Variant, rather than 'IsQxl'?

I wondered if you would ask that question! :)

The reason is that at that point Private->Variant does not
*necessarily* distinguish QXL from stdvga. Originally, yes,
Private->Variant distinguishes QXL (QEMU_VIDEO_BOCHS) from stdvga
(QEMU_VIDEO_BOCHS_MMIO), but please see this in
QemuVideoControllerDriverStart():

  //
  // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
  //
  if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
    EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;

    Status = Private->PciIo->GetBarAttributes (
                        Private->PciIo,
                        PCI_BAR_IDX2,
                        NULL,
                        (VOID**) &MmioDesc
                        );
    if (EFI_ERROR (Status) ||
        MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
      DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
      Private->Variant = QEMU_VIDEO_BOCHS;
    } else {
      DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
              MmioDesc->AddrRangeMin));
    }

    if (!EFI_ERROR (Status)) {
      FreePool (MmioDesc);
    }
  }

There's a path here where Private->Variant changes from
QEMU_VIDEO_BOCHS_MMIO to QEMU_VIDEO_BOCHS, ie. an stdvga card would
appear as QXL.

For this reason, I added the IsQxl parameter, and I fill it in from:

  case QEMU_VIDEO_BOCHS:
    Status = QemuVideoBochsModeSetup (Private,
               (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS));

The expression does not use Private->Variant, it uses Card->Variant.

I thought about introducing more fields to Private, but it seemed
overkill; the difference is only in QemuVideoBochsModeSetup(), and that
one can key off a local variable of the caller.

Thanks,
Laszlo

------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
Jordan Justen Aug. 25, 2014, 11:41 p.m. UTC | #5
On Mon, Aug 25, 2014 at 2:56 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> On 08/25/14 23:42, Jordan Justen wrote:
>> On Mon, Aug 25, 2014 at 2:21 PM, Laszlo Ersek <lersek@redhat.com>
>> wrote:
>>> On 08/25/14 14:43, Gerd Hoffmann wrote:
>>>>   Hi,
>>>>
>>>>> 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.
>>>>
>>>> Value returned by VBE_DISPI_INDEX_VIDEO_MEMORY_64K being wrong is a
>>>> qemu bug.  We have releases with the bug in the wild though, so
>>>> adding this as (temporary?) workaround is sensible IMO.  The comment
>>>> should be updated saying so though.
>>>
>>> Thanks for the review!
>>>
>>> If the workaround is stable in your opinion (ie. it can be relied
>>> upon even after the qemu problem with
>>> VBE_DISPI_INDEX_VIDEO_MEMORY_64K is fixed), then I'd probably leave
>>> it in, even in the long term.
>>>
>>> Jordan, is it enough if I only reword the commit message below, or do
>>> you want me to resubmit the patch?
>>
>> Why not use Private->Variant, rather than 'IsQxl'?
>
> I wondered if you would ask that question! :)
>
> The reason is that at that point Private->Variant does not
> *necessarily* distinguish QXL from stdvga. Originally, yes,
> Private->Variant distinguishes QXL (QEMU_VIDEO_BOCHS) from stdvga
> (QEMU_VIDEO_BOCHS_MMIO), but please see this in
> QemuVideoControllerDriverStart():
>
>   //
>   // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
>   //
>   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
>     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
>
>     Status = Private->PciIo->GetBarAttributes (
>                         Private->PciIo,
>                         PCI_BAR_IDX2,
>                         NULL,
>                         (VOID**) &MmioDesc
>                         );
>     if (EFI_ERROR (Status) ||
>         MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
>       DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
>       Private->Variant = QEMU_VIDEO_BOCHS;
>     } else {
>       DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
>               MmioDesc->AddrRangeMin));
>     }
>
>     if (!EFI_ERROR (Status)) {
>       FreePool (MmioDesc);
>     }
>   }
>
> There's a path here where Private->Variant changes from
> QEMU_VIDEO_BOCHS_MMIO to QEMU_VIDEO_BOCHS, ie. an stdvga card would
> appear as QXL.
>
> For this reason, I added the IsQxl parameter, and I fill it in from:
>
>   case QEMU_VIDEO_BOCHS:
>     Status = QemuVideoBochsModeSetup (Private,
>                (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS));

Hmm, I see.

How about, for clarity, above, near where you first assign
Private->Variant, you also set a local IsQxl variable?

And a comment might not hurt:
//
// IsQxl is based on the detected Card->Variant, which at a
// later point might not match Private->Variant.
//

-Jordan

> The expression does not use Private->Variant, it uses Card->Variant.
>
> I thought about introducing more fields to Private, but it seemed
> overkill; the difference is only in QemuVideoBochsModeSetup(), and that
> one can key off a local variable of the caller.
>
> Thanks,
> Laszlo

------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
Laszlo Ersek Aug. 25, 2014, 11:47 p.m. UTC | #6
On 08/26/14 01:41, Jordan Justen wrote:
> On Mon, Aug 25, 2014 at 2:56 PM, Laszlo Ersek <lersek@redhat.com> wrote:
>> On 08/25/14 23:42, Jordan Justen wrote:
>>> On Mon, Aug 25, 2014 at 2:21 PM, Laszlo Ersek <lersek@redhat.com>
>>> wrote:
>>>> On 08/25/14 14:43, Gerd Hoffmann wrote:
>>>>>   Hi,
>>>>>
>>>>>> 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.
>>>>>
>>>>> Value returned by VBE_DISPI_INDEX_VIDEO_MEMORY_64K being wrong is a
>>>>> qemu bug.  We have releases with the bug in the wild though, so
>>>>> adding this as (temporary?) workaround is sensible IMO.  The comment
>>>>> should be updated saying so though.
>>>>
>>>> Thanks for the review!
>>>>
>>>> If the workaround is stable in your opinion (ie. it can be relied
>>>> upon even after the qemu problem with
>>>> VBE_DISPI_INDEX_VIDEO_MEMORY_64K is fixed), then I'd probably leave
>>>> it in, even in the long term.
>>>>
>>>> Jordan, is it enough if I only reword the commit message below, or do
>>>> you want me to resubmit the patch?
>>>
>>> Why not use Private->Variant, rather than 'IsQxl'?
>>
>> I wondered if you would ask that question! :)
>>
>> The reason is that at that point Private->Variant does not
>> *necessarily* distinguish QXL from stdvga. Originally, yes,
>> Private->Variant distinguishes QXL (QEMU_VIDEO_BOCHS) from stdvga
>> (QEMU_VIDEO_BOCHS_MMIO), but please see this in
>> QemuVideoControllerDriverStart():
>>
>>   //
>>   // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
>>   //
>>   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
>>     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
>>
>>     Status = Private->PciIo->GetBarAttributes (
>>                         Private->PciIo,
>>                         PCI_BAR_IDX2,
>>                         NULL,
>>                         (VOID**) &MmioDesc
>>                         );
>>     if (EFI_ERROR (Status) ||
>>         MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
>>       DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
>>       Private->Variant = QEMU_VIDEO_BOCHS;
>>     } else {
>>       DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
>>               MmioDesc->AddrRangeMin));
>>     }
>>
>>     if (!EFI_ERROR (Status)) {
>>       FreePool (MmioDesc);
>>     }
>>   }
>>
>> There's a path here where Private->Variant changes from
>> QEMU_VIDEO_BOCHS_MMIO to QEMU_VIDEO_BOCHS, ie. an stdvga card would
>> appear as QXL.
>>
>> For this reason, I added the IsQxl parameter, and I fill it in from:
>>
>>   case QEMU_VIDEO_BOCHS:
>>     Status = QemuVideoBochsModeSetup (Private,
>>                (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS));
> 
> Hmm, I see.
> 
> How about, for clarity, above, near where you first assign
> Private->Variant, you also set a local IsQxl variable?
> 
> And a comment might not hurt:
> //
> // IsQxl is based on the detected Card->Variant, which at a
> // later point might not match Private->Variant.
> //

Will do, thanks!
Laszlo


------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
Gerd Hoffmann Aug. 26, 2014, 6 a.m. UTC | #7
Hi,

> If the workaround is stable in your opinion (ie. it can be relied upon
> even after the qemu problem with VBE_DISPI_INDEX_VIDEO_MEMORY_64K is
> fixed), then I'd probably leave it in, even in the long term.

Yes, ROM (bar 2) struct layout is stable.

> Jordan, is it enough if I only reword the commit message below, or do
> you want me to resubmit the patch?

I think the comment in the code should be updated too.

cheers,
  Gerd



------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
diff mbox

Patch

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));