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)
{
switch (IrqNumber)

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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 */

View file

@ -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,