On 05/10/14 00:49, Jordan Justen wrote:
> On Thu, May 8, 2014 at 10:45 AM, Laszlo Ersek <ler...@redhat.com> wrote:
>> The Windows 2008 R2 SP1 UEFI guest's default video driver is buggy -- it
>> dereferences the real mode Int10h vector, loads the pointed-to handler
>> code, and executes what it thinks to be VGA BIOS services in an internal
>> real-mode emulator. Consequently, video mode switching doesn't work in
>> Windows 2008 R2 SP1 when it runs on the pure UEFI build of OVMF, making
>> the guest uninstallable.
> 
> Can you add a Windows 2008 section to the README?

Good point, will do.

> For example, I think -vga qxl needs to be used, right?

One of '-vga std' and '-vga qxl'. The latter is recommended because then
you can install the QXL XDDM guest driver, which gives you S3 and a
number of graphics resolutions.

[snip]

>> +#pragma pack (1)
>> +typedef struct {
>> +  UINT8  Signature[4];
>> +  UINT16 VesaVersion;
>> +  UINT32 OemNameAddress;
>> +  UINT32 Capabilities;
>> +  UINT32 ModeListAddress;
>> +  UINT16 VideoMem64K;
>> +  UINT16 OemSoftwareVersion;
>> +  UINT32 VendorNameAddress;
>> +  UINT32 ProductNameAddress;
>> +  UINT32 ProductRevAddress;
>> +} VBE_INFO_BASE;
>> +
>> +typedef struct {
>> +  VBE_INFO_BASE  Base;
>> +  UINT8          Buffer[256 - sizeof (VBE_INFO_BASE)];
>> +} VBE_INFO;
>> +
>> +typedef struct {
>> +  UINT16 ModeAttr;
>> +  UINT8  WindowAAttr;
>> +  UINT8  WindowBAttr;
>> +  UINT16 WindowGranularityKB;
>> +  UINT16 WindowSizeKB;
>> +  UINT16 WindowAStartSegment;
>> +  UINT16 WindowBStartSegment;
>> +  UINT32 WindowPositioningAddress;
>> +  UINT16 BytesPerScanLine;
>> +
>> +  UINT16 Width;
>> +  UINT16 Height;
>> +  UINT8  CharCellWidth;
>> +  UINT8  CharCellHeight;
>> +  UINT8  NumPlanes;
>> +  UINT8  BitsPerPixel;
>> +  UINT8  NumBanks;
>> +  UINT8  MemoryModel;
>> +  UINT8  BankSizeKB;
>> +  UINT8  NumImagePagesLessOne;
>> +  UINT8  Vbe3;
>> +
>> +  UINT8  RedMaskSize;
>> +  UINT8  RedMaskPos;
>> +  UINT8  GreenMaskSize;
>> +  UINT8  GreenMaskPos;
>> +  UINT8  BlueMaskSize;
>> +  UINT8  BlueMaskPos;
>> +  UINT8  ReservedMaskSize;
>> +  UINT8  ReservedMaskPos;
>> +  UINT8  DirectColorModeInfo;
>> +
>> +  UINT32 LfbAddress;
>> +  UINT32 OffScreenAddress;
>> +  UINT16 OffScreenSizeKB;
>> +
>> +  UINT16 BytesPerScanLineLinear;
>> +  UINT8  NumImagesLessOneBanked;
>> +  UINT8  NumImagesLessOneLinear;
>> +  UINT8  RedMaskSizeLinear;
>> +  UINT8  RedMaskPosLinear;
>> +  UINT8  GreenMaskSizeLinear;
>> +  UINT8  GreenMaskPosLinear;
>> +  UINT8  BlueMaskSizeLinear;
>> +  UINT8  BlueMaskPosLinear;
>> +  UINT8  ReservedMaskSizeLinear;
>> +  UINT8  ReservedMaskPosLinear;
>> +  UINT32 MaxPixelClockHz;
>> +  UINT8  Reserved[190];
>> +} VBE_MODE_INFO;
> 
> OvmfPkg/Include/IndustryStandard/LegacyVgaBios.h?

In general I prefer to expose type definitions only if there are at
least two users, but I can certainly do this, yes.

> 
>> +
>> +typedef struct {
>> +  UINT16 Offset;
>> +  UINT16 Segment;
>> +} IVT_ENTRY;
>> +#pragma pack ()
>> +
>> +//
>> +// This string is displayed by Windows 2008 R2 SP1 in the Screen Resolution,
>> +// Advanced Settings dialog. It should be short.
>> +//
>> +STATIC CONST CHAR8 mProductRevision[] = "OVMF Int10h (fake)";
>> +
>> +/**
>> +  Install the VBE Info and VBE Mode Info structures, and the VBE service
>> +  handler routine in the C segment. Point the real-mode Int10h interrupt 
>> vector
>> +  to the handler. The only advertised mode is 1024x768x32.
>> +
>> +  @param[in] CardName         Name of the video card to be exposed in the
>> +                              Product Name field of the VBE Info structure. 
>> The
>> +                              parameter must originate from a
>> +                              QEMU_VIDEO_CARD.Name field.
>> +  @param[in] FrameBufferBase  Guest-physical base address of the video 
>> card's
>> +                              frame buffer.
>> +
>> +  @retval EFI_SUCCESS  Shim successfully installed.
>> +  @return              gBS->AllocatePages() status codes.
>> +**/
>> +EFI_STATUS
>> +InstallVbeShim (
>> +  IN CONST CHAR16         *CardName,
>> +  IN EFI_PHYSICAL_ADDRESS FrameBufferBase
>> +  )
>> +{
>> +  UINTN                Pam1Address;
>> +  UINT8                Pam1;
>> +  EFI_PHYSICAL_ADDRESS SegmentC;
>> +  UINTN                SegmentCPages;
>> +  EFI_STATUS           Status;
>> +  VBE_INFO             *VbeInfoFull;
>> +  VBE_INFO_BASE        *VbeInfo;
>> +  UINT8                *Ptr;
>> +  UINTN                Printed;
>> +  VBE_MODE_INFO        *VbeModeInfo;
>> +  EFI_PHYSICAL_ADDRESS Segment0;
>> +  UINTN                Segment0Pages;
>> +  IVT_ENTRY            *Int0x10;
>> +
>> +  Pam1Address = PCI_LIB_ADDRESS (0, 0, 0, 0x5A);
> 
> Should we use LegacyRegion here?

I had considered that, yes:

> I guess that would mean always enabling Csm/CsmSupportLib.

I had checked this source code, and I had decided against using it. It's
too big IMO, the LegacyRegion2*() interfaces are overkill, and I don't
like the "CsmSupportLib" name / dependency either (I want to avoid the
CSM with this patch).

(Side note: the header file with the lib's public interfaces should be
moved under OvmfPkg/Include/Library/ as well, shouldn't it?)

The sole purpose of this patch is bug compatibility with Windows 2008
R2. I think it's alright to cut corners and to get dirty here.

For example, in a perfect world, a UEFI video driver should have no
business messing with the PAM registers, be that via CsmSupportLib or
more directly with PciLib. Once we do that, we might as well opt for the
shortest / simplest solution.

> 
>> +  //
>> +  // low nibble covers 0xC0000 to 0xC3FFF
>> +  // high nibble covers 0xC4000 to 0xC7FFF
>> +  // bit1 in each nibble is Write Enable
>> +  // bit0 in each nibble is Read Enable
>> +  //
>> +  Pam1 = PciRead8 (Pam1Address);
>> +  PciWrite8 (Pam1Address, Pam1 | (BIT1 | BIT0));
>> +
>> +  //
>> +  // We never added memory space durig PEI or DXE for the C segment, so we
>> +  // don't need to (and can't) allocate from there. Also, guest operating
>> +  // systems will see a hole in the UEFI memory map there.
>> +  //
>> +  SegmentC      = 0xC0000;
>> +  SegmentCPages = 4;
>> +
>> +  ASSERT (sizeof mVbeShim <= EFI_PAGES_TO_SIZE (SegmentCPages));
>> +  CopyMem ((VOID *)(UINTN)SegmentC, mVbeShim, sizeof mVbeShim);
>> +
>> +  //
>> +  // Fill in the VBE INFO structure.
>> +  //
>> +  VbeInfoFull = (VBE_INFO *)(UINTN)SegmentC;
>> +  VbeInfo     = &VbeInfoFull->Base;
>> +  Ptr         = VbeInfoFull->Buffer;
>> +
>> +  CopyMem (VbeInfo->Signature, "VESA", 4);
>> +  VbeInfo->VesaVersion = 0x0300;
>> +
>> +  VbeInfo->OemNameAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr);
>> +  CopyMem (Ptr, "QEMU", 5);
>> +  Ptr += 5;
>> +
>> +  VbeInfo->Capabilities = BIT0; // DAC can be switched into 8-bit mode
>> +
>> +  VbeInfo->ModeListAddress = (UINT32)(SegmentC << 12 | (UINT16)(UINTN)Ptr);
>> +  *(UINT16*)Ptr = 0x00f1; // mode number
>> +  Ptr += 2;
>> +  *(UINT16*)Ptr = 0xFFFF; // mode list terminator
>> +  Ptr += 2;
>> +
>> +  VbeInfo->VideoMem64K = (UINT16)((1024 * 768 * 4 + 65535) / 65536);
>> +  VbeInfo->OemSoftwareVersion = 0x0000;
>> +
>> +  VbeInfo->VendorNameAddress = (UINT32)(SegmentC << 12 | 
>> (UINT16)(UINTN)Ptr);
>> +  CopyMem (Ptr, "OVMF", 5);
>> +  Ptr += 5;
>> +
>> +  VbeInfo->ProductNameAddress = (UINT32)(SegmentC << 12 | 
>> (UINT16)(UINTN)Ptr);
>> +  Printed = AsciiSPrint ((CHAR8 *)Ptr,
>> +              sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer), 
>> "%s",
>> +              CardName);
>> +  Ptr += Printed + 1;
>> +
>> +  VbeInfo->ProductRevAddress = (UINT32)(SegmentC << 12 | 
>> (UINT16)(UINTN)Ptr);
>> +  CopyMem (Ptr, mProductRevision, sizeof mProductRevision);
>> +  Ptr += sizeof mProductRevision;
>> +
>> +  ASSERT (sizeof VbeInfoFull->Buffer >= Ptr - VbeInfoFull->Buffer);
>> +  ZeroMem (Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer));
>> +
>> +  //
>> +  // Fil in the VBE MODE INFO structure.
>> +  //
>> +  VbeModeInfo = (VBE_MODE_INFO *)(VbeInfoFull + 1);
>> +
>> +  //
>> +  // bit0: mode supported by present hardware configuration
>> +  // bit1: optional information available (must be =1 for VBE v1.2+)
>> +  // bit3: set if color, clear if monochrome
>> +  // bit4: set if graphics mode, clear if text mode
>> +  // bit5: mode is not VGA-compatible
>> +  // bit7: linear framebuffer mode supported
>> +  //
>> +  VbeModeInfo->ModeAttr = BIT7 | BIT5 | BIT4 | BIT3 | BIT1 | BIT0;
>> +
>> +  //
>> +  // bit0: exists
>> +  // bit1: bit1: readable
>> +  // bit2: writeable
>> +  //
>> +  VbeModeInfo->WindowAAttr              = BIT2 | BIT1 | BIT0;
>> +
>> +  VbeModeInfo->WindowBAttr              = 0x00;
>> +  VbeModeInfo->WindowGranularityKB      = 0x0040;
>> +  VbeModeInfo->WindowSizeKB             = 0x0040;
>> +  VbeModeInfo->WindowAStartSegment      = 0xA000;
>> +  VbeModeInfo->WindowBStartSegment      = 0x0000;
>> +  VbeModeInfo->WindowPositioningAddress = 0x0000;
>> +  VbeModeInfo->BytesPerScanLine         = 1024 * 4;
>> +
>> +  VbeModeInfo->Width                = 1024;
>> +  VbeModeInfo->Height               = 768;
>> +  VbeModeInfo->CharCellWidth        = 8;
>> +  VbeModeInfo->CharCellHeight       = 16;
>> +  VbeModeInfo->NumPlanes            = 1;
>> +  VbeModeInfo->BitsPerPixel         = 32;
>> +  VbeModeInfo->NumBanks             = 1;
>> +  VbeModeInfo->MemoryModel          = 6; // direct color
>> +  VbeModeInfo->BankSizeKB           = 0;
>> +  VbeModeInfo->NumImagePagesLessOne = 0;
>> +  VbeModeInfo->Vbe3                 = 0x01;
>> +
>> +  VbeModeInfo->RedMaskSize      = 8;
>> +  VbeModeInfo->RedMaskPos       = 16;
>> +  VbeModeInfo->GreenMaskSize    = 8;
>> +  VbeModeInfo->GreenMaskPos     = 8;
>> +  VbeModeInfo->BlueMaskSize     = 8;
>> +  VbeModeInfo->BlueMaskPos      = 0;
>> +  VbeModeInfo->ReservedMaskSize = 8;
>> +  VbeModeInfo->ReservedMaskPos  = 24;
>> +
>> +  //
>> +  // bit1: Bytes in reserved field may be used by application
>> +  //
>> +  VbeModeInfo->DirectColorModeInfo = BIT1;
>> +
>> +  VbeModeInfo->LfbAddress       = (UINT32)FrameBufferBase;
>> +  VbeModeInfo->OffScreenAddress = 0;
>> +  VbeModeInfo->OffScreenSizeKB  = 0;
>> +
>> +  VbeModeInfo->BytesPerScanLineLinear = 1024 * 4;
>> +  VbeModeInfo->NumImagesLessOneBanked = 0;
>> +  VbeModeInfo->NumImagesLessOneLinear = 0;
>> +  VbeModeInfo->RedMaskSizeLinear      = 8;
>> +  VbeModeInfo->RedMaskPosLinear       = 16;
>> +  VbeModeInfo->GreenMaskSizeLinear    = 8;
>> +  VbeModeInfo->GreenMaskPosLinear     = 8;
>> +  VbeModeInfo->BlueMaskSizeLinear     = 8;
>> +  VbeModeInfo->BlueMaskPosLinear      = 0;
>> +  VbeModeInfo->ReservedMaskSizeLinear = 8;
>> +  VbeModeInfo->ReservedMaskPosLinear  = 24;
>> +  VbeModeInfo->MaxPixelClockHz        = 0;
>> +
>> +  ZeroMem (VbeModeInfo->Reserved, sizeof VbeModeInfo->Reserved);
>> +
>> +  //
>> +  // Clear Write Enable (bit1), keep Read Enable (bit0) set
>> +  //
>> +  PciWrite8 (Pam1Address, (Pam1 & ~BIT1) | BIT0);
>> +
>> +  Segment0      = 0;
>> +  Segment0Pages = 1;
>> +  Status = gBS->AllocatePages (AllocateAddress, EfiReservedMemoryType,
>> +                  Segment0Pages, &Segment0);
>> +  if (EFI_ERROR (Status)) {
>> +    goto RestorePam1;
>> +  }
> 
> If CSM is enabled, we will fail to allocate, right?

It's not clear what you mean by

  If the CSM is enabled

In that premise you probably include -D CSM_ENABLE, and having placed
the SeaBIOS CSM binary at OvmfPkg/Csm/Csm16/Csm16.bin. As a consequence,
the following are added to the build (marking libraries and drivers with
their INF files):

- OvmfPkg/Csm/CsmSupportLib/CsmSupportLib.inf
  (built into IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf)
- IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
- IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
- OvmfPkg/Csm/Csm16/Csm16.inf (the SeaBIOS binary)

However, these are not sufficient to get a working CSM. At least the
following patch from David Woodhouse (or one of its variants) is needed
in addition (not committed in upstream):

  LegacyBios: Add UmbStart,UmbEnd fields to EFI_COMPATIBILITY16_TABLE

Did you include the presence of this patch in your question?

Additionally, there's another (similarly downstream only) patch

  OvmfPkg: Don't build in QemuVideoDxe when we have CSM

Did you include the presence of this patch in your question?

In order to test your question, I need to build a tree that matches your
question precisely.

If you did assume the presence of both patches in the build, then the
answer is

  If the CSM is enabled, then this code never runs, because it is
  excluded from the build.

> If we don't error here, and install the int10-stub, then wouldn't
> Windows 2008 still be able to use QemuVideoDxe?

Independently of the above: if allocating the page at guest-phys address
0 fails (for any reason), then
- we must not overwrite data in it (we don't own the page -- something
else stores data there)
- consequently we can't point the IVT entry to our handler,
- hence Windows 2008 won't find (and won't be able to emulate) our
handler code.

(At least I assume that by

  Windows 2008 still be able to use QemuVideoDxe

you mean the emulation of the Int10h handler.)

> 
>> +  //
>> +  // This is a UEFI driver -- the arch protocols have been installed
>> +  // previously. Among those, the CPU arch protocol has configured the IDT, 
>> so
>> +  // we can overwrite the IVT used in real mode.
>> +  //
>> +  Int0x10 = (IVT_ENTRY *)(UINTN)Segment0 + 0x10;
>> +
>> +  //
>> +  // See SVN r14218.
>> +  //
>> +  ASSERT (Int0x10->Segment == 0x0000);
>> +  ASSERT (Int0x10->Offset  == 0x0000);
>> +
>> +  Int0x10->Segment = SegmentC >> 4;
>> +  Int0x10->Offset  = (EFI_PHYSICAL_ADDRESS)(UINTN)(VbeModeInfo + 1) - 
>> SegmentC;
>> +
>> +  DEBUG ((EFI_D_INFO, "%a: VBE shim installed\n", __FUNCTION__));
>> +  return EFI_SUCCESS;
>> +
>> +RestorePam1:
>> +  PciWrite8 (Pam1Address, Pam1);
>> +
>> +  DEBUG ((EFI_D_ERROR, "%a: VBE shim installation failed: %r\n", 
>> __FUNCTION__,
>> +    Status));
>> +  return Status;
>> +}
>> diff --git a/OvmfPkg/QemuVideoDxe/VbeShim.asm 
>> b/OvmfPkg/QemuVideoDxe/VbeShim.asm
>> new file mode 100644
>> index 0000000..bb3d601
>> --- /dev/null
>> +++ b/OvmfPkg/QemuVideoDxe/VbeShim.asm
>> @@ -0,0 +1,302 @@
>> +;------------------------------------------------------------------------------
>> +; @file
>> +; A minimal Int10h stub that allows the Windows 2008 R2 SP1 UEFI guest's 
>> buggy,
>> +; default VGA driver to switch to 1024x768x32, on the stdvga and QXL video
>> +; cards of QEMU.
>> +;
>> +; Copyright (C) 2014, Red Hat, Inc.
>> +; Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
>> +;
>> +; This program and the accompanying materials are licensed and made 
>> available
>> +; under the terms and conditions of the BSD License which accompanies this
>> +; distribution.  The full text of the license may be found at
>> +; http://opensource.org/licenses/bsd-license.php
>> +;
>> +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
>> WITHOUT
>> +; WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
>> +;
>> +;------------------------------------------------------------------------------
>> +
>> +BITS 16
>> +ORG 0
>> +
>> +VbeInfo:
>> +TIMES 256 nop
>> +
>> +VbeModeInfo:
>> +TIMES 256 nop
>> +
>> +
>> +Handler:
>> +  cmp  ax, 0x4f00
>> +  je   GetInfo
>> +  cmp  ax, 0x4f01
>> +  je   GetModeInfo
>> +  cmp  ax, 0x4f02
>> +  je   SetMode
>> +  cmp  ax, 0x4f03
>> +  je   GetMode
>> +  cmp  ax, 0x4f10
>> +  je   GetPmCapabilities
>> +  cmp  ax, 0x4f15
>> +  je   ReadEdid
>> +  cmp  ah, 0x00
>> +  je   SetModeLegacy
>> +  mov  si, StrUnkownFunction
>> +  call PrintStringSi
>> +Hang:
>> +  jmp Hang
>> +
>> +
>> +GetInfo:
>> +  push es
>> +  push di
>> +  push ds
>> +  push si
>> +  push cx
>> +
>> +  mov  si, StrEnterGetInfo
>> +  call PrintStringSi
>> +
>> +  ; target (es:di) set on input
>> +  push cs
>> +  pop  ds
>> +  mov  si, VbeInfo
>> +  ; source (ds:si) set now
>> +
>> +  mov  cx, 256
>> +  cld
>> +  rep movsb
>> +
>> +  pop  cx
>> +  pop  si
>> +  pop  ds
>> +  pop  di
>> +  pop  es
>> +  jmp  Success
>> +
>> +
>> +GetModeInfo:
>> +  push es
>> +  push di
>> +  push ds
>> +  push si
>> +  push cx
>> +
>> +  mov  si, StrEnterGetModeInfo
>> +  call PrintStringSi
>> +
>> +  and  cx, ~0x4000 ; clear potentially set LFB bit in mode number
>> +  cmp  cx, 0x00f1
>> +  je   KnownMode1
>> +  mov  si, StrUnkownMode
>> +  call PrintStringSi
>> +  jmp  Hang
>> +KnownMode1:
>> +  ; target (es:di) set on input
>> +  push cs
>> +  pop  ds
>> +  mov  si, VbeModeInfo
>> +  ; source (ds:si) set now
>> +
>> +  mov  cx, 256
>> +  cld
>> +  rep movsb
>> +
>> +  pop  cx
>> +  pop  si
>> +  pop  ds
>> +  pop  di
>> +  pop  es
>> +  jmp  Success
>> +
>> +
>> +%define ATT_ADDRESS_REGISTER   0x03c0
>> +%define VBE_DISPI_IOPORT_INDEX 0x01ce
>> +%define VBE_DISPI_IOPORT_DATA  0x01d0
>> +
>> +%define VBE_DISPI_INDEX_XRES        0x1
>> +%define VBE_DISPI_INDEX_YRES        0x2
>> +%define VBE_DISPI_INDEX_BPP         0x3
>> +%define VBE_DISPI_INDEX_ENABLE      0x4
>> +%define VBE_DISPI_INDEX_BANK        0x5
>> +%define VBE_DISPI_INDEX_VIRT_WIDTH  0x6
>> +%define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
>> +%define VBE_DISPI_INDEX_X_OFFSET    0x8
>> +%define VBE_DISPI_INDEX_Y_OFFSET    0x9
>> +
>> +%define VBE_DISPI_ENABLED     0x01
>> +%define VBE_DISPI_LFB_ENABLED 0x40
>> +
>> +%macro BochsWrite 2
>> +  push dx
>> +  push ax
>> +
>> +  mov  dx, VBE_DISPI_IOPORT_INDEX
>> +  mov  ax, %1
>> +  out  dx, ax
>> +
>> +  mov  dx, VBE_DISPI_IOPORT_DATA
>> +  mov  ax, %2
>> +  out  dx, ax
>> +
>> +  pop  ax
>> +  pop  dx
>> +%endmacro
>> +
>> +SetMode:
>> +  push si
>> +  push dx
>> +  push ax
>> +
>> +  mov  si, StrEnterSetMode
>> +  call PrintStringSi
>> +
>> +  cmp  bx, 0x40f1
>> +  je   KnownMode2
>> +  mov  si, StrUnkownMode
>> +  call PrintStringSi
>> +  jmp  Hang
>> +KnownMode2:
>> +
>> +  ; unblank
>> +  mov  dx, ATT_ADDRESS_REGISTER
>> +  mov  al, 0x20
>> +  out  dx, al
>> +
>> +  BochsWrite VBE_DISPI_INDEX_ENABLE,        0
>> +  BochsWrite VBE_DISPI_INDEX_BANK,          0
>> +  BochsWrite VBE_DISPI_INDEX_X_OFFSET,      0
>> +  BochsWrite VBE_DISPI_INDEX_Y_OFFSET,      0
>> +  BochsWrite VBE_DISPI_INDEX_BPP,          32
>> +  BochsWrite VBE_DISPI_INDEX_XRES,       1024
>> +  BochsWrite VBE_DISPI_INDEX_VIRT_WIDTH, 1024
>> +  BochsWrite VBE_DISPI_INDEX_YRES,        768
>> +  BochsWrite VBE_DISPI_INDEX_VIRT_HEIGHT, 768
>> +  BochsWrite VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | 
>> VBE_DISPI_LFB_ENABLED
>> +
>> +  pop  ax
>> +  pop  dx
>> +  pop  si
>> +  jmp  Success
>> +
>> +
>> +GetMode:
>> +  push si
>> +  mov  si, StrEnterGetMode
>> +  call PrintStringSi
>> +  mov  bx, 0x40f1
>> +  pop  si
>> +  jmp  Success
>> +
>> +
>> +GetPmCapabilities:
>> +  push si
>> +  mov  si, StrGetPmCapabilities
>> +  call PrintStringSi
>> +  pop  si
>> +  jmp  Unsupported
>> +
>> +
>> +ReadEdid:
>> +  push si
>> +  mov  si, StrReadEdid
>> +  call PrintStringSi
>> +  pop  si
>> +  jmp  Unsupported
>> +
>> +
>> +SetModeLegacy:
>> +  push si
>> +  mov  si, StrEnterSetModeLegacy
>> +  call PrintStringSi
>> +
>> +  cmp  al, 0x03
>> +  je   KnownMode3
>> +  cmp  al, 0x12
>> +  je   KnownMode4
>> +  mov  si, StrUnkownMode
>> +  call PrintStringSi
>> +  jmp  Hang
>> +KnownMode3:
>> +  mov  al, 0x30
>> +  jmp  SetModeLegacyDone
>> +KnownMode4:
>> +  mov  al, 0x20
>> +SetModeLegacyDone:
>> +  mov  si, StrExitSuccess
>> +  call PrintStringSi
>> +  pop  si
>> +  iret
>> +
>> +
>> +Success:
>> +  push si
>> +  mov  si, StrExitSuccess
>> +  call PrintStringSi
>> +  pop  si
>> +
>> +  mov  ax, 0x004f
>> +  iret
>> +
>> +
>> +Unsupported:
>> +  push si
>> +  mov  si, StrExitUnsupported
>> +  call PrintStringSi
>> +  pop  si
>> +
>> +  mov  ax, 0x014f
>> +  iret
>> +
>> +
>> +PrintStringSi:
>> +  pusha
>> +  push  ds ; save original
>> +  push  cs
>> +  pop   ds
>> +  mov   dx, 0x0402
>> +PrintStringSiLoop:
>> +  lodsb
>> +  cmp   al, 0
>> +  je    PrintStringSiDone
>> +  out   dx, al
>> +  jmp   PrintStringSiLoop
>> +PrintStringSiDone:
>> +  pop   ds ; restore original
>> +  popa
>> +  ret
> 
> Can you guard this debug with an ifdef, and disable it by default?

The routine is called from several places. Do you want me to make all
the function calls DEBUG-dependent too, or does it suffice if I make
only the body of the function (everything but the "ret" instruction)
build-time conditional, and leave the function calls in place?

> 
>> +
>> +
>> +StrExitSuccess:
>> +  db 'Exit', 0x0a, 0
>> +
>> +StrExitUnsupported:
>> +  db 'Unsupported', 0x0a, 0
>> +
>> +StrUnkownFunction:
>> +  db 'Unknown Function', 0x0a, 0
>> +
>> +StrEnterGetInfo:
>> +  db 'GetInfo', 0x0a, 0
>> +
>> +StrEnterGetModeInfo:
>> +  db 'GetModeInfo', 0x0a, 0
>> +
>> +StrEnterGetMode:
>> +  db 'GetMode', 0x0a, 0
>> +
>> +StrEnterSetMode:
>> +  db 'SetMode', 0x0a, 0
>> +
>> +StrEnterSetModeLegacy:
>> +  db 'SetModeLegacy', 0x0a, 0
>> +
>> +StrUnkownMode:
>> +  db 'Unkown Mode', 0x0a, 0
>> +
>> +StrGetPmCapabilities:
>> +  db 'GetPmCapabilities', 0x0a, 0
>> +
>> +StrReadEdid:
>> +  db 'ReadEdid', 0x0a, 0
> 
> Bonus point for dropping these strings when debug is disabled. :)

That seems to imply that I can't load the address of these strings into
SI (when setting up the function calls), littering the code with ifdefs...

> 
> Seems like a macro could make that happen.

Ah, you mean the function call should be a macro, which (dependent on
the DEBUG define) would either expand to nothing, or to a function call
(taking the string's label as a parameter). I can try that.

> 
>> diff --git a/OvmfPkg/QemuVideoDxe/VbeShim.sh 
>> b/OvmfPkg/QemuVideoDxe/VbeShim.sh
>> new file mode 100755
>> index 0000000..37e7586
>> --- /dev/null
>> +++ b/OvmfPkg/QemuVideoDxe/VbeShim.sh
> 
> This script is great. :)
> 
>> @@ -0,0 +1,82 @@
>> +#!/bin/sh
>> +###
>> +# @file
>> +# Shell script to assemble and dump the fake Int10h handler from NASM 
>> source to
>> +# a C array.
>> +#
>> +# Copyright (C) 2014, Red Hat, Inc.
>> +# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
>> +#
>> +# This program and the accompanying materials are licensed and made 
>> available
>> +# under the terms and conditions of the BSD License which accompanies this
>> +# distribution.  The full text of the license may be found at
>> +# http://opensource.org/licenses/bsd-license.php
>> +#
>> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
>> WITHOUT
>> +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
>> +#
>> +###
>> +
>> +set -e -u
>> +
>> +STEM=$(dirname -- "$0")/$(basename -- "$0" .sh)
>> +
>> +#
>> +# Install exit handler -- remove temporary files.
>> +#
>> +exit_handler()
>> +{
>> +  rm -f "$STEM".bin "$STEM".disasm "$STEM".offsets "$STEM".insns 
>> "$STEM".bytes
>> +}
>> +trap exit_handler EXIT
>> +
>> +#
>> +# Assemble the source file.
>> +#
>> +nasm -o "$STEM".bin "$STEM".asm
>> +
>> +#
>> +# Disassemble it, in order to get a binary dump associated with the source.
>> +#
>> +ndisasm "$STEM".bin >"$STEM".disasm
>> +
>> +#
>> +# Create three files, each with one column of the disassembly.
>> +#
>> +# The first column contains the offsets, and it starts the comment.
>> +#
>> +cut -c 1-8 "$STEM".disasm \
>> +| sed -e 's,^,  /* ,' >"$STEM".offsets
>> +
>> +#
>> +# The second column contains the assembly-language instructions, and it 
>> closes
>> +# the comment. We first pad it to 30 characters.
>> +#
>> +cut -c 29- "$STEM".disasm \
>> +| sed -e 's,$,                              ,' \
>> +      -e 's,^\(.\{30\}\).*$,\1 */,' >"$STEM".insns
>> +
>> +#
>> +# The third column contains the bytes corresponding to the instruction,
>> +# represented as C integer constants. First strip trailing whitespace from 
>> the
>> +# middle column of the input disassembly, then process pairs of nibbles.
>> +#
>> +cut -c 11-28 "$STEM".disasm \
>> +| sed -e 's, \+$,,' -e 's/\(..\)/ 0x\1,/g' >"$STEM".bytes
>> +
>> +#
>> +# Write the output file, recombining the columns. The output should have 
>> CRLF
>> +# line endings.
>> +#
>> +{
>> +  printf '//\n'
>> +  printf '// THIS IS A GENERATED FILE. DO NOT EDIT.\n'
> 
> How about:
> THIS FILE IS GENERATED BY $STEM

"$STEM" would include the directory name too, but I can certainly do
$(basename -- "$0").

In addition, for v2 I'm thinking about changing the memory allocation
type (of the page at 0) from EfiReservedMemoryType back to
EfiBootServicesCode (same as in your int10-stub branch). The argument
goes like this:

1. correctly written UEFI OSes (ie. all except Windows 2008 R2) don't
care about the Int10h entry, hence they shouldn't lose a page forever
(EfiReservedMemoryType does that)

2.a. "boot services code" vs. "reserved" makes no difference before
ExitBootServices() -- both types protect the IVT from other boot-time
allocations.

2.b. Windows 2008 R2 accesses the IVT regardless of the type of the
memory allocation that we cover it with. It will certainly not free and
then *overwrite* the page at zero (after we've covered it with "boot
services code"), because then it couldn't fetch the Int10h entry from it
(for emulation).

IOW, OSes different from Windows 2008 R2 don't care at all, hence they
shouldn't be penalized; and Windows 2008 R2 doesn't overwrite the IVT
anyway (at runtime either) before fetching the Int10h entry, so we don't
need to protect Win2k8r2 "from itself". Hence we should only protect
(allocate) this page from other UEFI components.

Thanks
Laszlo

------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.
Get unparalleled scalability from the best Selenium testing platform available
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to