mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 21:36:11 +00:00
[NTVDM]
- Add a basic boot sequence functionality (read from CMOS); will be improved in the future. - Print a "FATAL BOOT FAILURE" error message when INT 18h is called. - Fail startup if we cannot mount the available hard disk images. - Improve some diagnostic error messages. svn path=/trunk/; revision=69421
This commit is contained in:
parent
b1b7020854
commit
59136514da
8 changed files with 216 additions and 154 deletions
|
@ -161,6 +161,31 @@ static const BYTE PostCode[] =
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
static VOID BiosCharPrint(CHAR Character)
|
||||||
|
{
|
||||||
|
/* Save AX and BX */
|
||||||
|
USHORT AX = getAX();
|
||||||
|
USHORT BX = getBX();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the parameters:
|
||||||
|
* AL contains the character to print,
|
||||||
|
* BL contains the character attribute,
|
||||||
|
* BH contains the video page to use.
|
||||||
|
*/
|
||||||
|
setAL(Character);
|
||||||
|
setBL(DEFAULT_ATTRIBUTE);
|
||||||
|
setBH(Bda->VideoPage);
|
||||||
|
|
||||||
|
/* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
|
||||||
|
setAH(0x0E);
|
||||||
|
Int32Call(&BiosContext, BIOS_VIDEO_INTERRUPT);
|
||||||
|
|
||||||
|
/* Restore AX and BX */
|
||||||
|
setBX(BX);
|
||||||
|
setAX(AX);
|
||||||
|
}
|
||||||
|
|
||||||
static VOID WINAPI BiosException(LPWORD Stack)
|
static VOID WINAPI BiosException(LPWORD Stack)
|
||||||
{
|
{
|
||||||
/* Get the exception number and call the emulator API */
|
/* Get the exception number and call the emulator API */
|
||||||
|
@ -505,6 +530,8 @@ static VOID WINAPI BiosMiscService(LPWORD Stack)
|
||||||
|
|
||||||
static VOID WINAPI BiosRomBasic(LPWORD Stack)
|
static VOID WINAPI BiosRomBasic(LPWORD Stack)
|
||||||
{
|
{
|
||||||
|
PrintMessageAnsi(BiosCharPrint, "FATAL: INT18: BOOT FAILURE.");
|
||||||
|
|
||||||
/* ROM Basic is unsupported, display a message to the user */
|
/* ROM Basic is unsupported, display a message to the user */
|
||||||
DisplayMessage(L"NTVDM doesn't support ROM Basic. The VDM is closing.");
|
DisplayMessage(L"NTVDM doesn't support ROM Basic. The VDM is closing.");
|
||||||
|
|
||||||
|
@ -518,79 +545,110 @@ extern VOID WINAPI BiosDiskService(LPWORD Stack);
|
||||||
|
|
||||||
static VOID WINAPI BiosBootstrapLoader(LPWORD Stack)
|
static VOID WINAPI BiosBootstrapLoader(LPWORD Stack)
|
||||||
{
|
{
|
||||||
|
USHORT BootOrder;
|
||||||
|
|
||||||
|
USHORT AX, BX, CX, DX, ES;
|
||||||
|
AX = getAX();
|
||||||
|
BX = getBX();
|
||||||
|
CX = getCX();
|
||||||
|
DX = getDX();
|
||||||
|
ES = getES();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In real BIOSes one loads the bootsector read from a diskette
|
* Read the boot sequence order from the CMOS, old behaviour AMI-style.
|
||||||
* or from a disk, copy it to 0000:7C00 and then boot it.
|
*
|
||||||
* Since we are 32-bit VM and we hardcode our DOS at the moment,
|
* For more information, see:
|
||||||
* just call the DOS 32-bit initialization code.
|
* http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/PC/BIOS/orgs.asm
|
||||||
|
* http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/PC/BIOS/boot.c
|
||||||
|
* http://bochs.sourceforge.net/cgi-bin/lxr/source/iodev/cmos.cc
|
||||||
|
* https://web.archive.org/web/20111209041013/http://www-ivs.cs.uni-magdeburg.de/~zbrog/asm/cmos.html
|
||||||
|
* http://www.bioscentral.com/misc/cmosmap.htm
|
||||||
|
*/
|
||||||
|
IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SYSOP);
|
||||||
|
BootOrder = (IOReadB(CMOS_DATA_PORT) & 0x20) >> 5;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BootOrder =
|
||||||
|
* 0: Hard Disk, then Floppy Disk
|
||||||
|
* 1: Floppy Disk, then Hard Disk
|
||||||
|
* In all cases, if booting from those devices failed,
|
||||||
|
* ROM DOS-32 is started. If it fails, INT 18h is called.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DPRINT("BiosBootstrapLoader -->\n");
|
DPRINT("BiosBootstrapLoader (BootOrder = 0x%02X) -->\n", BootOrder);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format of the BootOrder command:
|
||||||
|
* 2 bytes. Each half-byte contains the ID of the drive to boot.
|
||||||
|
* Currently defined:
|
||||||
|
* 0x0: 1st Floppy disk
|
||||||
|
* 0x1: 1st Hard disk
|
||||||
|
* Other, or 0xF: Stop boot sequence.
|
||||||
|
*/
|
||||||
|
BootOrder = 0xFF00 | ((1 << (4 * BootOrder)) & 0xFF);
|
||||||
|
|
||||||
|
Retry:
|
||||||
|
switch (BootOrder & 0x0F)
|
||||||
{
|
{
|
||||||
USHORT i;
|
/* Boot from 1st floppy drive */
|
||||||
|
case 0:
|
||||||
USHORT AX, BX, CX, DX, ES;
|
|
||||||
AX = getAX();
|
|
||||||
BX = getBX();
|
|
||||||
CX = getCX();
|
|
||||||
DX = getDX();
|
|
||||||
ES = getES();
|
|
||||||
|
|
||||||
// i = 0;
|
|
||||||
i = 1;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
if (i == 0)
|
setAH(0x02); // Read sectors
|
||||||
{
|
setAL(0x01); // Number of sectors
|
||||||
/* Boot from 1st floppy drive */
|
setDH(0x00); // Head 0
|
||||||
|
setCH(0x00); // Cylinder 0
|
||||||
|
setCL(0x01); // Sector 1
|
||||||
|
setDL(0x00); // First diskette drive (used by loader code, so should not be cleared)
|
||||||
|
setES(0x0000); // Write data in 0000:7C00
|
||||||
|
setBX(0x7C00);
|
||||||
|
BiosDiskService(Stack);
|
||||||
|
if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
|
||||||
|
DPRINT1("An error happened while loading the bootsector from floppy 0, error = %d\n", getAH());
|
||||||
|
|
||||||
setAH(0x02); // Read sectors
|
break;
|
||||||
setAL(0x01); // Number of sectors
|
}
|
||||||
setDH(0x00); // First head
|
|
||||||
setCH(0x00); // First cylinder
|
|
||||||
setCL(0x01); // First sector
|
|
||||||
setDL(0x00); // First diskette drive (used by loader code, so should not be cleared)
|
|
||||||
setES(0x0000); // Place data in 0000:7C00
|
|
||||||
setBX(0x7C00);
|
|
||||||
BiosDiskService(Stack);
|
|
||||||
if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
|
|
||||||
DPRINT1("An error happened while loading the bootsector from floppy 0, error = %d\n", getAH());
|
|
||||||
}
|
|
||||||
else if (i == 1)
|
|
||||||
{
|
|
||||||
/* Boot from 1st HDD drive */
|
|
||||||
|
|
||||||
setAH(0x02); // Read sectors
|
/* Boot from 1st HDD drive */
|
||||||
setAL(0x01); // Number of sectors
|
case 1:
|
||||||
setDH(0x00); // First head
|
{
|
||||||
setCH(0x00); // First cylinder
|
setAH(0x02); // Read sectors
|
||||||
setCL(0x01); // First sector
|
setAL(0x01); // Number of sectors
|
||||||
setDL(0x80); // First HDD drive (used by loader code, so should not be cleared)
|
setDH(0x00); // Head 0
|
||||||
setES(0x0000); // Place data in 0000:7C00
|
setCH(0x00); // Cylinder 0
|
||||||
setBX(0x7C00);
|
setCL(0x01); // Sector 1
|
||||||
BiosDiskService(Stack);
|
setDL(0x80); // First HDD drive (used by loader code, so should not be cleared)
|
||||||
if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
|
setES(0x0000); // Write data in 0000:7C00
|
||||||
DPRINT1("An error happened while loading the bootsector from HDD 0, error = %d\n", getAH());
|
setBX(0x7C00);
|
||||||
}
|
BiosDiskService(Stack);
|
||||||
// } while (i++ < 1);
|
if (!(Stack[STACK_FLAGS] & EMULATOR_FLAG_CF)) goto Quit;
|
||||||
} while (i-- > 0);
|
DPRINT1("An error happened while loading the bootsector from HDD 0, error = %d\n", getAH());
|
||||||
|
|
||||||
/* Clear everything, we are going to load DOS32 */
|
break;
|
||||||
setAX(AX);
|
}
|
||||||
setBX(BX);
|
|
||||||
setCX(CX);
|
default:
|
||||||
setDX(DX);
|
goto StartDos;
|
||||||
setES(ES);
|
|
||||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Go to next drive and invalidate the last half-byte. */
|
||||||
|
BootOrder = (BootOrder >> 4) | 0xF000;
|
||||||
|
goto Retry;
|
||||||
|
|
||||||
|
StartDos:
|
||||||
|
/* Clear everything, we are going to load DOS32 */
|
||||||
|
setAX(AX);
|
||||||
|
setBX(BX);
|
||||||
|
setCX(CX);
|
||||||
|
setDX(DX);
|
||||||
|
setES(ES);
|
||||||
|
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||||
|
|
||||||
/* Load our DOS */
|
/* Load our DOS */
|
||||||
DosBootsectorInitialize();
|
DosBootsectorInitialize();
|
||||||
|
|
||||||
Quit:
|
Quit:
|
||||||
/*
|
/*
|
||||||
* Position CPU to 0000:7C00 to boot the OS.
|
* Jump to 0000:7C00 to boot the OS.
|
||||||
*
|
*
|
||||||
* Since we are called via the INT32 mechanism, we need to correctly set
|
* Since we are called via the INT32 mechanism, we need to correctly set
|
||||||
* CS:IP, not by changing the current one (otherwise the interrupt could
|
* CS:IP, not by changing the current one (otherwise the interrupt could
|
||||||
|
|
|
@ -82,83 +82,6 @@ VOID DosCharPrint(CHAR Character)
|
||||||
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This function, derived from ntvdm.c!DisplayMessage, is used by the BIOS and
|
|
||||||
* the DOS to display messages to an output device. A printer function is given
|
|
||||||
* for printing the characters.
|
|
||||||
*/
|
|
||||||
static VOID
|
|
||||||
DisplayMessageAnsiV(IN CHAR_PRINT CharPrint,
|
|
||||||
IN LPCSTR Format,
|
|
||||||
IN va_list args)
|
|
||||||
{
|
|
||||||
static CHAR CurChar = 0;
|
|
||||||
LPSTR str;
|
|
||||||
|
|
||||||
#ifndef WIN2K_COMPLIANT
|
|
||||||
CHAR StaticBuffer[256];
|
|
||||||
LPSTR Buffer = StaticBuffer; // Use the static buffer by default.
|
|
||||||
#else
|
|
||||||
CHAR Buffer[2048]; // Large enough. If not, increase it by hand.
|
|
||||||
#endif
|
|
||||||
size_t MsgLen;
|
|
||||||
|
|
||||||
#ifndef WIN2K_COMPLIANT
|
|
||||||
/*
|
|
||||||
* Retrieve the message length and if it is too long, allocate
|
|
||||||
* an auxiliary buffer; otherwise use the static buffer.
|
|
||||||
* The string is built to be NULL-terminated.
|
|
||||||
*/
|
|
||||||
MsgLen = _vscprintf(Format, args);
|
|
||||||
if (MsgLen >= ARRAYSIZE(StaticBuffer))
|
|
||||||
{
|
|
||||||
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(CHAR));
|
|
||||||
if (Buffer == NULL)
|
|
||||||
{
|
|
||||||
/* Allocation failed, use the static buffer and display a suitable error message */
|
|
||||||
Buffer = StaticBuffer;
|
|
||||||
Format = "DisplayMessageAnsi()\nOriginal message is too long and allocating an auxiliary buffer failed.";
|
|
||||||
MsgLen = strlen(Format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
MsgLen = ARRAYSIZE(Buffer) - 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(CHAR));
|
|
||||||
_vsnprintf(Buffer, MsgLen, Format, args);
|
|
||||||
|
|
||||||
/* Display the message */
|
|
||||||
DPRINT1("\n\nNTVDM DOS32\n%s\n\n", Buffer);
|
|
||||||
|
|
||||||
MsgLen = strlen(Buffer);
|
|
||||||
str = Buffer;
|
|
||||||
while (MsgLen--)
|
|
||||||
{
|
|
||||||
if (*str == '\n' && CurChar != '\r')
|
|
||||||
CharPrint('\r');
|
|
||||||
|
|
||||||
CurChar = *str++;
|
|
||||||
CharPrint(CurChar);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef WIN2K_COMPLIANT
|
|
||||||
/* Free the buffer if needed */
|
|
||||||
if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
DemDisplayMessage(IN CHAR_PRINT CharPrint,
|
|
||||||
IN LPCSTR Format, ...)
|
|
||||||
{
|
|
||||||
va_list Parameters;
|
|
||||||
|
|
||||||
va_start(Parameters, Format);
|
|
||||||
DisplayMessageAnsiV(CharPrint, Format, Parameters);
|
|
||||||
va_end(Parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static VOID DemLoadNTDOSKernel(VOID)
|
static VOID DemLoadNTDOSKernel(VOID)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,18 +29,13 @@
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
typedef VOID (*CHAR_PRINT)(IN CHAR Character);
|
|
||||||
VOID BiosCharPrint(CHAR Character);
|
VOID BiosCharPrint(CHAR Character);
|
||||||
VOID DosCharPrint(CHAR Character);
|
|
||||||
|
|
||||||
VOID DemDisplayMessage(IN CHAR_PRINT CharPrint,
|
|
||||||
IN LPCSTR Format, ...);
|
|
||||||
|
|
||||||
#define BiosDisplayMessage(Format, ...) \
|
#define BiosDisplayMessage(Format, ...) \
|
||||||
DemDisplayMessage(BiosCharPrint, (Format), ##__VA_ARGS__)
|
PrintMessageAnsi(BiosCharPrint, (Format), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
VOID DosCharPrint(CHAR Character);
|
||||||
#define DosDisplayMessage(Format, ...) \
|
#define DosDisplayMessage(Format, ...) \
|
||||||
DemDisplayMessage(DosCharPrint, (Format), ##__VA_ARGS__)
|
PrintMessageAnsi(DosCharPrint, (Format), ##__VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN DosShutdown(BOOLEAN Immediate);
|
BOOLEAN DosShutdown(BOOLEAN Immediate);
|
||||||
|
|
|
@ -564,14 +564,22 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mount the available hard disks */
|
/*
|
||||||
|
* Mount the available hard disks. Contrary to floppies, failing
|
||||||
|
* mounting a hard disk is considered as an unrecoverable error.
|
||||||
|
*/
|
||||||
for (i = 0; i < ARRAYSIZE(GlobalSettings.HardDisks); ++i)
|
for (i = 0; i < ARRAYSIZE(GlobalSettings.HardDisks); ++i)
|
||||||
{
|
{
|
||||||
if (GlobalSettings.HardDisks[i].Length != 0 &&
|
if (GlobalSettings.HardDisks[i].Length != 0 &&
|
||||||
GlobalSettings.HardDisks[i].Buffer &&
|
GlobalSettings.HardDisks[i].Buffer &&
|
||||||
GlobalSettings.HardDisks[i].Buffer != '\0')
|
GlobalSettings.HardDisks[i].Buffer != '\0')
|
||||||
{
|
{
|
||||||
MountDisk(HARD_DISK, i, GlobalSettings.HardDisks[i].Buffer, FALSE);
|
if (!MountDisk(HARD_DISK, i, GlobalSettings.HardDisks[i].Buffer, FALSE))
|
||||||
|
{
|
||||||
|
wprintf(L"FATAL: Failed to mount hard disk file '%Z'.\n", &GlobalSettings);
|
||||||
|
EmulatorCleanup();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ typedef enum _CMOS_REGISTERS
|
||||||
CMOS_REG_BASE_MEMORY_HIGH = 0x16,
|
CMOS_REG_BASE_MEMORY_HIGH = 0x16,
|
||||||
CMOS_REG_EXT_MEMORY_LOW = 0x17,
|
CMOS_REG_EXT_MEMORY_LOW = 0x17,
|
||||||
CMOS_REG_EXT_MEMORY_HIGH = 0x18,
|
CMOS_REG_EXT_MEMORY_HIGH = 0x18,
|
||||||
|
CMOS_REG_SYSOP = 0x2D,
|
||||||
CMOS_REG_ACTUAL_EXT_MEMORY_LOW = 0x30,
|
CMOS_REG_ACTUAL_EXT_MEMORY_LOW = 0x30,
|
||||||
CMOS_REG_ACTUAL_EXT_MEMORY_HIGH = 0x31,
|
CMOS_REG_ACTUAL_EXT_MEMORY_HIGH = 0x31,
|
||||||
CMOS_REG_CENTURY = 0x32,
|
CMOS_REG_CENTURY = 0x32,
|
||||||
|
|
|
@ -199,7 +199,7 @@ MountFDI(IN PDISK_IMAGE DiskImage,
|
||||||
if (FileSize == INVALID_FILE_SIZE && GetLastError() != ERROR_SUCCESS)
|
if (FileSize == INVALID_FILE_SIZE && GetLastError() != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
/* We failed, bail out */
|
/* We failed, bail out */
|
||||||
DisplayMessage(L"Error when retrieving file size, or size too large (%d).", FileSize);
|
DisplayMessage(L"MountFDI: Error when retrieving file size, or size too large (%d).", FileSize);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +547,11 @@ MountDisk(IN DISK_TYPE DiskType,
|
||||||
FileName, hFile != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
|
FileName, hFile != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
|
||||||
|
|
||||||
/* If we failed, bail out */
|
/* If we failed, bail out */
|
||||||
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
DisplayMessage(L"MountDisk: Error when opening disk file '%S' (Error: %u).", FileName, GetLastError());
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* OK, we have a handle to the file */
|
/* OK, we have a handle to the file */
|
||||||
|
|
||||||
|
@ -563,7 +567,7 @@ MountDisk(IN DISK_TYPE DiskType,
|
||||||
GetLastError() == ERROR_INVALID_FUNCTION)
|
GetLastError() == ERROR_INVALID_FUNCTION)
|
||||||
{
|
{
|
||||||
/* Objects other than real files are not supported */
|
/* Objects other than real files are not supported */
|
||||||
DisplayMessage(L"'%S' is not a valid disk file.", FileName);
|
DisplayMessage(L"MountDisk: '%S' is not a valid disk file.", FileName);
|
||||||
goto Quit;
|
goto Quit;
|
||||||
}
|
}
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
|
@ -571,7 +575,7 @@ MountDisk(IN DISK_TYPE DiskType,
|
||||||
GetLastError() == ERROR_INVALID_FUNCTION)
|
GetLastError() == ERROR_INVALID_FUNCTION)
|
||||||
{
|
{
|
||||||
/* Objects other than real files are not supported */
|
/* Objects other than real files are not supported */
|
||||||
DisplayMessage(L"'%S' is not a valid disk file.", FileName);
|
DisplayMessage(L"MountDisk: '%S' is not a valid disk file.", FileName);
|
||||||
goto Quit;
|
goto Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -562,9 +562,9 @@ DisplayMessage(IN LPCWSTR Format, ...)
|
||||||
WCHAR Buffer[2048]; // Large enough. If not, increase it by hand.
|
WCHAR Buffer[2048]; // Large enough. If not, increase it by hand.
|
||||||
#endif
|
#endif
|
||||||
size_t MsgLen;
|
size_t MsgLen;
|
||||||
va_list Parameters;
|
va_list args;
|
||||||
|
|
||||||
va_start(Parameters, Format);
|
va_start(args, Format);
|
||||||
|
|
||||||
#ifndef WIN2K_COMPLIANT
|
#ifndef WIN2K_COMPLIANT
|
||||||
/*
|
/*
|
||||||
|
@ -572,7 +572,7 @@ DisplayMessage(IN LPCWSTR Format, ...)
|
||||||
* an auxiliary buffer; otherwise use the static buffer.
|
* an auxiliary buffer; otherwise use the static buffer.
|
||||||
* The string is built to be NULL-terminated.
|
* The string is built to be NULL-terminated.
|
||||||
*/
|
*/
|
||||||
MsgLen = _vscwprintf(Format, Parameters);
|
MsgLen = _vscwprintf(Format, args);
|
||||||
if (MsgLen >= ARRAYSIZE(StaticBuffer))
|
if (MsgLen >= ARRAYSIZE(StaticBuffer))
|
||||||
{
|
{
|
||||||
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(WCHAR));
|
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(WCHAR));
|
||||||
|
@ -589,9 +589,9 @@ DisplayMessage(IN LPCWSTR Format, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(WCHAR));
|
RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(WCHAR));
|
||||||
_vsnwprintf(Buffer, MsgLen, Format, Parameters);
|
_vsnwprintf(Buffer, MsgLen, Format, args);
|
||||||
|
|
||||||
va_end(Parameters);
|
va_end(args);
|
||||||
|
|
||||||
/* Display the message */
|
/* Display the message */
|
||||||
DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
|
DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
|
||||||
|
@ -603,6 +603,76 @@ DisplayMessage(IN LPCWSTR Format, ...)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function, derived from DisplayMessage, is used by the BIOS and
|
||||||
|
* the DOS to display messages to an output device. A printer function
|
||||||
|
* is given for printing the characters.
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
PrintMessageAnsi(IN CHAR_PRINT CharPrint,
|
||||||
|
IN LPCSTR Format, ...)
|
||||||
|
{
|
||||||
|
static CHAR CurChar = 0;
|
||||||
|
LPSTR str;
|
||||||
|
|
||||||
|
#ifndef WIN2K_COMPLIANT
|
||||||
|
CHAR StaticBuffer[256];
|
||||||
|
LPSTR Buffer = StaticBuffer; // Use the static buffer by default.
|
||||||
|
#else
|
||||||
|
CHAR Buffer[2048]; // Large enough. If not, increase it by hand.
|
||||||
|
#endif
|
||||||
|
size_t MsgLen;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, Format);
|
||||||
|
|
||||||
|
#ifndef WIN2K_COMPLIANT
|
||||||
|
/*
|
||||||
|
* Retrieve the message length and if it is too long, allocate
|
||||||
|
* an auxiliary buffer; otherwise use the static buffer.
|
||||||
|
* The string is built to be NULL-terminated.
|
||||||
|
*/
|
||||||
|
MsgLen = _vscprintf(Format, args);
|
||||||
|
if (MsgLen >= ARRAYSIZE(StaticBuffer))
|
||||||
|
{
|
||||||
|
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(CHAR));
|
||||||
|
if (Buffer == NULL)
|
||||||
|
{
|
||||||
|
/* Allocation failed, use the static buffer and display a suitable error message */
|
||||||
|
Buffer = StaticBuffer;
|
||||||
|
Format = "DisplayMessageAnsi()\nOriginal message is too long and allocating an auxiliary buffer failed.";
|
||||||
|
MsgLen = strlen(Format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
MsgLen = ARRAYSIZE(Buffer) - 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(CHAR));
|
||||||
|
_vsnprintf(Buffer, MsgLen, Format, args);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
/* Display the message */
|
||||||
|
// DPRINT1("\n\nNTVDM DOS32\n%s\n\n", Buffer);
|
||||||
|
|
||||||
|
MsgLen = strlen(Buffer);
|
||||||
|
str = Buffer;
|
||||||
|
while (MsgLen--)
|
||||||
|
{
|
||||||
|
if (*str == '\n' && CurChar != '\r')
|
||||||
|
CharPrint('\r');
|
||||||
|
|
||||||
|
CurChar = *str++;
|
||||||
|
CharPrint(CurChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef WIN2K_COMPLIANT
|
||||||
|
/* Free the buffer if needed */
|
||||||
|
if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static VOID
|
static VOID
|
||||||
ConsoleCleanup(VOID);
|
ConsoleCleanup(VOID);
|
||||||
|
|
||||||
|
@ -877,7 +947,7 @@ wmain(INT argc, WCHAR *argv[])
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Load global VDM settings */
|
/* Load the global VDM settings */
|
||||||
LoadGlobalSettings(&GlobalSettings);
|
LoadGlobalSettings(&GlobalSettings);
|
||||||
|
|
||||||
DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
|
DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
|
||||||
|
|
|
@ -94,7 +94,10 @@ extern HWND hConsoleWnd;
|
||||||
/*
|
/*
|
||||||
* Interface functions
|
* Interface functions
|
||||||
*/
|
*/
|
||||||
|
typedef VOID (*CHAR_PRINT)(IN CHAR Character);
|
||||||
VOID DisplayMessage(IN LPCWSTR Format, ...);
|
VOID DisplayMessage(IN LPCWSTR Format, ...);
|
||||||
|
VOID PrintMessageAnsi(IN CHAR_PRINT CharPrint,
|
||||||
|
IN LPCSTR Format, ...);
|
||||||
|
|
||||||
/*static*/ VOID
|
/*static*/ VOID
|
||||||
CreateVdmMenu(HANDLE ConOutHandle);
|
CreateVdmMenu(HANDLE ConOutHandle);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue