Fix several bugs:
The file was not entirely read due to an integer overflow.
The second WORD of the Program Segment Prefix (PSP) is not the number of allocated
paragraphs, but the segment of the last paragraph.
Fix the order of registers (SI and DI were mixed up with SP and BP).
Implement interrupt 0x11.
Implement redirection for reading/writing characters.


svn path=/branches/ntvdm/; revision=59409
This commit is contained in:
Aleksandar Andrejevic 2013-07-02 02:08:30 +00:00
parent 40e7d3a9fb
commit 36f251eca0
6 changed files with 58 additions and 24 deletions

View file

@ -445,6 +445,12 @@ VOID BiosTimeService()
} }
} }
VOID BiosEquipmentService()
{
/* Return the equipment list */
EmulatorSetRegister(EMULATOR_REG_AX, BIOS_EQUIPMENT_LIST);
}
VOID BiosHandleIrq(BYTE IrqNumber) VOID BiosHandleIrq(BYTE IrqNumber)
{ {
switch (IrqNumber) switch (IrqNumber)

View file

@ -23,10 +23,12 @@
#define BIOS_PIC_SLAVE_INT 0x70 #define BIOS_PIC_SLAVE_INT 0x70
#define BIOS_SEGMENT 0xF000 #define BIOS_SEGMENT 0xF000
#define BIOS_VIDEO_INTERRUPT 0x10 #define BIOS_VIDEO_INTERRUPT 0x10
#define BIOS_EQUIPMENT_INTERRUPT 0x11
#define BIOS_KBD_INTERRUPT 0x16 #define BIOS_KBD_INTERRUPT 0x16
#define BIOS_TIME_INTERRUPT 0x1A #define BIOS_TIME_INTERRUPT 0x1A
#define CONSOLE_FONT_HEIGHT 8 #define CONSOLE_FONT_HEIGHT 8
#define BIOS_KBD_BUFFER_SIZE 256 #define BIOS_KBD_BUFFER_SIZE 256
#define BIOS_EQUIPMENT_LIST 0x3C // HACK: Disable FPU for now
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
@ -36,6 +38,7 @@ VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress);
WORD BiosPeekCharacter(); WORD BiosPeekCharacter();
WORD BiosGetCharacter(); WORD BiosGetCharacter();
VOID BiosVideoService(); VOID BiosVideoService();
VOID BiosEquipmentService();
VOID BiosKeyboardService(); VOID BiosKeyboardService();
VOID BiosTimeService(); VOID BiosTimeService();
VOID BiosHandleIrq(BYTE IrqNumber); VOID BiosHandleIrq(BYTE IrqNumber);

View file

@ -79,7 +79,10 @@ static WORD DosCopyEnvironmentBlock(WORD SourceSegment)
/* Advance to the next string */ /* Advance to the next string */
Ptr += strlen(Ptr) + 1; Ptr += strlen(Ptr) + 1;
DestBuffer += strlen(Ptr) + 1; DestBuffer += strlen(Ptr);
/* Put a zero after the string */
*(DestBuffer++) = 0;
} }
/* Set the final zero */ /* 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[0] = 0xCD; // int 0x20
PspBlock->Exit[1] = 0x20; PspBlock->Exit[1] = 0x20;
/* Set the program size */ /* Set the number of the last paragraph */
PspBlock->MemSize = ProgramSize; PspBlock->LastParagraph = PspSegment + ProgramSize - 1;
/* Save the interrupt vectors */ /* Save the interrupt vectors */
PspBlock->TerminateAddress = IntVecTable[0x22]; PspBlock->TerminateAddress = IntVecTable[0x22];
@ -633,7 +636,8 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
LPSTR ProgramFilePath, Parameters[128]; LPSTR ProgramFilePath, Parameters[128];
CHAR CommandLineCopy[128]; CHAR CommandLineCopy[128];
INT ParamCount = 0; INT ParamCount = 0;
WORD i, Segment = 0, FileSize, ExeSize; DWORD Segment = 0;
DWORD i, FileSize, ExeSize;
PIMAGE_DOS_HEADER Header; PIMAGE_DOS_HEADER Header;
PDWORD RelocationTable; PDWORD RelocationTable;
PWORD RelocWord; PWORD RelocWord;
@ -700,13 +704,22 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
// TODO: Verify checksum and executable! // TODO: Verify checksum and executable!
/* Get the base size of the file, in paragraphs (rounded up) */ /* 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 */ /* Add the PSP size, in paragraphs */
for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--) 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 */ /* Try to allocate that much memory */
Segment = DosAllocateMemory(ExeSize + (sizeof(DOS_PSP) >> 4) + i, NULL); Segment = DosAllocateMemory(ExeSize, NULL);
if (Segment != 0) break; if (Segment != 0) break;
} }
@ -715,7 +728,8 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
/* Initialize the PSP */ /* Initialize the PSP */
DosInitializePsp(Segment, DosInitializePsp(Segment,
CommandLine, ExeSize + (sizeof(DOS_PSP) >> 4) + i, CommandLine,
ExeSize,
EnvBlock); EnvBlock);
/* The process owns its own memory */ /* The process owns its own memory */
@ -865,21 +879,21 @@ Done:
CHAR DosReadCharacter() 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 */ /* Use the file reading function */
do Character = BiosGetCharacter(); DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
while (!Character);
return Character; return Character;
} }
VOID DosPrintCharacter(CHAR Character) VOID DosPrintCharacter(CHAR Character)
{ {
// TODO: STDOUT can be redirected under DOS 2.0+ WORD BytesWritten;
if (Character == '\r') Character = '\n';
putchar(Character); /* Use the file writing function */
DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten);
} }
VOID DosInt20h(WORD CodeSegment) VOID DosInt20h(WORD CodeSegment)
@ -1382,7 +1396,7 @@ BOOLEAN DosInitialize()
/* Initialize the MCB */ /* Initialize the MCB */
Mcb->BlockType = 'Z'; Mcb->BlockType = 'Z';
Mcb->Size = (WORD)USER_MEMORY_SIZE; Mcb->Size = USER_MEMORY_SIZE;
Mcb->OwnerPsp = 0; Mcb->OwnerPsp = 0;
/* Get the environment strings */ /* Get the environment strings */
@ -1428,8 +1442,10 @@ BOOLEAN DosInitialize()
/* Move to the next string */ /* Move to the next string */
SourcePtr += wcslen(SourcePtr) + 1; SourcePtr += wcslen(SourcePtr) + 1;
DestPtr += strlen(AsciiString) + 1; DestPtr += strlen(AsciiString);
*(DestPtr++) = 0;
} }
*DestPtr = 0;
/* Free the memory allocated for environment strings */ /* Free the memory allocated for environment strings */
FreeEnvironmentStringsW(Environment); FreeEnvironmentStringsW(Environment);

View file

@ -19,10 +19,13 @@
#define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT" #define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT"
#define DOS_COMMAND_INTERPRETER L"%SystemRoot%\\system32\\COMMAND.COM /k %SystemRoot%\\system32\\AUTOEXEC.NT" #define DOS_COMMAND_INTERPRETER L"%SystemRoot%\\system32\\COMMAND.COM /k %SystemRoot%\\system32\\AUTOEXEC.NT"
#define FIRST_MCB_SEGMENT 0x1000 #define FIRST_MCB_SEGMENT 0x1000
#define USER_MEMORY_SIZE 0x8FFFF #define USER_MEMORY_SIZE 0x8FFF
#define SYSTEM_PSP 0x08 #define SYSTEM_PSP 0x08
#define SYSTEM_ENV_BLOCK 0x800 #define SYSTEM_ENV_BLOCK 0x800
#define INVALID_DOS_HANDLE 0xFFFF #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 DOS_SFT_SIZE 255
#define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0))) #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))) #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 typedef struct _DOS_PSP
{ {
BYTE Exit[2]; BYTE Exit[2];
WORD MemSize; WORD LastParagraph;
BYTE Reserved0[6]; BYTE Reserved0[6];
DWORD TerminateAddress; DWORD TerminateAddress;
DWORD BreakAddress; DWORD BreakAddress;

View file

@ -216,6 +216,12 @@ static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number)
BiosVideoService(); BiosVideoService();
break; break;
} }
case BIOS_EQUIPMENT_INTERRUPT:
{
/* This is the BIOS "get equipment" command, call the BIOS */
BiosEquipmentService();
break;
}
case BIOS_KBD_INTERRUPT: case BIOS_KBD_INTERRUPT:
{ {
/* This is the keyboard BIOS interrupt, call the BIOS */ /* This is the keyboard BIOS interrupt, call the BIOS */
@ -267,7 +273,7 @@ static VOID EmulatorHardwareIntAck(PVOID Context, BYTE Number)
BOOLEAN EmulatorInitialize() BOOLEAN EmulatorInitialize()
{ {
/* Allocate memory for the 16-bit address space */ /* 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; if (BaseAddress == NULL) return FALSE;
/* Initialize the softx86 CPU emulator */ /* Initialize the softx86 CPU emulator */

View file

@ -53,10 +53,10 @@ typedef enum
EMULATOR_REG_CX, EMULATOR_REG_CX,
EMULATOR_REG_DX, EMULATOR_REG_DX,
EMULATOR_REG_BX, EMULATOR_REG_BX,
EMULATOR_REG_SI,
EMULATOR_REG_DI,
EMULATOR_REG_SP, EMULATOR_REG_SP,
EMULATOR_REG_BP, EMULATOR_REG_BP,
EMULATOR_REG_SI,
EMULATOR_REG_DI,
EMULATOR_REG_ES, EMULATOR_REG_ES,
EMULATOR_REG_CS, EMULATOR_REG_CS,
EMULATOR_REG_SS, EMULATOR_REG_SS,