2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018-2019 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
25 #define PORT_DATA 0x71
27 /* CMOS RTC registers */
29 #define REG_ALARM_SEC 1
31 #define REG_ALARM_MIN 3
33 #define REG_ALARM_HOUR 5
43 #define STATA_BUSY (1 << 7)
44 #define STATB_24HR (1 << 1)
45 #define STATB_BIN (1 << 2)
47 #define HOUR_PM_BIT (1 << 7)
49 #define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf))
51 static void read_rtc(struct tm *tm);
52 static int read_reg(int reg);
60 start_time = mktime(&tm);
62 printf("System real-time clock: %s", asctime(&tm));
66 static void read_rtc(struct tm *tm)
70 /* wait for any clock updates to finish */
71 while(read_reg(REG_STATA) & STATA_BUSY);
73 tm->tm_sec = read_reg(REG_SEC);
74 tm->tm_min = read_reg(REG_MIN);
75 tm->tm_hour = read_reg(REG_HOUR);
76 tm->tm_mday = read_reg(REG_DAY);
77 tm->tm_mon = read_reg(REG_MONTH);
78 tm->tm_year = read_reg(REG_YEAR);
80 /* in 12hour mode, bit 7 means post-meridiem */
81 pm = tm->tm_hour & HOUR_PM_BIT;
82 tm->tm_hour &= ~HOUR_PM_BIT;
84 /* convert to binary if needed */
85 statb = read_reg(REG_STATB);
86 if(!(statb & STATB_BIN)) {
87 tm->tm_sec = BCD_TO_BIN(tm->tm_sec);
88 tm->tm_min = BCD_TO_BIN(tm->tm_min);
89 tm->tm_hour = BCD_TO_BIN(tm->tm_hour);
90 tm->tm_mday = BCD_TO_BIN(tm->tm_mday);
91 tm->tm_mon = BCD_TO_BIN(tm->tm_mon);
92 tm->tm_year = BCD_TO_BIN(tm->tm_year);
95 /* make the year an offset from 1900 */
96 if(tm->tm_year < 100) {
102 /* if tm_hour is in 12h mode, convert to 24h */
103 if(!(statb & STATB_24HR)) {
104 if(tm->tm_hour == 12) {
112 tm->tm_mon -= 1; /* we want months to start from 0 */
115 static int read_reg(int reg)
120 val = inb(PORT_DATA);