- Remove some hardcoded values.
- Reshuffle again DOS initialization to better reflect how it is done in the real world (see "Advanced MS-DOS Programming" by Ray Duncan, Chapter 2 "MS-DOS in Operation"): split DOS data stuff into DOS BIOS data, and DOS kernel data areas.

In preparation for an upcoming commit.

svn path=/trunk/; revision=68585
This commit is contained in:
Hermès Bélusca-Maïto 2015-08-01 12:41:22 +00:00
parent 88adae5ab6
commit 4d6da0ec7a
5 changed files with 143 additions and 127 deletions

View file

@ -32,6 +32,13 @@
/* PRIVATE VARIABLES **********************************************************/
// CALLBACK16 BiosContext;
/* PUBLIC VARIABLES ***********************************************************/
/* Global DOS BIOS data area */
PBIOS_DATA BiosData;
/* PRIVATE FUNCTIONS **********************************************************/
/* PUBLIC FUNCTIONS ***********************************************************/
@ -63,7 +70,7 @@ BOOLEAN DosCheckInput(VOID)
return FALSE;
}
if (Descriptor->DeviceInfo & (1 << 7))
if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
{
WORD Result;
PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
@ -155,28 +162,61 @@ BOOLEAN DosBuildSysEnvBlock(VOID)
BOOLEAN DosBIOSInitialize(VOID)
{
#if 0
UCHAR i;
CHAR CurrentDirectory[MAX_PATH];
CHAR DosDirectory[DOS_DIR_LENGTH];
LPSTR Path;
FILE *Stream;
WCHAR Buffer[256];
#endif
/* Set the data segment */
setDS(DOS_DATA_SEGMENT);
setDS(BIOS_DATA_SEGMENT);
/* Initialize the DOS stack */
// Stack just before FIRST_MCB_SEGMENT and after SYSTEM_ENV_BLOCK
// FIXME: Add a block of fixed size for the stack in DOS_DATA instead!
/* Initialize the global DOS BIOS data area */
BiosData = (PBIOS_DATA)SEG_OFF_TO_PTR(BIOS_DATA_SEGMENT, 0x0000);
/* Initialize the DOS BIOS stack */
// FIXME: Add a block of fixed size for the stack in BIOS/DOS_DATA instead!
setSS(0x0F00);
setSP(0x0FF0);
setBP(0x091E); // DOS base stack pointer relic value
/* Initialize memory management */
DosInitializeMemory();
/*
* Initialize the INT 13h (BIOS Disk Services) handler chain support.
*
* The INT 13h handler chain is some functionality that allows DOS
* to insert disk filter drivers in between the (hooked) INT 13h handler
* and its original handler.
* Typically, those are:
* - filter for detecting disk changes (for floppy disks),
* - filter for tracking formatting calls and correcting DMA boundary errors,
* - a possible filter to work around a bug in a particular version of PC-AT's
* IBM's ROM BIOS (on systems with model byte FCh and BIOS date "01/10/84" only)
* (see http://www.ctyme.com/intr/rb-4453.htm for more details).
*
* This functionality is known to be used by some legitimate programs,
* by Windows 3.x, as well as some illegitimate ones (aka. virii).
*
* See extra information about this support in dos.h
*/
// FIXME: Should be done by the DOS BIOS
BiosData->RomBiosInt13 = ((PULONG)BaseAddress)[0x13];
BiosData->PrevInt13 = BiosData->RomBiosInt13;
// RegisterDosInt32(0x13, DosInt13h); // Unused at the moment!
//
// HERE: Do all hardware initialization needed for DOS
//
/*
* SysInit part...
*/
// InitializeContext(&DosContext, BIOS_CODE_SEGMENT, 0x0010);
/* Initialize the DOS kernel (DosInit) */
if (!DosKRNLInitialize())
{
DisplayMessage(L"Failed to load the DOS kernel! Exiting...");
return FALSE;
}
/* DOS kernel loading succeeded, we can finish the initialization */
/* Build the system master environment block (inherited by the shell) */
if (!DosBuildSysEnvBlock())
@ -184,44 +224,7 @@ BOOLEAN DosBIOSInitialize(VOID)
DPRINT1("An error occurred when setting up the system environment block.\n");
}
#if 0
/* Clear the current directory buffer */
RtlZeroMemory(CurrentDirectories, sizeof(CurrentDirectories));
/* Get the current directory */
if (!GetCurrentDirectoryA(MAX_PATH, CurrentDirectory))
{
// TODO: Use some kind of default path?
return FALSE;
}
/* Convert that to a DOS path */
if (!GetShortPathNameA(CurrentDirectory, DosDirectory, DOS_DIR_LENGTH))
{
// TODO: Use some kind of default path?
return FALSE;
}
/* Set the drive */
Sda->CurrentDrive = DosDirectory[0] - 'A';
/* Get the directory part of the path */
Path = strchr(DosDirectory, '\\');
if (Path != NULL)
{
/* Skip the backslash */
Path++;
}
/* Set the directory */
if (Path != NULL)
{
strncpy(CurrentDirectories[Sda->CurrentDrive], Path, DOS_DIR_LENGTH);
}
/* Read CONFIG.SYS */
/* TODO: Read CONFIG.NT/SYS */
Stream = _wfopen(DOS_CONFIG_PATH, L"r");
if (Stream != NULL)
{
@ -232,10 +235,7 @@ BOOLEAN DosBIOSInitialize(VOID)
fclose(Stream);
}
#endif
/* Initialize the DOS kernel */
return DosKRNLInitialize();
return TRUE;
}
/* EOF */

View file

@ -191,7 +191,6 @@ VOID WINAPI DosInt21h(LPWORD Stack)
BYTE Character;
SYSTEMTIME SystemTime;
PCHAR String;
PDOS_INPUT_BUFFER InputBuffer;
Sda->InDos++;
@ -351,7 +350,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
case 0x0A:
{
WORD Count = 0;
InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
PDOS_INPUT_BUFFER InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
DPRINT("Read Buffered Input\n");
@ -2199,12 +2198,12 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
case 0x13:
{
/* Save the old values of PrevInt13 and RomBiosInt13 */
ULONG OldInt13 = DosData->PrevInt13;
ULONG OldBiosInt13 = DosData->RomBiosInt13;
ULONG OldInt13 = BiosData->PrevInt13;
ULONG OldBiosInt13 = BiosData->RomBiosInt13;
/* Set PrevInt13 and RomBiosInt13 to their new values */
DosData->PrevInt13 = MAKELONG(getDX(), getDS());
DosData->RomBiosInt13 = MAKELONG(getBX(), getES());
BiosData->PrevInt13 = MAKELONG(getDX(), getDS());
BiosData->RomBiosInt13 = MAKELONG(getBX(), getES());
/* Return in DS:DX the old value of PrevInt13 */
setDS(HIWORD(OldInt13));
@ -2271,8 +2270,6 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
BOOLEAN DosKRNLInitialize(VOID)
{
#if 1
UCHAR i;
PDOS_SFT Sft;
LPSTR Path;
@ -2281,7 +2278,8 @@ BOOLEAN DosKRNLInitialize(VOID)
CHAR CurrentDirectory[MAX_PATH];
CHAR DosDirectory[DOS_DIR_LENGTH];
const BYTE NullDriverRoutine[] = {
static const BYTE NullDriverRoutine[] =
{
/* Strategy routine entry */
0x26, // mov [Request.Status], DOS_DEVSTAT_DONE
0xC7,
@ -2294,13 +2292,17 @@ BOOLEAN DosKRNLInitialize(VOID)
0xCB, // retf
};
FILE *Stream;
WCHAR Buffer[256];
/* Set the data segment */
setDS(DOS_DATA_SEGMENT);
/* Initialize the global DOS data area */
DosData = (PDOS_DATA)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT, 0x0000);
RtlZeroMemory(DosData, sizeof(*DosData));
/* Initialize the DOS stack */
setSS(DOS_DATA_SEGMENT);
setSP(DOS_DATA_OFFSET(DosStack) + sizeof(DosData->DosStack) - sizeof(WORD));
/* Initialize the list of lists */
SysVars = &DosData->SysVars;
RtlZeroMemory(SysVars, sizeof(*SysVars));
@ -2409,18 +2411,8 @@ BOOLEAN DosKRNLInitialize(VOID)
RtlZeroMemory(&Sft->FileDescriptors[i], sizeof(DOS_FILE_DESCRIPTOR));
}
/* Read CONFIG.SYS */
Stream = _wfopen(DOS_CONFIG_PATH, L"r");
if (Stream != NULL)
{
while (fgetws(Buffer, 256, Stream))
{
// TODO: Parse the line
}
fclose(Stream);
}
#endif
/* Initialize memory management */
DosInitializeMemory();
/* Initialize the callback context */
InitializeContext(&DosContext, DOS_CODE_SEGMENT, 0x0000);
@ -2449,29 +2441,6 @@ BOOLEAN DosKRNLInitialize(VOID)
RegisterDosInt32(0x2C, NULL);
RegisterDosInt32(0x2D, NULL);
/*
* Initialize the INT 13h (BIOS Disk Services) handler chain support.
*
* The INT 13h handler chain is some functionality that allows DOS
* to insert disk filter drivers in between the (hooked) INT 13h handler
* and its original handler.
* Typically, those are:
* - filter for detecting disk changes (for floppy disks),
* - filter for tracking formatting calls and correcting DMA boundary errors,
* - a possible filter to work around a bug in a particular version of PC-AT's
* IBM's ROM BIOS (on systems with model byte FCh and BIOS date "01/10/84" only)
* (see http://www.ctyme.com/intr/rb-4453.htm for more details).
*
* This functionality is known to be used by some legitimate programs,
* by Windows 3.x, as well as some illegitimate ones (aka. virii).
*
* See extra information about this support in dos.h
*/
// FIXME: Should be done by the DOS BIOS
DosData->RomBiosInt13 = ((PULONG)BaseAddress)[0x13];
DosData->PrevInt13 = DosData->RomBiosInt13;
// RegisterDosInt32(0x13, DosInt13h); // Unused at the moment!
/* Initialize country data */
DosCountryInitialize();

View file

@ -27,22 +27,26 @@
#define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT"
#define DOS_COMMAND_INTERPRETER L"%SystemRoot%\\system32\\COMMAND.COM /k %SystemRoot%\\system32\\AUTOEXEC.NT"
#define SYSTEM_PSP 0x08
#define SYSTEM_ENV_BLOCK 0x800
#define DOS_CODE_SEGMENT 0x70
#define DOS_DATA_SEGMENT 0xA0
#define BIOS_CODE_SEGMENT 0x70
#define BIOS_DATA_SEGMENT 0x70
#define DOS_CODE_SEGMENT 0x80
#define DOS_DATA_SEGMENT 0xA5
#define DOS_DATA_OFFSET(x) FIELD_OFFSET(DOS_DATA, x)
#define SYSTEM_ENV_BLOCK 0x600 // FIXME: Should be dynamic
#define SYSTEM_PSP 0x0008
#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_DIR_LENGTH 64
#define NUM_DRIVES ('Z' - 'A' + 1)
#define DOS_CHAR_ATTRIBUTE 0x07
#define DOS_SFT_SIZE 255 // Value of the 'FILES=' command; maximum 255
#define DOS_DIR_LENGTH 64
#define NUM_DRIVES ('Z' - 'A' + 1)
#define DOS_CHAR_ATTRIBUTE 0x07
#pragma pack(push, 1)
@ -230,8 +234,27 @@ typedef struct _DOS_SDA
DWORD PrevCallFrame;
} DOS_SDA, *PDOS_SDA;
/*
* DOS kernel data structure
*/
typedef struct _DOS_DATA
{
DOS_SYSVARS SysVars;
BYTE NullDriverRoutine[7];
WORD DosVersion; // DOS version to report to programs (can be different from the true one)
DOS_SDA Sda;
CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
BYTE DosStack[384];
BYTE Sft[ANYSIZE_ARRAY];
} DOS_DATA, *PDOS_DATA;
/*
* DOS BIOS data structure at segment 70h
*/
typedef struct _BIOS_DATA
{
BYTE StartupCode[20]; // 0x00 - 20 bytes: large enough for now!
/*
* INT 13h (BIOS Disk Services) handler chain support.
*
@ -256,22 +279,20 @@ typedef struct _DOS_DATA
* http://repo.hackerzvoice.net/depot_madchat/vxdevl/vdat/tuvd0001.htm
* http://vxheaven.org/lib/vsm01.html
*/
DWORD RomBiosInt13;
DWORD PrevInt13; // FIXME: Put it at 0070:00B4
BYTE Padding0[0xB0 - /*FIELD_OFFSET(BIOS_DATA, StartupCode)*/ 20];
DWORD RomBiosInt13; // 0xb0
DWORD PrevInt13; // 0xb4
BYTE Padding1[0x100 - 0xB8]; // 0xb8
} BIOS_DATA, *PBIOS_DATA;
DOS_SYSVARS SysVars;
BYTE NullDriverRoutine[7];
WORD DosVersion; // DOS version to report to programs (can be different from the true one)
DOS_SDA Sda;
CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
BYTE Sft[ANYSIZE_ARRAY];
} DOS_DATA, *PDOS_DATA;
C_ASSERT(sizeof(BIOS_DATA) == 0x100);
#pragma pack(pop)
/* VARIABLES ******************************************************************/
extern BOOLEAN DoEcho;
extern BOOLEAN DoEcho; // FIXME: Maybe move inside BiosData? (it's set by BIOS but used by CON driver in DOS BIOS)
extern PBIOS_DATA BiosData;
extern PDOS_DATA DosData;
extern PDOS_SYSVARS SysVars;
extern PDOS_SDA Sda;
@ -279,11 +300,13 @@ extern PDOS_SDA Sda;
/* FUNCTIONS ******************************************************************/
extern CALLBACK16 DosContext;
#define RegisterDosInt32(IntNumber, IntHandler) \
#define RegisterDosInt32(IntNumber, IntHandler) \
do { \
DosContext.NextOffset += RegisterInt32(MAKELONG(DosContext.NextOffset, \
DosContext.Segment), \
(IntNumber), (IntHandler), NULL); \
ASSERT((0x20 <= IntNumber) && (IntNumber <= 0x2F)); \
RegisterInt32(DosContext.TrampolineFarPtr + \
DosContext.TrampolineSize + \
(IntNumber - 0x20) * Int16To32StubSize, \
(IntNumber), (IntHandler), NULL); \
} while(0);
/*

View file

@ -12,6 +12,30 @@
#pragma pack(push, 1)
#if 0 // Real DOS-5 SFT entry, for reference only
typedef struct _DOS_FILE_DESCRIPTOR_DOS5
{
WORD RefCount; // 0x00
WORD OpenMode; // 0x02
BYTE Attributes; // 0x04
WORD DeviceInfo; // 0x05
DWORD DevicePointer; // 0x07
WORD StartCluster; // 0x0b
WORD Time; // 0x0d
WORD Date; // 0x0f
DWORD Size; // 0x11
DWORD Position; // 0x15
BYTE Reserved0[7]; // 0x19
CHAR FileName[11]; // 0x20
BYTE Reserved1[6]; // 0x2b
WORD OwnerPsp; // 0x31
BYTE Reserved2[8]; // 0x33
} DOS_FILE_DESCRIPTOR_DOS5, *PDOS_FILE_DESCRIPTOR_DOS5;
C_ASSERT(sizeof(DOS_FILE_DESCRIPTOR_DOS5) == 0x3B);
#endif
// Modified DOS SFT entry, compatible for NTVDM only
typedef struct _DOS_FILE_DESCRIPTOR
{
WORD RefCount;

View file

@ -360,7 +360,7 @@ BOOLEAN DosCloseHandle(WORD DosHandle)
/* Check if the reference count fell to zero */
if (!Descriptor->RefCount)
{
if (Descriptor->DeviceInfo & (1 << 7))
if (Descriptor->DeviceInfo & FILE_INFO_DEVICE)
{
PDOS_DEVICE_NODE Node = DosGetDriverNode(Descriptor->DevicePointer);
@ -369,7 +369,7 @@ BOOLEAN DosCloseHandle(WORD DosHandle)
}
else
{
/* Close the win32 handle */
/* Close the Win32 handle */
CloseHandle(Descriptor->Win32Handle);
}
}