[NTVDM]: Commit some local changes that can be committed now:

- Whitespace fixes.
- Improve some DPRINTs.
- hardcoded_values--;
- Fix DisplayMessage() for NULL-terminated strings.
- Free the allocated block of memory in the mouse driver cleanup procedure.
- Properly inherit the parent process environment block if needed.
- Return the correct last error if DosCopyEnvironmentBlock fails.
- Big ifs turned into switch.
- Implement some INT 2Fh DOS multiplex functions (AX=1200h "Installation check", AX=1203h "Get DOS data segment", AX=1214h "Compare FAR pointers", AX=122Fh "Set DOS version to return"); remove the DPRINT for AX=1680h "Release Current Virtual Machine Time-slice".
- Stubplement INT 2Ah "DOS critical sections / network" (it just monitors calls to itself at the moment).
- Use the boot drive root path as the current directory if we failed retrieving a valid one.
- Offsetize the DOS_SYSVARS members (so that I don't have to compute by head the offsets, especially when some of the members is a structure from which I don't know in advance its size); add some C_ASSERTs on the size of DOS standard structures.
- Move the NullDriverRoutine buffer outside the sysvars buffer (because it has nothing to do inside it).
- In ConDrvReadInput: do not echo the first part of an extended character.
- Add basic support for changing the reported DosVersion.

svn path=/trunk/; revision=68395
This commit is contained in:
Hermès Bélusca-Maïto 2015-07-13 01:21:46 +00:00
parent 9dc9e37fcc
commit 597a383e60
13 changed files with 270 additions and 135 deletions

View file

@ -32,9 +32,6 @@
/* PRIVATE VARIABLES **********************************************************/ /* PRIVATE VARIABLES **********************************************************/
// static BYTE CurrentDrive;
// static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
@ -105,7 +102,13 @@ BOOLEAN DosBuildSysEnvBlock(VOID)
LPSTR SourcePtr, Environment; LPSTR SourcePtr, Environment;
LPSTR DestPtr = (LPSTR)SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0); LPSTR DestPtr = (LPSTR)SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0);
/* Get the environment strings */ /*
* Get the environment strings
*
* NOTE: On non-STANDALONE builds, this corresponds to the VDM environment
* as created by BaseVDM for NTVDM. On STANDALONE builds this is the Win32
* environment. In this last case we need to convert it to a proper VDM env.
*/
SourcePtr = Environment = GetEnvironmentStrings(); SourcePtr = Environment = GetEnvironmentStrings();
if (Environment == NULL) return FALSE; if (Environment == NULL) return FALSE;
@ -231,10 +234,6 @@ BOOLEAN DosBIOSInitialize(VOID)
#endif #endif
/* Register the DOS 32-bit Interrupts */
// RegisterDosInt32(0x20, DosInt20h);
/* Initialize the DOS kernel */ /* Initialize the DOS kernel */
return DosKRNLInitialize(); return DosKRNLInitialize();
} }

View file

@ -61,9 +61,11 @@ WORD NTAPI ConDrvReadInput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
/* Check if this is a special character */ /* Check if this is a special character */
if (Character == 0) ExtendedCode = getAH(); if (Character == 0) ExtendedCode = getAH();
if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
Pointer[BytesRead++] = Character; Pointer[BytesRead++] = Character;
if (Character != 0 && DoEcho)
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
/* Stop on first carriage return */ /* Stop on first carriage return */
if (Character == '\r') if (Character == '\r')
{ {

View file

@ -98,30 +98,30 @@ DosGetCountryInfo(IN OUT PWORD CountryId,
(LPSTR)&CountryInfo->DecimalSep, (LPSTR)&CountryInfo->DecimalSep,
sizeof(CountryInfo->DecimalSep)); sizeof(CountryInfo->DecimalSep));
if (Return == 0) return LOWORD(GetLastError()); if (Return == 0) return LOWORD(GetLastError());
Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE, Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDATE,
(LPSTR)&CountryInfo->DateSep, (LPSTR)&CountryInfo->DateSep,
sizeof(CountryInfo->DateSep)); sizeof(CountryInfo->DateSep));
if (Return == 0) return LOWORD(GetLastError()); if (Return == 0) return LOWORD(GetLastError());
Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIME, Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIME,
(LPSTR)&CountryInfo->TimeSep, (LPSTR)&CountryInfo->TimeSep,
sizeof(CountryInfo->TimeSep)); sizeof(CountryInfo->TimeSep));
if (Return == 0) return LOWORD(GetLastError()); if (Return == 0) return LOWORD(GetLastError());
// NOTE: '4: Symbol replace decimal separator' is unsupported. // NOTE: '4: Symbol replace decimal separator' is unsupported.
Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER, Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY | LOCALE_RETURN_NUMBER,
(LPSTR)&NumVal, (LPSTR)&NumVal,
sizeof(NumVal)); sizeof(NumVal));
if (Return == 0) return LOWORD(GetLastError()); if (Return == 0) return LOWORD(GetLastError());
CountryInfo->CurrencyFormat = (BYTE)NumVal; CountryInfo->CurrencyFormat = (BYTE)NumVal;
Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER, // LOCALE_IDIGITS | LOCALE_RETURN_NUMBER Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER, // LOCALE_IDIGITS | LOCALE_RETURN_NUMBER
(LPSTR)&NumVal, (LPSTR)&NumVal,
sizeof(NumVal)); sizeof(NumVal));
if (Return == 0) return LOWORD(GetLastError()); if (Return == 0) return LOWORD(GetLastError());
CountryInfo->CurrencyDigitsNum = (BYTE)NumVal; CountryInfo->CurrencyDigitsNum = (BYTE)NumVal;
Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ITIME | LOCALE_RETURN_NUMBER, Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ITIME | LOCALE_RETURN_NUMBER,
(LPSTR)&NumVal, (LPSTR)&NumVal,
sizeof(NumVal)); sizeof(NumVal));
@ -129,7 +129,7 @@ DosGetCountryInfo(IN OUT PWORD CountryId,
CountryInfo->TimeFormat = (BYTE)NumVal; CountryInfo->TimeFormat = (BYTE)NumVal;
CountryInfo->CaseMapPtr = MAKELONG(FIELD_OFFSET(COUNTRY_DATA, CaseMapRoutine), CountryDataSegment); CountryInfo->CaseMapPtr = MAKELONG(FIELD_OFFSET(COUNTRY_DATA, CaseMapRoutine), CountryDataSegment);
// CountryInfo->DataListSep; // CountryInfo->DataListSep;
return ERROR_SUCCESS; return ERROR_SUCCESS;
@ -240,7 +240,7 @@ BOOLEAN DosCountryInitialize(VOID)
CountryDataSegment = DosAllocateMemory(sizeof(COUNTRY_DATA), NULL); CountryDataSegment = DosAllocateMemory(sizeof(COUNTRY_DATA), NULL);
if (CountryDataSegment == 0) return FALSE; if (CountryDataSegment == 0) return FALSE;
CountryData = (PCOUNTRY_DATA)SEG_OFF_TO_PTR(CountryDataSegment, 0x0000); CountryData = (PCOUNTRY_DATA)SEG_OFF_TO_PTR(CountryDataSegment, 0x0000);
RtlMoveMemory(CountryData->CaseMapRoutine, RtlMoveMemory(CountryData->CaseMapRoutine,
CaseMapRoutine, CaseMapRoutine,
sizeof(CaseMapRoutine)); sizeof(CaseMapRoutine));

View file

@ -123,6 +123,7 @@ typedef struct _DOS_DRIVER
}; };
}; };
} DOS_DRIVER, *PDOS_DRIVER; } DOS_DRIVER, *PDOS_DRIVER;
C_ASSERT(sizeof(DOS_DRIVER) == 0x12);
typedef struct _DOS_REQUEST_HEADER typedef struct _DOS_REQUEST_HEADER
{ {

View file

@ -91,7 +91,7 @@ static BOOLEAN DosChangeDirectory(LPSTR Directory)
return FALSE; return FALSE;
} }
/* Check whether the directory string is of format "?:..." */ /* Check whether the directory string is of format "X:..." */
if (strlen(Directory) >= 2 && Directory[1] == ':') if (strlen(Directory) >= 2 && Directory[1] == ':')
{ {
/* Get the drive number */ /* Get the drive number */
@ -114,8 +114,8 @@ static BOOLEAN DosChangeDirectory(LPSTR Directory)
Attributes = GetFileAttributesA(Directory); Attributes = GetFileAttributesA(Directory);
/* Make sure the path exists and is a directory */ /* Make sure the path exists and is a directory */
if ((Attributes == INVALID_FILE_ATTRIBUTES) if ((Attributes == INVALID_FILE_ATTRIBUTES) ||
|| !(Attributes & FILE_ATTRIBUTE_DIRECTORY)) !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
{ {
Sda->LastErrorCode = ERROR_PATH_NOT_FOUND; Sda->LastErrorCode = ERROR_PATH_NOT_FOUND;
return FALSE; return FALSE;
@ -146,17 +146,11 @@ static BOOLEAN DosChangeDirectory(LPSTR Directory)
return FALSE; return FALSE;
} }
/* Get the directory part of the path */ /* Get the directory part of the path and set the current directory for the drive */
Path = strchr(DosDirectory, '\\'); Path = strchr(DosDirectory, '\\');
if (Path != NULL) if (Path != NULL)
{ {
/* Skip the backslash */ Path++; // Skip the backslash
Path++;
}
/* Set the directory for the drive */
if (Path != NULL)
{
strncpy(DosData->CurrentDirectories[DriveNumber], Path, DOS_DIR_LENGTH); strncpy(DosData->CurrentDirectories[DriveNumber], Path, DOS_DIR_LENGTH);
} }
else else
@ -829,8 +823,10 @@ VOID WINAPI DosInt21h(LPWORD Stack)
DWORD NumberOfFreeClusters; DWORD NumberOfFreeClusters;
DWORD TotalNumberOfClusters; DWORD TotalNumberOfClusters;
if (getDL() == 0x00) RootPath[0] = 'A' + Sda->CurrentDrive; if (getDL() == 0x00)
else RootPath[0] = 'A' + getDL() - 1; RootPath[0] = 'A' + Sda->CurrentDrive;
else
RootPath[0] = 'A' + getDL() - 1;
if (GetDiskFreeSpaceA(RootPath, if (GetDiskFreeSpaceA(RootPath,
&SectorsPerCluster, &SectorsPerCluster,
@ -914,7 +910,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
{ {
WORD CountryId = getAL() < 0xFF ? getAL() : getBX(); WORD CountryId = getAL() < 0xFF ? getAL() : getBX();
WORD ErrorCode; WORD ErrorCode;
ErrorCode = DosGetCountryInfo(&CountryId, ErrorCode = DosGetCountryInfo(&CountryId,
(PDOS_COUNTRY_INFO)SEG_OFF_TO_PTR(getDS(), getDX())); (PDOS_COUNTRY_INFO)SEG_OFF_TO_PTR(getDS(), getDX()));
@ -1110,7 +1106,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
* See Ralf Brown: http://www.ctyme.com/intr/rb-2797.htm * See Ralf Brown: http://www.ctyme.com/intr/rb-2797.htm
* "AX destroyed (DOS 3.3) AL seems to be drive of deleted file." * "AX destroyed (DOS 3.3) AL seems to be drive of deleted file."
*/ */
setAL(FileName[0] - 'A'); setAL(RtlUpperChar(FileName[0]) - 'A');
} }
else else
{ {
@ -1519,54 +1515,68 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Get/Set Memory Management Options */ /* Get/Set Memory Management Options */
case 0x58: case 0x58:
{ {
if (getAL() == 0x00) switch (getAL())
{ {
/* Get allocation strategy */ /* Get allocation strategy */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; case 0x00:
setAX(Sda->AllocStrategy); {
} Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else if (getAL() == 0x01) setAX(Sda->AllocStrategy);
{ break;
}
/* Set allocation strategy */ /* Set allocation strategy */
case 0x01:
if ((getBL() & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
== (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
{ {
/* Can't set both */ if ((getBL() & (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; == (DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
setAX(ERROR_INVALID_PARAMETER); {
/* Can't set both */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
setAX(ERROR_INVALID_PARAMETER);
break;
}
if ((getBL() & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
> DOS_ALLOC_LAST_FIT)
{
/* Invalid allocation strategy */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
setAX(ERROR_INVALID_PARAMETER);
break;
}
Sda->AllocStrategy = getBL();
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
break; break;
} }
if ((getBL() & 0x3F) > DOS_ALLOC_LAST_FIT)
{
/* Invalid allocation strategy */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
setAX(ERROR_INVALID_PARAMETER);
break;
}
Sda->AllocStrategy = getBL();
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else if (getAL() == 0x02)
{
/* Get UMB link state */ /* Get UMB link state */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; case 0x02:
setAL(DosUmbLinked ? 0x01 : 0x00); {
} Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else if (getAL() == 0x03) setAL(DosUmbLinked ? 0x01 : 0x00);
{ break;
}
/* Set UMB link state */ /* Set UMB link state */
if (getBX()) DosLinkUmb(); case 0x03:
else DosUnlinkUmb(); {
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; if (getBX())
} DosLinkUmb();
else else
{ DosUnlinkUmb();
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
break;
}
/* Invalid or unsupported function */ /* Invalid or unsupported function */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; default:
setAX(ERROR_INVALID_FUNCTION); {
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
setAX(ERROR_INVALID_FUNCTION);
}
} }
break; break;
@ -2021,10 +2031,77 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
setAX(AX); setAX(AX);
} }
VOID WINAPI DosInt2Ah(LPWORD Stack)
{
DPRINT1("INT 2Ah, AX=%4xh called\n", getAX());
}
VOID WINAPI DosInt2Fh(LPWORD Stack) VOID WINAPI DosInt2Fh(LPWORD Stack)
{ {
switch (getAH()) switch (getAH())
{ {
/* DOS 3+ Internal Utility Functions */
case 0x12:
{
DPRINT1("INT 2Fh, AX=%4xh DOS Internal Utility Function called\n", getAX());
switch (getAL())
{
/* Installation Check */
case 0x00:
{
setAL(0xFF);
break;
}
/* Get DOS Data Segment */
case 0x03:
{
setDS(DOS_DATA_SEGMENT);
break;
}
/* Compare FAR Pointers */
case 0x14:
{
PVOID PointerFromFarPointer1 = SEG_OFF_TO_PTR(getDS(), getSI());
PVOID PointerFromFarPointer2 = SEG_OFF_TO_PTR(getES(), getDI());
BOOLEAN AreEqual = (PointerFromFarPointer1 == PointerFromFarPointer2);
setZF(AreEqual);
setCF(!AreEqual);
break;
}
/* Set DOS Version Number to return */
case 0x2F:
{
WORD DosVersion = getDX();
// Special case: return the true DOS version when DX=00h
if (DosVersion == 0x0000)
DosData->DosVersion = DOS_VERSION;
else
DosData->DosVersion = DosVersion;
break;
}
}
break;
}
/* Mostly Windows 2.x/3.x/9x support */
case 0x16:
{
/*
* AL=80h is DOS/Windows/DPMI "Release Current Virtual Machine Time-slice"
* Just do nothing in this case.
*/
if (getAL() != 0x80) goto Default;
break;
}
/* Extended Memory Specification */ /* Extended Memory Specification */
case 0x43: case 0x43:
{ {
@ -2057,7 +2134,7 @@ VOID WINAPI DosInt2Fh(LPWORD Stack)
break; break;
} }
default: default: Default:
{ {
DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n", DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
getAH(), getAL()); getAH(), getAL());
@ -2073,6 +2150,8 @@ BOOLEAN DosKRNLInitialize(VOID)
UCHAR i; UCHAR i;
PDOS_SFT Sft; PDOS_SFT Sft;
LPSTR Path; LPSTR Path;
BOOLEAN Success = TRUE;
DWORD dwRet;
CHAR CurrentDirectory[MAX_PATH]; CHAR CurrentDirectory[MAX_PATH];
CHAR DosDirectory[DOS_DIR_LENGTH]; CHAR DosDirectory[DOS_DIR_LENGTH];
@ -2103,60 +2182,89 @@ BOOLEAN DosKRNLInitialize(VOID)
SysVars->FirstSft = MAKELONG(DOS_DATA_OFFSET(Sft), DOS_DATA_SEGMENT); SysVars->FirstSft = MAKELONG(DOS_DATA_OFFSET(Sft), DOS_DATA_SEGMENT);
SysVars->CurrentDirs = MAKELONG(DOS_DATA_OFFSET(CurrentDirectories), SysVars->CurrentDirs = MAKELONG(DOS_DATA_OFFSET(CurrentDirectories),
DOS_DATA_SEGMENT); DOS_DATA_SEGMENT);
/* The last drive can be redefined with the LASTDRIVE command. At the moment, set the real maximum possible, 'Z'. */ /*
SysVars->NumLocalDrives = 'Z' - 'A' + 1; * The last drive can be redefined with the LASTDRIVE command.
* At the moment, set the real maximum possible, 'Z'.
*/
SysVars->NumLocalDrives = 'Z' - 'A' + 1; // See #define NUM_DRIVES in dos.h
/* The boot drive is initialized to the %SYSTEMDRIVE% value */ /* The boot drive is initialized to the %SYSTEMDRIVE% value */
// NOTE: Using the NtSystemRoot system variable might be OS-specific... // NOTE: Using the NtSystemRoot system variable might be OS-specific...
SysVars->BootDrive = SharedUserData->NtSystemRoot[0] - 'A' + 1; SysVars->BootDrive = RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0]) - 'A' + 1;
/* Initialize the NUL device driver */ /* Initialize the NUL device driver */
SysVars->NullDevice.Link = 0xFFFFFFFF; SysVars->NullDevice.Link = 0xFFFFFFFF;
SysVars->NullDevice.DeviceAttributes = DOS_DEVATTR_NUL | DOS_DEVATTR_CHARACTER; SysVars->NullDevice.DeviceAttributes = DOS_DEVATTR_NUL | DOS_DEVATTR_CHARACTER;
SysVars->NullDevice.StrategyRoutine = FIELD_OFFSET(DOS_SYSVARS, NullDriverRoutine); // Offset from within the DOS data segment
SysVars->NullDevice.StrategyRoutine = DOS_DATA_OFFSET(NullDriverRoutine);
// Hardcoded to the RETF inside StrategyRoutine
SysVars->NullDevice.InterruptRoutine = SysVars->NullDevice.StrategyRoutine + 6; SysVars->NullDevice.InterruptRoutine = SysVars->NullDevice.StrategyRoutine + 6;
RtlFillMemory(SysVars->NullDevice.DeviceName, RtlFillMemory(SysVars->NullDevice.DeviceName,
sizeof(SysVars->NullDevice.DeviceName), sizeof(SysVars->NullDevice.DeviceName),
' '); ' ');
RtlCopyMemory(SysVars->NullDevice.DeviceName, "NUL", strlen("NUL")); RtlCopyMemory(SysVars->NullDevice.DeviceName, "NUL", strlen("NUL"));
RtlCopyMemory(SysVars->NullDriverRoutine, RtlCopyMemory(DosData->NullDriverRoutine,
NullDriverRoutine, NullDriverRoutine,
sizeof(NullDriverRoutine)); sizeof(NullDriverRoutine));
/* Default DOS version to report */
DosData->DosVersion = DOS_VERSION;
/* Initialize the swappable data area */ /* Initialize the swappable data area */
Sda = &DosData->Sda; Sda = &DosData->Sda;
RtlZeroMemory(Sda, sizeof(*Sda)); RtlZeroMemory(Sda, sizeof(*Sda));
/* Get the current directory */ /* Get the current directory and convert it to a DOS path */
if (!GetCurrentDirectoryA(sizeof(CurrentDirectory), CurrentDirectory)) dwRet = GetCurrentDirectoryA(sizeof(CurrentDirectory), CurrentDirectory);
if (dwRet == 0)
{ {
// TODO: Use some kind of default path? Success = FALSE;
return FALSE; DPRINT1("GetCurrentDirectoryA failed (Error: %u)\n", GetLastError());
}
else if (dwRet > sizeof(CurrentDirectory))
{
Success = FALSE;
DPRINT1("Current directory too long (%d > MAX_PATH) for GetCurrentDirectoryA\n", dwRet);
} }
/* Convert it to a DOS path */ if (Success)
if (!GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory)))
{ {
// TODO: Use some kind of default path? dwRet = GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory));
return FALSE; if (dwRet == 0)
{
Success = FALSE;
DPRINT1("GetShortPathNameA failed (Error: %u)\n", GetLastError());
}
else if (dwRet > sizeof(DosDirectory))
{
Success = FALSE;
DPRINT1("Short path too long (%d > DOS_DIR_LENGTH) for GetShortPathNameA\n", dwRet);
}
} }
/* Set the drive */ if (!Success)
{
/* We failed, use the boot drive instead */
DosDirectory[0] = SysVars->BootDrive + 'A' - 1;
DosDirectory[1] = ':';
DosDirectory[2] = '\\';
DosDirectory[3] = '\0';
}
/* Set the current drive */
Sda->CurrentDrive = RtlUpperChar(DosDirectory[0]) - 'A'; Sda->CurrentDrive = RtlUpperChar(DosDirectory[0]) - 'A';
/* Get the directory part of the path */ /* Get the directory part of the path and set the current directory */
Path = strchr(DosDirectory, '\\'); Path = strchr(DosDirectory, '\\');
if (Path != NULL) if (Path != NULL)
{ {
/* Skip the backslash */ Path++; // Skip the backslash
Path++;
}
/* Set the directory */
if (Path != NULL)
{
strncpy(DosData->CurrentDirectories[Sda->CurrentDrive], Path, DOS_DIR_LENGTH); strncpy(DosData->CurrentDirectories[Sda->CurrentDrive], Path, DOS_DIR_LENGTH);
} }
else
{
DosData->CurrentDirectories[Sda->CurrentDrive][0] = '\0';
}
/* Set the current PSP to the system PSP */ /* Set the current PSP to the system PSP */
Sda->CurrentPsp = SYSTEM_PSP; Sda->CurrentPsp = SYSTEM_PSP;
@ -2205,7 +2313,13 @@ BOOLEAN DosKRNLInitialize(VOID)
RegisterDosInt32(0x2F, DosInt2Fh ); // Multiplex Interrupt RegisterDosInt32(0x2F, DosInt2Fh ); // Multiplex Interrupt
/* Unimplemented DOS interrupts */ /* Unimplemented DOS interrupts */
RegisterDosInt32(0x2A, NULL); // Network - Installation Check RegisterDosInt32(0x2A, DosInt2Ah); // DOS Critical Sections / Network
// RegisterDosInt32(0x2E, NULL); // COMMAND.COM "Reload Transient"
/* Reserved DOS interrupts */
RegisterDosInt32(0x2B, NULL);
RegisterDosInt32(0x2C, NULL);
RegisterDosInt32(0x2D, NULL);
/* Initialize country data */ /* Initialize country data */
DosCountryInitialize(); DosCountryInitialize();

View file

@ -80,21 +80,25 @@ typedef struct _DOS_SYSVARS
WORD FirstMcb; WORD FirstMcb;
/* This is where the SYSVARS really start */ /* This is where the SYSVARS really start */
DWORD FirstDpb; DWORD FirstDpb; // 0x00
DWORD FirstSft; DWORD FirstSft; // 0x04
DWORD ActiveClock; DWORD ActiveClock; // 0x08
DWORD ActiveCon; DWORD ActiveCon; // 0x0c
BYTE Reserved0[6]; BYTE Reserved0[6]; // 0x10
DWORD CurrentDirs; DWORD CurrentDirs; // 0x16
BYTE Reserved1[6]; BYTE Reserved1[6]; // 0x1a
BYTE NumBlockDevices; BYTE NumBlockDevices; // 0x20
BYTE NumLocalDrives; // Set by LASTDRIVE BYTE NumLocalDrives; // 0x21 - Set by LASTDRIVE
DOS_DRIVER NullDevice; DOS_DRIVER NullDevice; // 0x22
BYTE NullDriverRoutine[7]; BYTE Reserved2; // 0x34
BYTE Reserved2[8]; WORD ProgramVersionTable; // 0x35
BYTE BootDrive; DWORD SetVerTable; // 0x37
BYTE UseDwordMoves; WORD Reserved3[2]; // 0x3b
WORD ExtMemSize; WORD BuffersNumber; // 0x3f - 'x' parameter in "BUFFERS=x,y" command
WORD BuffersLookaheadNumber; // 0x41 - 'y' parameter in "BUFFERS=x,y" command
BYTE BootDrive; // 0x43
BYTE UseDwordMoves; // 0x44
WORD ExtMemSize; // 0x45
} DOS_SYSVARS, *PDOS_SYSVARS; } DOS_SYSVARS, *PDOS_SYSVARS;
typedef struct _DOS_CLOCK_TRANSFER_RECORD typedef struct _DOS_CLOCK_TRANSFER_RECORD
@ -232,6 +236,8 @@ typedef struct _DOS_SDA
typedef struct _DOS_DATA typedef struct _DOS_DATA
{ {
DOS_SYSVARS SysVars; DOS_SYSVARS SysVars;
BYTE NullDriverRoutine[7];
WORD DosVersion; // DOS version to report to programs (can be different from the true one)
DOS_SDA Sda; DOS_SDA Sda;
CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH]; CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
BYTE Sft[ANYSIZE_ARRAY]; BYTE Sft[ANYSIZE_ARRAY];
@ -242,8 +248,7 @@ typedef struct _DOS_DATA
/* VARIABLES ******************************************************************/ /* VARIABLES ******************************************************************/
extern BOOLEAN DoEcho; extern BOOLEAN DoEcho;
extern WORD DosErrorLevel; extern PDOS_DATA DosData;
extern WORD DosLastError;
extern PDOS_SYSVARS SysVars; extern PDOS_SYSVARS SysVars;
extern PDOS_SDA Sda; extern PDOS_SDA Sda;

View file

@ -77,7 +77,7 @@ WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
/* Make sure it's valid */ /* Make sure it's valid */
if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z') if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z')
{ {
DPRINT("The DOS memory arena is corrupted!\n"); DPRINT1("The DOS memory arena is corrupted!\n");
Sda->LastErrorCode = ERROR_ARENA_TRASHED; Sda->LastErrorCode = ERROR_ARENA_TRASHED;
return 0; return 0;
} }
@ -94,7 +94,7 @@ WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
/* Check if this block is big enough */ /* Check if this block is big enough */
if (CurrentMcb->Size < Size) goto Next; if (CurrentMcb->Size < Size) goto Next;
switch (Sda->AllocStrategy & 0x3F) switch (Sda->AllocStrategy & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW))
{ {
case DOS_ALLOC_FIRST_FIT: case DOS_ALLOC_FIRST_FIT:
{ {
@ -159,7 +159,7 @@ Done:
if (CurrentMcb->Size > Size) if (CurrentMcb->Size > Size)
{ {
/* It is, split it into two blocks */ /* It is, split it into two blocks */
if ((Sda->AllocStrategy & 0x3F) != DOS_ALLOC_LAST_FIT) if ((Sda->AllocStrategy & ~(DOS_ALLOC_HIGH | DOS_ALLOC_HIGH_LOW)) != DOS_ALLOC_LAST_FIT)
{ {
PDOS_MCB NextMcb = SEGMENT_TO_MCB(Result + Size + 1); PDOS_MCB NextMcb = SEGMENT_TO_MCB(Result + Size + 1);

View file

@ -29,6 +29,7 @@ typedef struct _DOS_MCB
BYTE Unused[3]; BYTE Unused[3];
CHAR Name[8]; CHAR Name[8];
} DOS_MCB, *PDOS_MCB; } DOS_MCB, *PDOS_MCB;
C_ASSERT(sizeof(DOS_MCB) == 0x10);
#pragma pack(pop) #pragma pack(pop)
/* VARIABLES ******************************************************************/ /* VARIABLES ******************************************************************/

View file

@ -166,7 +166,7 @@ VOID DosClonePsp(WORD DestSegment, WORD SourceSegment)
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress); LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
/* Literally copy the PSP first */ /* Literally copy the PSP first */
RtlCopyMemory(DestPsp, SourcePsp, sizeof(DOS_PSP)); RtlCopyMemory(DestPsp, SourcePsp, sizeof(*DestPsp));
/* Save the interrupt vectors */ /* Save the interrupt vectors */
DestPsp->TerminateAddress = IntVecTable[0x22]; DestPsp->TerminateAddress = IntVecTable[0x22];
@ -222,7 +222,8 @@ VOID DosCreatePsp(WORD Segment, WORD ProgramSize)
PspBlock->HandleTablePtr = MAKELONG(0x18, Segment); PspBlock->HandleTablePtr = MAKELONG(0x18, Segment);
/* Set the DOS version */ /* Set the DOS version */
PspBlock->DosVersion = DOS_VERSION; // FIXME: This is here that SETVER stuff enters into action!
PspBlock->DosVersion = DosData->DosVersion;
/* Set the far call opcodes */ /* Set the far call opcodes */
PspBlock->FarCall[0] = 0xCD; // int 0x21 PspBlock->FarCall[0] = 0xCD; // int 0x21
@ -377,16 +378,20 @@ DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
/* If no optional environment is given... */ /* If no optional environment is given... */
if (Environment == NULL) if (Environment == NULL)
{ {
/* ... get the one from the parameter block */
ASSERT(Parameters); ASSERT(Parameters);
Environment = (LPCSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0); /* ... get the one from the parameter block (if not NULL)... */
if (Parameters->Environment)
Environment = (LPCSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0);
/* ... or the one from the parent (otherwise) */
else
Environment = (LPCSTR)SEG_OFF_TO_PTR(SEGMENT_TO_PSP(Sda->CurrentPsp)->EnvBlock, 0);
} }
/* Copy the environment block to DOS memory */ /* Copy the environment block to DOS memory */
EnvBlock = DosCopyEnvironmentBlock(Environment, ExecutablePath); EnvBlock = DosCopyEnvironmentBlock(Environment, ExecutablePath);
if (EnvBlock == 0) if (EnvBlock == 0)
{ {
Result = ERROR_NOT_ENOUGH_MEMORY; Result = Sda->LastErrorCode;
goto Cleanup; goto Cleanup;
} }
} }
@ -431,7 +436,6 @@ DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
/* Try to allocate that much memory */ /* Try to allocate that much memory */
Segment = DosAllocateMemory((WORD)TotalSize, &MaxAllocSize); Segment = DosAllocateMemory((WORD)TotalSize, &MaxAllocSize);
if (Segment == 0) if (Segment == 0)
{ {
/* Check if there's at least enough memory for the minimum size */ /* Check if there's at least enough memory for the minimum size */
@ -460,8 +464,10 @@ DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
SEGMENT_TO_PSP(Segment)->EnvBlock = EnvBlock; SEGMENT_TO_PSP(Segment)->EnvBlock = EnvBlock;
/* Calculate the segment where the program should be loaded */ /* Calculate the segment where the program should be loaded */
if (!LoadHigh) LoadSegment = Segment + (sizeof(DOS_PSP) >> 4); if (!LoadHigh)
else LoadSegment = Segment + TotalSize - BaseSize; LoadSegment = Segment + (sizeof(DOS_PSP) >> 4);
else
LoadSegment = Segment + TotalSize - BaseSize;
RelocFactor = LoadSegment; RelocFactor = LoadSegment;
} }

View file

@ -1025,11 +1025,15 @@ BOOLEAN DosMouseInitialize(VOID)
VOID DosMouseCleanup(VOID) VOID DosMouseCleanup(VOID)
{ {
if (DriverState.ShowCount > 0) EraseMouseCursor();
DosMouseDisable();
/* Restore the old mouse service interrupt handler */ /* Restore the old mouse service interrupt handler */
((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT] = OldIntHandler; ((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT] = OldIntHandler;
if (DriverState.ShowCount > 0) EraseMouseCursor(); DosFreeMemory(MouseDataSegment);
DosMouseDisable(); MouseDataSegment = 0;
MouseData = 0;
} }
/* EOF */ /* EOF */

View file

@ -454,7 +454,7 @@ VOID CmosInitialize(VOID)
OPEN_ALWAYS, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL); NULL);
DPRINT1("CMOS opening %s ; GetLastError() = %u\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError()); DPRINT1("CMOS opening %s (Error: %u)\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
if (hCmosRam != INVALID_HANDLE_VALUE) if (hCmosRam != INVALID_HANDLE_VALUE)
{ {
@ -469,7 +469,7 @@ VOID CmosInitialize(VOID)
DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n", CmosSize, sizeof(CmosMemory)); DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n", CmosSize, sizeof(CmosMemory));
RtlZeroMemory(&CmosMemory, sizeof(CmosMemory)); RtlZeroMemory(&CmosMemory, sizeof(CmosMemory));
} }
DPRINT1("CMOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError()); DPRINT1("CMOS loading %s (Error: %u)\n", Success ? "succeeded" : "failed", GetLastError());
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN); SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
} }

View file

@ -127,7 +127,7 @@ VdmMenuExists(HMENU hConsoleMenu)
{ {
if (GetMenuItemID(hConsoleMenu, i) == ID_SHOWHIDE_MOUSE) if (GetMenuItemID(hConsoleMenu, i) == ID_SHOWHIDE_MOUSE)
{ {
/* set VdmMenuPos to the position of the existing menu */ /* Set VdmMenuPos to the position of the existing menu */
VdmMenuPos = i - 1; VdmMenuPos = i - 1;
return TRUE; return TRUE;
} }
@ -225,7 +225,7 @@ static VOID EnableExtraHardware(HANDLE ConsoleInput)
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
VOID VOID
DisplayMessage(LPCWSTR Format, ...) DisplayMessage(IN LPCWSTR Format, ...)
{ {
#ifndef WIN2K_COMPLIANT #ifndef WIN2K_COMPLIANT
WCHAR StaticBuffer[256]; WCHAR StaticBuffer[256];
@ -242,11 +242,12 @@ DisplayMessage(LPCWSTR Format, ...)
/* /*
* Retrieve the message length and if it is too long, allocate * Retrieve the message length and if it is too long, allocate
* an auxiliary buffer; otherwise use the static buffer. * an auxiliary buffer; otherwise use the static buffer.
* The string is built to be NULL-terminated.
*/ */
MsgLen = _vscwprintf(Format, Parameters) + 1; // NULL-terminated MsgLen = _vscwprintf(Format, Parameters);
if (MsgLen > ARRAYSIZE(StaticBuffer)) if (MsgLen >= ARRAYSIZE(StaticBuffer))
{ {
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, MsgLen * sizeof(WCHAR)); Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(WCHAR));
if (Buffer == NULL) if (Buffer == NULL)
{ {
/* Allocation failed, use the static buffer and display a suitable error message */ /* Allocation failed, use the static buffer and display a suitable error message */
@ -256,11 +257,15 @@ DisplayMessage(LPCWSTR Format, ...)
} }
} }
#else #else
MsgLen = ARRAYSIZE(Buffer); MsgLen = ARRAYSIZE(Buffer) - 1;
#endif #endif
/* Display the message */ RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(WCHAR));
_vsnwprintf(Buffer, MsgLen, Format, Parameters); _vsnwprintf(Buffer, MsgLen, Format, Parameters);
va_end(Parameters);
/* Display the message */
DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer); DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
MessageBoxW(NULL, Buffer, L"NTVDM Subsystem", MB_OK); MessageBoxW(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
@ -268,8 +273,6 @@ DisplayMessage(LPCWSTR Format, ...)
/* Free the buffer if needed */ /* Free the buffer if needed */
if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
#endif #endif
va_end(Parameters);
} }
static BOOL static BOOL

View file

@ -75,7 +75,7 @@ extern WCHAR** NtVdmArgv;
/* /*
* Interface functions * Interface functions
*/ */
VOID DisplayMessage(LPCWSTR Format, ...); VOID DisplayMessage(IN LPCWSTR Format, ...);
/*static*/ VOID /*static*/ VOID
CreateVdmMenu(HANDLE ConOutHandle); CreateVdmMenu(HANDLE ConOutHandle);