Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenbios.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Hardware Abstraction Layer (HAL) 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: halx86/generic/bios.c 00005 * PURPOSE: BIOS Access Routines 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 * Alex Ionescu (alex.ionescu@reactos.org) 00008 */ 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <hal.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 #include <setjmp.h> 00016 00017 void HalpTrap0D(); 00018 00019 /* GLOBALS ********************************************************************/ 00020 00021 // 00022 // PTE Data 00023 // 00024 ULONG HalpSavedPfn; 00025 HARDWARE_PTE HalpSavedPte; 00026 00027 // 00028 // IDT Data 00029 // 00030 PVOID HalpGpfHandler; 00031 PVOID HalpBopHandler; 00032 00033 // 00034 // TSS Data 00035 // 00036 ULONG HalpSavedEsp0; 00037 USHORT HalpSavedTss; 00038 00039 // 00040 // IOPM Data 00041 // 00042 USHORT HalpSavedIopmBase; 00043 PUSHORT HalpSavedIoMap; 00044 USHORT HalpSavedIoMapData[32][2]; 00045 ULONG HalpSavedIoMapEntries; 00046 00047 /* Where the protected mode stack is */ 00048 ULONG_PTR HalpSavedEsp; 00049 00050 /* Where the real mode code ends */ 00051 extern PVOID HalpRealModeEnd; 00052 00053 /* Context saved for return from v86 mode */ 00054 jmp_buf HalpSavedContext; 00055 00056 00057 /* V86 OPCODE HANDLERS ********************************************************/ 00058 00059 BOOLEAN 00060 FASTCALL 00061 HalpOpcodeInvalid(IN PHAL_BIOS_FRAME BiosFrame) 00062 { 00063 /* Print error message */ 00064 DPRINT1("HAL: An invalid V86 opcode was encountered at address %x:%x\n", 00065 BiosFrame->SegCs, BiosFrame->Eip); 00066 00067 /* Break */ 00068 DbgBreakPoint(); 00069 return FALSE; 00070 } 00071 00072 BOOLEAN 00073 FASTCALL 00074 HalpPushInt(IN PHAL_BIOS_FRAME BiosFrame, 00075 IN ULONG Interrupt) 00076 { 00077 PUSHORT Stack; 00078 ULONG Eip; 00079 00080 /* Calculate stack address (SP) */ 00081 Stack = (PUSHORT)(BiosFrame->SsBase + (BiosFrame->Esp & 0xFFFF)); 00082 00083 /* Push EFlags */ 00084 Stack--; 00085 *Stack = BiosFrame->EFlags & 0xFFFF; 00086 00087 /* Push CS */ 00088 Stack--; 00089 *Stack = BiosFrame->SegCs & 0xFFFF; 00090 00091 /* Push IP */ 00092 Stack--; 00093 *Stack = BiosFrame->Eip & 0xFFFF; 00094 00095 /* Compute new CS:IP from the IVT address for this interrupt entry */ 00096 Eip = *(PULONG)(Interrupt * 4); 00097 BiosFrame->Eip = Eip & 0xFFFF; 00098 BiosFrame->SegCs = Eip >> 16; 00099 00100 /* Update stack address */ 00101 BiosFrame->Esp = (ULONG_PTR)Stack & 0xFFFF; 00102 00103 /* Update CS to linear */ 00104 BiosFrame->CsBase = BiosFrame->SegCs << 4; 00105 BiosFrame->CsLimit = 0xFFFF; 00106 BiosFrame->CsFlags = 0; 00107 00108 /* We're done */ 00109 return TRUE; 00110 } 00111 00112 BOOLEAN 00113 FASTCALL 00114 HalpOpcodeINTnn(IN PHAL_BIOS_FRAME BiosFrame) 00115 { 00116 UCHAR Interrupt; 00117 PKTRAP_FRAME TrapFrame; 00118 00119 /* Convert SS to linear */ 00120 BiosFrame->SsBase = BiosFrame->SegSs << 4; 00121 BiosFrame->SsLimit = 0xFFFF; 00122 BiosFrame->SsFlags = 0; 00123 00124 /* Increase EIP and validate */ 00125 BiosFrame->Eip++; 00126 if (BiosFrame->Eip > BiosFrame->CsLimit) return FALSE; 00127 00128 /* Read interrupt number */ 00129 Interrupt = *(PUCHAR)(BiosFrame->CsBase + BiosFrame->Eip); 00130 00131 /* Increase EIP and push the interrupt */ 00132 BiosFrame->Eip++; 00133 if (HalpPushInt(BiosFrame, Interrupt)) 00134 { 00135 /* Update the trap frame */ 00136 TrapFrame = BiosFrame->TrapFrame; 00137 TrapFrame->HardwareSegSs = BiosFrame->SegSs; 00138 TrapFrame->HardwareEsp = BiosFrame->Esp; 00139 TrapFrame->SegCs = BiosFrame->SegCs; 00140 TrapFrame->EFlags = BiosFrame->EFlags; 00141 00142 /* Success */ 00143 return TRUE; 00144 } 00145 00146 /* Failure */ 00147 return FALSE; 00148 } 00149 00150 BOOLEAN 00151 FASTCALL 00152 HalpDispatchV86Opcode(IN PKTRAP_FRAME TrapFrame) 00153 { 00154 UCHAR Instruction; 00155 HAL_BIOS_FRAME BiosFrame; 00156 00157 /* Fill out the BIOS frame */ 00158 BiosFrame.TrapFrame = TrapFrame; 00159 BiosFrame.SegSs = TrapFrame->HardwareSegSs; 00160 BiosFrame.Esp = TrapFrame->HardwareEsp; 00161 BiosFrame.EFlags = TrapFrame->EFlags; 00162 BiosFrame.SegCs = TrapFrame->SegCs; 00163 BiosFrame.Eip = TrapFrame->Eip; 00164 BiosFrame.Prefix = 0; 00165 00166 /* Convert CS to linear */ 00167 BiosFrame.CsBase = BiosFrame.SegCs << 4; 00168 BiosFrame.CsLimit = 0xFFFF; 00169 BiosFrame.CsFlags = 0; 00170 00171 /* Validate IP */ 00172 if (BiosFrame.Eip > BiosFrame.CsLimit) return FALSE; 00173 00174 /* Read IP */ 00175 Instruction = *(PUCHAR)(BiosFrame.CsBase + BiosFrame.Eip); 00176 if (Instruction != 0xCD) 00177 { 00178 /* We only support INT */ 00179 HalpOpcodeInvalid(&BiosFrame); 00180 return FALSE; 00181 } 00182 00183 /* Handle the interrupt */ 00184 if (HalpOpcodeINTnn(&BiosFrame)) 00185 { 00186 /* Update EIP */ 00187 TrapFrame->Eip = BiosFrame.Eip; 00188 00189 /* We're done */ 00190 return TRUE; 00191 } 00192 00193 /* Failure */ 00194 return FALSE; 00195 } 00196 00197 /* V86 TRAP HANDLERS **********************************************************/ 00198 00199 #ifndef _MINIHAL_ 00200 DECLSPEC_NORETURN 00201 VOID 00202 FASTCALL 00203 HalpTrap0DHandler(IN PKTRAP_FRAME TrapFrame) 00204 { 00205 /* Enter the trap */ 00206 KiEnterTrap(TrapFrame); 00207 00208 /* Check if this is a V86 trap */ 00209 if (TrapFrame->EFlags & EFLAGS_V86_MASK) 00210 { 00211 /* Dispatch the opcode and exit the trap */ 00212 HalpDispatchV86Opcode(TrapFrame); 00213 KiEoiHelper(TrapFrame); 00214 } 00215 00216 /* Strange, it isn't! This can happen during NMI */ 00217 DPRINT1("HAL: Trap0D while not in V86 mode\n"); 00218 KiDumpTrapFrame(TrapFrame); 00219 while (TRUE); 00220 } 00221 00222 VOID 00223 DECLSPEC_NORETURN 00224 HalpTrap06() 00225 { 00226 /* Restore ES/DS to known good values first */ 00227 Ke386SetEs(KGDT_R3_DATA | RPL_MASK); 00228 Ke386SetDs(KGDT_R3_DATA | RPL_MASK); 00229 Ke386SetFs(KGDT_R0_PCR); 00230 00231 /* Restore the stack */ 00232 KeGetPcr()->TSS->Esp0 = HalpSavedEsp0; 00233 00234 /* Return back to where we left */ 00235 longjmp(HalpSavedContext, 1); 00236 UNREACHABLE; 00237 } 00238 00239 /* V8086 ENTER ****************************************************************/ 00240 00241 VOID 00242 NTAPI 00243 HalpBiosCall() 00244 { 00245 /* Must be volatile so it doesn't get optimized away! */ 00246 volatile KTRAP_FRAME V86TrapFrame; 00247 ULONG_PTR StackOffset, CodeOffset; 00248 00249 /* Save the context, check for return */ 00250 if (_setjmp(HalpSavedContext)) 00251 { 00252 /* Returned from v86 */ 00253 return; 00254 } 00255 00256 /* Kill alignment faults */ 00257 __writecr0(__readcr0() & ~CR0_AM); 00258 00259 /* Set new stack address */ 00260 KeGetPcr()->TSS->Esp0 = (ULONG)&V86TrapFrame - 0x20 - sizeof(FX_SAVE_AREA); 00261 00262 /* Compute segmented IP and SP offsets */ 00263 StackOffset = (ULONG_PTR)&HalpRealModeEnd - 4 - (ULONG_PTR)HalpRealModeStart; 00264 CodeOffset = (ULONG_PTR)HalpRealModeStart & 0xFFF; 00265 00266 /* Now build the V86 trap frame */ 00267 V86TrapFrame.V86Es = 0; 00268 V86TrapFrame.V86Ds = 0; 00269 V86TrapFrame.V86Gs = 0; 00270 V86TrapFrame.V86Fs = 0; 00271 V86TrapFrame.HardwareSegSs = 0x2000; 00272 V86TrapFrame.HardwareEsp = StackOffset + CodeOffset; 00273 V86TrapFrame.EFlags = __readeflags() | EFLAGS_V86_MASK | EFLAGS_IOPL; 00274 V86TrapFrame.SegCs = 0x2000; 00275 V86TrapFrame.Eip = CodeOffset; 00276 00277 /* Exit to V86 mode */ 00278 HalpExitToV86((PKTRAP_FRAME)&V86TrapFrame); 00279 } 00280 #endif 00281 00282 /* FUNCTIONS ******************************************************************/ 00283 00284 VOID 00285 NTAPI 00286 HalpBorrowTss(VOID) 00287 { 00288 USHORT Tss; 00289 PKGDTENTRY TssGdt; 00290 ULONG_PTR TssLimit; 00291 PKTSS TssBase; 00292 00293 // 00294 // Get the current TSS and its GDT entry 00295 // 00296 Tss = Ke386GetTr(); 00297 TssGdt = &((PKIPCR)KeGetPcr())->GDT[Tss / sizeof(KGDTENTRY)]; 00298 00299 // 00300 // Get the KTSS limit and check if it has IOPM space 00301 // 00302 TssLimit = TssGdt->LimitLow | TssGdt->HighWord.Bits.LimitHi << 16; 00303 00304 // 00305 // If the KTSS doesn't have enough space this is probably an NMI or DF 00306 // 00307 if (TssLimit > IOPM_SIZE) 00308 { 00309 // 00310 // We are good to go 00311 // 00312 HalpSavedTss = 0; 00313 return; 00314 } 00315 00316 // 00317 // Get the "real" TSS 00318 // 00319 TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / sizeof(KGDTENTRY)]; 00320 TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | 00321 TssGdt->HighWord.Bytes.BaseMid << 16 | 00322 TssGdt->HighWord.Bytes.BaseHi << 24); 00323 00324 // 00325 // Switch to it 00326 // 00327 KeGetPcr()->TSS = TssBase; 00328 00329 // 00330 // Set it up 00331 // 00332 TssGdt->HighWord.Bits.Type = I386_TSS; 00333 TssGdt->HighWord.Bits.Pres = 1; 00334 TssGdt->HighWord.Bits.Dpl = 0; 00335 00336 // 00337 // Load new TSS and return old one 00338 // 00339 Ke386SetTr(KGDT_TSS); 00340 HalpSavedTss = Tss; 00341 } 00342 00343 VOID 00344 NTAPI 00345 HalpReturnTss(VOID) 00346 { 00347 PKGDTENTRY TssGdt; 00348 PKTSS TssBase; 00349 00350 // 00351 // Get the original TSS 00352 // 00353 TssGdt = &((PKIPCR)KeGetPcr())->GDT[HalpSavedTss / sizeof(KGDTENTRY)]; 00354 TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | 00355 TssGdt->HighWord.Bytes.BaseMid << 16 | 00356 TssGdt->HighWord.Bytes.BaseHi << 24); 00357 00358 // 00359 // Switch to it 00360 // 00361 KeGetPcr()->TSS = TssBase; 00362 00363 // 00364 // Set it up 00365 // 00366 TssGdt->HighWord.Bits.Type = I386_TSS; 00367 TssGdt->HighWord.Bits.Pres = 1; 00368 TssGdt->HighWord.Bits.Dpl = 0; 00369 00370 // 00371 // Load old TSS 00372 // 00373 Ke386SetTr(HalpSavedTss); 00374 } 00375 00376 VOID 00377 NTAPI 00378 HalpStoreAndClearIopm(VOID) 00379 { 00380 USHORT i, j; 00381 PUSHORT Entry = HalpSavedIoMap; 00382 00383 // 00384 // Loop the I/O Map 00385 // 00386 for (i = j = 0; i < (IOPM_SIZE) / 2; i++) 00387 { 00388 // 00389 // Check for non-FFFF entry 00390 // 00391 if (*Entry != 0xFFFF) 00392 { 00393 // 00394 // Save it 00395 // 00396 ASSERT(j < 32); 00397 HalpSavedIoMapData[j][0] = i; 00398 HalpSavedIoMapData[j][1] = *Entry; 00399 j++; 00400 } 00401 00402 // 00403 // Clear it 00404 // 00405 *Entry++ = 0; 00406 } 00407 00408 // 00409 // Terminate it 00410 // 00411 while (i++ < (IOPM_FULL_SIZE / 2)) *Entry++ = 0xFFFF; 00412 00413 // 00414 // Return the entries we saved 00415 // 00416 HalpSavedIoMapEntries = j; 00417 } 00418 00419 VOID 00420 NTAPI 00421 HalpRestoreIopm(VOID) 00422 { 00423 ULONG i = HalpSavedIoMapEntries; 00424 00425 // 00426 // Set default state 00427 // 00428 RtlFillMemory(HalpSavedIoMap, IOPM_FULL_SIZE, 0xFF); 00429 00430 // 00431 // Restore the backed up copy, and initialize it 00432 // 00433 while (i--) HalpSavedIoMap[HalpSavedIoMapData[i][0]] = HalpSavedIoMapData[i][1]; 00434 } 00435 00436 #ifndef _MINIHAL_ 00437 VOID 00438 NTAPI 00439 HalpMapRealModeMemory(VOID) 00440 { 00441 PHARDWARE_PTE Pte, V86Pte; 00442 ULONG i; 00443 00444 // 00445 // Get the page table directory for the lowest meg of memory 00446 // 00447 Pte = HalAddressToPde(0); 00448 HalpSavedPfn = Pte->PageFrameNumber; 00449 HalpSavedPte = *Pte; 00450 00451 // 00452 // Map it to the HAL reserved region and make it valid 00453 // 00454 Pte->Valid = 1; 00455 Pte->Write = 1; 00456 Pte->Owner = 1; 00457 Pte->PageFrameNumber = (HalAddressToPde(0xFFC00000))->PageFrameNumber; 00458 00459 // 00460 // Flush the TLB 00461 // 00462 HalpFlushTLB(); 00463 00464 // 00465 // Now loop the first meg of memory 00466 // 00467 for (i = 0; i < 0x100000; i += PAGE_SIZE) 00468 { 00469 // 00470 // Identity map it 00471 // 00472 Pte = HalAddressToPte(i); 00473 Pte->PageFrameNumber = i >> PAGE_SHIFT; 00474 Pte->Valid = 1; 00475 Pte->Write = 1; 00476 Pte->Owner = 1; 00477 } 00478 00479 // 00480 // Now get the entry for our real mode V86 code and the target 00481 // 00482 Pte = HalAddressToPte(0x20000); 00483 V86Pte = HalAddressToPte(&HalpRealModeStart); 00484 do 00485 { 00486 // 00487 // Map the physical address into our real-mode region 00488 // 00489 Pte->PageFrameNumber = V86Pte->PageFrameNumber; 00490 00491 // 00492 // Keep going until we've reached the end of our region 00493 // 00494 Pte++; 00495 V86Pte++; 00496 } while (V86Pte <= HalAddressToPte(&HalpRealModeEnd)); 00497 00498 // 00499 // Flush the TLB 00500 // 00501 HalpFlushTLB(); 00502 } 00503 00504 VOID 00505 NTAPI 00506 HalpSwitchToRealModeTrapHandlers(VOID) 00507 { 00508 // 00509 // Save the current Invalid Opcode and General Protection Fault Handlers 00510 // 00511 HalpGpfHandler = KeQueryInterruptHandler(13); 00512 HalpBopHandler = KeQueryInterruptHandler(6); 00513 00514 // 00515 // Now set our own GPF handler to handle exceptions while in real mode 00516 // 00517 KeRegisterInterruptHandler(13, HalpTrap0D); 00518 00519 // 00520 // And our own invalid opcode handler to detect the BOP to get us out 00521 // 00522 KeRegisterInterruptHandler(6, HalpTrap06); 00523 } 00524 #endif 00525 00526 VOID 00527 NTAPI 00528 HalpSetupRealModeIoPermissionsAndTask(VOID) 00529 { 00530 // 00531 // Switch to valid TSS 00532 // 00533 HalpBorrowTss(); 00534 00535 // 00536 // Save a copy of the I/O Map and delete it 00537 // 00538 HalpSavedIoMap = (PUSHORT)&(KeGetPcr()->TSS->IoMaps[0]); 00539 HalpStoreAndClearIopm(); 00540 00541 // 00542 // Save the IOPM and switch to the real-mode one 00543 // 00544 HalpSavedIopmBase = KeGetPcr()->TSS->IoMapBase; 00545 KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1); 00546 00547 // 00548 // Save our stack pointer 00549 // 00550 HalpSavedEsp0 = KeGetPcr()->TSS->Esp0; 00551 } 00552 00553 VOID 00554 NTAPI 00555 HalpRestoreTrapHandlers(VOID) 00556 { 00557 // 00558 // Keep dummy GPF handler in case we get an NMI during V8086 00559 // 00560 if (!HalpNMIInProgress) 00561 { 00562 // 00563 // Not an NMI -- put back the original handler 00564 // 00565 KeRegisterInterruptHandler(13, HalpGpfHandler); 00566 } 00567 00568 // 00569 // Restore invalid opcode handler 00570 // 00571 KeRegisterInterruptHandler(6, HalpBopHandler); 00572 } 00573 00574 VOID 00575 NTAPI 00576 HalpRestoreIoPermissionsAndTask(VOID) 00577 { 00578 // 00579 // Restore the stack pointer 00580 // 00581 KeGetPcr()->TSS->Esp0 = HalpSavedEsp0; 00582 00583 // 00584 // Restore the I/O Map 00585 // 00586 HalpRestoreIopm(); 00587 00588 // 00589 // Restore the IOPM 00590 // 00591 KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase; 00592 00593 // 00594 // Restore the TSS 00595 // 00596 if (HalpSavedTss) HalpReturnTss(); 00597 } 00598 00599 VOID 00600 NTAPI 00601 HalpUnmapRealModeMemory(VOID) 00602 { 00603 ULONG i; 00604 PHARDWARE_PTE Pte; 00605 00606 // 00607 // Loop the first meg of memory 00608 // 00609 for (i = 0; i < 0x100000; i += PAGE_SIZE) 00610 { 00611 // 00612 // Invalidate each PTE 00613 // 00614 Pte = HalAddressToPte(i); 00615 Pte->Valid = 0; 00616 Pte->Write = 0; 00617 Pte->Owner = 0; 00618 Pte->PageFrameNumber = 0; 00619 } 00620 00621 // 00622 // Restore the PDE for the lowest megabyte of memory 00623 // 00624 Pte = HalAddressToPde(0); 00625 *Pte = HalpSavedPte; 00626 Pte->PageFrameNumber = HalpSavedPfn; 00627 00628 // 00629 // Flush the TLB 00630 // 00631 HalpFlushTLB(); 00632 } 00633 00634 #ifndef _MINIHAL_ 00635 BOOLEAN 00636 NTAPI 00637 HalpBiosDisplayReset(VOID) 00638 { 00639 ULONG Flags; 00640 PHARDWARE_PTE IdtPte; 00641 BOOLEAN RestoreWriteProtection = FALSE; 00642 00643 // 00644 // Disable interrupts 00645 // 00646 Flags = __readeflags(); 00647 _disable(); 00648 00649 // 00650 // Map memory available to the V8086 real-mode code 00651 // 00652 HalpMapRealModeMemory(); 00653 00654 // 00655 // On P5, the first 7 entries of the IDT are write protected to work around 00656 // the cmpxchg8b lock errata. Unprotect them here so we can set our custom 00657 // invalid op-code handler. 00658 // 00659 IdtPte = HalAddressToPte(((PKIPCR)KeGetPcr())->IDT); 00660 RestoreWriteProtection = IdtPte->Write != 0; 00661 IdtPte->Write = 1; 00662 00663 // 00664 // Use special invalid opcode and GPF trap handlers 00665 // 00666 HalpSwitchToRealModeTrapHandlers(); 00667 00668 // 00669 // Configure the IOPM and TSS 00670 // 00671 HalpSetupRealModeIoPermissionsAndTask(); 00672 00673 // 00674 // Now jump to real mode 00675 // 00676 HalpBiosCall(); 00677 00678 // 00679 // Restore kernel trap handlers 00680 // 00681 HalpRestoreTrapHandlers(); 00682 00683 // 00684 // Restore write permission 00685 // 00686 IdtPte->Write = RestoreWriteProtection; 00687 00688 // 00689 // Restore TSS and IOPM 00690 // 00691 HalpRestoreIoPermissionsAndTask(); 00692 00693 // 00694 // Restore low memory mapping 00695 // 00696 HalpUnmapRealModeMemory(); 00697 00698 // 00699 // Restore interrupts if they were previously enabled 00700 // 00701 __writeeflags(Flags); 00702 return TRUE; 00703 } 00704 #endif 00705 00706 /* EOF */ Generated on Sun May 27 2012 04:28:43 for ReactOS by
1.7.6.1
|