DRAFT: Take more than your usual care.

x86BiosCall

This function executes a software interrupt in the shadow memory of the x86 BIOS emulator.

Declaration

BOOLEAN
x86BiosCall (
    ULONG InterruptNumber,
    X86_BIOS_REGISTERS *Registers);

Since the X86BIOS_REGISTERS structure appears to be used only for this function, its definition may as well be given here:

typedef struct _X86BIOS_REGISTERS {
    ULONG Eax;
    ULONG Ecx;
    ULONG Edx;
    ULONG Ebx;
    ULONG Ebp;
    ULONG Esi;
    ULONG Edi;
    USHORT SegDs;
    USHORT SegEs;
} X86BIOS_REGISTERS, *PX86BIOS_REGISTERS;

Parameters

The InterruptNumber argument is the number of the software interrupt to emulate for calling the BIOS.

The Registers argument is the address of a structure that provides values to load into registers for calling the BIOS and in which the function returns the values that these registers have when the BIOS is done.

Return Value

The function returns TRUE for success, else FALSE.

Behaviour

If the x86 BIOS emulator is not yet initialised, the function fails. Otherwise, the interrupt is at least started in the sense that if it does not complete, the function fails and the following message is written to the debugger:

HAL: Interrupt emulation failed, status %lx

The following are known values for the status:

2 divide by zero
4 emulator not initialised
5 execution of hlt instruction
7 invalid s-i-b byte detected when decoding an instruction
8 bad enter instruction
9 invalid port number
a instruction invalid because operand is not a register
b instruction invalid because operand is a register
c illegal opcode
d overflow detected by bound instruction
e code read beyond segment limit
f stack pushed beyond segment limit
10 stack popped beyond segment limit

Given that the emulator is initialised, the interrupt is started by:

The bytes at cs:ip are then interpreted as real-mode x86 instructions, which alter the shadow registers, memory and ports more or less as actual real-mode execution would affect the real registers, memory and ports.

The interrupt completes successfully if execution of any iret or retf (or ret) would return to FFFF:FFFF (regardless of the stack pointer).

Availability

The x86BiosCall function is exported by name from the HAL in version 6.0 and higher. It is undocumented. Names given above for the X86BIOS_REGISTERS structure and its members are all invented for this article, in the absence of knowing what names Microsoft uses.

Use by Microsoft

Two uses are known by Microsoft. Both are concerned specifically with int 10h, which is the BIOS’s interface for video functionality.

The more specific is for the boot video driver (BOOTVID.DLL) to reset the display adapter. The kernel calls either VidInitialize or VidResetDisplay. The actual resetting is arranged by BOOTVID calling indirectly through HalPrivateDispatchTable. This ordinarily gets through to the HAL, which resets the display by executing int 10h function 00h to set the display mode to 12h.

The general use by Microsoft is to support the VideoPortInt10 function and the Int10CallBios member of the VIDEO_PORT_INT10_INTERFACE structure obtained through the VideoPortQueryServices function. These functions are exported from VIDEOPRT.SYS (and are documented). VIDEOPRT uses the x86 BIOS emulator unless the following registry key exists:

Key: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GraphicsDrivers\DisableEmulator

If the key can be opened for read and write access, then accessing int 10h through VIDEOPRT actually does execute virtual-8086 code using Ke386CallBios.