diff --git a/subsystems/ntvdm/bios.c b/subsystems/ntvdm/bios.c index 9208495aea5..5a796cf24dd 100644 --- a/subsystems/ntvdm/bios.c +++ b/subsystems/ntvdm/bios.c @@ -445,6 +445,12 @@ VOID BiosTimeService() } } +VOID BiosEquipmentService() +{ + /* Return the equipment list */ + EmulatorSetRegister(EMULATOR_REG_AX, BIOS_EQUIPMENT_LIST); +} + VOID BiosHandleIrq(BYTE IrqNumber) { switch (IrqNumber) diff --git a/subsystems/ntvdm/bios.h b/subsystems/ntvdm/bios.h index 548e40f4603..54fbdf66ae8 100644 --- a/subsystems/ntvdm/bios.h +++ b/subsystems/ntvdm/bios.h @@ -23,10 +23,12 @@ #define BIOS_PIC_SLAVE_INT 0x70 #define BIOS_SEGMENT 0xF000 #define BIOS_VIDEO_INTERRUPT 0x10 +#define BIOS_EQUIPMENT_INTERRUPT 0x11 #define BIOS_KBD_INTERRUPT 0x16 #define BIOS_TIME_INTERRUPT 0x1A #define CONSOLE_FONT_HEIGHT 8 #define BIOS_KBD_BUFFER_SIZE 256 +#define BIOS_EQUIPMENT_LIST 0x3C // HACK: Disable FPU for now /* FUNCTIONS ******************************************************************/ @@ -36,6 +38,7 @@ VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress); WORD BiosPeekCharacter(); WORD BiosGetCharacter(); VOID BiosVideoService(); +VOID BiosEquipmentService(); VOID BiosKeyboardService(); VOID BiosTimeService(); VOID BiosHandleIrq(BYTE IrqNumber); diff --git a/subsystems/ntvdm/dos.c b/subsystems/ntvdm/dos.c index a17512ad2ff..71ec4d724f7 100644 --- a/subsystems/ntvdm/dos.c +++ b/subsystems/ntvdm/dos.c @@ -79,7 +79,10 @@ static WORD DosCopyEnvironmentBlock(WORD SourceSegment) /* Advance to the next string */ Ptr += strlen(Ptr) + 1; - DestBuffer += strlen(Ptr) + 1; + DestBuffer += strlen(Ptr); + + /* Put a zero after the string */ + *(DestBuffer++) = 0; } /* Set the final zero */ @@ -590,8 +593,8 @@ VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WOR PspBlock->Exit[0] = 0xCD; // int 0x20 PspBlock->Exit[1] = 0x20; - /* Set the program size */ - PspBlock->MemSize = ProgramSize; + /* Set the number of the last paragraph */ + PspBlock->LastParagraph = PspSegment + ProgramSize - 1; /* Save the interrupt vectors */ PspBlock->TerminateAddress = IntVecTable[0x22]; @@ -633,7 +636,8 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock) LPSTR ProgramFilePath, Parameters[128]; CHAR CommandLineCopy[128]; INT ParamCount = 0; - WORD i, Segment = 0, FileSize, ExeSize; + DWORD Segment = 0; + DWORD i, FileSize, ExeSize; PIMAGE_DOS_HEADER Header; PDWORD RelocationTable; PWORD RelocWord; @@ -700,13 +704,22 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock) // 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; + ExeSize = (((Header->e_cp - 1) * 512) + 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--) + /* Add the PSP size, in paragraphs */ + ExeSize += sizeof(DOS_PSP) >> 4; + + /* Add the maximum size that should be allocated */ + ExeSize += Header->e_maxalloc; + + /* Make sure it does not pass 0xFFFF */ + if (ExeSize > 0xFFFF) ExeSize = 0xFFFF; + + /* Reduce the size one by one until the allocation is successful */ + for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--, ExeSize--) { /* Try to allocate that much memory */ - Segment = DosAllocateMemory(ExeSize + (sizeof(DOS_PSP) >> 4) + i, NULL); + Segment = DosAllocateMemory(ExeSize, NULL); if (Segment != 0) break; } @@ -715,7 +728,8 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock) /* Initialize the PSP */ DosInitializePsp(Segment, - CommandLine, ExeSize + (sizeof(DOS_PSP) >> 4) + i, + CommandLine, + ExeSize, EnvBlock); /* The process owns its own memory */ @@ -865,21 +879,21 @@ Done: CHAR DosReadCharacter() { - // TODO: STDIN can be redirected under DOS 2.0+ - CHAR Character = 0; + CHAR Character = '\0'; + WORD BytesRead; - /* A zero value for the character indicates a special key */ - do Character = BiosGetCharacter(); - while (!Character); + /* Use the file reading function */ + DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead); return Character; } VOID DosPrintCharacter(CHAR Character) { - // TODO: STDOUT can be redirected under DOS 2.0+ - if (Character == '\r') Character = '\n'; - putchar(Character); + WORD BytesWritten; + + /* Use the file writing function */ + DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten); } VOID DosInt20h(WORD CodeSegment) @@ -1382,7 +1396,7 @@ BOOLEAN DosInitialize() /* Initialize the MCB */ Mcb->BlockType = 'Z'; - Mcb->Size = (WORD)USER_MEMORY_SIZE; + Mcb->Size = USER_MEMORY_SIZE; Mcb->OwnerPsp = 0; /* Get the environment strings */ @@ -1428,8 +1442,10 @@ BOOLEAN DosInitialize() /* Move to the next string */ SourcePtr += wcslen(SourcePtr) + 1; - DestPtr += strlen(AsciiString) + 1; + DestPtr += strlen(AsciiString); + *(DestPtr++) = 0; } + *DestPtr = 0; /* Free the memory allocated for environment strings */ FreeEnvironmentStringsW(Environment); diff --git a/subsystems/ntvdm/dos.h b/subsystems/ntvdm/dos.h index b832c954c45..0c5f1bea37f 100644 --- a/subsystems/ntvdm/dos.h +++ b/subsystems/ntvdm/dos.h @@ -19,10 +19,13 @@ #define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT" #define DOS_COMMAND_INTERPRETER L"%SystemRoot%\\system32\\COMMAND.COM /k %SystemRoot%\\system32\\AUTOEXEC.NT" #define FIRST_MCB_SEGMENT 0x1000 -#define USER_MEMORY_SIZE 0x8FFFF +#define USER_MEMORY_SIZE 0x8FFF #define SYSTEM_PSP 0x08 #define SYSTEM_ENV_BLOCK 0x800 #define INVALID_DOS_HANDLE 0xFFFF +#define DOS_INPUT_HANDLE 0 +#define DOS_OUTPUT_HANDLE 1 +#define DOS_ERROR_HANDLE 2 #define DOS_SFT_SIZE 255 #define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0))) #define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0))) @@ -56,7 +59,7 @@ typedef struct _DOS_FCB typedef struct _DOS_PSP { BYTE Exit[2]; - WORD MemSize; + WORD LastParagraph; BYTE Reserved0[6]; DWORD TerminateAddress; DWORD BreakAddress; diff --git a/subsystems/ntvdm/emulator.c b/subsystems/ntvdm/emulator.c index 3f23d529b1e..a502dda33d5 100644 --- a/subsystems/ntvdm/emulator.c +++ b/subsystems/ntvdm/emulator.c @@ -216,6 +216,12 @@ static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number) BiosVideoService(); break; } + case BIOS_EQUIPMENT_INTERRUPT: + { + /* This is the BIOS "get equipment" command, call the BIOS */ + BiosEquipmentService(); + break; + } case BIOS_KBD_INTERRUPT: { /* This is the keyboard BIOS interrupt, call the BIOS */ @@ -267,7 +273,7 @@ static VOID EmulatorHardwareIntAck(PVOID Context, BYTE Number) BOOLEAN EmulatorInitialize() { /* Allocate memory for the 16-bit address space */ - BaseAddress = HeapAlloc(GetProcessHeap(), 0, MAX_ADDRESS); + BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS); if (BaseAddress == NULL) return FALSE; /* Initialize the softx86 CPU emulator */ diff --git a/subsystems/ntvdm/emulator.h b/subsystems/ntvdm/emulator.h index fc94305671a..b8eb9c1b7d1 100644 --- a/subsystems/ntvdm/emulator.h +++ b/subsystems/ntvdm/emulator.h @@ -53,10 +53,10 @@ typedef enum EMULATOR_REG_CX, EMULATOR_REG_DX, EMULATOR_REG_BX, - EMULATOR_REG_SI, - EMULATOR_REG_DI, EMULATOR_REG_SP, EMULATOR_REG_BP, + EMULATOR_REG_SI, + EMULATOR_REG_DI, EMULATOR_REG_ES, EMULATOR_REG_CS, EMULATOR_REG_SS,