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.d... + * 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/d... ============================================================================== --- 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/d... ============================================================================== --- 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/emula... ============================================================================== --- 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/hardw... ============================================================================== --- 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/hardw... ============================================================================== --- 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/ntvdm... ============================================================================== --- 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/ntvdm... ============================================================================== --- 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);