ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

bios.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.