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
		
			
				
	
	
		
			288 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
| ;------------------------------------------------------------------------------
 | |
| ; @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.
 | |
| ;
 | |
| ;------------------------------------------------------------------------------
 | |
| 
 | |
| ; 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
 |