summaryrefslogblamecommitdiffstats
path: root/private/ntos/nthals/halx86/i386/xxbiosc.c
blob: 6b5f1cc69a18815e9c64ca6da6c892c21f825450 (plain) (tree)










































































































































































































































































































                                                                              
/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    xxbiosc.c

Abstract:

    This module implements the protect-mode routines necessary to make the
    transition to real mode and return to protected mode.

Author:

    John Vert (jvert) 29-Oct-1991


Environment:

    Kernel mode only.
    Probably a panic-stop, so we cannot use any system services.

Revision History:

--*/
#include "halp.h"

//
// Function definitions
//


ULONG
HalpBorrowTss(
    VOID
    );

VOID
HalpReturnTss(
    ULONG TssSelector
    );

VOID
HalpBiosCall(
    VOID
    );


VOID
HalpTrap06(
    VOID
    );


VOID
HalpTrap0D(
    VOID
    );

VOID
HalpBiosDisplayReset(
    VOID
    )

/*++

Routine Description:

    Calls BIOS by putting the machine into V86 mode.  This involves setting up
    a physical==virtual identity mapping for the first 1Mb of memory, setting
    up V86-specific trap handlers, and granting I/O privilege to the V86
    process by editing the IOPM bitmap in the TSS.

Environment:

    Interrupts disabled.

Arguments:

    None

Return Value:

    None.

--*/

{
    HARDWARE_PTE OldPageTable;
    USHORT OldIoMapBase;
    ULONG OldEsp0;
    PHARDWARE_PTE Pte;
    PHARDWARE_PTE V86CodePte;
    ULONG cnt;
    ULONG OldTrap0DHandler;
    ULONG OldTrap06Handler;
    PUCHAR IoMap;
    ULONG Virtual;
//    KIRQL OldIrql;
    ULONG OriginalTssSelector;
    extern PVOID HalpRealModeStart;
    extern PVOID HalpRealModeEnd;
PHARDWARE_PTE  PointerPde;
ULONG   PageFrame;
ULONG   PageFrameEnd;

    //
    // Interrupts are off, but V86 mode might turn them back on again.
    //
    HalpDisableAllInterrupts ();

    //
    // We need to set up an identity mapping in the first page table.  First,
    // we save away the old page table.
    //
    OldPageTable = *MiGetPdeAddress(0);

    //
    // Now we put the HAL page table into the first slot of the page
    // directory.  Note that this page table is now the first and last
    // entries in the page directory.
    //
    Pte = MiGetPdeAddress(0);
    Pte->PageFrameNumber = MiGetPdeAddress(0xffc00000)->PageFrameNumber;
    Pte->Valid = 1;
    Pte->Write = 1;
    Pte->Owner = 1;         // User-accessible

    //
    // Flush TLB
    //

    HalpFlushTLB();

    //
    // Map the first 1Mb of virtual memory to the first 1Mb of physical
    // memory
    //
    for (Virtual=0; Virtual < 0x100000; Virtual += PAGE_SIZE) {
        Pte = MiGetPteAddress(Virtual);
        Pte->PageFrameNumber = ((ULONG)Virtual >> PAGE_SHIFT);
        Pte->Valid = 1;
        Pte->Write = 1;
        Pte->Owner = 1;         // User-accessible
    }

    //
    // Map our code into the virtual machine
    //

    Pte = MiGetPteAddress(0x20000);
    PointerPde = MiGetPdeAddress(&HalpRealModeStart);

    if ( PointerPde->LargePage ) {
        //
        // Map real mode PTEs into virtual mapping.  The source PDE is
        // from the indenity large pte map, so map the virtual machine PTEs
        // based on the base of the large PDE frame.
        //

        PageFrame = ((ULONG)(&HalpRealModeStart) >> 12) & 0x3FF;
        PageFrameEnd = ((ULONG)(&HalpRealModeEnd) >> 12) & 0x3FF;
        do {

            Pte->PageFrameNumber = PointerPde->PageFrameNumber + PageFrame;

            ++Pte;
            ++PageFrame;

        } while (PageFrame <= PageFrameEnd);

    } else {

        //
        // Map real mode PTEs into virtual machine PTEs, by copying the
        // page frames from the source to the virtual machine PTEs.
        //

        V86CodePte = MiGetPteAddress(&HalpRealModeStart);
        do {
            Pte->PageFrameNumber = V86CodePte->PageFrameNumber;
    
            ++Pte;
            ++V86CodePte;
    
        } while ( V86CodePte <= MiGetPteAddress(&HalpRealModeEnd) );

    }
    //
    // Flush TLB
    //

    HalpFlushTLB();

    //
    // We need to replace the current TRAP D handler with our own, so
    // we can do instruction emulation for V86 mode
    //

    OldTrap0DHandler = KiReturnHandlerAddressFromIDT(0xd);
    KiSetHandlerAddressToIDT(0xd, HalpTrap0D);

    OldTrap06Handler = KiReturnHandlerAddressFromIDT(6);
    KiSetHandlerAddressToIDT(6, HalpTrap06);

    //
    // Make sure current TSS has IoMap space available.  If no, borrow
    // Normal TSS.
    //

    OriginalTssSelector = HalpBorrowTss();

    //
    // Overwrite the first access map with zeroes, so the V86 code can
    // party on all the registers.
    //
    IoMap = (PUCHAR)&(KeGetPcr()->TSS->IoMaps[0]);

    for (cnt=0; cnt<IOPM_SIZE; cnt++) {
        IoMap[cnt] = 0;
    }
    for (cnt=IOPM_SIZE; cnt<PIOPM_SIZE; cnt++) {
        IoMap[cnt] = 0xff;
    }
    OldIoMapBase = KeGetPcr()->TSS->IoMapBase;

    KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1);

    //
    // Save the current ESP0, as HalpBiosCall() trashes it.
    //
    OldEsp0 = KeGetPcr()->TSS->Esp0;

    //
    // Call the V86-mode code
    //
    HalpBiosCall();

    //
    // Restore the TRAP handlers
    //

    KiSetHandlerAddressToIDT(0xd, OldTrap0DHandler);
    KiSetHandlerAddressToIDT(6, OldTrap06Handler);

    //
    // Restore Esp0 value
    //
    KeGetPcr()->TSS->Esp0 = OldEsp0;

    KeGetPcr()->TSS->IoMapBase = OldIoMapBase;

    //
    // Return borrowed TSS if any.
    //

    if (OriginalTssSelector != 0) {
        HalpReturnTss(OriginalTssSelector);
    }

    //
    // Unmap the first 1Mb of virtual memory
    //
    for (Virtual = 0; Virtual < 0x100000; Virtual += PAGE_SIZE) {
        Pte = MiGetPteAddress(Virtual);
        Pte->PageFrameNumber = 0;
        Pte->Valid = 0;
        Pte->Write = 0;
    }

    //
    // Restore the original page table that we replaced.
    //
    *MiGetPdeAddress(0) = OldPageTable;

    //
    // Flush TLB
    //

    HalpFlushTLB();

    //
    // This function is only used during a system crash.  We don't re-
    // enable interrupts.
    //
    // KeLowerIrql(OldIrql);
}

HAL_DISPLAY_BIOS_INFORMATION
HalpGetDisplayBiosInformation (
    VOID
    )
{
    // this hal uses native int-10

    return HalDisplayInt10Bios;
}