From ca06374c9fb25477910b8d20c10db551e091dc82 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Mon, 24 Jun 2013 01:59:09 +0000 Subject: [PATCH] [NTOSKRNL] Check for old-style MZ executable in PeFmtCreateSection. [NTVDM] Fix bugs. Implement MZ executable loading. svn path=/branches/ntvdm/; revision=59328 --- ntoskrnl/mm/section.c | 4 +++ subsystems/ntvdm/dos.c | 65 +++++++++++++++++++++++++++++++++++-- subsystems/ntvdm/emulator.c | 6 ++-- subsystems/ntvdm/ntvdm.c | 8 +++-- subsystems/ntvdm/ntvdm.h | 4 +-- 5 files changed, 76 insertions(+), 11 deletions(-) diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index 42ccf97a2b0..ee925a1029e 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -237,6 +237,10 @@ NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader, if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE) DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic)); + /* check if this is an old MZ executable */ + if(pidhDosHeader->e_lfarlc < 0x40) + DIE(("Old-style MZ executable found, e_lfarlc is %d\n", pidhDosHeader->e_lfarlc)); + /* not a Windows executable */ if(pidhDosHeader->e_lfanew <= 0) DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew)); diff --git a/subsystems/ntvdm/dos.c b/subsystems/ntvdm/dos.c index 29b89ff8116..8e9290b95e5 100644 --- a/subsystems/ntvdm/dos.c +++ b/subsystems/ntvdm/dos.c @@ -320,7 +320,10 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock) LPSTR ProgramFilePath, Parameters[128]; CHAR CommandLineCopy[128]; INT ParamCount = 0; - WORD Segment, FileSize; + WORD i, Segment, FileSize, ExeSize; + PIMAGE_DOS_HEADER Header; + PDWORD RelocationTable; + PWORD RelocWord; /* Save a copy of the command line */ strcpy(CommandLineCopy, CommandLine); @@ -366,8 +369,64 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock) { /* EXE file */ - // TODO: NOT IMPLEMENTED - DisplayMessage(L"EXE files are not yet supported!"); + /* Get the MZ header */ + Header = (PIMAGE_DOS_HEADER)Address; + + // TODO: Verify checksum and executable! + + /* Get the base size of the file, in paragraphs (rounded up) */ + ExeSize = (((Header->e_cp - 1) << 8) + Header->e_cblp + 0x0F) >> 4; + + /* Loop from the maximum to the minimum number of extra paragraphs */ + for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--) + { + /* Try to allocate that much memory */ + Segment = DosAllocateMemory(ExeSize + (sizeof(DOS_PSP) >> 4) + i); + if (Segment != 0) break; + } + + /* Check if at least the lowest allocation was successful */ + if (Segment == 0) goto Cleanup; + + /* Initialize the PSP */ + DosInitializePsp(Segment, + CommandLine, ExeSize + (sizeof(DOS_PSP) >> 4) + i, + EnvBlock); + + /* Copy the program to Segment:0100 */ + RtlCopyMemory((PVOID)((ULONG_PTR)BaseAddress + + TO_LINEAR(Segment, 0x100)), + Address + (Header->e_cparhdr << 4), + FileSize - (Header->e_cparhdr << 4)); + + /* Get the relocation table */ + RelocationTable = (PDWORD)(Address + Header->e_lfarlc); + + /* Perform relocations */ + for (i = 0; i < Header->e_crlc; i++) + { + /* Get a pointer to the word that needs to be patched */ + RelocWord = (PWORD)((ULONG_PTR)BaseAddress + + TO_LINEAR(Segment + HIWORD(RelocationTable[i]), + 0x100 + LOWORD(RelocationTable[i]))); + + /* Add the number of the EXE segment to it */ + *RelocWord += Segment + (sizeof(DOS_PSP) >> 4); + } + + /* Set the initial segment registers */ + EmulatorSetRegister(EMULATOR_REG_DS, Segment); + EmulatorSetRegister(EMULATOR_REG_ES, Segment); + + /* Set the stack to the location from the header */ + EmulatorSetStack(Segment + (sizeof(DOS_PSP) >> 4) + Header->e_ss, + Header->e_sp); + + /* Execute */ + CurrentPsp = Segment; + EmulatorExecute(Segment + Header->e_cs, sizeof(DOS_PSP) + Header->e_ip); + + Success = TRUE; } else { diff --git a/subsystems/ntvdm/emulator.c b/subsystems/ntvdm/emulator.c index 2d09c5843b3..265acd9abae 100644 --- a/subsystems/ntvdm/emulator.c +++ b/subsystems/ntvdm/emulator.c @@ -254,13 +254,13 @@ VOID EmulatorInterrupt(BYTE Number) ULONG EmulatorGetRegister(ULONG Register) { - if (Register < EMULATOR_REG_CS) + if (Register < EMULATOR_REG_ES) { return EmulatorContext.state->general_reg[Register].val; } else { - return EmulatorContext.state->segment_reg[(Register >> 3) - 1].val; + return EmulatorContext.state->segment_reg[Register - EMULATOR_REG_ES].val; } } @@ -272,7 +272,7 @@ VOID EmulatorSetRegister(ULONG Register, ULONG Value) } else { - EmulatorContext.state->segment_reg[(Register >> 3) - 1].val = Value; + EmulatorContext.state->segment_reg[Register - EMULATOR_REG_ES].val = Value; } } diff --git a/subsystems/ntvdm/ntvdm.c b/subsystems/ntvdm/ntvdm.c index 429b5a1b2bb..f20457cfed6 100644 --- a/subsystems/ntvdm/ntvdm.c +++ b/subsystems/ntvdm/ntvdm.c @@ -42,6 +42,7 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType) { /* Perform interrupt 0x23 */ EmulatorInterrupt(0x23); + break; } default: { @@ -124,9 +125,12 @@ INT wmain(INT argc, WCHAR *argv[]) } /* Continue CPU emulation */ - for (i = 0; i < STEPS_PER_CYCLE; i++) EmulatorStep(); + for (i = 0; (i < STEPS_PER_CYCLE) && VdmRunning; i++) + { + EmulatorStep(); + Cycles++; + } - Cycles += STEPS_PER_CYCLE; if ((CurrentTickCount - LastCyclePrintout) >= 1000) { DPRINT1("NTVDM: %d Instructions Per Second\n", Cycles); diff --git a/subsystems/ntvdm/ntvdm.h b/subsystems/ntvdm/ntvdm.h index 896ce7a4ecf..28ea8b8b60b 100644 --- a/subsystems/ntvdm/ntvdm.h +++ b/subsystems/ntvdm/ntvdm.h @@ -102,12 +102,10 @@ typedef enum EMULATOR_REG_DI, EMULATOR_REG_SP, EMULATOR_REG_BP, + EMULATOR_REG_ES, EMULATOR_REG_CS, EMULATOR_REG_SS, EMULATOR_REG_DS, - EMULATOR_REG_ES, - EMULATOR_REG_FS, - EMULATOR_REG_GS } EMULATOR_REGISTER; #pragma pack(push, 1)