From af35d7f04690439645c56e972ba4abbb7fe751a1 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Tue, 27 May 2014 21:10:45 +0000 Subject: [PATCH] [FAST486][NTVDM] Several fixes in fast486 and ntvdm: DosCopyEnvironmentBlock - prepend the program name tag (0x0001) to the program name. Fast486OpcodePushByteImm, Fast486OpcodePushImm - sign-extend instead of zero-extending. Fast486InterruptInternal - The parameter is supposed to be the type of the gate, not a boolean. GET_SEGMENT_RPL will not work on real-mode selectors, use a special field for the RPL. Loading a data segment with the NULL selector should never generate an exception. Mask out the highest-order byte of the physical address when loading a descriptor table in 16-bit mode. Fast486InterruptInternal - The interrupt gate type determines the size. CORE-8257 #resolve #comment Fixed in revision r63482. svn path=/trunk/; revision=63482 --- .../include/reactos/libs/fast486/fast486.h | 1 + reactos/lib/fast486/common.c | 22 ++++++++--- reactos/lib/fast486/common.h | 2 +- reactos/lib/fast486/common.inl | 37 ++++++++++++------- reactos/lib/fast486/opcodes.c | 8 ++-- reactos/lib/fast486/opgroups.c | 11 +++++- reactos/subsystems/ntvdm/dos/dos32krnl/dos.c | 4 ++ reactos/subsystems/ntvdm/dos/dos32krnl/dos.h | 1 + 8 files changed, 61 insertions(+), 25 deletions(-) diff --git a/reactos/include/reactos/libs/fast486/fast486.h b/reactos/include/reactos/libs/fast486/fast486.h index 5fa729159fb..434f06cee03 100644 --- a/reactos/include/reactos/libs/fast486/fast486.h +++ b/reactos/include/reactos/libs/fast486/fast486.h @@ -251,6 +251,7 @@ typedef struct _FAST486_SEG_REG ULONG DirConf : 1; ULONG Executable : 1; ULONG SystemType : 1; + ULONG Rpl : 2; ULONG Dpl : 2; ULONG Present : 1; ULONG Size : 1; diff --git a/reactos/lib/fast486/common.c b/reactos/lib/fast486/common.c index 36f026ec331..4babb2d366b 100644 --- a/reactos/lib/fast486/common.c +++ b/reactos/lib/fast486/common.c @@ -65,7 +65,7 @@ Fast486ReadMemory(PFAST486_STATE State, return FALSE; } - if ((!InstFetch && (GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)) + if ((!InstFetch && (CachedDescriptor->Rpl > CachedDescriptor->Dpl)) || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl)) { Fast486Exception(State, FAST486_EXCEPTION_GP); @@ -132,7 +132,7 @@ Fast486WriteMemory(PFAST486_STATE State, return FALSE; } - if ((GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl) + if ((CachedDescriptor->Rpl > CachedDescriptor->Dpl) || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl)) { Fast486Exception(State, FAST486_EXCEPTION_GP); @@ -164,14 +164,26 @@ BOOLEAN Fast486InterruptInternal(PFAST486_STATE State, USHORT SegmentSelector, ULONG Offset, - BOOLEAN InterruptGate) + ULONG GateType) { + BOOLEAN GateSize = (GateType == FAST486_IDT_INT_GATE_32) + || (GateType == FAST486_IDT_TRAP_GATE_32); + /* Check for protected mode */ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) { FAST486_TSS Tss; USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector; ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long; + + if (GateSize != (State->SegmentRegs[FAST486_REG_CS].Size)) + { + /* + * The gate size doesn't match the current operand size, so toggle + * the OPSIZE flag. + */ + State->PrefixFlags ^= FAST486_PREFIX_OPSIZE; + } /* Check if the interrupt handler is more privileged */ if (Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector)) @@ -257,7 +269,7 @@ Fast486InterruptInternal(PFAST486_STATE State, /* Push the instruction pointer */ if (!Fast486StackPush(State, State->InstPtr.Long)) return FALSE; - if (InterruptGate) + if ((GateType == FAST486_IDT_INT_GATE) || (GateType == FAST486_IDT_INT_GATE_32)) { /* Disable interrupts after a jump to an interrupt gate handler */ State->Flags.If = FALSE; @@ -270,7 +282,7 @@ Fast486InterruptInternal(PFAST486_STATE State, return FALSE; } - if (State->SegmentRegs[FAST486_REG_CS].Size) + if (GateSize) { /* 32-bit code segment, use EIP */ State->InstPtr.Long = Offset; diff --git a/reactos/lib/fast486/common.h b/reactos/lib/fast486/common.h index 1bfdb311ef2..677bd19b378 100644 --- a/reactos/lib/fast486/common.h +++ b/reactos/lib/fast486/common.h @@ -159,7 +159,7 @@ Fast486InterruptInternal PFAST486_STATE State, USHORT SegmentSelector, ULONG Offset, - BOOLEAN InterruptGate + ULONG GateType ); VOID diff --git a/reactos/lib/fast486/common.inl b/reactos/lib/fast486/common.inl index fff8fc01474..a558ed461e9 100644 --- a/reactos/lib/fast486/common.inl +++ b/reactos/lib/fast486/common.inl @@ -542,24 +542,32 @@ Fast486LoadSegment(PFAST486_STATE State, { /* Loading a data segment */ - if (!GdtEntry.SystemType) + if (GET_SEGMENT_INDEX(Selector) != 0) { - /* This is a special descriptor */ - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); - 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 ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl) + || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) + { + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + return FALSE; + } - if (!GdtEntry.Present) + if (!GdtEntry.Present) + { + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); + return FALSE; + } + } + else { - Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); - return FALSE; + /* This is a NULL selector */ + RtlZeroMemory(&GdtEntry, sizeof(GdtEntry)); } } @@ -572,6 +580,7 @@ Fast486LoadSegment(PFAST486_STATE State, 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; diff --git a/reactos/lib/fast486/opcodes.c b/reactos/lib/fast486/opcodes.c index 1a8f1260484..e6f91a94d98 100644 --- a/reactos/lib/fast486/opcodes.c +++ b/reactos/lib/fast486/opcodes.c @@ -3702,9 +3702,9 @@ FAST486_OPCODE_HANDLER(Fast486OpcodePushImm) } else { - USHORT Data; + SHORT Data; - if (!Fast486FetchWord(State, &Data)) + if (!Fast486FetchWord(State, (PUSHORT)&Data)) { /* Exception occurred */ return FALSE; @@ -3837,12 +3837,12 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm) FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm) { - UCHAR Data; + CHAR Data; /* Make sure this is the right instruction */ ASSERT(Opcode == 0x6A); - if (!Fast486FetchByte(State, &Data)) + if (!Fast486FetchByte(State, (PUCHAR)&Data)) { /* Exception occurred */ return FALSE; diff --git a/reactos/lib/fast486/opgroups.c b/reactos/lib/fast486/opgroups.c index 264fa66ba2c..efcaa1641ae 100644 --- a/reactos/lib/fast486/opgroups.c +++ b/reactos/lib/fast486/opgroups.c @@ -2018,10 +2018,13 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01) { UCHAR TableReg[6]; FAST486_MOD_REG_RM ModRegRm; - BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; + BOOLEAN OperandSize, AddressSize; FAST486_SEG_REGS Segment = FAST486_REG_DS; + OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; + NO_LOCK_PREFIX(); + TOGGLE_OPSIZE(OperandSize); TOGGLE_ADSIZE(AddressSize); if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) @@ -2117,6 +2120,9 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01) State->Gdtr.Size = *((PUSHORT)TableReg); State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]); + /* In 16-bit mode the highest byte is masked out */ + if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF; + return TRUE; } @@ -2153,6 +2159,9 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01) State->Idtr.Size = *((PUSHORT)TableReg); State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]); + /* In 16-bit mode the highest byte is masked out */ + if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF; + return TRUE; } diff --git a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c index 353fa6d3c22..ad218f1a10b 100644 --- a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c +++ b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.c @@ -442,6 +442,10 @@ static WORD DosCopyEnvironmentBlock(LPCVOID Environment, LPCSTR ProgramName) /* Set the final zero */ *(DestBuffer++) = 0; + /* Store the special program name tag */ + *(DestBuffer++) = LOWORD(DOS_PROGRAM_NAME_TAG); + *(DestBuffer++) = HIWORD(DOS_PROGRAM_NAME_TAG); + /* Copy the program name after the environment block */ strcpy(DestBuffer, ProgramName); diff --git a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h index e2f0cef368c..abbef7e142d 100644 --- a/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h +++ b/reactos/subsystems/ntvdm/dos/dos32krnl/dos.h @@ -47,6 +47,7 @@ #define DOS_DIR_LENGTH 64 #define NUM_DRIVES ('Z' - 'A' + 1) #define DOS_CHAR_ATTRIBUTE 0x07 +#define DOS_PROGRAM_NAME_TAG 0x0001 enum DOS_ALLOC_STRATEGY {