Author: hbelusca
Date: Thu Oct 1 00:09:24 2015
New Revision: 69421
URL:
http://svn.reactos.org/svn/reactos?rev=69421&view=rev
Log:
[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.
Modified:
trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.h
trunk/reactos/subsystems/mvdm/ntvdm/emulator.c
trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h
trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c
trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.c
trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c [iso-8859-1] Thu Oct 1
00:09:24 2015
@@ -161,6 +161,31 @@
/* 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)
{
/* Get the exception number and call the emulator API */
@@ -505,6 +530,8 @@
static VOID WINAPI BiosRomBasic(LPWORD Stack)
{
+ PrintMessageAnsi(BiosCharPrint, "FATAL: INT18: BOOT FAILURE.");
+
/* ROM Basic is unsupported, display a message to the user */
DisplayMessage(L"NTVDM doesn't support ROM Basic. The VDM is
closing.");
@@ -518,79 +545,110 @@
static VOID WINAPI BiosBootstrapLoader(LPWORD Stack)
{
- /*
- * In real BIOSes one loads the bootsector read from a diskette
- * 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,
- * just call the DOS 32-bit initialization code.
- */
-
- DPRINT("BiosBootstrapLoader -->\n");
-
+ USHORT BootOrder;
+
+ USHORT AX, BX, CX, DX, ES;
+ AX = getAX();
+ BX = getBX();
+ CX = getCX();
+ DX = getDX();
+ ES = getES();
+
+ /*
+ * Read the boot sequence order from the CMOS, old behaviour AMI-style.
+ *
+ * For more information, see:
+ *
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.…
+ *
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 (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;
-
- USHORT AX, BX, CX, DX, ES;
- AX = getAX();
- BX = getBX();
- CX = getCX();
- DX = getDX();
- ES = getES();
-
- // i = 0;
- i = 1;
- do
- {
- if (i == 0)
- {
- /* Boot from 1st floppy drive */
-
- setAH(0x02); // Read sectors
- 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
- setAL(0x01); // Number of sectors
- setDH(0x00); // First head
- setCH(0x00); // First cylinder
- setCL(0x01); // First sector
- setDL(0x80); // First HDD 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 HDD 0,
error = %d\n", getAH());
- }
- // } while (i++ < 1);
- } while (i-- > 0);
-
- /* Clear everything, we are going to load DOS32 */
- setAX(AX);
- setBX(BX);
- setCX(CX);
- setDX(DX);
- setES(ES);
- Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ /* Boot from 1st floppy drive */
+ case 0:
+ {
+ setAH(0x02); // Read sectors
+ setAL(0x01); // Number of sectors
+ 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());
+
+ break;
+ }
+
+ /* Boot from 1st HDD drive */
+ case 1:
+ {
+ setAH(0x02); // Read sectors
+ setAL(0x01); // Number of sectors
+ setDH(0x00); // Head 0
+ setCH(0x00); // Cylinder 0
+ setCL(0x01); // Sector 1
+ setDL(0x80); // First HDD 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 HDD 0,
error = %d\n", getAH());
+
+ break;
+ }
+
+ default:
+ goto StartDos;
}
+
+ /* 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 */
DosBootsectorInitialize();
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
* CS:IP, not by changing the current one (otherwise the interrupt could
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c [iso-8859-1] Thu Oct 1 00:09:24 2015
@@ -80,83 +80,6 @@
VOID DosCharPrint(CHAR 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);
}
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.h [iso-8859-1] Thu Oct 1 00:09:24 2015
@@ -29,18 +29,13 @@
/* FUNCTIONS ******************************************************************/
-typedef VOID (*CHAR_PRINT)(IN CHAR Character);
VOID BiosCharPrint(CHAR Character);
+#define BiosDisplayMessage(Format, ...) \
+ PrintMessageAnsi(BiosCharPrint, (Format), ##__VA_ARGS__)
+
VOID DosCharPrint(CHAR Character);
-
-VOID DemDisplayMessage(IN CHAR_PRINT CharPrint,
- IN LPCSTR Format, ...);
-
-#define BiosDisplayMessage(Format, ...) \
- DemDisplayMessage(BiosCharPrint, (Format), ##__VA_ARGS__)
-
#define DosDisplayMessage(Format, ...) \
- DemDisplayMessage(DosCharPrint, (Format), ##__VA_ARGS__)
+ PrintMessageAnsi(DosCharPrint, (Format), ##__VA_ARGS__)
BOOLEAN DosShutdown(BOOLEAN Immediate);
Modified: trunk/reactos/subsystems/mvdm/ntvdm/emulator.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/emul…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/emulator.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/emulator.c [iso-8859-1] Thu Oct 1 00:09:24 2015
@@ -564,14 +564,22 @@
}
}
- /* 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)
{
if (GlobalSettings.HardDisks[i].Length != 0 &&
GlobalSettings.HardDisks[i].Buffer &&
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;
+ }
}
}
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h [iso-8859-1] Thu Oct 1 00:09:24
2015
@@ -70,6 +70,7 @@
CMOS_REG_BASE_MEMORY_HIGH = 0x16,
CMOS_REG_EXT_MEMORY_LOW = 0x17,
CMOS_REG_EXT_MEMORY_HIGH = 0x18,
+ CMOS_REG_SYSOP = 0x2D,
CMOS_REG_ACTUAL_EXT_MEMORY_LOW = 0x30,
CMOS_REG_ACTUAL_EXT_MEMORY_HIGH = 0x31,
CMOS_REG_CENTURY = 0x32,
Modified: trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/hard…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/hardware/disk.c [iso-8859-1] Thu Oct 1 00:09:24
2015
@@ -199,7 +199,7 @@
if (FileSize == INVALID_FILE_SIZE && GetLastError() != ERROR_SUCCESS)
{
/* 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;
}
@@ -547,7 +547,11 @@
FileName, hFile != INVALID_HANDLE_VALUE ? "succeeded" :
"failed", GetLastError());
/* 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 */
@@ -563,7 +567,7 @@
GetLastError() == ERROR_INVALID_FUNCTION)
{
/* 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;
}
SetLastError(0);
@@ -571,7 +575,7 @@
GetLastError() == ERROR_INVALID_FUNCTION)
{
/* 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;
}
Modified: trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/ntvd…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.c [iso-8859-1] Thu Oct 1 00:09:24 2015
@@ -562,9 +562,9 @@
WCHAR Buffer[2048]; // Large enough. If not, increase it by hand.
#endif
size_t MsgLen;
- va_list Parameters;
-
- va_start(Parameters, Format);
+ va_list args;
+
+ va_start(args, Format);
#ifndef WIN2K_COMPLIANT
/*
@@ -572,7 +572,7 @@
* an auxiliary buffer; otherwise use the static buffer.
* The string is built to be NULL-terminated.
*/
- MsgLen = _vscwprintf(Format, Parameters);
+ MsgLen = _vscwprintf(Format, args);
if (MsgLen >= ARRAYSIZE(StaticBuffer))
{
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) *
sizeof(WCHAR));
@@ -589,13 +589,83 @@
#endif
RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(WCHAR));
- _vsnwprintf(Buffer, MsgLen, Format, Parameters);
-
- va_end(Parameters);
+ _vsnwprintf(Buffer, MsgLen, Format, args);
+
+ va_end(args);
/* Display the message */
DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
MessageBoxW(hConsoleWnd, Buffer, L"NTVDM Subsystem", MB_OK);
+
+#ifndef WIN2K_COMPLIANT
+ /* Free the buffer if needed */
+ if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+#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 */
@@ -877,7 +947,7 @@
}
#endif
- /* Load global VDM settings */
+ /* Load the global VDM settings */
LoadGlobalSettings(&GlobalSettings);
DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
Modified: trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/ntvd…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/ntvdm.h [iso-8859-1] Thu Oct 1 00:09:24 2015
@@ -94,7 +94,10 @@
/*
* Interface functions
*/
+typedef VOID (*CHAR_PRINT)(IN CHAR Character);
VOID DisplayMessage(IN LPCWSTR Format, ...);
+VOID PrintMessageAnsi(IN CHAR_PRINT CharPrint,
+ IN LPCSTR Format, ...);
/*static*/ VOID
CreateVdmMenu(HANDLE ConOutHandle);