[HAL]
[reactos.git] / reactos / hal / halx86 / generic / bios.c
index 279764d..5db0980 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * PROJECT:         ReactOS HAL
- * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            hal/halx86/generic/bios.c
+ * PROJECT:         ReactOS Hardware Abstraction Layer (HAL)
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            halx86/generic/bios.c
  * PURPOSE:         BIOS Access Routines
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ *                  Alex Ionescu (alex.ionescu@reactos.org)
  */
 
 /* INCLUDES *******************************************************************/
 #include <hal.h>
 #define NDEBUG
 #include <debug.h>
+#include <setjmp.h>
+
+void HalpTrap0D();
 
 /* GLOBALS ********************************************************************/
 
-UCHAR HalpIopmSaveBuffer[0x2000];
+//
+// PTE Data
+//
 ULONG HalpSavedPfn;
 HARDWARE_PTE HalpSavedPte;
-ULONG HalpGpfHandler;
-ULONG HalpBopHandler;
-USHORT HalpSavedIopmBase;
-PUCHAR HalpSavedIoMap;
+
+//
+// IDT Data
+//
+PVOID HalpGpfHandler;
+PVOID HalpBopHandler;
+
+//
+// TSS Data
+//
 ULONG HalpSavedEsp0;
+USHORT HalpSavedTss;
+
+//
+// IOPM Data
+//
+USHORT HalpSavedIopmBase;
+PUSHORT HalpSavedIoMap;
+USHORT HalpSavedIoMapData[32][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;
+
+/* REAL MODE CODE AND STACK START HERE ****************************************/
+
+VOID
+DECLSPEC_NORETURN
+HalpRealModeStart(VOID)
+{
+    /* Do the video BIOS interrupt */
+    HalpCallBiosInterrupt(VIDEO_SERVICES, (SET_VIDEO_MODE << 8) | (GRAPHICS_MODE_12));
+    
+    /* Issue the BOP */
+    KiIssueBop();
+    
+    /* We want the stack to be inside this function so we can map real mode */
+    HalpRealModeStack(sizeof(ULONG), PAGE_SIZE / 2);
+    UNREACHABLE;
+}
+
+/* REAL MODE CODE AND STACK END HERE ******************************************/
+
+/* V86 OPCODE HANDLERS ********************************************************/
+
+BOOLEAN
+FASTCALL
+HalpOpcodeInvalid(IN PHAL_BIOS_FRAME BiosFrame)
+{
+    /* Print error message */
+    DPRINT1("HAL: An invalid V86 opcode was encountered at address %x:%x\n",
+            BiosFrame->SegCs, BiosFrame->Eip);
+
+    /* Break */
+    DbgBreakPoint();
+    return FALSE;
+}
+
+BOOLEAN
+FASTCALL
+HalpPushInt(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;
+}
+
+BOOLEAN
+FASTCALL
+HalpOpcodeINTnn(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;
+}
+
+BOOLEAN
+FASTCALL
+HalpDispatchV86Opcode(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 **********************************************************/
+
+VOID
+FASTCALL
+DECLSPEC_NORETURN
+HalpTrap0DHandler(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);
+    while (TRUE);
+}
+
+VOID
+DECLSPEC_NORETURN
+HalpTrap06()
+{
+    /* 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;
+}
 
-#define GetPdeAddress(x) (PHARDWARE_PTE)(((((ULONG_PTR)(x)) >> 22) << 2) + 0xC0300000)
-#define GetPteAddress(x) (PHARDWARE_PTE)(((((ULONG_PTR)(x)) >> 12) << 2) + 0xC0000000)
+/* V8086 ENTER ****************************************************************/
+
+VOID
+NTAPI
+HalpBiosCall()
+{
+    /* 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 */
+    KiDirectTrapReturn((PKTRAP_FRAME)&V86TrapFrame);
+}
 
 /* FUNCTIONS ******************************************************************/
 
 VOID
 NTAPI
-HalpStoreAndClearIopm(IN PUCHAR IoMap)
+HalpBorrowTss(VOID)
 {
-    ULONG i;
+    USHORT Tss;
+    PKGDTENTRY TssGdt;
+    ULONG_PTR TssLimit;
+    PKTSS TssBase;
+
+    //
+    // Get the current TSS and its GDT entry
+    //
+    Tss = Ke386GetTr();
+    TssGdt = &((PKIPCR)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 = &((PKIPCR)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;
+}
+
+VOID
+NTAPI
+HalpReturnTss(VOID)
+{
+    PKGDTENTRY TssGdt;
+    PKTSS TssBase;
     
-    /* Backup the old I/O Map */
-    RtlCopyMemory(HalpIopmSaveBuffer, IoMap, 0x2000);
+    //
+    // Get the original TSS
+    //
+    TssGdt = &((PKIPCR)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;
 
-    /* Erase the current one */
-    for (i = 0; i < 0x2000; i++) IoMap[i] = 0;
-    for (i = 0x2000; i < 0x2004; i++) IoMap[i] = 0xFF;
+    //
+    // Load old TSS
+    //
+    Ke386SetTr(HalpSavedTss);
 }
 
 VOID
 NTAPI
-HalpRestoreIopm(IN PUCHAR IoMap)
+HalpStoreAndClearIopm(VOID)
 {
-    ULONG i;
+    ULONG i, j;
+    PUSHORT Entry = HalpSavedIoMap;
+
+    //
+    // Loop the I/O Map
+    //
+    for (i = j = 0; i < (IOPM_SIZE) / 2; i++)
+    {
+        //
+        // Check for non-FFFF entry
+        //
+        if (*Entry != 0xFFFF)
+        {
+            //
+            // Save it
+            //
+            ASSERT(j < 32);
+            HalpSavedIoMapData[j][0] = i;
+            HalpSavedIoMapData[j][1] = *Entry;
+        }
+
+        //
+        // Clear it
+        //
+        *Entry++ = 0;
+    }
 
-    /* Restore the backed up copy, and initialize it */
-    RtlCopyMemory(IoMap, HalpIopmSaveBuffer, 0x2000);
-    for (i = 0x2000; i < 0x2004; i++) IoMap[i] = 0xFF;
+    //
+    // Terminate it
+    //
+    while (i++ < (IOPM_FULL_SIZE / 2)) *Entry++ = 0xFFFF;
+
+    //
+    // Return the entries we saved
+    //
+    HalpSavedIoMapEntries = j;
+}
+
+VOID
+NTAPI
+HalpRestoreIopm(VOID)
+{
+    ULONG i = HalpSavedIoMapEntries;
+
+    //
+    // Set default state
+    //
+    RtlFillMemory(HalpSavedIoMap, 0xFF, IOPM_FULL_SIZE);
+
+    //
+    // Restore the backed up copy, and initialize it
+    //
+    while (i--) HalpSavedIoMap[HalpSavedIoMapData[i][0]] = HalpSavedIoMapData[i][1];
 }
 
 VOID
@@ -59,89 +454,112 @@ HalpMapRealModeMemory(VOID)
 {
     PHARDWARE_PTE Pte, V86Pte;
     ULONG i;
-    
-    /* Get the page table directory for the lowest meg of memory */
-    Pte = GetPdeAddress(0);
+
+    //
+    // 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 */ 
+
+    //
+    // Map it to the HAL reserved region and make it valid
+    //
     Pte->Valid = 1;
     Pte->Write = 1;
     Pte->Owner = 1;
-    Pte->PageFrameNumber = (GetPdeAddress(0xFFC00000))->PageFrameNumber;
-    
-    /* Flush the TLB by resetting CR3 */
-    __writecr3(__readcr3());
-    
-    /* Now loop the first meg of memory */
+    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 = GetPteAddress((PVOID)i);
+        //
+        // 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 = GetPteAddress(0x20000);
-    V86Pte = GetPteAddress(&HalpRealModeStart);
+
+    //
+    // 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 */
+        //
+        // Map the physical address into our real-mode region
+        //
         Pte->PageFrameNumber = V86Pte->PageFrameNumber;
         
-        /* Keep going until we've reached the end of our region */
+        //
+        // Keep going until we've reached the end of our region
+        //
         Pte++;
         V86Pte++;
-    } while (V86Pte <= GetPteAddress(&HalpRealModeEnd));
-    
-    /* Flush the TLB by resetting CR3 */
-    __writecr3(__readcr3());
+    } while (V86Pte <= HalAddressToPte(&HalpRealModeEnd));
+
+    //
+    // Flush the TLB
+    //
+    HalpFlushTLB();
 }
 
 VOID
 NTAPI
 HalpSwitchToRealModeTrapHandlers(VOID)
 {
-    ULONG Handler;
+    //
+    // Save the current Invalid Opcode and General Protection Fault Handlers
+    //
+    HalpGpfHandler = KeQueryInterruptHandler(13);
+    HalpBopHandler = KeQueryInterruptHandler(6);
 
-    /* Save the current Invalid Opcode and General Protection Fault Handlers */
-    HalpGpfHandler = ((((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset << 16) &
-                       0xFFFF0000) |
-        (((PKIPCR)KeGetPcr())->IDT[13].Offset & 0xFFFF);
-    HalpBopHandler = ((((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset << 16) &
-                       0xFFFF0000) |
-        (((PKIPCR)KeGetPcr())->IDT[6].Offset & 0xFFFF);
-    
-    /* Now set our own GPF handler to handle exceptions while in real mode */
-    Handler = (ULONG_PTR)HalpTrap0D;
-    ((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset =
-        (USHORT)((Handler >> 16) & 0xFFFF);
-    ((PKIPCR)KeGetPcr())->IDT[13].Offset = (USHORT)Handler;
-    
-    /* And our own invalid opcode handler to detect the BOP to get us out */
-    Handler = (ULONG_PTR)HalpTrap06;
-    ((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset =
-        (USHORT)((Handler >> 16) & 0xFFFF);
-    ((PKIPCR)KeGetPcr())->IDT[6].Offset = (USHORT)Handler;
+    //
+    // 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);
 }
 
 VOID
 NTAPI
 HalpSetupRealModeIoPermissionsAndTask(VOID)
 {
-    /* Save a copy of the I/O Map and delete it */
-    HalpSavedIoMap = (PUCHAR)&(KeGetPcr()->TSS->IoMaps[0]);
-    HalpStoreAndClearIopm(HalpSavedIoMap);
-    
-    /* Save the IOPM and switch to the real-mode one */
+    //
+    // Switch to valid TSS
+    //
+    HalpBorrowTss();
+
+    //
+    // Save a copy of the I/O Map and delete it
+    //
+    HalpSavedIoMap = (PUSHORT)&(KeGetPcr()->TSS->IoMaps[0]);
+    HalpStoreAndClearIopm();
+
+    //
+    // Save the IOPM and switch to the real-mode one
+    //
     HalpSavedIopmBase = KeGetPcr()->TSS->IoMapBase;
     KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1);
-    
-    /* Save our stack pointer */
+
+    //
+    // Save our stack pointer
+    //
     HalpSavedEsp0 = KeGetPcr()->TSS->Esp0; 
 }
 
@@ -149,27 +567,46 @@ VOID
 NTAPI
 HalpRestoreTrapHandlers(VOID)
 {
-    /* We're back, restore the handlers we over-wrote */
-    ((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset =
-    (USHORT)((HalpGpfHandler >> 16) & 0xFFFF);
-    ((PKIPCR)KeGetPcr())->IDT[13].Offset = (USHORT)HalpGpfHandler;    
-    ((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset =
-        (USHORT)((HalpBopHandler >> 16) & 0xFFFF);
-    ((PKIPCR)KeGetPcr())->IDT[6].Offset = (USHORT)HalpBopHandler;
+    //
+    // 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);
 }
 
 VOID
 NTAPI
 HalpRestoreIoPermissionsAndTask(VOID)
 {
-    /* Restore the stack pointer */
+    //
+    // Restore the stack pointer
+    //
     KeGetPcr()->TSS->Esp0 = HalpSavedEsp0;
-    
-    /* Restore the I/O Map */
-    HalpRestoreIopm(HalpSavedIoMap);
-    
-    /* Restore the IOPM */
-    KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase;    
+
+    //
+    // Restore the I/O Map
+    //
+    HalpRestoreIopm();
+
+    //
+    // Restore the IOPM
+    //
+    KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase;
+
+    //
+    // Restore the TSS
+    //
+    if (HalpSavedTss) HalpReturnTss();
 }
 
 VOID
@@ -179,58 +616,101 @@ HalpUnmapRealModeMemory(VOID)
     ULONG i;
     PHARDWARE_PTE Pte;
 
-    /* Loop the first meg of memory */
+    //
+    // Loop the first meg of memory
+    //
     for (i = 0; i < 0x100000; i += PAGE_SIZE)
     {
-        /* Invalidate each PTE */
-        Pte = GetPteAddress((PVOID)i);
+        //
+        // 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 = GetPdeAddress(0);
+
+    //
+    // Restore the PDE for the lowest megabyte of memory
+    //
+    Pte = HalAddressToPde(0);
     *Pte = HalpSavedPte;
     Pte->PageFrameNumber = HalpSavedPfn;
-    
-    /* Flush the TLB by resetting CR3 */
-    __writecr3(__readcr3());
+
+    //
+    // Flush the TLB
+    //
+    HalpFlushTLB();
 }
 
 BOOLEAN
 NTAPI
 HalpBiosDisplayReset(VOID)
 {
-    ULONG Flags = 0;
+    ULONG Flags;
+    PHARDWARE_PTE IdtPte;
+    BOOLEAN RestoreWriteProtection = FALSE;
 
-    /* Disable interrupts */
-    Ke386SaveFlags(Flags);
+    //
+    // Disable interrupts
+    //
+    Flags = __readeflags();
     _disable();
 
-    /* Map memory available to the V8086 real-mode code */
+    //
+    // Map memory available to the V8086 real-mode code
+    //
     HalpMapRealModeMemory();
 
-    /* Use special invalid opcode and GPF trap handlers */
+    // 
+    // 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(((PKIPCR)KeGetPcr())->IDT);
+    RestoreWriteProtection = IdtPte->Write;
+    IdtPte->Write = 1;
+
+    //
+    // Use special invalid opcode and GPF trap handlers
+    //
     HalpSwitchToRealModeTrapHandlers();
 
-    /* Configure the IOPM and TSS */
+    //
+    // Configure the IOPM and TSS
+    //
     HalpSetupRealModeIoPermissionsAndTask();
 
-    /* Now jump to real mode */
+    //
+    // Now jump to real mode
+    //
     HalpBiosCall();
 
-    /* Restore kernel trap handlers */
+    //
+    // Restore kernel trap handlers
+    //
     HalpRestoreTrapHandlers();
-    
-    /* Restore TSS and IOPM */
+
+    //
+    // Restore write permission
+    //
+    IdtPte->Write = RestoreWriteProtection;
+
+    //
+    // Restore TSS and IOPM
+    //
     HalpRestoreIoPermissionsAndTask();
     
-    /* Restore low memory mapping */
+    //
+    // Restore low memory mapping
+    //
     HalpUnmapRealModeMemory();
 
-    /* Restore interrupts if they were previously enabled */
-    Ke386RestoreFlags(Flags);
+    //
+    // Restore interrupts if they were previously enabled
+    //
+    __writeeflags(Flags);
     return TRUE;
 }