diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios.c b/reactos/subsystems/mvdm/ntvdm/bios/bios.c index 3043e092c78..e2cf18a2402 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios.c @@ -23,12 +23,13 @@ #include "io.h" #include "hardware/cmos.h" +#include + /* DEFINES ********************************************************************/ /* BOP Identifiers */ #define BOP_RESET 0x00 // Windows NTVDM (SoftPC) BIOS calls BOP 0x00 - // to let the virtual machine initialize itself - // the IVT and its hardware. + // to let the virtual machine perform the POST. #define BOP_EQUIPLIST 0x11 #define BOP_GETMEMSIZE 0x12 @@ -43,94 +44,95 @@ PBIOS_CONFIG_TABLE Bct; /* PUBLIC FUNCTIONS ***********************************************************/ -VOID WINAPI BiosEquipmentService(LPWORD Stack) +VOID WINAPI +WinNtVdmBiosReset(LPWORD Stack) { - /* Return the equipment list */ - setAX(Bda->EquipmentList); -} + DisplayMessage(L"You are loading Windows NTVDM BIOS!\n"); + // Bios32Post(Stack); -VOID WINAPI BiosGetMemorySize(LPWORD Stack) -{ - /* Return the conventional memory size in kB, typically 640 kB */ - setAX(Bda->MemorySize); + DisplayMessage(L"ReactOS NTVDM doesn't support Windows NTVDM BIOS at the moment. The VDM will shut down."); + EmulatorTerminate(); } BOOLEAN -BiosInitialize(IN LPCSTR BiosFileName) +BiosInitialize(IN LPCSTR BiosFileName, + IN LPCSTR RomFiles OPTIONAL) { BOOLEAN Success = FALSE; + BOOLEAN Success2 = FALSE; + LPCSTR RomFile; + LPSTR ptr; + ULONG RomAddress; + CHAR RomFileName[MAX_PATH + 10 + 1]; /* Disable interrupts */ setIF(0); /* Initialize the BDA and the BCT pointers */ - Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0x0000); + Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT , 0x0000); // The BCT is found at F000:E6F5 for 100% compatible BIOSes. Bct = (PBIOS_CONFIG_TABLE)SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE6F5); - /**** HACK! HACK! for Windows NTVDM BIOS ****/ - // WinNtVdmBiosSupportInitialize(); + /* Register the BIOS support BOPs */ + RegisterBop(BOP_RESET, WinNtVdmBiosReset); // Needed for Windows NTVDM (SoftPC) BIOS. + RegisterBop(BOP_EQUIPLIST , BiosEquipmentService); // Needed by Windows NTVDM (SoftPC) BIOS + RegisterBop(BOP_GETMEMSIZE, BiosGetMemorySize); // and also NTDOS!! - // /* Register the BIOS support BOPs */ - // RegisterBop(BOP_EQUIPLIST , BiosEquipmentService); - // RegisterBop(BOP_GETMEMSIZE, BiosGetMemorySize); - - if (BiosFileName && BiosFileName[0] != '\0') + if (BiosFileName == NULL) { - PVOID BiosLocation = NULL; - DWORD BiosSize = 0; - - Success = LoadBios(BiosFileName, &BiosLocation, &BiosSize); - DPRINT1("BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError()); - - if (!Success) return FALSE; - - DisplayMessage(L"First bytes at 0x%p: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n" - L"3 last bytes at 0x%p: 0x%02x 0x%02x 0x%02x", - BiosLocation, - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 0), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 1), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 2), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 3), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 4), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 5), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 6), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 7), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 8), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 9), - - (PVOID)((ULONG_PTR)BiosLocation + BiosSize - 2), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 2), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 1), - *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 0)); - - DisplayMessage(L"POST at 0x%p: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", - TO_LINEAR(getCS(), getIP()), - *(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 0), - *(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 1), - *(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 2), - *(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 3), - *(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 4)); - - /* Boot it up */ - - /* - * The CPU is already in reset-mode so that - * CS:IP points to F000:FFF0 as required. - */ - DisplayMessage(L"CS=0x%p ; IP=0x%p", getCS(), getIP()); - // setCS(0xF000); - // setIP(0xFFF0); - - Success = TRUE; - } - else - { - WriteProtectRom((PVOID)ROM_AREA_START, - ROM_AREA_END - ROM_AREA_START + 1); - Success = Bios32Loaded = Bios32Initialize(); } + else if (BiosFileName[0] != '\0') + { + PVOID BiosLocation = NULL; + + Success = LoadBios(BiosFileName, &BiosLocation, NULL); + DPRINT1("BIOS file '%s' loading %s at address 0x%08x; GetLastError() = %u\n", + BiosFileName, Success ? "succeeded" : "failed", BiosLocation, GetLastError()); + } + else // if (BiosFileName[0] == '\0') + { + /* Do nothing */ + Success = TRUE; + } + + /* Bail out now if we failed to load any BIOS file */ + if (!Success) return FALSE; + + /* Load optional ROMs */ + if (RomFiles) + { + RomFile = RomFiles; + while (*RomFile) + { + strncpy(RomFileName, RomFile, ARRAYSIZE(RomFileName)); + RomFileName[ARRAYSIZE(RomFileName)-1] = '\0'; + + ptr = strchr(RomFileName, '|'); // Since '|' is forbidden as a valid file name, we use it as a separator for the ROM address. + if (!ptr) goto Skip; + *ptr++ = '\0'; + + RomAddress = strtoul(ptr, NULL, 0); // ROM segment + RomAddress <<= 4; // Convert to real address + if (RomAddress == 0) goto Skip; + + Success2 = LoadRom(RomFileName, (PVOID)RomAddress, NULL); + DPRINT1("ROM file '%s' loading %s at address 0x%08x; GetLastError() = %u\n", + RomFileName, Success2 ? "succeeded" : "failed", RomAddress, GetLastError()); + +Skip: + RomFile += strlen(RomFile) + 1; + } + } + + /* + * Boot it up. + * The CPU is already in reset-mode so that + * CS:IP points to F000:FFF0 as required. + */ + // DisplayMessage(L"CS:IP=%04X:%04X", getCS(), getIP()); + // setCS(0xF000); + // setIP(0xFFF0); // /* Enable interrupts */ // setIF(1); diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios.h b/reactos/subsystems/mvdm/ntvdm/bios/bios.h index e8f30ba503c..1fe7b14b927 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios.h @@ -18,8 +18,7 @@ /* BOP Identifiers */ #define BOP_RESET 0x00 // Windows NTVDM (SoftPC) BIOS calls BOP 0x00 - // to let the virtual machine initialize itself - // the IVT and its hardware. + // to let the virtual machine perform the POST. #define BOP_EQUIPLIST 0x11 #define BOP_GETMEMSIZE 0x12 @@ -29,10 +28,6 @@ #define BDA_SEGMENT 0x40 #define BIOS_SEGMENT 0xF000 -// HACK: Disable FPU for now because it is not fully ready yet for being used -// by all applications (e.g. QBasic runtime would use the native FPU if the bit -// is set, but then subsequently fails, unless the FPU bit is unset in that case -// QBasic uses its emulated FPU). #define BIOS_EQUIPMENT_LIST 0x2E // Bit1: FPU, Bit 2: Mouse #pragma pack(push, 1) @@ -104,7 +99,8 @@ typedef struct BYTE Reserved5[2]; // 0x90 BYTE Reserved6[2]; // 0x92 BYTE Reserved7[2]; // 0x94 - WORD KeybdStatusFlags; // 0x96 + BYTE KeybdStatusFlags; // 0x96 + BYTE KeybdLedFlags; // 0x97 DWORD Reserved9; // 0x98 DWORD Reserved10; // 0x9c DWORD Reserved11[2]; // 0xa0 @@ -165,7 +161,8 @@ VOID WINAPI BiosEquipmentService(LPWORD Stack); VOID WINAPI BiosGetMemorySize(LPWORD Stack); BOOLEAN -BiosInitialize(IN LPCSTR BiosFileName); +BiosInitialize(IN LPCSTR BiosFileName, + IN LPCSTR RomFiles OPTIONAL); VOID BiosCleanup(VOID); diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c index a4df846e86e..29a457c9202 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c @@ -10,8 +10,9 @@ #define NDEBUG -/* For BIOS Version number */ +/* BIOS Version number and Copyright */ #include +#include #include "ntvdm.h" #include "emulator.h" @@ -106,19 +107,39 @@ $fffe ; System Model ID #define BIOS_REVISION 0x00 // FIXME: Find a nice PS/2 486 + 487 BIOS combination! +static const BIOS_CONFIG_TABLE BiosConfigTable = +{ + sizeof(BIOS_CONFIG_TABLE), // Length + + BIOS_MODEL, // BIOS Model + BIOS_SUBMODEL, // BIOS Sub-Model + BIOS_REVISION, // BIOS Revision + + // Feature bytes + { + 0x78, // At the moment we don't have any Extended BIOS Area; see http://www.ctyme.com/intr/rb-1594.htm#Table510 + 0x00, // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511 + 0x10, // Bit 4: POST supports ROM-to-RAM enable/disable + 0x00, + 0x00 + } +}; + + /* * WARNING! For compatibility purposes the string "IBM" should be at F000:E00E . - * Some programs alternatively look at "COPR. IBM" that is at F000:E008 . + * Some programs otherwise look for "COPR. IBM" at F000:E008 . */ -static const CHAR BiosCopyright[] = "0000000 NTVDM IBM Compatible 486 32-bit BIOS Copyright (C) ReactOS Team 1996-2014"; -static const CHAR BiosVersion[] = "ReactOS NTVDM 32-bit BIOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")"; +static const CHAR BiosCopyright[] = "0000000 NTVDM IBM COMPATIBLE 486 BIOS COPYRIGHT (C) ReactOS Team 1996-"COPYRIGHT_YEAR; +static const CHAR BiosVersion[] = "ReactOS NTVDM 32-bit BIOS Version "KERNEL_VERSION_STR"\0" + "BIOS32 Version "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")"; static const CHAR BiosDate[] = "06/17/13"; C_ASSERT(sizeof(BiosCopyright)-1 <= 0x5B); // Ensures that we won't overflow on the POST Code starting at F000:E05B C_ASSERT(sizeof(BiosDate)-1 == 0x08); /* 16-bit bootstrap code at F000:FFF0 */ -static BYTE Bootstrap[] = +static const BYTE Bootstrap[] = { 0xEA, // jmp far ptr 0x5B, 0xE0, 0x00, 0xF0, // F000:E05B @@ -128,7 +149,7 @@ static BYTE Bootstrap[] = * POST code at F000:E05B. All the POST is done in 32 bit * and only at the end it calls the bootstrap interrupt. */ -static BYTE PostCode[] = +static const BYTE PostCode[] = { LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), BOP_RESET, // Call BIOS POST 0xCD, BIOS_BOOTSTRAP_LOADER, // INT 0x19 @@ -145,6 +166,18 @@ static VOID WINAPI BiosException(LPWORD Stack) EmulatorException(ExceptionNumber, Stack); } +VOID WINAPI BiosEquipmentService(LPWORD Stack) +{ + /* Return the equipment list */ + setAX(Bda->EquipmentList); +} + +VOID WINAPI BiosGetMemorySize(LPWORD Stack) +{ + /* Return the conventional memory size in kB, typically 640 kB */ + setAX(Bda->MemorySize); +} + static VOID WINAPI BiosMiscService(LPWORD Stack) { switch (getAH()) @@ -162,7 +195,7 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) break; } - /* Wait On External Event */ + /* Wait on External Event */ case 0x41: { BYTE Value; @@ -242,7 +275,6 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) /* Repeat the BOP if we shouldn't return */ setCF(!Return); - break; } @@ -272,7 +304,6 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) /* Clear CF */ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; - break; } @@ -325,7 +356,6 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) /* Clear CF */ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; - break; } @@ -335,7 +365,7 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) DPRINT1("BIOS INT 15h, AH=89h \"Switch to Protected Mode\" is UNIMPLEMENTED"); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - break; + goto Default; } /* Get Configuration */ @@ -349,28 +379,44 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) /* Call successful; clear CF */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; - break; } /* Return Extended-Bios Data-Area Segment Address (PS) */ case 0xC1: { - // Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; - // setES(???); - - UNIMPLEMENTED; - /* We do not support EBDA yet */ + UNIMPLEMENTED; Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - - break; + goto Default; } /* Pointing Device BIOS Interface (PS) */ case 0xC2: { BiosMousePs2Interface(Stack); + UNIMPLEMENTED; // Remove it when BiosMousePs2Interface is implemented! + goto Default; + } + + /* Get CPU Type and Mask Revision */ + case 0xC9: + { + /* + * We can see this function as a CPUID replacement. + * See Ralf Brown: http://www.ctyme.com/intr/rb-1613.htm + * for more information. + */ + + /* + * Fast486 is a 486DX with FPU included, + * but old enough to not support CPUID. + */ + setCX(0x0400); + + /* Call successful; clear CF */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } @@ -437,10 +483,19 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) break; } - default: + default: Default: { DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n", getAH()); + + /* + * The original signification of the error code 0x86 is that + * no PC Cassette is present. The CF is also set in this case. + * To keep backward compatibility, newer BIOSes use this value + * to indicate an unimplemented call in INT 15h. + */ + setAH(0x86); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } } } @@ -490,6 +545,7 @@ static VOID WINAPI BiosTimeService(LPWORD Stack) { switch (getAH()) { + /* Get System Time */ case 0x00: { /* Set AL to 1 if midnight had passed, 0 otherwise */ @@ -505,6 +561,7 @@ static VOID WINAPI BiosTimeService(LPWORD Stack) break; } + /* Set System Time */ case 0x01: { /* Set the tick count to CX:DX */ @@ -516,6 +573,62 @@ static VOID WINAPI BiosTimeService(LPWORD Stack) break; } + /* Get Real-Time Clock Time */ + case 0x02: + { + UCHAR StatusB; + + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_HOURS); + setCH(IOReadB(CMOS_DATA_PORT)); + + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MINUTES); + setCL(IOReadB(CMOS_DATA_PORT)); + + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_SECONDS); + setDH(IOReadB(CMOS_DATA_PORT)); + + /* Daylight Savings Time */ + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_STATUS_B); + StatusB = IOReadB(CMOS_DATA_PORT); + setDL(StatusB & 0x01); + + /* Clear CF */ + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + // /* Set Real-Time Clock Time */ + // case 0x03: + // { + // break; + // } + + /* Get Real-Time Clock Date */ + case 0x04: + { + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_CENTURY); + setCH(IOReadB(CMOS_DATA_PORT)); + + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_YEAR); + setCL(IOReadB(CMOS_DATA_PORT)); + + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_MONTH); + setDH(IOReadB(CMOS_DATA_PORT)); + + IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_DAY); + setDL(IOReadB(CMOS_DATA_PORT)); + + /* Clear CF */ + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + // /* Set Real-Time Clock Date */ + // case 0x05: + // { + // break; + // } + default: { DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n", @@ -675,7 +788,7 @@ static VOID InitializeBiosInt32(VOID) /* Zero out all of the IVT (0x00 -- 0xFF) */ RtlZeroMemory(BaseAddress, 0x0100 * sizeof(ULONG)); -#ifdef ADVANCED_DEBUGGING +#if defined(ADVANCED_DEBUGGING) && (ADVANCED_DEBUGGING_LEVEL >= 3) // Initialize all the interrupt vectors to the default one. for (i = 0x00; i <= 0xFF; i++) RegisterBiosInt32(i, NULL); @@ -756,36 +869,21 @@ static VOID InitializeBiosData(VOID) Bda->MemorySize = MAKEWORD(Low, High); } -static VOID InitializeBiosInfo(VOID) -{ - RtlZeroMemory(Bct, sizeof(*Bct)); - - Bct->Length = sizeof(*Bct); - Bct->Model = BIOS_MODEL; - Bct->SubModel = BIOS_SUBMODEL; - Bct->Revision = BIOS_REVISION; - Bct->Feature[0] = 0x70; // At the moment we don't support "wait for external event (INT 15/AH=41h)", we also don't have any "extended BIOS area allocated (usually at top of RAM)"; see http://www.ctyme.com/intr/rb-1594.htm#Table510 - Bct->Feature[1] = 0x00; // We don't support anything from here; see http://www.ctyme.com/intr/rb-1594.htm#Table511 - Bct->Feature[2] = 0x00; - Bct->Feature[3] = 0x00; - Bct->Feature[4] = 0x00; -} - - /* * The BIOS POST (Power On-Self Test) */ -static VOID +/*static*/ VOID WINAPI Bios32Post(LPWORD Stack) { static BOOLEAN FirstBoot = TRUE; -#if 0 - BOOLEAN Success; -#endif BYTE ShutdownStatus; + /* + * Initialize BIOS/Keyboard/Video RAM dynamic data + */ + DPRINT("Bios32Post\n"); /* Disable interrupts */ @@ -879,7 +977,6 @@ Bios32Post(LPWORD Stack) * - if the word is 0000h, perform a cold reboot (aka. Reset). Everything gets initialized. * - if the word is 1234h, perform a warm reboot (aka. Ctrl-Alt-Del). Some stuff is skipped. */ - switch (Bda->SoftReset) { case 0x0000: @@ -906,17 +1003,22 @@ Bios32Post(LPWORD Stack) FirstBoot = FALSE; - /* Initialize the BDA and the BIOS ROM Information */ + /* Initialize the BDA */ InitializeBiosData(); - InitializeBiosInfo(); /* Initialize the User Data Area at 0050:XXXX */ RtlZeroMemory(SEG_OFF_TO_PTR(0x50, 0x0000), sizeof(USER_DATA_AREA)); + + + //////// NOTE: This is more or less bios-specific //////// + /* * Initialize IVT and hardware */ + // WriteUnProtectRom(...); + /* Register the BIOS 32-bit Interrupts */ InitializeBiosInt32(); @@ -924,30 +1026,15 @@ Bios32Post(LPWORD Stack) BiosHwSetup(); /* Initialize the Keyboard, Video and Mouse BIOS */ - if (!KbdBios32Initialize() || !VidBios32Initialize() || !MouseBios32Initialize()) - { - /* Stop the VDM */ - EmulatorTerminate(); - return; - } + KbdBios32Post(); + VidBiosPost(); + MouseBios32Post(); -#if 0 - /* Initialize the Keyboard and Video BIOS */ - if (!KbdBiosInitialize() || !VidBiosInitialize()) - { - /* Stop the VDM */ - EmulatorTerminate(); - return; - } -#endif + // WriteProtectRom(...); + + //////// End of more or less bios-specific section /////// - ///////////// MUST BE DONE AFTER IVT INITIALIZATION !! ///////////////////// -#if 0 - /* Load some ROMs */ - Success = LoadRom("boot.bin", (PVOID)0xE0000, NULL); - DPRINT1("Test ROM loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError()); -#endif SearchAndInitRoms(&BiosContext); @@ -968,29 +1055,42 @@ Quit: BOOLEAN Bios32Initialize(VOID) { /* - * Initialize BIOS32 static data + * Initialize BIOS/Keyboard/Video ROM static data */ - /* Bootstrap code */ - RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE05B), PostCode , sizeof(PostCode )); - RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF0), Bootstrap, sizeof(Bootstrap)); - /* System BIOS Copyright */ - RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1); + RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE000), BiosCopyright, sizeof(BiosCopyright)-1); /* System BIOS Version */ - RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xE080), BiosVersion, sizeof(BiosVersion)-1); - // FIXME: or E061, or E100 ?? + RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE070), BiosVersion, sizeof(BiosVersion)-1); /* System BIOS Date */ - RtlCopyMemory(SEG_OFF_TO_PTR(0xF000, 0xFFF5), BiosDate, sizeof(BiosDate)-1); + RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF5), BiosDate, sizeof(BiosDate)-1); + + /* Bootstrap code */ + RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE05B), PostCode , sizeof(PostCode )); + RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFF0), Bootstrap, sizeof(Bootstrap)); + + /* BIOS ROM Information */ + RtlCopyMemory(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xE6F5), &BiosConfigTable, sizeof(BiosConfigTable)); /* System BIOS Model (same as Bct->Model) */ - *(PBYTE)(SEG_OFF_TO_PTR(0xF000, 0xFFFE)) = BIOS_MODEL; + *(PBYTE)(SEG_OFF_TO_PTR(BIOS_SEGMENT, 0xFFFE)) = BIOS_MODEL; + + /* Initialize the Keyboard and Video BIOS */ + if (!KbdBiosInitialize() || !VidBiosInitialize() || !MouseBiosInitialize()) + { + /* Stop the VDM */ + EmulatorTerminate(); + return FALSE; + } /* Redefine our POST function */ RegisterBop(BOP_RESET, Bios32Post); + WriteProtectRom((PVOID)TO_LINEAR(BIOS_SEGMENT, 0x0000), + ROM_AREA_END - TO_LINEAR(BIOS_SEGMENT, 0x0000) + 1); + /* We are done */ return TRUE; } @@ -999,7 +1099,7 @@ VOID Bios32Cleanup(VOID) { MouseBios32Cleanup(); VidBios32Cleanup(); - KbdBios32Cleanup(); + KbdBiosCleanup(); } /* EOF */ diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.c index 1eef4b89e80..6f12851a602 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.c @@ -80,7 +80,8 @@ static BOOLEAN BiosKbdBufferPop(VOID) return TRUE; } -static VOID WINAPI BiosKeyboardService(LPWORD Stack) +/* static */ +VOID WINAPI BiosKeyboardService(LPWORD Stack) { switch (getAH()) { @@ -168,11 +169,16 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack) case 0x12: { /* - * Be careful! The returned word is similar to Bda->KeybdShiftFlags + * Be careful! The returned word is similar to 'Bda->KeybdShiftFlags' * but the high byte is organized differently: - * the bytes 2 and 3 of the high byte are not the same... + * the bits 2 and 3 of the high byte are not the same: + * instead they correspond to the right CTRL and ALT keys as specified + * in bits 2 and 3 of LOBYTE(Bda->KeybdStatusFlags). */ - WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF); + // Bda->KeybdShiftFlags & 0xF3FF; + WORD KeybdShiftFlags = MAKEWORD(LOBYTE(Bda->KeybdShiftFlags), + (HIBYTE(Bda->KeybdShiftFlags ) & 0xF3) | + (LOBYTE(Bda->KeybdStatusFlags) & 0x0C)); /* Return the extended keyboard shift status word */ setAX(KeybdShiftFlags); @@ -188,7 +194,8 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack) } // Keyboard IRQ 1 -static VOID WINAPI BiosKeyboardIrq(LPWORD Stack) +/* static */ +VOID WINAPI BiosKeyboardIrq(LPWORD Stack) { static BOOLEAN Extended = FALSE; BOOLEAN SkipScanCode; @@ -222,9 +229,14 @@ static VOID WINAPI BiosKeyboardIrq(LPWORD Stack) if (ScanCode == 0xE0) { Extended = TRUE; + Bda->KeybdStatusFlags |= 0x02; goto Quit; } + // FIXME: For diagnostic purposes. We should decide what to do then!! + if (ScanCode == 0xE1) + DPRINT1("BiosKeyboardIrq, ScanCode == 0xE1\n"); + /* Check whether CF is clear. If so, skip the scan code. */ if (SkipScanCode) goto Quit; @@ -249,10 +261,12 @@ static VOID WINAPI BiosKeyboardIrq(LPWORD Stack) break; } - case VK_CONTROL: case VK_SHIFT: case VK_LSHIFT: case VK_RSHIFT: + case VK_CONTROL: + case VK_RCONTROL: + case VK_LCONTROL: case VK_MENU: case VK_LMENU: case VK_RMENU: @@ -288,19 +302,27 @@ static VOID WINAPI BiosKeyboardIrq(LPWORD Stack) /* Clear the keyboard flags */ Bda->KeybdShiftFlags = 0; + // Release right CTRL and ALT keys + Bda->KeybdStatusFlags &= ~(BDA_KBDFLAG_RCTRL | BDA_KBDFLAG_RALT); /* Set the appropriate flags based on the state */ - if (BiosKeyboardMap[VK_SHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT; + // SHIFT if (BiosKeyboardMap[VK_RSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RSHIFT; if (BiosKeyboardMap[VK_LSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT; + if (BiosKeyboardMap[VK_SHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT; + // CTRL + if (BiosKeyboardMap[VK_RCONTROL] & (1 << 7)) Bda->KeybdStatusFlags |= BDA_KBDFLAG_RCTRL; + if (BiosKeyboardMap[VK_LCONTROL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LCTRL; if (BiosKeyboardMap[VK_CONTROL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CTRL; + // ALT + if (BiosKeyboardMap[VK_RMENU] & (1 << 7)) Bda->KeybdStatusFlags |= BDA_KBDFLAG_RALT; + if (BiosKeyboardMap[VK_LMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LALT; if (BiosKeyboardMap[VK_MENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_ALT; + // Others if (BiosKeyboardMap[VK_SCROLL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL_ON; if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK_ON; if (BiosKeyboardMap[VK_CAPITAL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK_ON; if (BiosKeyboardMap[VK_INSERT] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT_ON; - if (BiosKeyboardMap[VK_RMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RALT; - if (BiosKeyboardMap[VK_LMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LALT; if (BiosKeyboardMap[VK_SNAPSHOT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SYSRQ; if (BiosKeyboardMap[VK_PAUSE] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_PAUSE; if (BiosKeyboardMap[VK_SCROLL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL; @@ -310,6 +332,8 @@ static VOID WINAPI BiosKeyboardIrq(LPWORD Stack) /* Clear the extended key flag */ Extended = FALSE; + Bda->KeybdStatusFlags &= ~0x02; // Remove the 0xE0 code flag + // Bda->KeybdStatusFlags &= ~0x01; // Remove the 0xE1 code flag DPRINT("BiosKeyboardIrq - Character = 0x%X, ScanCode = 0x%X, KeybdShiftFlags = 0x%X\n", Character, ScanCode, Bda->KeybdShiftFlags); @@ -320,11 +344,8 @@ Quit: /* PUBLIC FUNCTIONS ***********************************************************/ -BOOLEAN KbdBios32Initialize(VOID) +VOID KbdBios32Post(VOID) { - /* Initialize the common Keyboard BIOS Support Library */ - if (!KbdBiosInitialize()) return FALSE; - /* Initialize the BDA */ Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer); Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD); @@ -334,6 +355,10 @@ BOOLEAN KbdBios32Initialize(VOID) RtlFillMemory(((LPVOID)((ULONG_PTR)Bda + Bda->KeybdBufferStart)), BIOS_KBD_BUFFER_SIZE * sizeof(WORD), 'A'); + Bda->KeybdShiftFlags = 0; + Bda->KeybdStatusFlags = (1 << 4); // 101/102 enhanced keyboard installed + Bda->KeybdLedFlags = 0; + /* * Register the BIOS 32-bit Interrupts: * - Software vector handler @@ -341,14 +366,6 @@ BOOLEAN KbdBios32Initialize(VOID) */ RegisterBiosInt32(BIOS_KBD_INTERRUPT, BiosKeyboardService); EnableHwIRQ(1, BiosKeyboardIrq); - - return TRUE; -} - -VOID KbdBios32Cleanup(VOID) -{ - /* Cleanup the common Keyboard BIOS Support Library */ - KbdBiosCleanup(); } /* EOF */ diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.h b/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.h index 211033c0aae..55d297b911d 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/kbdbios32.h @@ -18,12 +18,14 @@ #define BDA_KBDFLAG_RSHIFT (1 << 0) #define BDA_KBDFLAG_LSHIFT (1 << 1) #define BDA_KBDFLAG_CTRL (1 << 2) +#define BDA_KBDFLAG_RCTRL (1 << 2) // Used for KeybdStatusFlags #define BDA_KBDFLAG_ALT (1 << 3) +#define BDA_KBDFLAG_RALT (1 << 3) // Used for KeybdStatusFlags #define BDA_KBDFLAG_SCROLL_ON (1 << 4) #define BDA_KBDFLAG_NUMLOCK_ON (1 << 5) #define BDA_KBDFLAG_CAPSLOCK_ON (1 << 6) #define BDA_KBDFLAG_INSERT_ON (1 << 7) -#define BDA_KBDFLAG_RALT (1 << 8) +#define BDA_KBDFLAG_LCTRL (1 << 8) #define BDA_KBDFLAG_LALT (1 << 9) #define BDA_KBDFLAG_SYSRQ (1 << 10) #define BDA_KBDFLAG_PAUSE (1 << 11) @@ -34,8 +36,7 @@ /* FUNCTIONS ******************************************************************/ -BOOLEAN KbdBios32Initialize(VOID); -VOID KbdBios32Cleanup(VOID); +VOID KbdBios32Post(VOID); #endif /* _KBDBIOS32_H_ */ diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c index a17c410acd1..a044a21b59f 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c @@ -105,7 +105,7 @@ VOID BiosMousePs2Interface(LPWORD Stack) /* PUBLIC FUNCTIONS ***********************************************************/ -BOOLEAN MouseBios32Initialize(VOID) +VOID MouseBios32Post(VOID) { BYTE ControllerConfig; @@ -127,7 +127,10 @@ BOOLEAN MouseBios32Initialize(VOID) /* Set up the HW vector interrupts */ EnableHwIRQ(12, BiosMouseIrq); +} +BOOLEAN MouseBiosInitialize(VOID) +{ return TRUE; } diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.h b/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.h index 7339d7f5033..3e5aad90a0d 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.h @@ -15,7 +15,8 @@ VOID BiosMousePs2Interface(LPWORD Stack); -BOOLEAN MouseBios32Initialize(VOID); +VOID MouseBios32Post(VOID); +BOOLEAN MouseBiosInitialize(VOID); VOID MouseBios32Cleanup(VOID); #endif /* _MOUBIOS32_H_ */ diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vidbios32.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vidbios32.c index 7a40da8c607..fd1a7a17255 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vidbios32.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vidbios32.c @@ -13,33 +13,59 @@ #define NDEBUG #include "ntvdm.h" +#include "emulator.h" +#include "cpu/bop.h" #include "int32.h" #include "vidbios32.h" #include #include "bios32p.h" +/* DEFINES ********************************************************************/ + +/* BOP Identifiers */ +#define BOP_VIDEO_INT 0x10 + /* PUBLIC FUNCTIONS ***********************************************************/ +extern VOID WINAPI VidBiosVideoService(LPWORD Stack); +static VOID WINAPI VidBiosINT(LPWORD Stack) +{ + /* + * Set up a false stack to hardwire the BOP function (that can directly + * manipulate CPU registers) to the 32-bit interrupt function (which uses + * the stack to be able to modify the original CS:IP and FLAGS). + * + * See int32.h stack codes. + */ + WORD EmuStack[4]; + DWORD Flags = getEFLAGS(); + + DPRINT1("Calling BOP VidBiosINT\n"); + + EmuStack[STACK_FLAGS] = LOWORD(Flags); + EmuStack[STACK_CS] = getCS(); + EmuStack[STACK_IP] = getIP(); + EmuStack[STACK_INT_NUM] = BOP_VIDEO_INT; + + VidBiosVideoService(EmuStack); + + setIP(EmuStack[STACK_IP]); + setCS(EmuStack[STACK_CS]); + setEFLAGS(MAKELONG(EmuStack[STACK_FLAGS], HIWORD(Flags))); +} + BOOLEAN VidBios32Initialize(VOID) { - /* Initialize the common Video BIOS Support Library */ - if (!VidBiosInitialize()) return FALSE; - - /* Register the BIOS 32-bit Interrupts */ - RegisterBiosInt32(BIOS_VIDEO_INTERRUPT, VidBiosVideoService); - - /* Vectors that should be implemented */ - RegisterBiosInt32(0x42, NULL); // Relocated Default INT 10h Video Services - RegisterBiosInt32(0x6D, NULL); // Video BIOS Entry Point - + /* Register the BIOS support BOPs */ + RegisterBop(BOP_VIDEO_INT, VidBiosINT); return TRUE; } VOID VidBios32Cleanup(VOID) { - /* Cleanup the common Video BIOS Support Library */ - VidBiosCleanup(); + /* Unregister the BIOS support BOPs */ + RegisterBop(BOP_VIDEO_INT, NULL); } /* EOF */ diff --git a/reactos/subsystems/mvdm/ntvdm/bios/kbdbios.c b/reactos/subsystems/mvdm/ntvdm/bios/kbdbios.c index 27d2f0f521c..1913fb8a580 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/kbdbios.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/kbdbios.c @@ -13,6 +13,7 @@ #include "ntvdm.h" #include "emulator.h" #include "cpu/bop.h" +#include "int32.h" #include "bios.h" // #include "kbdbios.h" @@ -25,27 +26,73 @@ /* PUBLIC FUNCTIONS ***********************************************************/ +extern VOID WINAPI BiosKeyboardIrq(LPWORD Stack); static VOID WINAPI KbdBiosIRQ(LPWORD Stack) { - DPRINT1("KbdBiosIRQ is UNIMPLEMENTED\n"); + /* + * Set up a false stack to hardwire the BOP function (that can directly + * manipulate CPU registers) to the 32-bit interrupt function (which uses + * the stack to be able to modify the original CS:IP and FLAGS). + * + * See int32.h stack codes. + */ + WORD EmuStack[4]; + DWORD Flags = getEFLAGS(); + + DPRINT1("Calling BOP KbdBiosIRQ\n"); + + EmuStack[STACK_FLAGS] = LOWORD(Flags); + EmuStack[STACK_CS] = getCS(); + EmuStack[STACK_IP] = getIP(); + EmuStack[STACK_INT_NUM] = BOP_KBD_IRQ; + + BiosKeyboardIrq(EmuStack); + + setIP(EmuStack[STACK_IP]); + setCS(EmuStack[STACK_CS]); + setEFLAGS(MAKELONG(EmuStack[STACK_FLAGS], HIWORD(Flags))); } +extern VOID WINAPI BiosKeyboardService(LPWORD Stack); static VOID WINAPI KbdBiosINT(LPWORD Stack) { - DPRINT1("KbdBiosINT is UNIMPLEMENTED\n"); + /* + * Set up a false stack to hardwire the BOP function (that can directly + * manipulate CPU registers) to the 32-bit interrupt function (which uses + * the stack to be able to modify the original CS:IP and FLAGS). + * + * See int32.h stack codes. + */ + WORD EmuStack[4]; + DWORD Flags = getEFLAGS(); + + DPRINT1("Calling BOP KbdBiosINT\n"); + + EmuStack[STACK_FLAGS] = LOWORD(Flags); + EmuStack[STACK_CS] = getCS(); + EmuStack[STACK_IP] = getIP(); + EmuStack[STACK_INT_NUM] = BOP_KBD_IRQ; + + BiosKeyboardService(EmuStack); + + setIP(EmuStack[STACK_IP]); + setCS(EmuStack[STACK_CS]); + setEFLAGS(MAKELONG(EmuStack[STACK_FLAGS], HIWORD(Flags))); } BOOLEAN KbdBiosInitialize(VOID) { /* Register the BIOS support BOPs */ - RegisterBop(BOP_KBD_IRQ, KbdBiosIRQ); - RegisterBop(BOP_KBD_INT, KbdBiosINT); - + RegisterBop(BOP_KBD_IRQ, KbdBiosIRQ); // BiosKeyboardIrq in kbdbios32.c + RegisterBop(BOP_KBD_INT, KbdBiosINT); // BiosKeyboardService in kbdbios32.c return TRUE; } VOID KbdBiosCleanup(VOID) { + /* Unregister the BIOS support BOPs */ + RegisterBop(BOP_KBD_IRQ, NULL); + RegisterBop(BOP_KBD_INT, NULL); } /* EOF */ diff --git a/reactos/subsystems/mvdm/ntvdm/bios/rom.c b/reactos/subsystems/mvdm/ntvdm/bios/rom.c index f3ff5797a87..3cba9b5bd97 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/rom.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/rom.c @@ -81,22 +81,6 @@ LoadRomFileByHandle(IN HANDLE RomFileHandle, BytesRead); } -static UCHAR -ComputeChecksum(IN ULONG RomLocation, - IN ULONG RomSize) -{ - ULONG RomLastAddress = RomLocation + RomSize; - UCHAR Sum = 0x00; // Using a UCHAR guarantees that we wrap at 0xFF i.e. we do a sum modulo 0x100. - - while (RomLocation < RomLastAddress) - { - Sum += *(PUCHAR)REAL_TO_PHYS(RomLocation); - ++RomLocation; - } - - return Sum; -} - static VOID InitRomRange(IN PCALLBACK16 Context, IN ULONG Start, @@ -115,16 +99,16 @@ InitRomRange(IN PCALLBACK16 Context, /* Check the control sum of the ROM */ /* - * If this is an adapter ROM (Start: C8000, End: E0000), its - * reported size is stored in byte 2 of the ROM. + * If this is an adapter ROM (Start: C8000, End: E0000), + * its reported size is stored in byte 2 of the ROM. * * If this is an expansion ROM (Start: E0000, End: F0000), * its real length is 64kB. */ - RomSize = *(PUCHAR)REAL_TO_PHYS(Address + 2) * 512; + RomSize = *(PUCHAR)REAL_TO_PHYS(Address + 2) * 512; // Size in blocks of 512 bytes if (Address >= 0xE0000) RomSize = 0x10000; - Checksum = ComputeChecksum(Address, RomSize); + Checksum = CalcRomChecksum(Address, RomSize); if (Checksum == 0x00) { EntryPoint = Address + 3; @@ -156,6 +140,29 @@ WriteProtectRom(IN PVOID RomLocation, NULL, ShadowRomWrite); } +BOOLEAN +WriteUnProtectRom(IN PVOID RomLocation, + IN ULONG RomSize) +{ + return MemRemoveFastMemoryHook(RomLocation, RomSize); +} + +UCHAR +CalcRomChecksum(IN ULONG RomLocation, + IN ULONG RomSize) +{ + ULONG RomLastAddress = RomLocation + RomSize; + UCHAR Sum = 0x00; // Using a UCHAR guarantees that we wrap at 0xFF i.e. we do a sum modulo 0x100. + + while (RomLocation < RomLastAddress) + { + Sum += *(PUCHAR)REAL_TO_PHYS(RomLocation); + ++RomLocation; + } + + return Sum; +} + BOOLEAN LoadBios(IN PCSTR BiosFileName, OUT PVOID* BiosLocation OPTIONAL, @@ -242,6 +249,9 @@ LoadRom(IN PCSTR RomFileName, VOID SearchAndInitRoms(IN PCALLBACK16 Context) { + /* Video ROMs -- Start: C0000, End: C8000, 2kB blocks */ + InitRomRange(Context, 0xC0000, 0xC8000, 0x0800); + /* Adapters ROMs -- Start: C8000, End: E0000, 2kB blocks */ InitRomRange(Context, 0xC8000, 0xE0000, 0x0800); diff --git a/reactos/subsystems/mvdm/ntvdm/bios/rom.h b/reactos/subsystems/mvdm/ntvdm/bios/rom.h index 5c74b54e01d..04f172411f6 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/rom.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/rom.h @@ -22,6 +22,14 @@ BOOLEAN WriteProtectRom(IN PVOID RomLocation, IN ULONG RomSize); +BOOLEAN +WriteUnProtectRom(IN PVOID RomLocation, + IN ULONG RomSize); + +UCHAR +CalcRomChecksum(IN ULONG RomLocation, + IN ULONG RomSize); + BOOLEAN LoadBios(IN PCSTR BiosFileName, OUT PVOID* BiosLocation OPTIONAL, diff --git a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c index bdce03298ae..c544c0a47cc 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c @@ -11,6 +11,10 @@ #define NDEBUG +/* BIOS Version number and Copyright */ +#include +#include + #include "ntvdm.h" #include "emulator.h" #include "cpu/cpu.h" @@ -18,17 +22,15 @@ #include "memory.h" #include "bios.h" +#include "bios32/bios32p.h" +#include "rom.h" #include "bios32/vbe.h" // #include "vidbios.h" +#include "bios32/vidbios32.h" #include "io.h" #include "hardware/video/svga.h" -/* DEFINES ********************************************************************/ - -/* BOP Identifiers */ -#define BOP_VIDEO_INT 0x10 - /* MACROS *********************************************************************/ // @@ -41,6 +43,19 @@ /* PRIVATE VARIABLES **********************************************************/ +/* + * WARNING! For compatibility purposes the string "IBM" should be at C000:001E. + */ +static const CHAR BiosInfo[] = + "00000000000 Emulation of IBM VGA Compatible ROM\0" + "CL-GD5434 VGA BIOS Version 1.41 \r\n" + "Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR"\r\n" + "The original CL-GD5434 card was created by Cirrus Logic, Inc.\r\n\0" + "BIOS Date: 06/17/13\0"; + +C_ASSERT(sizeof(BiosInfo)-1 <= 0xFF-0x05); // Ensures that we won't overflow on the Video Code + + /* * VGA Register Configurations for BIOS Video Modes. * The configurations were checked against SeaBIOS VGA BIOS. @@ -3862,8 +3877,12 @@ VOID VidBiosDetachFromConsole(VOID) Attached = FALSE; } -BOOLEAN VidBiosInitialize(VOID) +VOID VidBiosPost(VOID) { + /* + * Initialize VGA BIOS32 RAM dynamic data + */ + /* Some vectors are in fact addresses to tables */ ((PULONG)BaseAddress)[0x1D] = (ULONG)NULL; // Video Parameter Tables // Far pointer to the 8x8 graphics font for the 8x8 characters 80h-FFh @@ -3876,6 +3895,56 @@ BOOLEAN VidBiosInitialize(VOID) ((PULONG)BaseAddress)[0x42] = (ULONG)NULL; // Relocated Default INT 10h Video Services ((PULONG)BaseAddress)[0x6D] = (ULONG)NULL; // Video BIOS Entry Point + // + // FIXME: At the moment we always set a VGA mode. In the future, + // we should set this mode **only** when: + // - an app starts to use directly the video memory + // (that should be done in emulator.c) + // - or starts to use non-stream I/O interrupts + // (that should be done here, or maybe in VGA ??) + // + + Bda->CrtModeControl = 0x00; + Bda->CrtColorPaletteMask = 0x00; + Bda->VGADccIDActive = 0x08; // VGA w/ color analog active display + + /* Set the default video mode */ + VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE); + + /* Synchronize our cursor position with VGA */ + VidBiosSyncCursorPosition(); + + /* Register the BIOS 32-bit Interrupts */ + RegisterBiosInt32(BIOS_VIDEO_INTERRUPT, VidBiosVideoService); + + /* Vectors that should be implemented */ + RegisterBiosInt32(0x42, NULL); // Relocated Default INT 10h Video Services + RegisterBiosInt32(0x6D, NULL); // Video BIOS Entry Point + + /* Initialize VBE */ + VbeInitialized = VbeInitialize(); + if (!VbeInitialized) DPRINT1("Couldn't initialize VBE!\n"); +} + +BOOLEAN VidBiosInitialize(VOID) +{ + UCHAR Checksum; + + /* + * Initialize VGA BIOS32 static data + */ + + /* This is a ROM of size 'VIDEO_BIOS_ROM_SIZE' */ + *(PWORD)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0000)) = 0xAA55; + *(PBYTE)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0002)) = VIDEO_BIOS_ROM_SIZE / 512; // Size in blocks of 512 bytes + + /* Bootstrap code */ + *(PWORD)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0003)) = 0x90CB; // retf, nop + // RtlCopyMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0xFFF0), Bootstrap, sizeof(Bootstrap)); + + /* Video BIOS Information */ + RtlCopyMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, 0x0005), BiosInfo, sizeof(BiosInfo)-1); + /* Initialize the VGA static function table */ VgaStaticFuncTable = SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, VIDEO_STATE_INFO_OFFSET); RtlZeroMemory(VgaStaticFuncTable, sizeof(*VgaStaticFuncTable)); @@ -3896,31 +3965,15 @@ BOOLEAN VidBiosInitialize(VOID) RtlMoveMemory(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, FONT_8x14_OFFSET), Font8x14, sizeof(Font8x14)); - // - // FIXME: At the moment we always set a VGA mode. In the future, - // we should set this mode **only** when: - // - an app starts to use directly the video memory - // (that should be done in emulator.c) - // - or starts to use non-stream I/O interrupts - // (that should be done here, or maybe in VGA ??) - // + VidBios32Initialize(); - Bda->CrtModeControl = 0x00; - Bda->CrtColorPaletteMask = 0x00; - Bda->VGADccIDActive = 0x08; // VGA w/ color analog active display + /* Compute the ROM checksum and store it */ + *(PBYTE)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, VIDEO_BIOS_ROM_SIZE - 1)) = 0x00; + Checksum = CalcRomChecksum(TO_LINEAR(VIDEO_BIOS_DATA_SEG, 0x0000), VIDEO_BIOS_ROM_SIZE); + *(PBYTE)(SEG_OFF_TO_PTR(VIDEO_BIOS_DATA_SEG, VIDEO_BIOS_ROM_SIZE - 1)) = (0xFF - Checksum + 1) & 0xFF; - /* Set the default video mode */ - VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE); - - /* Synchronize our cursor position with VGA */ - VidBiosSyncCursorPosition(); - - /* Register the BIOS support BOPs */ - RegisterBop(BOP_VIDEO_INT, VidBiosVideoService); - - /* Initialize VBE */ - VbeInitialized = VbeInitialize(); - if (!VbeInitialized) DPRINT1("Couldn't initialize VBE!\n"); + WriteProtectRom((PVOID)TO_LINEAR(VIDEO_BIOS_DATA_SEG, 0x0000), + VIDEO_BIOS_ROM_SIZE); return TRUE; } diff --git a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h index 50dafcedf5b..c4970fe8e9d 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h @@ -26,12 +26,14 @@ #define CGA_ODD_VIDEO_SEG 0xBA00 #define VIDEO_BIOS_DATA_SEG 0xC000 -#define FONT_8x8_OFFSET 0x0000 -#define FONT_8x8_HIGH_OFFSET 0x0400 -#define FONT_8x16_OFFSET 0x0800 -#define FONT_8x14_OFFSET 0x1800 +#define FONT_8x8_OFFSET 0x0100 +#define FONT_8x8_HIGH_OFFSET 0x0500 +#define FONT_8x16_OFFSET 0x0900 +#define FONT_8x14_OFFSET 0x1900 -#define VIDEO_STATE_INFO_OFFSET 0x3000 // == 0x1800 + (sizeof(Font8x14) == 0x0E00) + 0x0A00 for padding +#define VIDEO_STATE_INFO_OFFSET 0x3000 // == 0x1900 + (sizeof(Font8x14) == 0x0E00) + 0x0900 for padding + +#define VIDEO_BIOS_ROM_SIZE 0x4000 typedef enum { @@ -109,6 +111,7 @@ VOID WINAPI VidBiosVideoService(LPWORD Stack); VOID VidBiosDetachFromConsole(VOID); VOID VidBiosAttachToConsole(VOID); +VOID VidBiosPost(VOID); BOOLEAN VidBiosInitialize(VOID); VOID VidBiosCleanup(VOID); diff --git a/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c b/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c index 390c1d26b75..87ba6caa3f0 100644 --- a/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c +++ b/reactos/subsystems/mvdm/ntvdm/hardware/cmos.c @@ -222,6 +222,12 @@ static BYTE CmosReadData(VOID) break; } + case CMOS_REG_CENTURY: + { + Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wYear / 100 + 19); + break; + } + case CMOS_REG_STATUS_C: { /* Return the old value */ @@ -363,6 +369,12 @@ static VOID CmosWriteData(BYTE Value) break; } + case CMOS_REG_CENTURY: + { + UNIMPLEMENTED; + break; + } + case CMOS_REG_STATUS_A: { CmosMemory.StatusRegA = Value & 0x7F; // Bit 7 is read-only diff --git a/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h b/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h index ac243ad9b5a..23d486cb0e2 100644 --- a/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h +++ b/reactos/subsystems/mvdm/ntvdm/hardware/cmos.h @@ -18,22 +18,24 @@ #define CMOS_BATTERY_OK 0x80 /* Status Register B flags */ +#define CMOS_STB_DST (1 << 0) #define CMOS_STB_24HOUR (1 << 1) #define CMOS_STB_BINARY (1 << 2) #define CMOS_STB_SQUARE_WAVE (1 << 3) #define CMOS_STB_INT_ON_UPDATE (1 << 4) #define CMOS_STB_INT_ON_ALARM (1 << 5) #define CMOS_STB_INT_PERIODIC (1 << 6) +#define CMOS_STB_UPDATE_CYCLE (1 << 7) /* Status Register C flags */ -#define CMOS_STC_UF CMOS_STB_INT_ON_UPDATE -#define CMOS_STC_AF CMOS_STB_INT_ON_ALARM -#define CMOS_STC_PF CMOS_STB_INT_PERIODIC +#define CMOS_STC_UF (1 << 4) +#define CMOS_STC_AF (1 << 5) +#define CMOS_STC_PF (1 << 6) #define CMOS_STC_IRQF (1 << 7) /* Default register values */ -#define CMOS_DEFAULT_STA 0x26 -#define CMOS_DEFAULT_STB CMOS_STB_24HOUR +#define CMOS_DEFAULT_STA 0x26 +#define CMOS_DEFAULT_STB CMOS_STB_24HOUR #define WRITE_CMOS_DATA(Cmos, Value) \ ((Cmos).StatusRegB & CMOS_STB_BINARY) ? (Value) : BCD_TO_BINARY(Value) @@ -65,6 +67,7 @@ typedef enum _CMOS_REGISTERS CMOS_REG_EXT_MEMORY_HIGH = 0x18, CMOS_REG_ACTUAL_EXT_MEMORY_LOW = 0x30, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH = 0x31, + CMOS_REG_CENTURY = 0x32, CMOS_REG_MAX = 0x40 } CMOS_REGISTERS, *PCMOS_REGISTERS; @@ -107,6 +110,8 @@ typedef struct BYTE StatusRegD; // 0x0d BYTE Diagnostics; // 0x0e BYTE ShutdownStatus; // 0x0f + BYTE Padding[0x22]; // 0x10 + BYTE Century; // 0x32 }; BYTE Regs1[0x10]; // 0x00 - 0x0f BYTE Regs [0x40]; // 0x00 - 0x3f diff --git a/reactos/subsystems/mvdm/ntvdm/ntvdm.c b/reactos/subsystems/mvdm/ntvdm/ntvdm.c index ac247dbb538..84bf6feb349 100644 --- a/reactos/subsystems/mvdm/ntvdm/ntvdm.c +++ b/reactos/subsystems/mvdm/ntvdm/ntvdm.c @@ -526,6 +526,25 @@ wmain(INT argc, WCHAR *argv[]) #endif +#ifdef ADVANCED_DEBUGGING + { + INT i = 20; + + printf("Waiting for debugger (10 secs).."); + while (i--) + { + printf("."); + if (IsDebuggerPresent()) + { + DbgBreakPoint(); + break; + } + Sleep(500); + } + printf("Continue\n"); + } +#endif + /* Load global VDM settings */ LoadGlobalSettings(); @@ -549,8 +568,8 @@ wmain(INT argc, WCHAR *argv[]) goto Cleanup; } - /* Initialize the system BIOS */ - if (!BiosInitialize(NULL)) + /* Initialize the system BIOS and option ROMs */ + if (!BiosInitialize(NULL, NULL)) { wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n"); goto Cleanup; diff --git a/reactos/subsystems/mvdm/ntvdm/ntvdm.h b/reactos/subsystems/mvdm/ntvdm/ntvdm.h index 08044dd77b3..825971ef5a9 100644 --- a/reactos/subsystems/mvdm/ntvdm/ntvdm.h +++ b/reactos/subsystems/mvdm/ntvdm/ntvdm.h @@ -63,6 +63,10 @@ DWORD WINAPI SetLastConsoleEventActive(VOID); */ // #define ADVANCED_DEBUGGING +#ifdef ADVANCED_DEBUGGING +#define ADVANCED_DEBUGGING_LEVEL 1 +#endif + /* FUNCTIONS ******************************************************************/ extern HANDLE VdmTaskEvent;