Sync with trunk r63502.
[reactos.git] / lib / fast486 / common.inl
index 6324605..a558ed4 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#include "common.h"
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
+FORCEINLINE
+INT
+Fast486GetCurrentPrivLevel(PFAST486_STATE State)
+{
+    /* Return the CPL, or 3 if we're in virtual 8086 mode */
+    return (!State->Flags.Vm) ? State->Cpl : 3;
+}
+
+FORCEINLINE
+ULONG
+Fast486GetPageTableEntry(PFAST486_STATE State,
+                         ULONG VirtualAddress,
+                         BOOLEAN MarkAsDirty)
+{
+    ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
+    ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
+    FAST486_PAGE_DIR DirectoryEntry;
+    FAST486_PAGE_TABLE TableEntry;
+    ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
+
+    if ((State->Tlb != NULL)
+        && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
+    {
+        /* Return the cached entry */
+        return State->Tlb[VirtualAddress >> 12];
+    }
+
+    /* Read the directory entry */
+    State->MemReadCallback(State,
+                           PageDirectory + PdeIndex * sizeof(ULONG),
+                           &DirectoryEntry.Value,
+                           sizeof(DirectoryEntry));
+
+    /* Make sure it is present */
+    if (!DirectoryEntry.Present) return 0;
+
+    /* Was the directory entry accessed before? */
+    if (!DirectoryEntry.Accessed)
+    {
+        /* Well, it is now */
+        DirectoryEntry.Accessed = TRUE;
+
+        /* Write back the directory entry */
+        State->MemWriteCallback(State,
+                                PageDirectory + PdeIndex * sizeof(ULONG),
+                                &DirectoryEntry.Value,
+                                sizeof(DirectoryEntry));
+    }
+
+    /* Read the table entry */
+    State->MemReadCallback(State,
+                           (DirectoryEntry.TableAddress << 12)
+                           + PteIndex * sizeof(ULONG),
+                           &TableEntry.Value,
+                           sizeof(TableEntry));
+
+    /* Make sure it is present */
+    if (!TableEntry.Present) return 0;
+
+    if (MarkAsDirty) TableEntry.Dirty = TRUE;
+
+    /* Was the table entry accessed before? */
+    if (!TableEntry.Accessed)
+    {
+        /* Well, it is now */
+        TableEntry.Accessed = TRUE;
+
+        /* Write back the table entry */
+        State->MemWriteCallback(State,
+                                (DirectoryEntry.TableAddress << 12)
+                                + PteIndex * sizeof(ULONG),
+                                &TableEntry.Value,
+                                sizeof(TableEntry));
+    }
+
+    /*
+     * The resulting permissions depend on the permissions
+     * in the page directory table too
+     */
+    TableEntry.Writeable &= DirectoryEntry.Writeable;
+    TableEntry.Usermode &= DirectoryEntry.Usermode;
+
+    if (State->Tlb != NULL)
+    {
+        /* Set the TLB entry */
+        State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
+    }
+
+    /* Return the table entry */
+    return TableEntry.Value;
+}
+
+FORCEINLINE
+BOOLEAN
+Fast486ReadLinearMemory(PFAST486_STATE State,
+                        ULONG LinearAddress,
+                        PVOID Buffer,
+                        ULONG Size)
+{
+    /* Check if paging is enabled */
+    if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
+    {
+        ULONG Page;
+        FAST486_PAGE_TABLE TableEntry;
+        INT Cpl = Fast486GetCurrentPrivLevel(State);
+        ULONG BufferOffset = 0;
+
+        for (Page = PAGE_ALIGN(LinearAddress);
+             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+             Page += PAGE_SIZE)
+        {
+            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+            /* Get the table entry */
+            TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
+
+            if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+            {
+                /* Exception */
+                Fast486ExceptionWithErrorCode(State,
+                                              FAST486_EXCEPTION_PF,
+                                              TableEntry.Value & 0x07);
+                return FALSE;
+            }
+
+            /* Check if this is the first page */
+            if (Page == PAGE_ALIGN(LinearAddress))
+            {
+                /* Start reading from the offset from the beginning of the page */
+                PageOffset = PAGE_OFFSET(LinearAddress);
+                PageLength -= PageOffset;
+            }
+
+            /* Check if this is the last page */
+            if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
+            {
+                /* Read only a part of the page */
+                PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
+            }
+
+            /* Read the memory */
+            State->MemReadCallback(State,
+                                   (TableEntry.Address << 12) | PageOffset,
+                                   (PVOID)((ULONG_PTR)Buffer + BufferOffset),
+                                   PageLength);
+
+            BufferOffset += PageLength;
+        }
+    }
+    else
+    {
+        /* Read the memory */
+        State->MemReadCallback(State, LinearAddress, Buffer, Size);
+    }
+
+    return TRUE;
+}
+
+FORCEINLINE
+BOOLEAN
+Fast486WriteLinearMemory(PFAST486_STATE State,
+                         ULONG LinearAddress,
+                         PVOID Buffer,
+                         ULONG Size)
+{
+    /* Check if paging is enabled */
+    if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
+    {
+        ULONG Page;
+        FAST486_PAGE_TABLE TableEntry;
+        INT Cpl = Fast486GetCurrentPrivLevel(State);
+        ULONG BufferOffset = 0;
+
+        for (Page = PAGE_ALIGN(LinearAddress);
+             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+             Page += PAGE_SIZE)
+        {
+            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+            /* Get the table entry */
+            TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
+
+            if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+                || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
+                && !TableEntry.Writeable))
+            {
+                /* Exception */
+                Fast486ExceptionWithErrorCode(State,
+                                              FAST486_EXCEPTION_PF,
+                                              TableEntry.Value & 0x07);
+                return FALSE;
+            }
+
+            /* Check if this is the first page */
+            if (Page == PAGE_ALIGN(LinearAddress))
+            {
+                /* Start writing from the offset from the beginning of the page */
+                PageOffset = PAGE_OFFSET(LinearAddress);
+                PageLength -= PageOffset;
+            }
+
+            /* Check if this is the last page */
+            if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
+            {
+                /* Write only a part of the page */
+                PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
+            }
+
+            /* Write the memory */
+            State->MemWriteCallback(State,
+                                    (TableEntry.Address << 12) | PageOffset,
+                                    (PVOID)((ULONG_PTR)Buffer + BufferOffset),
+                                    PageLength);
+
+            BufferOffset += PageLength;
+        }
+    }
+    else
+    {
+        /* Write the memory */
+        State->MemWriteCallback(State, LinearAddress, Buffer, Size);
+    }
+
+    return TRUE;
+}
+
 FORCEINLINE
 VOID
 Fast486Exception(PFAST486_STATE State,
@@ -35,7 +263,7 @@ BOOLEAN
 Fast486StackPush(PFAST486_STATE State,
                  ULONG Value)
 {
-    BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
+    BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
 
     /* The OPSIZE prefix toggles the size */
     if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
@@ -53,7 +281,7 @@ Fast486StackPush(PFAST486_STATE State,
         }
 
         /* Subtract ESP by 4 */
-        State->GeneralRegs[FAST486_REG_ESP].Long -= 4;
+        State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
 
         /* Store the value in SS:ESP */
         return Fast486WriteMemory(State,
@@ -68,14 +296,14 @@ Fast486StackPush(PFAST486_STATE State,
         USHORT ShortValue = LOWORD(Value);
 
         /* Check if SP is 1 */
-        if (State->GeneralRegs[FAST486_REG_ESP].Long == 1)
+        if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
         {
             Fast486Exception(State, FAST486_EXCEPTION_SS);
             return FALSE;
         }
 
         /* Subtract SP by 2 */
-        State->GeneralRegs[FAST486_REG_ESP].LowWord -= 2;
+        State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
 
         /* Store the value in SS:SP */
         return Fast486WriteMemory(State,
@@ -91,16 +319,15 @@ BOOLEAN
 Fast486StackPop(PFAST486_STATE State,
                 PULONG Value)
 {
-    ULONG LongValue;
-    USHORT ShortValue;
-    BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
+    BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
 
     /* The OPSIZE prefix toggles the size */
-    if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
+    TOGGLE_OPSIZE(Size);
 
     if (Size)
     {
         /* 32-bit size */
+        ULONG LongValue;
 
         /* Check if ESP is 0xFFFFFFFF */
         if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
@@ -122,7 +349,7 @@ Fast486StackPop(PFAST486_STATE State,
         }
 
         /* Increment ESP by 4 */
-        State->GeneralRegs[FAST486_REG_ESP].Long += 4;
+        State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
 
         /* Store the value in the result */
         *Value = LongValue;
@@ -130,6 +357,7 @@ Fast486StackPop(PFAST486_STATE State,
     else
     {
         /* 16-bit size */
+        USHORT ShortValue;
 
         /* Check if SP is 0xFFFF */
         if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
@@ -151,7 +379,7 @@ Fast486StackPop(PFAST486_STATE State,
         }
 
         /* Increment SP by 2 */
-        State->GeneralRegs[FAST486_REG_ESP].Long += 2;
+        State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
 
         /* Store the value in the result */
         *Value = ShortValue;
@@ -163,7 +391,7 @@ Fast486StackPop(PFAST486_STATE State,
 FORCEINLINE
 BOOLEAN
 Fast486LoadSegment(PFAST486_STATE State,
-                   INT Segment,
+                   FAST486_SEG_REGS Segment,
                    USHORT Selector)
 {
     PFAST486_SEG_REG CachedDescriptor;
@@ -177,20 +405,46 @@ Fast486LoadSegment(PFAST486_STATE State,
     /* Check for protected mode */
     if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
     {
-        /* Make sure the GDT contains the entry */
-        if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
+        if (!(Selector & SEGMENT_TABLE_INDICATOR))
         {
-            Fast486Exception(State, FAST486_EXCEPTION_GP);
-            return FALSE;
+            /* Make sure the GDT contains the entry */
+            if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
+            {
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return FALSE;
+            }
+
+            /* Read the GDT */
+            if (!Fast486ReadLinearMemory(State,
+                                         State->Gdtr.Address
+                                         + GET_SEGMENT_INDEX(Selector),
+                                         &GdtEntry,
+                                         sizeof(GdtEntry)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
         }
+        else
+        {
+            /* Make sure the LDT contains the entry */
+            if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
+            {
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return FALSE;
+            }
 
-        /* Read the GDT */
-        // FIXME: This code is only correct when paging is disabled!!!
-        State->MemReadCallback(State,
-                               State->Gdtr.Address
-                               + GET_SEGMENT_INDEX(Selector),
-                               &GdtEntry,
-                               sizeof(GdtEntry));
+            /* Read the LDT */
+            if (!Fast486ReadLinearMemory(State,
+                                         State->Ldtr.Base
+                                         + GET_SEGMENT_INDEX(Selector),
+                                         &GdtEntry,
+                                         sizeof(GdtEntry)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+        }
 
         if (Segment == FAST486_REG_SS)
         {
@@ -205,68 +459,128 @@ Fast486LoadSegment(PFAST486_STATE State,
             if (!GdtEntry.SystemType)
             {
                 /* This is a special descriptor */
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
                 return FALSE;
             }
 
             if (GdtEntry.Executable || !GdtEntry.ReadWrite)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
                 return FALSE;
             }
 
             if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
                 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
             {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
                 return FALSE;
             }
 
             if (!GdtEntry.Present)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_SS);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
                 return FALSE;
             }
         }
         else if (Segment == FAST486_REG_CS)
         {
             /* Loading the code segment */
-            // TODO: NOT IMPLEMENTED
-        }
-        else
-        {
-            /* Loading a data segment */
 
-            if (!GdtEntry.SystemType)
+            if (GET_SEGMENT_INDEX(Selector) == 0)
             {
-                /* This is a special descriptor */
                 Fast486Exception(State, FAST486_EXCEPTION_GP);
                 return FALSE;
             }
 
-            if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
-                && (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
+            if (!GdtEntry.SystemType)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
-                return FALSE;
+                // TODO: Call/interrupt/task gates NOT IMPLEMENTED!
+                UNIMPLEMENTED;
             }
+            else
+            {
+                if (!GdtEntry.Present)
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
+                    return FALSE;
+                }
 
-            if (!GdtEntry.Present)
+                if (!GdtEntry.Executable)
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                    return FALSE;
+                }
+
+                if (GdtEntry.DirConf)
+                {
+                    /* Conforming Code Segment */
+
+                    if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
+                    {
+                        /* Must be accessed from lower-privileged code */
+                        Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                        return FALSE;
+                    }
+                }
+                else
+                {
+                    /* Regular code segment */
+
+                    if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
+                        || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
+                    {
+                        Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                        return FALSE;
+                    }
+                }
+
+                /* Update CPL */
+                State->Cpl = GET_SEGMENT_RPL(Selector);
+            }
+        }
+        else
+        {
+            /* Loading a data segment */
+
+            if (GET_SEGMENT_INDEX(Selector) != 0)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_NP);
-                return FALSE;
+                if (!GdtEntry.SystemType)
+                {
+                    /* This is a special descriptor */
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                    return FALSE;
+                }
+
+                if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
+                    || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                    return FALSE;
+                }
+
+                if (!GdtEntry.Present)
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
+                    return FALSE;
+                }
+            }
+            else
+            {
+                /* This is a NULL selector */
+                RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
             }
         }
 
         /* Update the cache entry */
         CachedDescriptor->Selector = Selector;
-        CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseHigh << 24);
+        CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
         CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
         CachedDescriptor->Accessed = GdtEntry.Accessed;
         CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
         CachedDescriptor->DirConf = GdtEntry.DirConf;
         CachedDescriptor->Executable = GdtEntry.Executable;
         CachedDescriptor->SystemType = GdtEntry.SystemType;
+        CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
         CachedDescriptor->Dpl = GdtEntry.Dpl;
         CachedDescriptor->Present = GdtEntry.Present;
         CachedDescriptor->Size = GdtEntry.Size;
@@ -388,17 +702,20 @@ Fast486GetIntVector(PFAST486_STATE State,
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
     {
         /* Read from the IDT */
-        // FIXME: This code is only correct when paging is disabled!!!
-        State->MemReadCallback(State,
-                               State->Idtr.Address
-                               + Number * sizeof(*IdtEntry),
-                               IdtEntry,
-                               sizeof(*IdtEntry));
+        if (!Fast486ReadLinearMemory(State,
+                                     State->Idtr.Address
+                                     + Number * sizeof(*IdtEntry),
+                                     IdtEntry,
+                                     sizeof(*IdtEntry)))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
     }
     else
     {
         /* Read from the real-mode IVT */
-        
+
         /* Paging is always disabled in real mode */
         State->MemReadCallback(State,
                                State->Idtr.Address
@@ -417,10 +734,6 @@ Fast486GetIntVector(PFAST486_STATE State,
         IdtEntry->OffsetHigh = 0;
     }
 
-    /*
-     * Once paging support is implemented this function
-     * will not always return true
-     */
     return TRUE;
 }
 
@@ -487,7 +800,32 @@ Fast486ParseModRegRm(PFAST486_STATE State,
             Index = (SibByte >> 3) & 0x07;
             if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
             else Index = 0;
-            Base = State->GeneralRegs[SibByte & 0x07].Long;
+
+            if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
+            {
+                /* Use the register a base */
+                Base = State->GeneralRegs[SibByte & 0x07].Long;
+            }
+            else
+            {
+                /* Fetch the base */
+                if (!Fast486FetchDword(State, &Base))
+                {
+                    /* Exception occurred */
+                    return FALSE;
+                }
+            }
+
+            if ((SibByte & 0x07) == FAST486_REG_ESP)
+            {
+                /* Check if there is no segment override */
+                if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
+                {
+                    /* Add a SS: prefix */
+                    State->PrefixFlags |= FAST486_PREFIX_SEG;
+                    State->SegmentOverride = FAST486_REG_SS;
+                }
+            }
 
             /* Calculate the address */
             ModRegRm->MemoryAddress = Base + Index * Scale;
@@ -518,7 +856,7 @@ Fast486ParseModRegRm(PFAST486_STATE State,
         if (Mode == 1)
         {
             CHAR Offset;
-            
+
             /* Fetch the byte */
             if (!Fast486FetchByte(State, (PUCHAR)&Offset))
             {
@@ -532,7 +870,7 @@ Fast486ParseModRegRm(PFAST486_STATE State,
         else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
         {
             LONG Offset;
-            
+
             /* Fetch the dword */
             if (!Fast486FetchDword(State, (PULONG)&Offset))
             {
@@ -550,9 +888,8 @@ Fast486ParseModRegRm(PFAST486_STATE State,
         switch (RegMem)
         {
             case 0:
-            case 2:
             {
-                /* (SS:)[BX + SI] */
+                /* [BX + SI] */
                 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
                                            + State->GeneralRegs[FAST486_REG_ESI].LowWord;
 
@@ -560,15 +897,32 @@ Fast486ParseModRegRm(PFAST486_STATE State,
             }
 
             case 1:
-            case 3:
             {
-                /* (SS:)[BX + DI] */
+                /* [BX + DI] */
                 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
                                            + State->GeneralRegs[FAST486_REG_EDI].LowWord;
 
                 break;
             }
 
+            case 2:
+            {
+                /* SS:[BP + SI] */
+                ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
+                                           + State->GeneralRegs[FAST486_REG_ESI].LowWord;
+
+                break;
+            }
+
+            case 3:
+            {
+                /* SS:[BP + DI] */
+                ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
+                                           + State->GeneralRegs[FAST486_REG_EDI].LowWord;
+
+                break;
+            }
+
             case 4:
             {
                 /* [SI] */
@@ -625,7 +979,7 @@ Fast486ParseModRegRm(PFAST486_STATE State,
         if (Mode == 1)
         {
             CHAR Offset;
-            
+
             /* Fetch the byte */
             if (!Fast486FetchByte(State, (PUCHAR)&Offset))
             {
@@ -639,7 +993,7 @@ Fast486ParseModRegRm(PFAST486_STATE State,
         else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
         {
             SHORT Offset;
-            
+
             /* Fetch the word */
             if (!Fast486FetchWord(State, (PUSHORT)&Offset))
             {
@@ -667,51 +1021,57 @@ Fast486ReadModrmByteOperands(PFAST486_STATE State,
 {
     FAST486_SEG_REGS Segment = FAST486_REG_DS;
 
-    /* Get the register value */
-    if (ModRegRm->Register & 0x04)
-    {
-        /* AH, CH, DH, BH */
-        *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
-    }
-    else
-    {
-        /* AL, CL, DL, BL */
-        *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
-    }
-
-    if (!ModRegRm->Memory)
+    if (RegValue)
     {
-        /* Get the second register value */
-        if (ModRegRm->SecondRegister & 0x04)
+        /* Get the register value */
+        if (ModRegRm->Register & 0x04)
         {
             /* AH, CH, DH, BH */
-            *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
+            *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
         }
         else
         {
             /* AL, CL, DL, BL */
-            *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
+            *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
         }
     }
-    else
+
+    if (RmValue)
     {
-        /* Check for the segment override */
-        if (State->PrefixFlags & FAST486_PREFIX_SEG)
+        if (!ModRegRm->Memory)
         {
-            /* Use the override segment instead */
-            Segment = State->SegmentOverride;
+            /* Get the second register value */
+            if (ModRegRm->SecondRegister & 0x04)
+            {
+                /* AH, CH, DH, BH */
+                *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
+            }
+            else
+            {
+                /* AL, CL, DL, BL */
+                *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
+            }
         }
-
-        /* Read memory */
-        if (!Fast486ReadMemory(State,
-                               Segment,
-                               ModRegRm->MemoryAddress,
-                               FALSE,
-                               RmValue,
-                               sizeof(UCHAR)))
+        else
         {
-            /* Exception occurred */
-            return FALSE;
+            /* Check for the segment override */
+            if (State->PrefixFlags & FAST486_PREFIX_SEG)
+            {
+                /* Use the override segment instead */
+                Segment = State->SegmentOverride;
+            }
+
+            /* Read memory */
+            if (!Fast486ReadMemory(State,
+                                   Segment,
+                                   ModRegRm->MemoryAddress,
+                                   FALSE,
+                                   RmValue,
+                                   sizeof(UCHAR)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
         }
     }
 
@@ -727,33 +1087,39 @@ Fast486ReadModrmWordOperands(PFAST486_STATE State,
 {
     FAST486_SEG_REGS Segment = FAST486_REG_DS;
 
-    /* Get the register value */
-    *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
-
-    if (!ModRegRm->Memory)
+    if (RegValue)
     {
-        /* Get the second register value */
-        *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
+        /* Get the register value */
+        *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
     }
-    else
+
+    if (RmValue)
     {
-        /* Check for the segment override */
-        if (State->PrefixFlags & FAST486_PREFIX_SEG)
+        if (!ModRegRm->Memory)
         {
-            /* Use the override segment instead */
-            Segment = State->SegmentOverride;
+            /* Get the second register value */
+            *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
         }
-
-        /* Read memory */
-        if (!Fast486ReadMemory(State,
-                               Segment,
-                               ModRegRm->MemoryAddress,
-                               FALSE,
-                               RmValue,
-                               sizeof(USHORT)))
+        else
         {
-            /* Exception occurred */
-            return FALSE;
+            /* Check for the segment override */
+            if (State->PrefixFlags & FAST486_PREFIX_SEG)
+            {
+                /* Use the override segment instead */
+                Segment = State->SegmentOverride;
+            }
+
+            /* Read memory */
+            if (!Fast486ReadMemory(State,
+                                   Segment,
+                                   ModRegRm->MemoryAddress,
+                                   FALSE,
+                                   RmValue,
+                                   sizeof(USHORT)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
         }
     }
 
@@ -769,33 +1135,39 @@ Fast486ReadModrmDwordOperands(PFAST486_STATE State,
 {
     FAST486_SEG_REGS Segment = FAST486_REG_DS;
 
-    /* Get the register value */
-    *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
-
-    if (!ModRegRm->Memory)
+    if (RegValue)
     {
-        /* Get the second register value */
-        *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
+        /* Get the register value */
+        *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
     }
-    else
+
+    if (RmValue)
     {
-        /* Check for the segment override */
-        if (State->PrefixFlags & FAST486_PREFIX_SEG)
+        if (!ModRegRm->Memory)
         {
-            /* Use the override segment instead */
-            Segment = State->SegmentOverride;
+            /* Get the second register value */
+            *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
         }
-
-        /* Read memory */
-        if (!Fast486ReadMemory(State,
-                               Segment,
-                               ModRegRm->MemoryAddress,
-                               FALSE,
-                               RmValue,
-                               sizeof(ULONG)))
+        else
         {
-            /* Exception occurred */
-            return FALSE;
+            /* Check for the segment override */
+            if (State->PrefixFlags & FAST486_PREFIX_SEG)
+            {
+                /* Use the override segment instead */
+                Segment = State->SegmentOverride;
+            }
+
+            /* Read memory */
+            if (!Fast486ReadMemory(State,
+                                   Segment,
+                                   ModRegRm->MemoryAddress,
+                                   FALSE,
+                                   RmValue,
+                                   sizeof(ULONG)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
         }
     }