/*++ 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; cntTSS->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; }