Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716/* * PROJECT: ReactOS Hardware Abstraction Layer (HAL) * LICENSE: BSD - See COPYING.ARM in the top level directory * PURPOSE: BIOS Access Routines * PROGRAMMERS: ReactOS Portable Systems Group * Alex Ionescu (alex.ionescu@reactos.org) */
/* INCLUDES *******************************************************************/
#include <hal.h>
#define NDEBUG#include <debug.h>
#include <setjmp.h>
void __cdecl HalpTrap0D();
/* GLOBALS ********************************************************************/
//// PTE Data//ULONG HalpSavedPfn;HARDWARE_PTE HalpSavedPte;
//// IDT Data//PVOID HalpGpfHandler;PVOID HalpBopHandler;
//// TSS Data//ULONG HalpSavedEsp0;USHORT HalpSavedTss;
//// IOPM Data//USHORT HalpSavedIopmBase;PUSHORT HalpSavedIoMap;USHORT HalpSavedIoMapData[IOPM_SIZE / sizeof(USHORT)][2];ULONG HalpSavedIoMapEntries;
/* Where the protected mode stack is */ULONG_PTR HalpSavedEsp;
/* Where the real mode code ends */extern PVOID HalpRealModeEnd;
/* Context saved for return from v86 mode */jmp_buf HalpSavedContext;
/* V86 OPCODE HANDLERS ********************************************************/
BOOLEANFASTCALLHalpOpcodeInvalid(IN PHAL_BIOS_FRAME BiosFrame){ PUCHAR Inst = (PUCHAR)(BiosFrame->CsBase + BiosFrame->Eip);
/* Print error message */ DPRINT1("HAL: An invalid V86 opcode was encountered at address %X:%X\n" "Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", BiosFrame->SegCs, BiosFrame->Eip, Inst[0], Inst[1], Inst[2], Inst[3], Inst[4], Inst[5], Inst[6], Inst[7], Inst[8], Inst[9]);
/* Break */ DbgBreakPoint(); return FALSE;}
BOOLEANFASTCALLHalpPushInt(IN PHAL_BIOS_FRAME BiosFrame, IN ULONG Interrupt){ PUSHORT Stack; ULONG Eip;
/* Calculate stack address (SP) */ Stack = (PUSHORT)(BiosFrame->SsBase + (BiosFrame->Esp & 0xFFFF));
/* Push EFlags */ Stack--; *Stack = BiosFrame->EFlags & 0xFFFF;
/* Push CS */ Stack--; *Stack = BiosFrame->SegCs & 0xFFFF;
/* Push IP */ Stack--; *Stack = BiosFrame->Eip & 0xFFFF;
/* Compute new CS:IP from the IVT address for this interrupt entry */ Eip = *(PULONG)(Interrupt * 4); BiosFrame->Eip = Eip & 0xFFFF; BiosFrame->SegCs = Eip >> 16;
/* Update stack address */ BiosFrame->Esp = (ULONG_PTR)Stack & 0xFFFF;
/* Update CS to linear */ BiosFrame->CsBase = BiosFrame->SegCs << 4; BiosFrame->CsLimit = 0xFFFF; BiosFrame->CsFlags = 0;
/* We're done */ return TRUE;}
BOOLEANFASTCALLHalpOpcodeINTnn(IN PHAL_BIOS_FRAME BiosFrame){ UCHAR Interrupt; PKTRAP_FRAME TrapFrame;
/* Convert SS to linear */ BiosFrame->SsBase = BiosFrame->SegSs << 4; BiosFrame->SsLimit = 0xFFFF; BiosFrame->SsFlags = 0;
/* Increase EIP and validate */ BiosFrame->Eip++; if (BiosFrame->Eip > BiosFrame->CsLimit) return FALSE;
/* Read interrupt number */ Interrupt = *(PUCHAR)(BiosFrame->CsBase + BiosFrame->Eip);
/* Increase EIP and push the interrupt */ BiosFrame->Eip++; if (HalpPushInt(BiosFrame, Interrupt)) { /* Update the trap frame */ TrapFrame = BiosFrame->TrapFrame; TrapFrame->HardwareSegSs = BiosFrame->SegSs; TrapFrame->HardwareEsp = BiosFrame->Esp; TrapFrame->SegCs = BiosFrame->SegCs; TrapFrame->EFlags = BiosFrame->EFlags;
/* Success */ return TRUE; }
/* Failure */ return FALSE;}
BOOLEANFASTCALLHalpDispatchV86Opcode(IN PKTRAP_FRAME TrapFrame){ UCHAR Instruction; HAL_BIOS_FRAME BiosFrame;
/* Fill out the BIOS frame */ BiosFrame.TrapFrame = TrapFrame; BiosFrame.SegSs = TrapFrame->HardwareSegSs; BiosFrame.Esp = TrapFrame->HardwareEsp; BiosFrame.EFlags = TrapFrame->EFlags; BiosFrame.SegCs = TrapFrame->SegCs; BiosFrame.Eip = TrapFrame->Eip; BiosFrame.Prefix = 0;
/* Convert CS to linear */ BiosFrame.CsBase = BiosFrame.SegCs << 4; BiosFrame.CsLimit = 0xFFFF; BiosFrame.CsFlags = 0;
/* Validate IP */ if (BiosFrame.Eip > BiosFrame.CsLimit) return FALSE;
/* Read IP */ Instruction = *(PUCHAR)(BiosFrame.CsBase + BiosFrame.Eip); if (Instruction != 0xCD) { /* We only support INT */ HalpOpcodeInvalid(&BiosFrame); return FALSE; }
/* Handle the interrupt */ if (HalpOpcodeINTnn(&BiosFrame)) { /* Update EIP */ TrapFrame->Eip = BiosFrame.Eip;
/* We're done */ return TRUE; }
/* Failure */ return FALSE;}
/* V86 TRAP HANDLERS **********************************************************/
DECLSPEC_NORETURNVOIDFASTCALLHalpTrap0DHandler(IN PKTRAP_FRAME TrapFrame){ /* Enter the trap */ KiEnterTrap(TrapFrame);
/* Check if this is a V86 trap */ if (TrapFrame->EFlags & EFLAGS_V86_MASK) { /* Dispatch the opcode and exit the trap */ HalpDispatchV86Opcode(TrapFrame); KiEoiHelper(TrapFrame); }
/* Strange, it isn't! This can happen during NMI */ DPRINT1("HAL: Trap0D while not in V86 mode\n"); KiDumpTrapFrame(TrapFrame);
ERROR_FATAL(); while (TRUE); /* 'noreturn' function */}
VOIDDECLSPEC_NORETURNHalpTrap06(VOID){ /* Restore ES/DS to known good values first */ Ke386SetEs(KGDT_R3_DATA | RPL_MASK); Ke386SetDs(KGDT_R3_DATA | RPL_MASK); Ke386SetFs(KGDT_R0_PCR);
/* Restore the stack */ KeGetPcr()->TSS->Esp0 = HalpSavedEsp0;
/* Return back to where we left */ longjmp(HalpSavedContext, 1); UNREACHABLE;}
/* V8086 ENTER ****************************************************************/
VOIDNTAPIHalpBiosCall(VOID){ /* Must be volatile so it doesn't get optimized away! */ volatile KTRAP_FRAME V86TrapFrame; ULONG_PTR StackOffset, CodeOffset;
/* Save the context, check for return */ if (_setjmp(HalpSavedContext)) { /* Returned from v86 */ return; }
/* Kill alignment faults */ __writecr0(__readcr0() & ~CR0_AM);
/* Set new stack address */ KeGetPcr()->TSS->Esp0 = (ULONG)&V86TrapFrame - 0x20 - sizeof(FX_SAVE_AREA);
/* Compute segmented IP and SP offsets */ StackOffset = (ULONG_PTR)&HalpRealModeEnd - 4 - (ULONG_PTR)HalpRealModeStart; CodeOffset = (ULONG_PTR)HalpRealModeStart & 0xFFF;
/* Now build the V86 trap frame */ V86TrapFrame.V86Es = 0; V86TrapFrame.V86Ds = 0; V86TrapFrame.V86Gs = 0; V86TrapFrame.V86Fs = 0; V86TrapFrame.HardwareSegSs = 0x2000; V86TrapFrame.HardwareEsp = StackOffset + CodeOffset; V86TrapFrame.EFlags = __readeflags() | EFLAGS_V86_MASK | EFLAGS_IOPL; V86TrapFrame.SegCs = 0x2000; V86TrapFrame.Eip = CodeOffset;
/* Exit to V86 mode */ HalpExitToV86((PKTRAP_FRAME)&V86TrapFrame);}
/* FUNCTIONS ******************************************************************/
VOIDNTAPIHalpBorrowTss(VOID){ USHORT Tss; PKGDTENTRY TssGdt; ULONG_PTR TssLimit; PKTSS TssBase;
// // Get the current TSS and its GDT entry // Tss = Ke386GetTr(); TssGdt = &KeGetPcr()->GDT[Tss / sizeof(KGDTENTRY)];
// // Get the KTSS limit and check if it has IOPM space // TssLimit = TssGdt->LimitLow | TssGdt->HighWord.Bits.LimitHi << 16;
// // If the KTSS doesn't have enough space this is probably an NMI or DF // if (TssLimit > IOPM_SIZE) { // // We are good to go // HalpSavedTss = 0; return; }
// // Get the "real" TSS // TssGdt = &KeGetPcr()->GDT[KGDT_TSS / sizeof(KGDTENTRY)]; TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | TssGdt->HighWord.Bytes.BaseMid << 16 | TssGdt->HighWord.Bytes.BaseHi << 24);
// // Switch to it // KeGetPcr()->TSS = TssBase;
// // Set it up // TssGdt->HighWord.Bits.Type = I386_TSS; TssGdt->HighWord.Bits.Pres = 1; TssGdt->HighWord.Bits.Dpl = 0;
// // Load new TSS and return old one // Ke386SetTr(KGDT_TSS); HalpSavedTss = Tss;}
VOIDNTAPIHalpReturnTss(VOID){ PKGDTENTRY TssGdt; PKTSS TssBase;
// // Get the original TSS // TssGdt = &KeGetPcr()->GDT[HalpSavedTss / sizeof(KGDTENTRY)]; TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | TssGdt->HighWord.Bytes.BaseMid << 16 | TssGdt->HighWord.Bytes.BaseHi << 24);
// // Switch to it // KeGetPcr()->TSS = TssBase;
// // Set it up // TssGdt->HighWord.Bits.Type = I386_TSS; TssGdt->HighWord.Bits.Pres = 1; TssGdt->HighWord.Bits.Dpl = 0;
// // Load old TSS // Ke386SetTr(HalpSavedTss);}
VOIDNTAPIHalpStoreAndClearIopm(VOID){ USHORT i, j; PUSHORT Entry = HalpSavedIoMap;
// // Loop the I/O Map // for (i = j = 0; i < IOPM_SIZE / sizeof(USHORT); i++) { // // Check for non-FFFF entry // if (*Entry != 0xFFFF) { // // Save it // HalpSavedIoMapData[j][0] = i; HalpSavedIoMapData[j][1] = *Entry; j++; }
// // Clear it // *Entry++ = 0; }
// // Terminate it // while (i++ < IOPM_FULL_SIZE / sizeof(USHORT)) { *Entry++ = 0xFFFF; }
// // Return the entries we saved // HalpSavedIoMapEntries = j;}
VOIDNTAPIHalpRestoreIopm(VOID){ ULONG i = HalpSavedIoMapEntries;
// // Set default state // RtlFillMemory(HalpSavedIoMap, IOPM_FULL_SIZE, 0xFF);
// // Restore the backed up copy, and initialize it // while (i--) HalpSavedIoMap[HalpSavedIoMapData[i][0]] = HalpSavedIoMapData[i][1];}
VOIDNTAPIHalpMapRealModeMemory(VOID){ PHARDWARE_PTE Pte, V86Pte; ULONG i;
// // Get the page table directory for the lowest meg of memory // Pte = HalAddressToPde(0); HalpSavedPfn = Pte->PageFrameNumber; HalpSavedPte = *Pte;
// // Map it to the HAL reserved region and make it valid // Pte->Valid = 1; Pte->Write = 1; Pte->Owner = 1; Pte->PageFrameNumber = (HalAddressToPde(0xFFC00000))->PageFrameNumber;
// // Flush the TLB // HalpFlushTLB();
// // Now loop the first meg of memory // for (i = 0; i < 0x100000; i += PAGE_SIZE) { // // Identity map it // Pte = HalAddressToPte(i); Pte->PageFrameNumber = i >> PAGE_SHIFT; Pte->Valid = 1; Pte->Write = 1; Pte->Owner = 1; }
// // Now get the entry for our real mode V86 code and the target // Pte = HalAddressToPte(0x20000); V86Pte = HalAddressToPte(&HalpRealModeStart); do { // // Map the physical address into our real-mode region // Pte->PageFrameNumber = V86Pte->PageFrameNumber;
// // Keep going until we've reached the end of our region // Pte++; V86Pte++; } while (V86Pte <= HalAddressToPte(&HalpRealModeEnd));
// // Flush the TLB // HalpFlushTLB();}
VOIDNTAPIHalpSwitchToRealModeTrapHandlers(VOID){ // // Save the current Invalid Opcode and General Protection Fault Handlers // HalpGpfHandler = KeQueryInterruptHandler(13); HalpBopHandler = KeQueryInterruptHandler(6);
// // Now set our own GPF handler to handle exceptions while in real mode // KeRegisterInterruptHandler(13, HalpTrap0D);
// // And our own invalid opcode handler to detect the BOP to get us out // KeRegisterInterruptHandler(6, HalpTrap06);}
VOIDNTAPIHalpSetupRealModeIoPermissionsAndTask(VOID){ // // Switch to valid TSS // HalpBorrowTss();
// // Save a copy of the I/O Map and delete it // HalpSavedIoMap = (PUSHORT)KeGetPcr()->TSS->IoMaps[0].IoMap; HalpStoreAndClearIopm();
// // Save the IOPM and switch to the real-mode one // HalpSavedIopmBase = KeGetPcr()->TSS->IoMapBase; KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1);
// // Save our stack pointer // HalpSavedEsp0 = KeGetPcr()->TSS->Esp0;}
VOIDNTAPIHalpRestoreTrapHandlers(VOID){ // // Keep dummy GPF handler in case we get an NMI during V8086 // if (!HalpNMIInProgress) { // // Not an NMI -- put back the original handler // KeRegisterInterruptHandler(13, HalpGpfHandler); }
// // Restore invalid opcode handler // KeRegisterInterruptHandler(6, HalpBopHandler);}
VOIDNTAPIHalpRestoreIoPermissionsAndTask(VOID){ // // Restore the stack pointer // KeGetPcr()->TSS->Esp0 = HalpSavedEsp0;
// // Restore the I/O Map // HalpRestoreIopm();
// // Restore the IOPM // KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase;
// // Restore the TSS // if (HalpSavedTss) HalpReturnTss();}
VOIDNTAPIHalpUnmapRealModeMemory(VOID){ ULONG i; PHARDWARE_PTE Pte;
// // Loop the first meg of memory // for (i = 0; i < 0x100000; i += PAGE_SIZE) { // // Invalidate each PTE // Pte = HalAddressToPte(i); Pte->Valid = 0; Pte->Write = 0; Pte->Owner = 0; Pte->PageFrameNumber = 0; }
// // Restore the PDE for the lowest megabyte of memory // Pte = HalAddressToPde(0); *Pte = HalpSavedPte; Pte->PageFrameNumber = HalpSavedPfn;
// // Flush the TLB // HalpFlushTLB();}
BOOLEANNTAPIHalpBiosDisplayReset(VOID){#if defined(SARCH_XBOX) || defined(SARCH_PC98) /* There is no VGA BIOS on these machine types */ return FALSE;#else ULONG Flags; PHARDWARE_PTE IdtPte; BOOLEAN RestoreWriteProtection = FALSE;
// // Disable interrupts // Flags = __readeflags(); _disable();
// // Map memory available to the V8086 real-mode code // HalpMapRealModeMemory();
// // On P5, the first 7 entries of the IDT are write protected to work around // the cmpxchg8b lock errata. Unprotect them here so we can set our custom // invalid op-code handler. // IdtPte = HalAddressToPte(KeGetPcr()->IDT); RestoreWriteProtection = IdtPte->Write != 0; IdtPte->Write = 1;
// // Use special invalid opcode and GPF trap handlers // HalpSwitchToRealModeTrapHandlers();
// // Configure the IOPM and TSS // HalpSetupRealModeIoPermissionsAndTask();
// // Now jump to real mode // HalpBiosCall();
// // Restore kernel trap handlers // HalpRestoreTrapHandlers();
// // Restore write permission // IdtPte->Write = RestoreWriteProtection;
// // Restore TSS and IOPM // HalpRestoreIoPermissionsAndTask();
// // Restore low memory mapping // HalpUnmapRealModeMemory();
// // Restore interrupts if they were previously enabled // __writeeflags(Flags); return TRUE;#endif}
/* EOF */