[NTVDM]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 10 Nov 2013 13:12:02 +0000 (13:12 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 10 Nov 2013 13:12:02 +0000 (13:12 +0000)
- BIOS: Reorganize a bit the header, and close the input thread before closing the input handle (and not after).
- INT32: Fix a comment.
- CMOS: Put CMOS data into a structure called CMOS_MEMORY, introduce READ/WRITE_CMOS_DATA macros for simplifying code. Save CMOS memory into a file (à la Windows' NTVDM), which is loaded at startup.

svn path=/branches/ntvdm/; revision=60913

subsystems/ntvdm/bios.c
subsystems/ntvdm/bios.h
subsystems/ntvdm/cmos.c
subsystems/ntvdm/cmos.h
subsystems/ntvdm/emulator.c
subsystems/ntvdm/int32.c
subsystems/ntvdm/ntvdm.c

index 6f026e6..2363e5b 100644 (file)
@@ -568,6 +568,9 @@ BOOLEAN BiosInitialize(VOID)
 
 VOID BiosCleanup(VOID)
 {
 
 VOID BiosCleanup(VOID)
 {
+    /* Close the input thread handle */
+    if (InputThread != NULL) CloseHandle(InputThread);
+
     /* Restore the old screen buffer */
     SetConsoleActiveScreenBuffer(BiosConsoleOutput);
 
     /* Restore the old screen buffer */
     SetConsoleActiveScreenBuffer(BiosConsoleOutput);
 
@@ -577,9 +580,6 @@ VOID BiosCleanup(VOID)
     /* Close the console handles */
     if (BiosConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleOutput);
     if (BiosConsoleInput  != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleInput);
     /* Close the console handles */
     if (BiosConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleOutput);
     if (BiosConsoleInput  != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleInput);
-
-    /* Close the input thread handle */
-    if (InputThread != NULL) CloseHandle(InputThread);
 }
 
 WORD BiosPeekCharacter(VOID)
 }
 
 WORD BiosPeekCharacter(VOID)
index e89292d..7ca303c 100644 (file)
@@ -15,8 +15,8 @@
 
 /* DEFINES ********************************************************************/
 
 
 /* DEFINES ********************************************************************/
 
-#define ROM_AREA_START 0xE0000
-#define ROM_AREA_END 0xFFFFF
+#define ROM_AREA_START  0xE0000
+#define ROM_AREA_END    0xFFFFF
 
 #define BDA_SEGMENT     0x40
 #define BIOS_SEGMENT    0xF000
 
 #define BDA_SEGMENT     0x40
 #define BIOS_SEGMENT    0xF000
 #define CONSOLE_FONT_HEIGHT 8
 #define BIOS_KBD_BUFFER_SIZE 16
 #define BIOS_EQUIPMENT_LIST 0x2C // HACK: Disable FPU for now
 #define CONSOLE_FONT_HEIGHT 8
 #define BIOS_KBD_BUFFER_SIZE 16
 #define BIOS_EQUIPMENT_LIST 0x2C // HACK: Disable FPU for now
+
 #define BIOS_DEFAULT_VIDEO_MODE 0x03
 #define BIOS_MAX_PAGES 8
 #define BIOS_PAGE_SIZE 0x1000
 #define BIOS_MAX_VIDEO_MODE 0x13
 #define BIOS_DEFAULT_VIDEO_MODE 0x03
 #define BIOS_MAX_PAGES 8
 #define BIOS_PAGE_SIZE 0x1000
 #define BIOS_MAX_VIDEO_MODE 0x13
-#define DEFAULT_ATTRIBUTE 0x07
-#define GRAPHICS_VIDEO_SEG 0xA000
-#define TEXT_VIDEO_SEG 0xB800
+#define DEFAULT_ATTRIBUTE   0x07
+
+#define GRAPHICS_VIDEO_SEG  0xA000
+#define TEXT_VIDEO_SEG      0xB800
 
 #define BDA_KBDFLAG_RSHIFT      (1 << 0)
 #define BDA_KBDFLAG_LSHIFT      (1 << 1)
 
 #define BDA_KBDFLAG_RSHIFT      (1 << 0)
 #define BDA_KBDFLAG_LSHIFT      (1 << 1)
@@ -67,8 +69,6 @@ enum
     SCROLL_DIRECTION_RIGHT
 };
 
     SCROLL_DIRECTION_RIGHT
 };
 
-#pragma pack(push, 1)
-
 /*
  * BIOS Data Area at 0040:XXXX
  *
 /*
  * BIOS Data Area at 0040:XXXX
  *
@@ -76,6 +76,7 @@ enum
  * and: http://www.bioscentral.com/misc/bda.htm
  * for more information.
  */
  * and: http://www.bioscentral.com/misc/bda.htm
  * for more information.
  */
+#pragma pack(push, 1)
 typedef struct
 {
     WORD SerialPorts[4];                        // 0x00
 typedef struct
 {
     WORD SerialPorts[4];                        // 0x00
@@ -142,11 +143,10 @@ typedef struct
     BYTE Reserved17[15];                        // 0x121
     BYTE Reserved18[3];                         // 0x130
 } BIOS_DATA_AREA, *PBIOS_DATA_AREA;
     BYTE Reserved17[15];                        // 0x121
     BYTE Reserved18[3];                         // 0x130
 } BIOS_DATA_AREA, *PBIOS_DATA_AREA;
+#pragma pack(pop)
 
 C_ASSERT(sizeof(BIOS_DATA_AREA) == 0x133);
 
 
 C_ASSERT(sizeof(BIOS_DATA_AREA) == 0x133);
 
-#pragma pack(pop)
-
 /* FUNCTIONS ******************************************************************/
 
 extern PBIOS_DATA_AREA Bda;
 /* FUNCTIONS ******************************************************************/
 
 extern PBIOS_DATA_AREA Bda;
index be67438..f982bb3 100644 (file)
 
 /* PRIVATE VARIABLES **********************************************************/
 
 
 /* PRIVATE VARIABLES **********************************************************/
 
+static HANDLE hCmosRam = INVALID_HANDLE_VALUE;
+static CMOS_MEMORY CmosMemory;
+
 static BOOLEAN NmiEnabled = TRUE;
 static BOOLEAN NmiEnabled = TRUE;
-static BYTE StatusRegA = CMOS_DEFAULT_STA;
-static BYTE StatusRegB = CMOS_DEFAULT_STB;
-static BYTE StatusRegC = 0;
-static BYTE AlarmHour, AlarmMinute, AlarmSecond;
 static CMOS_REGISTERS SelectedRegister = CMOS_REG_STATUS_D;
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 static CMOS_REGISTERS SelectedRegister = CMOS_REG_STATUS_D;
 
 /* PUBLIC FUNCTIONS ***********************************************************/
@@ -59,45 +58,29 @@ BYTE CmosReadData(VOID)
     switch (SelectedRegister)
     {
         case CMOS_REG_SECONDS:
     switch (SelectedRegister)
     {
         case CMOS_REG_SECONDS:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? CurrentTime.wSecond
-                   : BINARY_TO_BCD(CurrentTime.wSecond);
-        }
+            return READ_CMOS_DATA(CmosMemory, CurrentTime.wSecond);
 
         case CMOS_REG_ALARM_SEC:
 
         case CMOS_REG_ALARM_SEC:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? AlarmSecond
-                   : BINARY_TO_BCD(AlarmSecond);
-        }
+            return READ_CMOS_DATA(CmosMemory, CmosMemory.AlarmSecond);
 
         case CMOS_REG_MINUTES:
 
         case CMOS_REG_MINUTES:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? CurrentTime.wMinute
-                   : BINARY_TO_BCD(CurrentTime.wMinute);
-        }
+            return READ_CMOS_DATA(CmosMemory, CurrentTime.wMinute);
 
         case CMOS_REG_ALARM_MIN:
 
         case CMOS_REG_ALARM_MIN:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? AlarmMinute
-                   : BINARY_TO_BCD(AlarmMinute);
-        }
+            return READ_CMOS_DATA(CmosMemory, CmosMemory.AlarmMinute);
 
         case CMOS_REG_HOURS:
         {
             BOOLEAN Afternoon = FALSE;
             BYTE Value = CurrentTime.wHour;
 
 
         case CMOS_REG_HOURS:
         {
             BOOLEAN Afternoon = FALSE;
             BYTE Value = CurrentTime.wHour;
 
-            if (!(StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
+            if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
             {
                 Value -= 12;
                 Afternoon = TRUE;
             }
 
             {
                 Value -= 12;
                 Afternoon = TRUE;
             }
 
-            if (!(StatusRegB & CMOS_STB_BINARY)) Value = BINARY_TO_BCD(Value);
+            Value = READ_CMOS_DATA(CmosMemory, Value);
 
             /* Convert to 12-hour */
             if (Afternoon) Value |= 0x80;
 
             /* Convert to 12-hour */
             if (Afternoon) Value |= 0x80;
@@ -108,15 +91,15 @@ BYTE CmosReadData(VOID)
         case CMOS_REG_ALARM_HRS:
         {
             BOOLEAN Afternoon = FALSE;
         case CMOS_REG_ALARM_HRS:
         {
             BOOLEAN Afternoon = FALSE;
-            BYTE Value = AlarmHour;
+            BYTE Value = CmosMemory.AlarmHour;
 
 
-            if (!(StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
+            if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
             {
                 Value -= 12;
                 Afternoon = TRUE;
             }
 
             {
                 Value -= 12;
                 Afternoon = TRUE;
             }
 
-            if (!(StatusRegB & CMOS_STB_BINARY)) Value = BINARY_TO_BCD(Value);
+            Value = READ_CMOS_DATA(CmosMemory, Value);
 
             /* Convert to 12-hour */
             if (Afternoon) Value |= 0x80;
 
             /* Convert to 12-hour */
             if (Afternoon) Value |= 0x80;
@@ -125,70 +108,42 @@ BYTE CmosReadData(VOID)
         }
 
         case CMOS_REG_DAY_OF_WEEK:
         }
 
         case CMOS_REG_DAY_OF_WEEK:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? CurrentTime.wDayOfWeek
-                   : BINARY_TO_BCD(CurrentTime.wDayOfWeek);
-        }
+            /*
+             * The CMOS value is 1-based but the
+             * GetLocalTime API value is 0-based.
+             * Correct it.
+             */
+            return READ_CMOS_DATA(CmosMemory, CurrentTime.wDayOfWeek + 1);
 
         case CMOS_REG_DAY:
 
         case CMOS_REG_DAY:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? CurrentTime.wDay
-                   :BINARY_TO_BCD(CurrentTime.wDay);
-        }
+            return READ_CMOS_DATA(CmosMemory, CurrentTime.wDay);
 
         case CMOS_REG_MONTH:
 
         case CMOS_REG_MONTH:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? CurrentTime.wMonth
-                   : BINARY_TO_BCD(CurrentTime.wMonth);
-        }
+            return READ_CMOS_DATA(CmosMemory, CurrentTime.wMonth);
 
         case CMOS_REG_YEAR:
 
         case CMOS_REG_YEAR:
-        {
-            return (StatusRegB & CMOS_STB_BINARY)
-                   ? (CurrentTime.wYear % 100)
-                   : BINARY_TO_BCD(CurrentTime.wYear % 100);
-        }
-
-        case CMOS_REG_STATUS_A:
-        {
-            return StatusRegA;
-        }
-
-        case CMOS_REG_STATUS_B:
-        {
-            return StatusRegB;
-        }
+            return READ_CMOS_DATA(CmosMemory, CurrentTime.wYear % 100);
 
         case CMOS_REG_STATUS_C:
         {
 
         case CMOS_REG_STATUS_C:
         {
-            BYTE Value = StatusRegC;
+            BYTE Value = CmosMemory.StatusRegC;
 
             /* Clear status register C */
 
             /* Clear status register C */
-            StatusRegC = 0;
+            CmosMemory.StatusRegC = 0x00;
 
             /* Return the old value */
             return Value;
         }
 
 
             /* Return the old value */
             return Value;
         }
 
+        case CMOS_REG_STATUS_A:
+        case CMOS_REG_STATUS_B:
         case CMOS_REG_STATUS_D:
         case CMOS_REG_STATUS_D:
-        {
-            /* Our CMOS battery works perfectly forever */
-            return CMOS_BATTERY_OK;
-        }
-
         case CMOS_REG_DIAGNOSTICS:
         case CMOS_REG_DIAGNOSTICS:
-        {
-            /* Diagnostics found no errors */
-            return 0;
-        }
-
+        case CMOS_REG_SHUTDOWN_STATUS:
         default:
         {
         default:
         {
-            /* Read ignored */
-            return 0;
+            // ASSERT(SelectedRegister < CMOS_REG_MAX);
+            return CmosMemory.Regs[SelectedRegister];
         }
     }
 
         }
     }
 
@@ -209,38 +164,26 @@ VOID CmosWriteData(BYTE Value)
         case CMOS_REG_SECONDS:
         {
             ChangeTime = TRUE;
         case CMOS_REG_SECONDS:
         {
             ChangeTime = TRUE;
-            CurrentTime.wSecond = (StatusRegB & CMOS_STB_BINARY)
-                                  ? Value
-                                  : BCD_TO_BINARY(Value);
-
+            CurrentTime.wSecond = WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
         case CMOS_REG_ALARM_SEC:
         {
             break;
         }
 
         case CMOS_REG_ALARM_SEC:
         {
-            AlarmSecond = (StatusRegB & CMOS_STB_BINARY)
-                          ? Value
-                          : BCD_TO_BINARY(Value);
-
+            CmosMemory.AlarmSecond = WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
         case CMOS_REG_MINUTES:
         {
             ChangeTime = TRUE;
             break;
         }
 
         case CMOS_REG_MINUTES:
         {
             ChangeTime = TRUE;
-            CurrentTime.wMinute = (StatusRegB & CMOS_STB_BINARY)
-                                  ? Value
-                                  : BCD_TO_BINARY(Value);
-
+            CurrentTime.wMinute = WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
         case CMOS_REG_ALARM_MIN:
         {
             break;
         }
 
         case CMOS_REG_ALARM_MIN:
         {
-            AlarmMinute = (StatusRegB & CMOS_STB_BINARY)
-                          ? Value
-                          : BCD_TO_BINARY(Value);
-
+            CmosMemory.AlarmMinute = WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
             break;
         }
 
@@ -250,15 +193,13 @@ VOID CmosWriteData(BYTE Value)
 
             ChangeTime = TRUE;
 
 
             ChangeTime = TRUE;
 
-            if (!(StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
+            if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
             {
                 Value &= ~0x80;
                 Afternoon = TRUE;
             }
 
             {
                 Value &= ~0x80;
                 Afternoon = TRUE;
             }
 
-            CurrentTime.wHour = (StatusRegB & CMOS_STB_BINARY)
-                                ? Value
-                                : BCD_TO_BINARY(Value);
+            CurrentTime.wHour = WRITE_CMOS_DATA(CmosMemory, Value);
 
             /* Convert to 24-hour format */
             if (Afternoon) CurrentTime.wHour += 12;
 
             /* Convert to 24-hour format */
             if (Afternoon) CurrentTime.wHour += 12;
@@ -270,18 +211,16 @@ VOID CmosWriteData(BYTE Value)
         {
             BOOLEAN Afternoon = FALSE;
 
         {
             BOOLEAN Afternoon = FALSE;
 
-            if (!(StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
+            if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
             {
                 Value &= ~0x80;
                 Afternoon = TRUE;
             }
 
             {
                 Value &= ~0x80;
                 Afternoon = TRUE;
             }
 
-            AlarmHour = (StatusRegB & CMOS_STB_BINARY)
-                        ? Value
-                        : BCD_TO_BINARY(Value);
+            CmosMemory.AlarmHour = WRITE_CMOS_DATA(CmosMemory, Value);
 
             /* Convert to 24-hour format */
 
             /* Convert to 24-hour format */
-            if (Afternoon) AlarmHour += 12;
+            if (Afternoon) CmosMemory.AlarmHour += 12;
 
             break;
         }
 
             break;
         }
@@ -289,30 +228,27 @@ VOID CmosWriteData(BYTE Value)
         case CMOS_REG_DAY_OF_WEEK:
         {
             ChangeTime = TRUE;
         case CMOS_REG_DAY_OF_WEEK:
         {
             ChangeTime = TRUE;
-            CurrentTime.wDayOfWeek = (StatusRegB & CMOS_STB_BINARY)
-                                     ? Value
-                                     : BCD_TO_BINARY(Value);
-
+            /*
+             * The CMOS value is 1-based but the
+             * SetLocalTime API value is 0-based.
+             * Correct it.
+             */
+            Value -= 1;
+            CurrentTime.wDayOfWeek = WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
         case CMOS_REG_DAY:
         {
             ChangeTime = TRUE;
             break;
         }
 
         case CMOS_REG_DAY:
         {
             ChangeTime = TRUE;
-            CurrentTime.wDay = (StatusRegB & CMOS_STB_BINARY)
-                               ? Value
-                               : BCD_TO_BINARY(Value);
-
+            CurrentTime.wDay = WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
         case CMOS_REG_MONTH:
         {
             ChangeTime = TRUE;
             break;
         }
 
         case CMOS_REG_MONTH:
         {
             ChangeTime = TRUE;
-            CurrentTime.wMonth = (StatusRegB & CMOS_STB_BINARY)
-                                 ? Value
-                                 : BCD_TO_BINARY(Value);
-
+            CurrentTime.wMonth = WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
             break;
         }
 
@@ -323,28 +259,30 @@ VOID CmosWriteData(BYTE Value)
             /* Clear everything except the century */
             CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
 
             /* Clear everything except the century */
             CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
 
-            CurrentTime.wYear += (StatusRegB & CMOS_STB_BINARY)
-                                 ? Value
-                                 : BCD_TO_BINARY(Value);
-
+            CurrentTime.wYear += WRITE_CMOS_DATA(CmosMemory, Value);
             break;
         }
 
         case CMOS_REG_STATUS_A:
         {
             break;
         }
 
         case CMOS_REG_STATUS_A:
         {
-            StatusRegA = Value;
+            CmosMemory.StatusRegA = Value & 0x7F; // Bit 7 is read-only
             break;
         }
 
         case CMOS_REG_STATUS_B:
         {
             break;
         }
 
         case CMOS_REG_STATUS_B:
         {
-            StatusRegB = Value;
+            CmosMemory.StatusRegB = Value;
             break;
         }
 
             break;
         }
 
+        case CMOS_REG_STATUS_C:
+        case CMOS_REG_STATUS_D:
+            // Status registers C and D are read-only
+            break;
+
         default:
         {
         default:
         {
-            /* Write ignored */
+            CmosMemory.Regs[SelectedRegister] = Value;
         }
     }
 
         }
     }
 
@@ -356,7 +294,7 @@ VOID CmosWriteData(BYTE Value)
 
 DWORD RtcGetTicksPerSecond(VOID)
 {
 
 DWORD RtcGetTicksPerSecond(VOID)
 {
-    BYTE RateSelect = StatusRegB & 0x0F;
+    BYTE RateSelect = CmosMemory.StatusRegB & 0x0F;
 
     if (RateSelect == 0)
     {
 
     if (RateSelect == 0)
     {
@@ -373,12 +311,12 @@ DWORD RtcGetTicksPerSecond(VOID)
 VOID RtcPeriodicTick(VOID)
 {
     /* Set PF */
 VOID RtcPeriodicTick(VOID)
 {
     /* Set PF */
-    StatusRegC |= CMOS_STC_PF;
+    CmosMemory.StatusRegC |= CMOS_STC_PF;
 
     /* Check if there should be an interrupt on a periodic timer tick */
 
     /* Check if there should be an interrupt on a periodic timer tick */
-    if (StatusRegB & CMOS_STB_INT_PERIODIC)
+    if (CmosMemory.StatusRegB & CMOS_STB_INT_PERIODIC)
     {
     {
-        StatusRegC |= CMOS_STC_IRQF;
+        CmosMemory.StatusRegC |= CMOS_STC_IRQF;
 
         /* Interrupt! */
         PicInterruptRequest(RTC_IRQ_NUMBER);
 
         /* Interrupt! */
         PicInterruptRequest(RTC_IRQ_NUMBER);
@@ -394,26 +332,91 @@ VOID RtcTimeUpdate(VOID)
     GetLocalTime(&CurrentTime);
 
     /* Set UF */
     GetLocalTime(&CurrentTime);
 
     /* Set UF */
-    StatusRegC |= CMOS_STC_UF;
+    CmosMemory.StatusRegC |= CMOS_STC_UF;
 
     /* Check if the time matches the alarm time */
 
     /* Check if the time matches the alarm time */
-    if ((CurrentTime.wHour == AlarmHour)
-        && (CurrentTime.wMinute == AlarmMinute)
-        && (CurrentTime.wSecond == AlarmSecond))
+    if ((CurrentTime.wHour   == CmosMemory.AlarmHour  ) &&
+        (CurrentTime.wMinute == CmosMemory.AlarmMinute) &&
+        (CurrentTime.wSecond == CmosMemory.AlarmSecond))
     {
         /* Set the alarm flag */
     {
         /* Set the alarm flag */
-        StatusRegC |= CMOS_STC_AF;
+        CmosMemory.StatusRegC |= CMOS_STC_AF;
 
         /* Set IRQF if there should be an interrupt */
 
         /* Set IRQF if there should be an interrupt */
-        if (StatusRegB & CMOS_STB_INT_ON_ALARM) StatusRegC |= CMOS_STC_IRQF;
+        if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_ALARM) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
     }
 
     /* Check if there should be an interrupt on update */
     }
 
     /* Check if there should be an interrupt on update */
-    if (StatusRegB & CMOS_STB_INT_ON_UPDATE) StatusRegC |= CMOS_STC_IRQF;
+    if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_UPDATE) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
 
 
-    if (StatusRegC & CMOS_STC_IRQF)
+    if (CmosMemory.StatusRegC & CMOS_STC_IRQF)
     {
         /* Interrupt! */
         PicInterruptRequest(RTC_IRQ_NUMBER);
     }
 }
     {
         /* Interrupt! */
         PicInterruptRequest(RTC_IRQ_NUMBER);
     }
 }
+
+BOOLEAN CmosInitialize(VOID)
+{
+    DWORD CmosSize = sizeof(CmosMemory);
+
+    /* File must not be opened before */
+    ASSERT(hCmosRam == INVALID_HANDLE_VALUE);
+
+    /* Clear the CMOS memory */
+    ZeroMemory(&CmosMemory, sizeof(CmosMemory));
+
+    /* Always open (and if needed, create) a RAM file with exclusive access */
+    SetLastError(0); // For debugging purposes
+    hCmosRam = CreateFileW(L"cmos.ram",
+                           GENERIC_READ | GENERIC_WRITE,
+                           0,
+                           NULL,
+                           OPEN_ALWAYS,
+                           FILE_ATTRIBUTE_NORMAL,
+                           NULL);
+    DPRINT1("CMOS opening %s ; GetLastError() = %u\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
+
+    if (hCmosRam != INVALID_HANDLE_VALUE)
+    {
+        BOOL Success = FALSE;
+
+        /* Attempt to fill the CMOS memory with the RAM file */
+        SetLastError(0); // For debugging purposes
+        Success = ReadFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
+        if (CmosSize != sizeof(CmosMemory))
+        {
+            /* Bad CMOS Ram file. Reinitialize the CMOS memory. */
+            DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n", CmosSize, sizeof(CmosMemory));
+            ZeroMemory(&CmosMemory, sizeof(CmosMemory));
+        }
+        DPRINT1("CMOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
+        SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
+    }
+
+    /* Overwrite some registers with default values */
+    CmosMemory.StatusRegA     = CMOS_DEFAULT_STA;
+    CmosMemory.StatusRegB     = CMOS_DEFAULT_STB;
+    CmosMemory.StatusRegC     = 0x00;
+    CmosMemory.StatusRegD     = CMOS_BATTERY_OK; // Our CMOS battery works perfectly forever.
+    CmosMemory.Diagnostics    = 0x00;            // Diagnostics must not find any errors.
+    CmosMemory.ShutdownStatus = 0x00;
+
+    return TRUE;
+}
+
+VOID CmosCleanup(VOID)
+{
+    DWORD CmosSize = sizeof(CmosMemory);
+
+    if (hCmosRam == INVALID_HANDLE_VALUE) return;
+
+    /* Flush the CMOS memory back to the RAM file and close it */
+    SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
+    WriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
+
+    CloseHandle(hCmosRam);
+    hCmosRam = INVALID_HANDLE_VALUE;
+}
+
+/* EOF */
index 5f7f632..6caec7b 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:       GPL - See COPYING in the top level directory
  * PROJECT:         ReactOS Virtual DOS Machine
  * FILE:            cmos.h
  * COPYRIGHT:       GPL - See COPYING in the top level directory
  * PROJECT:         ReactOS Virtual DOS Machine
  * FILE:            cmos.h
- * PURPOSE:         Real Time Clock emulation (header file)
+ * PURPOSE:         CMOS Real Time Clock emulation
  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  */
 
  * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  */
 
 #define BINARY_TO_BCD(x) (((x / 10) << 4) | (x % 10))
 #define BCD_TO_BINARY(x) (((x >> 4) * 10) + (x & 0x0F))
 
 #define BINARY_TO_BCD(x) (((x / 10) << 4) | (x % 10))
 #define BCD_TO_BINARY(x) (((x >> 4) * 10) + (x & 0x0F))
 
+#define WRITE_CMOS_DATA(Cmos, Value)    \
+    ((Cmos).StatusRegB & CMOS_STB_BINARY) ? (Value) : BCD_TO_BINARY(Value)
+
+#define READ_CMOS_DATA(Cmos, Value)     \
+    ((Cmos).StatusRegB & CMOS_STB_BINARY) ? (Value) : BINARY_TO_BCD(Value)
+
 typedef enum _CMOS_REGISTERS
 {
     CMOS_REG_SECONDS,
 typedef enum _CMOS_REGISTERS
 {
     CMOS_REG_SECONDS,
@@ -60,9 +66,63 @@ typedef enum _CMOS_REGISTERS
     CMOS_REG_STATUS_C,
     CMOS_REG_STATUS_D,
     CMOS_REG_DIAGNOSTICS,
     CMOS_REG_STATUS_C,
     CMOS_REG_STATUS_D,
     CMOS_REG_DIAGNOSTICS,
-    CMOS_REG_MAX
+    CMOS_REG_SHUTDOWN_STATUS,
+    CMOS_REG_MAX = 0x40
 } CMOS_REGISTERS, *PCMOS_REGISTERS;
 
 } CMOS_REGISTERS, *PCMOS_REGISTERS;
 
+
+/*
+ * CMOS Memory Map
+ *
+ * See the following documentation for more information:
+ * http://www.intel-assembler.it/portale/5/cmos-memory-map-123/cmos-memory-map-123.asp
+ * http://wiki.osdev.org/CMOS
+ * http://www.bioscentral.com/misc/cmosmap.htm
+ */
+#pragma pack(push, 1)
+typedef struct
+{
+    BYTE Second;        // 0x00
+    BYTE AlarmSecond;   // 0x01
+    BYTE Minute;        // 0x02
+    BYTE AlarmMinute;   // 0x03
+    BYTE Hour;          // 0x04
+    BYTE AlarmHour;     // 0x05
+    BYTE DayOfWeek;     // 0x06
+    BYTE Day;           // 0x07
+    BYTE Month;         // 0x08
+    BYTE Year;          // 0x09
+
+    BYTE StatusRegA;    // 0x0a
+    BYTE StatusRegB;    // 0x0b
+} CMOS_CLOCK, *PCMOS_CLOCK;
+
+typedef struct
+{
+    union
+    {
+        struct
+        {
+            CMOS_CLOCK;             // 0x00 - 0x0b
+            BYTE StatusRegC;        // 0x0c
+            BYTE StatusRegD;        // 0x0d
+            BYTE Diagnostics;       // 0x0e
+            BYTE ShutdownStatus;    // 0x0f
+        };
+        BYTE Regs1[0x10];           // 0x00 - 0x0f
+        BYTE Regs [0x40];           // 0x00 - 0x3f
+    };
+
+    /*
+     * Extended information 0x40 - 0x7f
+     */
+} CMOS_MEMORY, *PCMOS_MEMORY;
+#pragma pack(pop)
+
+C_ASSERT(sizeof(CMOS_MEMORY) == 0x40);
+
+/* FUNCTIONS ******************************************************************/
+
 BOOLEAN IsNmiEnabled(VOID);
 VOID CmosWriteAddress(BYTE Value);
 BYTE CmosReadData(VOID);
 BOOLEAN IsNmiEnabled(VOID);
 VOID CmosWriteAddress(BYTE Value);
 BYTE CmosReadData(VOID);
@@ -70,7 +130,10 @@ VOID CmosWriteData(BYTE Value);
 DWORD RtcGetTicksPerSecond(VOID);
 VOID RtcPeriodicTick(VOID);
 VOID RtcTimeUpdate(VOID);
 DWORD RtcGetTicksPerSecond(VOID);
 VOID RtcPeriodicTick(VOID);
 VOID RtcTimeUpdate(VOID);
-    
+
+BOOLEAN CmosInitialize(VOID);
+VOID CmosCleanup(VOID);
+
 #endif // _CMOS_H_
 
 /* EOF */
 #endif // _CMOS_H_
 
 /* EOF */
index 742112c..94e0f0a 100644 (file)
@@ -11,6 +11,7 @@
 #define NDEBUG
 
 #include "emulator.h"
 #define NDEBUG
 
 #include "emulator.h"
+#include "cmos.h"
 #include "bios.h"
 #include "bop.h"
 #include "dos.h"
 #include "bios.h"
 #include "bop.h"
 #include "dos.h"
@@ -19,7 +20,6 @@
 #include "pic.h"
 #include "ps2.h"
 #include "timer.h"
 #include "pic.h"
 #include "ps2.h"
 #include "timer.h"
-#include "cmos.h"
 
 /* PRIVATE VARIABLES **********************************************************/
 
 
 /* PRIVATE VARIABLES **********************************************************/
 
index 8916b5b..9fcf573 100644 (file)
@@ -163,7 +163,7 @@ VOID WINAPI InitializeInt32(WORD BiosSegment)
         // HACK: The following instruction should be HLT!
         BiosCode[Offset++] = 0x90; // nop
 
         // HACK: The following instruction should be HLT!
         BiosCode[Offset++] = 0x90; // nop
 
-        BiosCode[Offset++] = 0xEB; // jmp BOP_SEQ (offset -10)
+        BiosCode[Offset++] = 0xEB; // jmp BOP_SEQ (offset -11)
         BiosCode[Offset++] = 0xF5;
 
 // EXIT:
         BiosCode[Offset++] = 0xF5;
 
 // EXIT:
index a26f08f..974559d 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "ntvdm.h"
 #include "emulator.h"
 
 #include "ntvdm.h"
 #include "emulator.h"
+#include "cmos.h"
 #include "bios.h"
 #include "speaker.h"
 #include "vga.h"
 #include "bios.h"
 #include "speaker.h"
 #include "vga.h"
@@ -19,7 +20,6 @@
 #include "timer.h"
 #include "pic.h"
 #include "ps2.h"
 #include "timer.h"
 #include "pic.h"
 #include "ps2.h"
-#include "cmos.h"
 
 /*
  * Activate this line if you want to be able to test NTVDM with:
 
 /*
  * Activate this line if you want to be able to test NTVDM with:
@@ -117,6 +117,13 @@ INT wmain(INT argc, WCHAR *argv[])
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
+    /* Initialize the CMOS */
+    if (!CmosInitialize())
+    {
+        wprintf(L"FATAL: Failed to initialize the VDM CMOS.\n");
+        goto Cleanup;
+    }
+
     /* Initialize the system BIOS */
     if (!BiosInitialize())
     {
     /* Initialize the system BIOS */
     if (!BiosInitialize())
     {
@@ -227,6 +234,7 @@ INT wmain(INT argc, WCHAR *argv[])
 Cleanup:
     SpeakerCleanup();
     BiosCleanup();
 Cleanup:
     SpeakerCleanup();
     BiosCleanup();
+    CmosCleanup();
     EmulatorCleanup();
 
     DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");
     EmulatorCleanup();
 
     DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");