OvmfPkg: QemuVideoDxe: Int10h stub for Windows 7 & 2008 (stdvga, QXL)
The Windows 2008 R2 SP1 (and Windows 7) UEFI guest's default video driver
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.
This patch adds a VGABIOS "shim" to QemuVideoDxe. For the first stdvga or
QXL card bound, an extremely stripped down VGABIOS imitation is installed
in the C segment. It provides a real implementation for the few services
that are in fact necessary for the win2k8r2sp1 UEFI guest, plus some fakes
that the guest invokes but whose effect is not important.
The C segment is not present in the UEFI memory map prepared by OVMF. We
never add memory space that would cover it (either in PEI, in the form of
memory resource descriptor HOBs, or in DXE, via gDS->AddMemorySpace()).
This way the handler body is invisible to all non-buggy UEFI guests, and
the rest of edk2.
The Int10h real-mode IVT entry is covered with a Boot Services Code page,
making that too unaccessible to the rest of edk2. (Thus UEFI guest OSes
different from the Windows 2008 family can reclaim the page. The Windows
2008 family accesses the page at zero regardless of the allocation type.)
The patch is the result of collaboration:
Initial proof of concept IVT entry installation and handler skeleton (in
NASM) by Jordan Justen.
Service tracing and implementation, data collection/analysis, and C coding
by yours truly.
Last minute changes by Gerd Hoffmann:
- Use OEM mode number (0xf1) instead of standard 800x600 mode (0x143). The
resolution of the OEM mode (0xf1) is not standardized; the guest can't
expect anything from it in advance.
- Use 1024x768 rather than 800x600 for more convenience in the Windows
2008 R2 SP1 guest during OS installation, and after normal boot until
the QXL XDDM guest driver is installed.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15540 6f19259b-4bc3-4df7-8a09-765794883524
2014-05-20 18:33:00 +02:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; @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>
|
|
|
|
;
|
2019-04-04 01:06:33 +02:00
|
|
|
; SPDX-License-Identifier: BSD-2-Clause-Patent
|
OvmfPkg: QemuVideoDxe: Int10h stub for Windows 7 & 2008 (stdvga, QXL)
The Windows 2008 R2 SP1 (and Windows 7) UEFI guest's default video driver
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.
This patch adds a VGABIOS "shim" to QemuVideoDxe. For the first stdvga or
QXL card bound, an extremely stripped down VGABIOS imitation is installed
in the C segment. It provides a real implementation for the few services
that are in fact necessary for the win2k8r2sp1 UEFI guest, plus some fakes
that the guest invokes but whose effect is not important.
The C segment is not present in the UEFI memory map prepared by OVMF. We
never add memory space that would cover it (either in PEI, in the form of
memory resource descriptor HOBs, or in DXE, via gDS->AddMemorySpace()).
This way the handler body is invisible to all non-buggy UEFI guests, and
the rest of edk2.
The Int10h real-mode IVT entry is covered with a Boot Services Code page,
making that too unaccessible to the rest of edk2. (Thus UEFI guest OSes
different from the Windows 2008 family can reclaim the page. The Windows
2008 family accesses the page at zero regardless of the allocation type.)
The patch is the result of collaboration:
Initial proof of concept IVT entry installation and handler skeleton (in
NASM) by Jordan Justen.
Service tracing and implementation, data collection/analysis, and C coding
by yours truly.
Last minute changes by Gerd Hoffmann:
- Use OEM mode number (0xf1) instead of standard 800x600 mode (0x143). The
resolution of the OEM mode (0xf1) is not standardized; the guest can't
expect anything from it in advance.
- Use 1024x768 rather than 800x600 for more convenience in the Windows
2008 R2 SP1 guest during OS installation, and after normal boot until
the QXL XDDM guest driver is installed.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15540 6f19259b-4bc3-4df7-8a09-765794883524
2014-05-20 18:33:00 +02:00
|
|
|
;
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
; enable this macro for debug messages
|
|
|
|
;%define DEBUG
|
|
|
|
|
|
|
|
%macro DebugLog 1
|
|
|
|
%ifdef DEBUG
|
|
|
|
push si
|
|
|
|
mov si, %1
|
|
|
|
call PrintStringSi
|
|
|
|
pop si
|
|
|
|
%endif
|
|
|
|
%endmacro
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
DebugLog StrUnkownFunction
|
|
|
|
Hang:
|
|
|
|
jmp Hang
|
|
|
|
|
|
|
|
|
|
|
|
GetInfo:
|
|
|
|
push es
|
|
|
|
push di
|
|
|
|
push ds
|
|
|
|
push si
|
|
|
|
push cx
|
|
|
|
|
|
|
|
DebugLog StrEnterGetInfo
|
|
|
|
|
|
|
|
; 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
|
|
|
|
|
|
|
|
DebugLog StrEnterGetModeInfo
|
|
|
|
|
|
|
|
and cx, ~0x4000 ; clear potentially set LFB bit in mode number
|
|
|
|
cmp cx, 0x00f1
|
|
|
|
je KnownMode1
|
|
|
|
DebugLog StrUnkownMode
|
|
|
|
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 dx
|
|
|
|
push ax
|
|
|
|
|
|
|
|
DebugLog StrEnterSetMode
|
|
|
|
|
|
|
|
cmp bx, 0x40f1
|
|
|
|
je KnownMode2
|
|
|
|
DebugLog StrUnkownMode
|
|
|
|
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
|
|
|
|
jmp Success
|
|
|
|
|
|
|
|
|
|
|
|
GetMode:
|
|
|
|
DebugLog StrEnterGetMode
|
|
|
|
mov bx, 0x40f1
|
|
|
|
jmp Success
|
|
|
|
|
|
|
|
|
|
|
|
GetPmCapabilities:
|
|
|
|
DebugLog StrGetPmCapabilities
|
|
|
|
jmp Unsupported
|
|
|
|
|
|
|
|
|
|
|
|
ReadEdid:
|
|
|
|
DebugLog StrReadEdid
|
|
|
|
jmp Unsupported
|
|
|
|
|
|
|
|
|
|
|
|
SetModeLegacy:
|
|
|
|
DebugLog StrEnterSetModeLegacy
|
|
|
|
|
|
|
|
cmp al, 0x03
|
|
|
|
je KnownMode3
|
|
|
|
cmp al, 0x12
|
|
|
|
je KnownMode4
|
|
|
|
DebugLog StrUnkownMode
|
|
|
|
jmp Hang
|
|
|
|
KnownMode3:
|
|
|
|
mov al, 0x30
|
|
|
|
jmp SetModeLegacyDone
|
|
|
|
KnownMode4:
|
|
|
|
mov al, 0x20
|
|
|
|
SetModeLegacyDone:
|
|
|
|
DebugLog StrExitSuccess
|
|
|
|
iret
|
|
|
|
|
|
|
|
|
|
|
|
Success:
|
|
|
|
DebugLog StrExitSuccess
|
|
|
|
mov ax, 0x004f
|
|
|
|
iret
|
|
|
|
|
|
|
|
|
|
|
|
Unsupported:
|
|
|
|
DebugLog StrExitUnsupported
|
|
|
|
mov ax, 0x014f
|
|
|
|
iret
|
|
|
|
|
|
|
|
|
|
|
|
%ifdef DEBUG
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
%endif
|