From 7e119cf40b2277c5944aa0ffea422c29e54b0af1 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Sat, 28 Sep 2013 00:29:16 +0000 Subject: [PATCH] [SOFT386] Implement the LES and LDS instructions. Add optional support for BOPs (NTVDM-specific). Fix prefix handling in some functions. [NTVDM] Enable BOPs for Soft386 (when NEW_EMULATOR is defined). Fix the calling convention issue (softx86 uses cdecl, soft386 uses stdcall). svn path=/branches/ntvdm/; revision=60395 --- include/reactos/libs/soft386/soft386.h | 9 ++ lib/soft386/opcodes.c | 111 +++++++++++++++++++++---- lib/soft386/opcodes.h | 3 +- lib/soft386/soft386.c | 2 + subsystems/ntvdm/emulator.c | 30 +++++-- subsystems/ntvdm/emulator.h | 6 ++ 6 files changed, 135 insertions(+), 26 deletions(-) diff --git a/include/reactos/libs/soft386/soft386.h b/include/reactos/libs/soft386/soft386.h index 2df1947a0ff..21b61719e25 100644 --- a/include/reactos/libs/soft386/soft386.h +++ b/include/reactos/libs/soft386/soft386.h @@ -157,6 +157,14 @@ VOID PSOFT386_STATE State ); +typedef +VOID +(NTAPI *SOFT386_BOP_PROC) +( + PSOFT386_STATE State, + USHORT BopCode +); + typedef union _SOFT386_REG { union @@ -295,6 +303,7 @@ struct _SOFT386_STATE SOFT386_IO_READ_PROC IoReadCallback; SOFT386_IO_WRITE_PROC IoWriteCallback; SOFT386_IDLE_PROC IdleCallback; + SOFT386_BOP_PROC BopCallback; SOFT386_REG GeneralRegs[SOFT386_NUM_GEN_REGS]; SOFT386_SEG_REG SegmentRegs[SOFT386_NUM_SEG_REGS]; SOFT386_REG InstPtr; diff --git a/lib/soft386/opcodes.c b/lib/soft386/opcodes.c index d614df42620..45dcf463b6d 100644 --- a/lib/soft386/opcodes.c +++ b/lib/soft386/opcodes.c @@ -221,8 +221,8 @@ Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] = NULL, // TODO: OPCODE 0xC1 NOT SUPPORTED Soft386OpcodeRet, Soft386OpcodeRet, - Soft386OpcodeLes, - Soft386OpcodeLds, + Soft386OpcodeLdsLes, + Soft386OpcodeLdsLes, NULL, // TODO: OPCODE 0xC6 NOT SUPPORTED NULL, // TODO: OPCODE 0xC7 NOT SUPPORTED Soft386OpcodeEnter, @@ -4474,20 +4474,99 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeRet) return TRUE; } -SOFT386_OPCODE_HANDLER(Soft386OpcodeLes) +SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes) { - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; + UCHAR FarPointer[6]; + BOOLEAN OperandSize, AddressSize; + SOFT386_MOD_REG_RM ModRegRm; - return FALSE; -} + /* Make sure this is the right instruction */ + ASSERT((Opcode & 0xFE) == 0xC4); -SOFT386_OPCODE_HANDLER(Soft386OpcodeLds) -{ - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; + OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size; - return FALSE; + if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE) + { + /* The ADSIZE prefix toggles the size */ + AddressSize = !AddressSize; + } + + /* Get the operands */ + if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return FALSE; + } + + if (!ModRegRm.Memory) + { + /* Check if this is a BOP and the host supports BOPs */ + if ((Opcode == 0xC4) + && (ModRegRm.Register == SOFT386_REG_EAX) + && (ModRegRm.SecondRegister == SOFT386_REG_EBP) + && (State->BopCallback != NULL)) + { + USHORT BopCode; + + /* Fetch the BOP code */ + if (!Soft386FetchWord(State, &BopCode)) + { + /* Exception occurred */ + return FALSE; + } + + /* Call the BOP handler */ + State->BopCallback(State, BopCode); + + /* Return success */ + return TRUE; + } + + /* Invalid */ + Soft386Exception(State, SOFT386_EXCEPTION_UD); + return FALSE; + } + + if (!Soft386ReadMemory(State, + (State->PrefixFlags & SOFT386_PREFIX_SEG) + ? State->SegmentOverride : SOFT386_REG_DS, + ModRegRm.MemoryAddress, + FALSE, + FarPointer, + OperandSize ? 6 : 4)) + { + /* Exception occurred */ + return FALSE; + } + + if (OperandSize) + { + ULONG Offset = *((PULONG)FarPointer); + USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]); + + /* Set the register to the offset */ + State->GeneralRegs[ModRegRm.Register].Long = Offset; + + /* Load the segment */ + return Soft386LoadSegment(State, + (Opcode == 0xC4) + ? SOFT386_REG_ES : SOFT386_REG_DS, + Segment); + } + else + { + USHORT Offset = *((PUSHORT)FarPointer); + USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]); + + /* Set the register to the offset */ + State->GeneralRegs[ModRegRm.Register].LowWord = Offset; + + /* Load the segment */ + return Soft386LoadSegment(State, + (Opcode == 0xC4) + ? SOFT386_REG_ES : SOFT386_REG_DS, + Segment); + } } SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter) @@ -4508,7 +4587,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter) return FALSE; } - if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) + if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; @@ -4577,7 +4656,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave) return FALSE; } - if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) + if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; @@ -4705,7 +4784,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeIret) return FALSE; } - if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) + if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; @@ -5001,7 +5080,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop) return FALSE; } - if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) + if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; diff --git a/lib/soft386/opcodes.h b/lib/soft386/opcodes.h index fb13042fb08..b3c1450fbe6 100644 --- a/lib/soft386/opcodes.h +++ b/lib/soft386/opcodes.h @@ -115,8 +115,7 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags); SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf); SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf); SOFT386_OPCODE_HANDLER(Soft386OpcodeRet); -SOFT386_OPCODE_HANDLER(Soft386OpcodeLes); -SOFT386_OPCODE_HANDLER(Soft386OpcodeLds); +SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes); SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter); SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave); SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm); diff --git a/lib/soft386/soft386.c b/lib/soft386/soft386.c index 4f449d36c97..02cd048db92 100644 --- a/lib/soft386/soft386.c +++ b/lib/soft386/soft386.c @@ -211,6 +211,7 @@ Soft386Reset(PSOFT386_STATE State) SOFT386_IO_READ_PROC IoReadCallback = State->IoReadCallback; SOFT386_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback; SOFT386_IDLE_PROC IdleCallback = State->IdleCallback; + SOFT386_BOP_PROC BopCallback = State->BopCallback; /* Clear the entire structure */ RtlZeroMemory(State, sizeof(*State)); @@ -245,6 +246,7 @@ Soft386Reset(PSOFT386_STATE State) State->IoReadCallback = IoReadCallback; State->IoWriteCallback = IoWriteCallback; State->IdleCallback = IdleCallback; + State->BopCallback = BopCallback; } VOID diff --git a/subsystems/ntvdm/emulator.c b/subsystems/ntvdm/emulator.c index 6fba6da5c1c..b1bf5635e87 100644 --- a/subsystems/ntvdm/emulator.c +++ b/subsystems/ntvdm/emulator.c @@ -31,7 +31,7 @@ static BOOLEAN A20Line = FALSE; /* PRIVATE FUNCTIONS **********************************************************/ -static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) +static VOID NTVDMCALL EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) { UNREFERENCED_PARAMETER(Context); @@ -56,7 +56,7 @@ static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT S } } -static VOID EmulatorWriteMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) +static VOID NTVDMCALL EmulatorWriteMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) { UNREFERENCED_PARAMETER(Context); @@ -84,7 +84,7 @@ static VOID EmulatorWriteMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT } } -static VOID EmulatorReadIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) +static VOID NTVDMCALL EmulatorReadIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) { UNREFERENCED_PARAMETER(Context); UNREFERENCED_PARAMETER(Size); @@ -152,7 +152,7 @@ static VOID EmulatorReadIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) } } -static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) +static VOID NTVDMCALL EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size) { BYTE Byte = *Buffer; @@ -228,8 +228,6 @@ static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size } } -#ifndef NEW_EMULATOR - static VOID EmulatorBop(WORD Code) { WORD StackSegment, StackPointer, CodeSegment, InstructionPointer; @@ -241,8 +239,8 @@ static VOID EmulatorBop(WORD Code) StackSegment = EmulatorContext.state->segment_reg[SX86_SREG_SS].val; StackPointer = EmulatorContext.state->general_reg[SX86_REG_SP].val; #else - StackSegment = EmulatorContext.SegmentRegs[SOFT386_REG_SS].LowWord; - StackPointer = EmulatorContext.SegmentRegs[SOFT386_REG_SP].LowWord; + StackSegment = EmulatorContext.SegmentRegs[SOFT386_REG_SS].Selector; + StackPointer = EmulatorContext.GeneralRegs[SOFT386_REG_ESP].LowWord; #endif /* Get the stack */ @@ -341,6 +339,21 @@ static VOID EmulatorBop(WORD Code) } } +#ifdef NEW_EMULATOR +static VOID WINAPI EmulatorBiosOperation(PSOFT386_STATE State, WORD Code) +{ + /* + * HACK: To maintain softx86 compatbility, just call the old EmulatorBop here. + * Later on, when softx86 is no longer needed, the code from EmulatorBop should + * be moved here and should use the "State" variable. + */ + EmulatorBop(Code); +} + +#endif + +#ifndef NEW_EMULATOR + static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number) { UNREFERENCED_PARAMETER(Context); @@ -412,6 +425,7 @@ BOOLEAN EmulatorInitialize() EmulatorContext.MemWriteCallback = (SOFT386_MEM_WRITE_PROC)EmulatorWriteMemory; EmulatorContext.IoReadCallback = (SOFT386_IO_READ_PROC)EmulatorReadIo; EmulatorContext.IoWriteCallback = (SOFT386_IO_WRITE_PROC)EmulatorWriteIo; + EmulatorContext.BopCallback = (SOFT386_BOP_PROC)EmulatorBiosOperation; /* Reset the CPU */ Soft386Reset(&EmulatorContext); diff --git a/subsystems/ntvdm/emulator.h b/subsystems/ntvdm/emulator.h index 427c520ffcf..34270500d7c 100644 --- a/subsystems/ntvdm/emulator.h +++ b/subsystems/ntvdm/emulator.h @@ -86,10 +86,16 @@ enum }; #ifndef NEW_EMULATOR + +#define NTVDMCALL __cdecl extern softx86_ctx EmulatorContext; extern softx87_ctx FpuEmulatorContext; + #else + +#define NTVDMCALL __stdcall extern SOFT386_STATE EmulatorContext; + #endif /* FUNCTIONS ******************************************************************/