diff --git a/lib/soft386/CMakeLists.txt b/lib/soft386/CMakeLists.txt index 06a0f09eaf8..2ae818ee9ee 100644 --- a/lib/soft386/CMakeLists.txt +++ b/lib/soft386/CMakeLists.txt @@ -1,6 +1,7 @@ include_directories(${REACTOS_SOURCE_DIR}/include/reactos/libs/soft386) list(APPEND SOURCE - soft386.c) + soft386.c + common.c) add_library(soft386 ${SOURCE}) diff --git a/lib/soft386/common.c b/lib/soft386/common.c new file mode 100644 index 00000000000..6ce335e44c3 --- /dev/null +++ b/lib/soft386/common.c @@ -0,0 +1,302 @@ +/* + * COPYRIGHT: GPL - See COPYING in the top level directory + * PROJECT: 386/486 CPU Emulation Library + * FILE: common.c + * PURPOSE: Common functions used internally by Soft386. + * PROGRAMMERS: Aleksandar Andrejevic + */ + +/* INCLUDES *******************************************************************/ + +#include "common.h" + +/* PUBLIC FUNCTIONS ***********************************************************/ + +inline +BOOLEAN +Soft386ReadMemory(PSOFT386_STATE State, + INT SegmentReg, + ULONG Offset, + BOOLEAN InstFetch, + PVOID Buffer, + ULONG Size) +{ + ULONG LinearAddress; + PSOFT386_SEG_REG CachedDescriptor; + + ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS); + + /* Get the cached descriptor */ + CachedDescriptor = &State->SegmentRegs[SegmentReg]; + + if ((Offset + Size) >= CachedDescriptor->Limit) + { + /* Read beyond limit */ + // TODO: Generate exception #GP + + return FALSE; + } + + /* Check for protected mode */ + if (State->ControlRegisters[0] & SOFT386_CR0_PE) + { + /* Privilege checks */ + + if (!CachedDescriptor->Present) + { + // TODO: Generate exception #NP + return FALSE; + } + + if (GET_SEGMENT_DPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl) + { + // TODO: Generate exception #GP + return FALSE; + } + + if (InstFetch) + { + if (!CachedDescriptor->Executable) + { + /* Data segment not executable */ + + // TODO: Generate exception #GP + return FALSE; + } + } + else + { + if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite)) + { + /* Code segment not readable */ + + // TODO: Generate exception #GP + return FALSE; + } + } + } + + /* Find the linear address */ + LinearAddress = CachedDescriptor->Base + Offset; + + // TODO: Paging support! + + /* Did the host provide a memory hook? */ + if (State->MemReadCallback) + { + /* Yes, call the host */ + State->MemReadCallback(State, LinearAddress, Buffer, Size); + } + else + { + /* Read the memory directly */ + RtlMoveMemory(Buffer, (LPVOID)LinearAddress, Size); + } + + return TRUE; +} + +inline +BOOLEAN +Soft386WriteMemory(PSOFT386_STATE State, + INT SegmentReg, + ULONG Offset, + PVOID Buffer, + ULONG Size) +{ + ULONG LinearAddress; + PSOFT386_SEG_REG CachedDescriptor; + + ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS); + + /* Get the cached descriptor */ + CachedDescriptor = &State->SegmentRegs[SegmentReg]; + + if ((Offset + Size) >= CachedDescriptor->Limit) + { + /* Write beyond limit */ + // TODO: Generate exception #GP + + return FALSE; + } + + /* Check for protected mode */ + if (State->ControlRegisters[0] & SOFT386_CR0_PE) + { + /* Privilege checks */ + + if (!CachedDescriptor->Present) + { + // TODO: Generate exception #NP + return FALSE; + } + + if (GET_SEGMENT_DPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl) + { + // TODO: Generate exception #GP + return FALSE; + } + + if (CachedDescriptor->Executable) + { + /* Code segment not writable */ + + // TODO: Generate exception #GP + return FALSE; + } + else if (!CachedDescriptor->ReadWrite) + { + /* Data segment not writeable */ + + // TODO: Generate exception #GP + return FALSE; + } + } + + /* Find the linear address */ + LinearAddress = CachedDescriptor->Base + Offset; + + // TODO: Paging support! + + /* Did the host provide a memory hook? */ + if (State->MemWriteCallback) + { + /* Yes, call the host */ + State->MemWriteCallback(State, LinearAddress, Buffer, Size); + } + else + { + /* Write the memory directly */ + RtlMoveMemory((LPVOID)LinearAddress, Buffer, Size); + } + + return TRUE; +} + +inline +BOOLEAN +Soft386StackPush(PSOFT386_STATE State, ULONG Value) +{ + BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size; + + // TODO: Handle OPSIZE prefix. + + if (Size) + { + /* 32-bit size */ + + /* Check if ESP is between 1 and 3 */ + if (State->GeneralRegs[SOFT386_REG_ESP].Long >= 1 + && State->GeneralRegs[SOFT386_REG_ESP].Long <= 3) + { + // TODO: Exception #SS + return FALSE; + } + + /* Subtract ESP by 4 */ + State->GeneralRegs[SOFT386_REG_ESP].Long -= 4; + + /* Store the value in SS:ESP */ + return Soft386WriteMemory(State, + SOFT386_REG_SS, + State->GeneralRegs[SOFT386_REG_ESP].Long, + &Value, + sizeof(ULONG)); + } + else + { + /* 16-bit size */ + USHORT ShortValue = LOWORD(Value); + + /* Check if SP is 1 */ + if (State->GeneralRegs[SOFT386_REG_ESP].Long == 1) + { + // TODO: Exception #SS + return FALSE; + } + + /* Subtract SP by 2 */ + State->GeneralRegs[SOFT386_REG_ESP].LowWord -= 2; + + /* Store the value in SS:SP */ + return Soft386WriteMemory(State, + SOFT386_REG_SS, + State->GeneralRegs[SOFT386_REG_ESP].LowWord, + &ShortValue, + sizeof(USHORT)); + } +} + +inline +BOOLEAN +Soft386StackPop(PSOFT386_STATE State, PULONG Value) +{ + ULONG LongValue; + USHORT ShortValue; + BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size; + + // TODO: Handle OPSIZE prefix. + + if (Size) + { + /* 32-bit size */ + + /* Check if ESP is 0xFFFFFFFF */ + if (State->GeneralRegs[SOFT386_REG_ESP].Long == 0xFFFFFFFF) + { + // TODO: Exception #SS + return FALSE; + } + + /* Read the value from SS:ESP */ + if (!Soft386ReadMemory(State, + SOFT386_REG_SS, + State->GeneralRegs[SOFT386_REG_ESP].Long, + FALSE, + &LongValue, + sizeof(LongValue))) + { + /* An exception occurred */ + return FALSE; + } + + /* Increment ESP by 4 */ + State->GeneralRegs[SOFT386_REG_ESP].Long += 4; + + /* Store the value in the result */ + *Value = LongValue; + } + else + { + /* 16-bit size */ + + /* Check if SP is 0xFFFF */ + if (State->GeneralRegs[SOFT386_REG_ESP].LowWord == 0xFFFF) + { + // TODO: Exception #SS + return FALSE; + } + + /* Read the value from SS:SP */ + if (!Soft386ReadMemory(State, + SOFT386_REG_SS, + State->GeneralRegs[SOFT386_REG_ESP].LowWord, + FALSE, + &ShortValue, + sizeof(ShortValue))) + { + /* An exception occurred */ + return FALSE; + } + + /* Increment SP by 2 */ + State->GeneralRegs[SOFT386_REG_ESP].Long += 2; + + /* Store the value in the result */ + *Value = ShortValue; + } + + return TRUE; +} + +/* EOF */ diff --git a/lib/soft386/common.h b/lib/soft386/common.h new file mode 100644 index 00000000000..b316eebc192 --- /dev/null +++ b/lib/soft386/common.h @@ -0,0 +1,63 @@ +/* + * COPYRIGHT: GPL - See COPYING in the top level directory + * PROJECT: 386/486 CPU Emulation Library + * FILE: common.h + * PURPOSE: Common functions used internally by Soft386 (header file). + * PROGRAMMERS: Aleksandar Andrejevic + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +/* INCLUDES *******************************************************************/ + +#include + +/* DEFINES ********************************************************************/ + +#define GET_SEGMENT_DPL(s) ((s) & 3) + +/* FUNCTIONS ******************************************************************/ + +inline +BOOLEAN +Soft386ReadMemory +( + PSOFT386_STATE State, + INT SegmentReg, + ULONG Offset, + BOOLEAN InstFetch, + PVOID Buffer, + ULONG Size +); + +inline +BOOLEAN +Soft386WriteMemory +( + PSOFT386_STATE State, + INT SegmentReg, + ULONG Offset, + PVOID Buffer, + ULONG Size +); + +inline +BOOLEAN +Soft386StackPush +( + PSOFT386_STATE State, + ULONG Value +); + +inline +BOOLEAN +Soft386StackPop +( + PSOFT386_STATE State, + PULONG Value +); + +#endif // _COMMON_H_ + +/* EOF */ diff --git a/lib/soft386/soft386.c b/lib/soft386/soft386.c index d1f614759d9..a59cd171ea4 100644 --- a/lib/soft386/soft386.c +++ b/lib/soft386/soft386.c @@ -8,7 +8,7 @@ /* INCLUDES *******************************************************************/ -#include "soft386.h" +#include "common.h" /* DEFINES ********************************************************************/ @@ -23,6 +23,7 @@ typedef enum /* PRIVATE FUNCTIONS **********************************************************/ static +inline VOID NTAPI Soft386ExecutionControl(PSOFT386_STATE State, INT Command) @@ -210,3 +211,5 @@ Soft386Interrupt(PSOFT386_STATE State, UCHAR Number) // TODO: NOT IMPLEMENTED!!! UNIMPLEMENTED; } + +/* EOF */