1 
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <string.h>
5 
6 #include <sys/kassert.h>
7 #include <sys/kdebug.h>
8 #include <sys/ktime.h>
9 
10 #include "ioport.h"
11 
12 #define RTC_SECONDS	0x00
13 #define RTC_MINUTES	0x02
14 #define RTC_HOURS	0x04
15 #define RTC_WEEKDAY	0x06
16 #define RTC_DAY		0x07
17 #define RTC_MONTH	0x08
18 #define RTC_YEAR	0x09
19 
20 UnixEpoch RTC_ReadTime();
21 
22 void
RTC_Init()23 RTC_Init()
24 {
25     uint64_t startTSC, stopTSC;
26     UnixEpoch first, second;
27 
28     kprintf("RTC: Measuring CPU clock...\n");
29 
30     first = RTC_ReadTime();
31     while (1) {
32 	second = RTC_ReadTime();
33 	if (first != second)
34 	    break;
35 	first = second;
36     }
37     startTSC = Time_GetTSC();
38 
39     first = RTC_ReadTime();
40     while (1) {
41 	second = RTC_ReadTime();
42 	if (first != second)
43 	    break;
44 	first = second;
45     }
46     stopTSC = Time_GetTSC();
47 
48     kprintf("RTC: %lld Ticks Per Second: %lld\n", second, stopTSC - startTSC);
49 
50     KTime_SetTime(second, stopTSC, stopTSC - startTSC);
51 }
52 
53 static inline uint8_t
RTC_ReadReg(uint8_t reg)54 RTC_ReadReg(uint8_t reg)
55 {
56     outb(0x70, reg);
57     return inb(0x71);
58 }
59 
60 UnixEpoch
RTC_ReadTime()61 RTC_ReadTime()
62 {
63     KTime tm;
64     bool isPM = false;
65     uint8_t flags = RTC_ReadReg(0x0B);
66 
67     // Read RTC
68     tm.sec = RTC_ReadReg(RTC_SECONDS);
69     tm.min = RTC_ReadReg(RTC_MINUTES);
70     tm.hour = RTC_ReadReg(RTC_HOURS);
71     tm.wday = RTC_ReadReg(RTC_WEEKDAY);
72     tm.mday = RTC_ReadReg(RTC_DAY);
73     tm.month = RTC_ReadReg(RTC_MONTH);
74     tm.year = RTC_ReadReg(RTC_YEAR);
75 
76     // Convert BCD & 24-hour checks
77     if (tm.hour & 0x80) {
78 	isPM = true;
79     }
80     if ((flags & 0x04) == 0) {
81 #define BCD_TO_BIN(_B) ((_B & 0x0F) + ((_B >> 4) * 10))
82 	tm.sec = BCD_TO_BIN(tm.sec);
83 	tm.min = BCD_TO_BIN(tm.min);
84 	tm.hour = BCD_TO_BIN((tm.hour & 0x7F));
85 	tm.wday = BCD_TO_BIN(tm.wday);
86 	tm.mday = BCD_TO_BIN(tm.mday);
87 	tm.month = BCD_TO_BIN(tm.month);
88 	tm.year = BCD_TO_BIN(tm.year);
89     }
90     if (((flags & 0x02) == 0) && isPM) {
91 	tm.hour = (tm.hour + 12) % 24;
92     }
93 
94     tm.year += 2000;
95     tm.yday = -1;
96 
97     tm.wday -= 1;
98     tm.month -= 1;
99 
100 //    KTime_SetTime(&tm);
101     return KTime_ToEpoch(&tm);
102 }
103 
104