ReactOS 0.4.15-dev-8021-g7ce96fd
cmos.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/cmos.c
5 * PURPOSE: CMOS Real Time Clock emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "ntvdm.h"
12
13#define NDEBUG
14#include <debug.h>
15
16#include "emulator.h"
17#include "cmos.h"
18
19#include "io.h"
20#include "pic.h"
21#include "clock.h"
22
23/* PRIVATE VARIABLES **********************************************************/
24
25#define CMOS_RAM_FILE "cmos.ram"
26
29
32
35
36/* PRIVATE FUNCTIONS **********************************************************/
37
39{
40 BYTE RateSelect = CmosMemory.StatusRegA & 0x0F;
41
42 if (RateSelect == 0)
43 {
44 /* No periodic interrupt */
46 return;
47 }
48
49 /* 1 and 2 act like 8 and 9 */
50 if (RateSelect <= 2) RateSelect += 7;
51
52 SetHardwareTimerDelay(PeriodicTimer, HZ_TO_NS(1 << (16 - RateSelect)));
53 // FIXME: This call keeps EnableCount increasing without compensating it!
55}
56
58{
59 UNREFERENCED_PARAMETER(ElapsedTime);
60
61 /* Set PF */
63
64 /* Check if there should be an interrupt on a periodic timer tick */
65 if (CmosMemory.StatusRegB & CMOS_STB_INT_PERIODIC)
66 {
68
69 /* Interrupt! */
71 }
72}
73
74/* Should be called every second */
76{
77 SYSTEMTIME CurrentTime;
78
79 UNREFERENCED_PARAMETER(ElapsedTime);
80
81 /* Get the current time */
82 GetLocalTime(&CurrentTime);
83
84 /* Set UF */
86
87 /* Check if the time matches the alarm time */
88 if ((CurrentTime.wHour == CmosMemory.AlarmHour ) &&
89 (CurrentTime.wMinute == CmosMemory.AlarmMinute) &&
90 (CurrentTime.wSecond == CmosMemory.AlarmSecond))
91 {
92 /* Set the alarm flag */
94
95 /* Set IRQF if there should be an interrupt */
97 }
98
99 /* Check if there should be an interrupt on update */
101
103 {
104 /* Interrupt! */
106 }
107}
108
110{
112
113 /* Update the NMI enabled flag */
115
116 /* Get the register number */
117 Data &= ~CMOS_DISABLE_NMI;
118
119 if (Data < CMOS_REG_MAX)
120 {
121 /* Select the new register */
123 }
124 else
125 {
126 /* Default to Status Register D */
128 }
129}
130
132{
133 BYTE Value;
134 SYSTEMTIME CurrentTime;
135
137
138 /* Get the current time */
139 GetLocalTime(&CurrentTime);
140
141 switch (SelectedRegister)
142 {
143 case CMOS_REG_SECONDS:
144 {
145 Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wSecond);
146 break;
147 }
148
150 {
152 break;
153 }
154
155 case CMOS_REG_MINUTES:
156 {
157 Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wMinute);
158 break;
159 }
160
162 {
164 break;
165 }
166
167 case CMOS_REG_HOURS:
168 {
169 BOOLEAN Afternoon = FALSE;
170 Value = CurrentTime.wHour;
171
172 if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
173 {
174 Value -= 12;
175 Afternoon = TRUE;
176 }
177
179
180 /* Convert to 12-hour */
181 if (Afternoon) Value |= 0x80;
182
183 break;
184 }
185
187 {
188 BOOLEAN Afternoon = FALSE;
189 Value = CmosMemory.AlarmHour;
190
191 if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
192 {
193 Value -= 12;
194 Afternoon = TRUE;
195 }
196
198
199 /* Convert to 12-hour */
200 if (Afternoon) Value |= 0x80;
201
202 break;
203 }
204
206 {
207 /*
208 * The CMOS value is 1-based but the
209 * GetLocalTime API value is 0-based.
210 * Correct it.
211 */
212 Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wDayOfWeek + 1);
213 break;
214 }
215
216 case CMOS_REG_DAY:
217 {
218 Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wDay);
219 break;
220 }
221
222 case CMOS_REG_MONTH:
223 {
224 Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wMonth);
225 break;
226 }
227
228 case CMOS_REG_YEAR:
229 {
230 Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wYear % 100);
231 break;
232 }
233
234 case CMOS_REG_CENTURY:
235 {
236 Value = READ_CMOS_DATA(CmosMemory, CurrentTime.wYear / 100 + 19);
237 break;
238 }
239
241 {
242 /* Return the old status register value, then clear it */
244 CmosMemory.StatusRegC = 0x00;
245 break;
246 }
247
253 default:
254 {
255 // ASSERT(SelectedRegister < CMOS_REG_MAX);
257 }
258 }
259
260 /* Return to Status Register D */
262
263 return Value;
264}
265
267{
268 BOOLEAN ChangeTime = FALSE;
269 SYSTEMTIME CurrentTime;
270
272
273 /* Get the current time */
274 GetLocalTime(&CurrentTime);
275
276 switch (SelectedRegister)
277 {
278 case CMOS_REG_SECONDS:
279 {
280 ChangeTime = TRUE;
281 CurrentTime.wSecond = WRITE_CMOS_DATA(CmosMemory, Data);
282 break;
283 }
284
286 {
288 break;
289 }
290
291 case CMOS_REG_MINUTES:
292 {
293 ChangeTime = TRUE;
294 CurrentTime.wMinute = WRITE_CMOS_DATA(CmosMemory, Data);
295 break;
296 }
297
299 {
301 break;
302 }
303
304 case CMOS_REG_HOURS:
305 {
306 BOOLEAN Afternoon = FALSE;
307
308 ChangeTime = TRUE;
309
310 if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Data & 0x80))
311 {
312 Data &= ~0x80;
313 Afternoon = TRUE;
314 }
315
316 CurrentTime.wHour = WRITE_CMOS_DATA(CmosMemory, Data);
317
318 /* Convert to 24-hour format */
319 if (Afternoon) CurrentTime.wHour += 12;
320
321 break;
322 }
323
325 {
326 BOOLEAN Afternoon = FALSE;
327
328 if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Data & 0x80))
329 {
330 Data &= ~0x80;
331 Afternoon = TRUE;
332 }
333
335
336 /* Convert to 24-hour format */
337 if (Afternoon) CmosMemory.AlarmHour += 12;
338
339 break;
340 }
341
343 {
344 ChangeTime = TRUE;
345 /*
346 * The CMOS value is 1-based but the
347 * SetLocalTime API value is 0-based.
348 * Correct it.
349 */
350 Data -= 1;
352 break;
353 }
354
355 case CMOS_REG_DAY:
356 {
357 ChangeTime = TRUE;
358 CurrentTime.wDay = WRITE_CMOS_DATA(CmosMemory, Data);
359 break;
360 }
361
362 case CMOS_REG_MONTH:
363 {
364 ChangeTime = TRUE;
365 CurrentTime.wMonth = WRITE_CMOS_DATA(CmosMemory, Data);
366 break;
367 }
368
369 case CMOS_REG_YEAR:
370 {
371 ChangeTime = TRUE;
372
373 /* Clear everything except the century */
374 CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
375 CurrentTime.wYear += WRITE_CMOS_DATA(CmosMemory, Data);
376 break;
377 }
378
379 case CMOS_REG_CENTURY:
380 {
382 break;
383 }
384
386 {
387 CmosMemory.StatusRegA = Data & 0x7F; // Bit 7 is read-only
389 break;
390 }
391
393 {
394 CmosMemory.StatusRegB = Data;
395 break;
396 }
397
400 // Status registers C and D are read-only
401 break;
402
403 /* Is the following correct? */
406 {
407 /* Sync EMS and UMS */
410 break;
411 }
412
413 /* Is the following correct? */
416 {
417 /* Sync EMS and UMS */
420 break;
421 }
422
423 default:
424 {
426 }
427 }
428
429 if (ChangeTime) SetLocalTime(&CurrentTime);
430
431 /* Return to Status Register D */
433}
434
435
436/* PUBLIC FUNCTIONS ***********************************************************/
437
439{
440 return NmiEnabled;
441}
442
443static inline BOOL
449{
451 ULONG Written;
452
455 if (BytesWritten)
456 *BytesWritten = (Success ? Written : 0);
457 return Success;
458}
459
461{
463 WCHAR CmosPath[_countof(NtVdmPath) + _countof("\\" CMOS_RAM_FILE)];
464
465 /* CMOS file must not be opened before */
467
468 /* Always open (and if needed, create) a RAM file with shared access */
470 sizeof(CmosPath),
471 L"%s\\" L(CMOS_RAM_FILE),
472 NtVdmPath));
473 if (!Success)
474 DPRINT1("Could not create CMOS file path!\n");
475
476 if (Success)
477 {
479 hCmosRam = CreateFileW(CmosPath,
482 NULL,
485 NULL);
487 if (!Success)
488 DPRINT1("CMOS opening failed (Error: %u)\n", GetLastError());
489 }
490
491 /* Clear the CMOS memory */
493
494 /* Load the file only if it already existed and was opened, not newly created */
495 if (Success)
496 {
497 if ((GetLastError() == ERROR_ALREADY_EXISTS) /* || (GetLastError() == ERROR_FILE_EXISTS) */)
498 {
499 /* Attempt to load the CMOS memory from the RAM file */
500 DWORD CmosSize = sizeof(CmosMemory);
501 Success = ReadFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
502 if (!Success)
503 {
504 DPRINT1("CMOS loading failed (Error: %u)\n", GetLastError());
505 }
506 else if (CmosSize != sizeof(CmosMemory))
507 {
508 /* Invalid CMOS RAM file; reinitialize the CMOS memory */
509 DPRINT1("Invalid CMOS file, read %u bytes, expected %u bytes\n",
510 CmosSize, sizeof(CmosMemory));
511 Success = FALSE;
512 }
513 if (!Success)
514 {
515 /* Reset the CMOS memory and its RAM file */
518 }
519 }
520 else
521 {
522 /* Reset the CMOS RAM file */
524 }
526 }
527
528 /* Overwrite some registers with default values */
529 CmosMemory.StatusRegA = CMOS_DEFAULT_STA;
530 CmosMemory.StatusRegB = CMOS_DEFAULT_STB;
531 CmosMemory.StatusRegC = 0x00;
532 CmosMemory.StatusRegD = CMOS_BATTERY_OK; // Our CMOS battery works perfectly forever.
533 CmosMemory.Diagnostics = 0x00; // Diagnostics must not find any errors.
536
537 // HACK: For the moment, set the boot sequence to: 1-Floppy, 2-Hard Disk .
538 CmosMemory.Regs[CMOS_REG_SYSOP] |= (1 << 5);
539
540 /* Memory settings */
541
542 /*
543 * Conventional memory size is 640 kB,
544 * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
545 * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
546 * for more information.
547 */
550
552 CmosMemory.ActualExtMemoryLow = LOBYTE((MAX_ADDRESS - 0x100000) / 1024);
554 CmosMemory.ActualExtMemoryHigh = HIBYTE((MAX_ADDRESS - 0x100000) / 1024);
555
556 /* Register the I/O Ports */
559
561 HZ_TO_NS(1),
564 HZ_TO_NS(1000),
566}
567
569{
572
574 {
575 /* Flush the CMOS memory back to the RAM file and close it */
577 DWORD CmosSize = sizeof(CmosMemory);
578
579 Success = CmosWriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize);
580 if (!Success || (CmosSize != sizeof(CmosMemory)))
581 {
582 DPRINT1("CMOS saving failed (Error: %u), written %u bytes, expected %u bytes\n",
583 GetLastError(), CmosSize, sizeof(CmosMemory));
584 }
585
588 }
589}
590
591/* EOF */
unsigned char BOOLEAN
#define MAX_ADDRESS
#define DPRINT1
Definition: precomp.h:8
#define UNIMPLEMENTED
Definition: debug.h:115
Definition: bufpool.h:45
#define HARDWARE_TIMER_ENABLED
Definition: clock.h:15
#define HARDWARE_TIMER_PRECISE
Definition: clock.h:17
#define HZ_TO_NS(Freq)
Definition: clock.h:20
#define CMOS_STB_INT_ON_ALARM
Definition: cmos.h:26
#define CMOS_STB_24HOUR
Definition: cmos.h:22
#define CMOS_STC_AF
Definition: cmos.h:32
enum _CMOS_REGISTERS CMOS_REGISTERS
#define CMOS_BATTERY_OK
Definition: cmos.h:18
#define RTC_IRQ_NUMBER
Definition: cmos.h:14
#define CMOS_EQUIPMENT_LIST
Definition: cmos.h:41
#define CMOS_DISABLE_NMI
Definition: cmos.h:17
#define CMOS_STC_IRQF
Definition: cmos.h:34
#define CMOS_STB_INT_ON_UPDATE
Definition: cmos.h:25
#define CMOS_STC_UF
Definition: cmos.h:31
@ CMOS_REG_DAY
Definition: cmos.h:59
@ CMOS_REG_STATUS_A
Definition: cmos.h:62
@ CMOS_REG_EXT_MEMORY_HIGH
Definition: cmos.h:72
@ CMOS_REG_ALARM_HRS
Definition: cmos.h:57
@ CMOS_REG_ACTUAL_EXT_MEMORY_LOW
Definition: cmos.h:74
@ CMOS_REG_SHUTDOWN_STATUS
Definition: cmos.h:67
@ CMOS_REG_STATUS_B
Definition: cmos.h:63
@ CMOS_REG_MAX
Definition: cmos.h:77
@ CMOS_REG_MONTH
Definition: cmos.h:60
@ CMOS_REG_MINUTES
Definition: cmos.h:54
@ CMOS_REG_DAY_OF_WEEK
Definition: cmos.h:58
@ CMOS_REG_EXT_MEMORY_LOW
Definition: cmos.h:71
@ CMOS_REG_ALARM_MIN
Definition: cmos.h:55
@ CMOS_REG_STATUS_C
Definition: cmos.h:64
@ CMOS_REG_YEAR
Definition: cmos.h:61
@ CMOS_REG_SECONDS
Definition: cmos.h:52
@ CMOS_REG_HOURS
Definition: cmos.h:56
@ CMOS_REG_DIAGNOSTICS
Definition: cmos.h:66
@ CMOS_REG_ALARM_SEC
Definition: cmos.h:53
@ CMOS_REG_ACTUAL_EXT_MEMORY_HIGH
Definition: cmos.h:75
@ CMOS_REG_CENTURY
Definition: cmos.h:76
@ CMOS_REG_STATUS_D
Definition: cmos.h:65
@ CMOS_REG_SYSOP
Definition: cmos.h:73
#define CMOS_STB_INT_PERIODIC
Definition: cmos.h:27
#define READ_CMOS_DATA(Cmos, Value)
Definition: cmos.h:47
#define CMOS_ADDRESS_PORT
Definition: cmos.h:15
#define CMOS_STC_PF
Definition: cmos.h:33
#define CMOS_DEFAULT_STB
Definition: cmos.h:38
#define WRITE_CMOS_DATA(Cmos, Value)
Definition: cmos.h:44
#define CMOS_DEFAULT_STA
Definition: cmos.h:37
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define CloseHandle
Definition: compat.h:739
#define FILE_BEGIN
Definition: compat.h:761
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define SetFilePointer
Definition: compat.h:743
#define SetLastError(x)
Definition: compat.h:752
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define CreateFileW
Definition: compat.h:741
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define FILE_SHARE_READ
Definition: compat.h:136
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
BOOL WINAPI SetLocalTime(IN CONST SYSTEMTIME *lpSystemTime)
Definition: time.c:356
VOID WINAPI GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:286
@ Success
Definition: eventcreate.c:712
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
#define CMOS_DATA_PORT
Definition: halhw.h:12
CPPORT Port[4]
Definition: headless.c:35
#define LOBYTE(W)
Definition: jmemdos.c:487
#define HIBYTE(W)
Definition: jmemdos.c:486
#define ASSERT(a)
Definition: mode.c:44
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
#define OPEN_ALWAYS
Definition: disk.h:70
#define _Out_opt_
Definition: ms_sal.h:346
#define _In_
Definition: ms_sal.h:308
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define FASTCALL
Definition: nt_native.h:50
#define GENERIC_WRITE
Definition: nt_native.h:90
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
NTSTRSAFEVAPI RtlStringCbPrintfW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1173
WCHAR NtVdmPath[MAX_PATH]
Definition: ntvdm.c:35
#define L(x)
Definition: ntvdm.h:50
unsigned short USHORT
Definition: pedump.c:61
#define _countof(array)
Definition: sndvol32.h:68
BYTE StatusRegD
Definition: cmos.h:116
BYTE ActualExtMemoryHigh
Definition: cmos.h:131
BYTE ExtMemoryHigh
Definition: cmos.h:127
BYTE ShutdownStatus
Definition: cmos.h:118
BYTE EquipmentList
Definition: cmos.h:123
BYTE ExtMemoryLow
Definition: cmos.h:126
BYTE BaseMemoryHigh
Definition: cmos.h:125
BYTE Diagnostics
Definition: cmos.h:117
BYTE StatusRegC
Definition: cmos.h:115
BYTE Regs[0x40]
Definition: cmos.h:135
BYTE ActualExtMemoryLow
Definition: cmos.h:130
BYTE BaseMemoryLow
Definition: cmos.h:124
WORD wYear
Definition: winbase.h:905
WORD wMonth
Definition: winbase.h:906
WORD wHour
Definition: winbase.h:909
WORD wSecond
Definition: winbase.h:911
WORD wMinute
Definition: winbase.h:910
WORD wDay
Definition: winbase.h:908
WORD wDayOfWeek
Definition: winbase.h:907
PHARDWARE_TIMER CreateHardwareTimer(ULONG Flags, ULONGLONG Delay, PHARDWARE_TIMER_PROC Callback)
Definition: clock.c:144
VOID DisableHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:183
VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:210
VOID EnableHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:161
VOID SetHardwareTimerDelay(PHARDWARE_TIMER Timer, ULONGLONG NewDelay)
Definition: clock.c:197
BOOLEAN IsNmiEnabled(VOID)
Definition: cmos.c:438
static BOOLEAN NmiEnabled
Definition: cmos.c:30
static VOID FASTCALL RtcTimeUpdate(ULONGLONG ElapsedTime)
Definition: cmos.c:75
static VOID WINAPI CmosWriteAddress(USHORT Port, BYTE Data)
Definition: cmos.c:109
static CMOS_MEMORY CmosMemory
Definition: cmos.c:28
static BOOL CmosWriteFile(_In_ HANDLE FileHandle, _In_ PVOID Buffer, _In_ ULONG BufferSize, _Out_opt_ PULONG BytesWritten)
Definition: cmos.c:444
static VOID RtcUpdatePeriodicTimer(VOID)
Definition: cmos.c:38
static BYTE WINAPI CmosReadData(USHORT Port)
Definition: cmos.c:131
static VOID FASTCALL RtcPeriodicTick(ULONGLONG ElapsedTime)
Definition: cmos.c:57
VOID CmosCleanup(VOID)
Definition: cmos.c:568
static HANDLE hCmosRam
Definition: cmos.c:27
static PHARDWARE_TIMER ClockTimer
Definition: cmos.c:33
VOID CmosInitialize(VOID)
Definition: cmos.c:460
static CMOS_REGISTERS SelectedRegister
Definition: cmos.c:31
#define CMOS_RAM_FILE
Definition: cmos.c:25
static VOID WINAPI CmosWriteData(USHORT Port, BYTE Data)
Definition: cmos.c:266
static PHARDWARE_TIMER PeriodicTimer
Definition: cmos.c:34
VOID PicInterruptRequest(BYTE Number)
Definition: pic.c:192
VOID RegisterIoPort(USHORT Port, EMULATOR_INB_PROC InHandler, EMULATOR_OUTB_PROC OutHandler)
Definition: io.c:320
uint32_t * PULONG
Definition: typedefs.h:59
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define WINAPI
Definition: msvc.h:6
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193