Basic X86 RTC code

This commit is contained in:
Ali Mashtizadeh 2014-11-22 14:35:18 -08:00
parent 1b82af5c11
commit d9b68fc462
3 changed files with 136 additions and 0 deletions

View File

@ -31,6 +31,7 @@ src_amd64 = [
"dev/x86/debugcons.c",
"dev/x86/ide.c",
"dev/x86/ps2.c",
"dev/x86/rtc.c",
"dev/x86/sercons.c",
"dev/x86/vgacons.c",
]

View File

@ -22,6 +22,7 @@
#include "../dev/console.h"
extern void RTC_Init();
extern void PS2_Init();
extern void PCI_Init();
extern void IDE_Init();
@ -140,6 +141,8 @@ void Machine_Init()
IOAPIC_Enable(0); // Enable timer interrupts
Thread_Init();
RTC_Init();
PS2_Init();
PCI_Init();
IDE_Init();

132
sys/dev/x86/rtc.c Normal file
View File

@ -0,0 +1,132 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/spinlock.h>
#include "ioport.h"
#define RTC_SECONDS 0x00
#define RTC_MINUTES 0x02
#define RTC_HOURS 0x04
#define RTC_WEEKDAY 0x06
#define RTC_DAY 0x07
#define RTC_MONTH 0x08
#define RTC_YEAR 0x09
uint64_t RTC_ReadTime();
void
RTC_Init()
{
RTC_ReadTime();
}
static inline uint8_t
RTC_ReadReg(uint8_t reg)
{
outb(0x70, reg);
return inb(0x71);
}
static bool
RTC_IsLeapYear(uint64_t year)
{
if ((year % 4) != 0)
return false;
if ((year % 100) != 0)
return true;
if ((year % 400) != 0)
return false;
return true;
}
static int
RTC_DaysInMonth(uint64_t year, uint64_t month)
{
static const uint64_t days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ((month == 2) && RTC_IsLeapYear(year))
return 29;
else
return days[month];
}
static const char *dayOfWeek[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char *months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
uint64_t
RTC_ReadTime()
{
uint64_t days = 0;
uint64_t secs = 0;
uint64_t y, m;
// Read RTC
bool isPM = false;
uint64_t seconds = RTC_ReadReg(RTC_SECONDS);
uint64_t minutes = RTC_ReadReg(RTC_MINUTES);
uint64_t hours = RTC_ReadReg(RTC_HOURS);
uint64_t weekday = RTC_ReadReg(RTC_WEEKDAY);
uint64_t day = RTC_ReadReg(RTC_DAY);
uint64_t month = RTC_ReadReg(RTC_MONTH);
uint64_t year = RTC_ReadReg(RTC_YEAR);
uint8_t flags = RTC_ReadReg(0x0B);
// Convert BCD & 24-hour checks
if (hours & 0x80) {
isPM = true;
}
if ((flags & 0x04) == 0) {
#define BCD_TO_BIN(_B) ((_B & 0x0F) + ((_B >> 4) * 10))
seconds = BCD_TO_BIN(seconds);
minutes = BCD_TO_BIN(minutes);
hours = BCD_TO_BIN((hours & 0x7F));
weekday = BCD_TO_BIN(weekday);
day = BCD_TO_BIN(day);
month = BCD_TO_BIN(month);
year = BCD_TO_BIN(year);
}
if (((flags & 0x02) == 0) && isPM) {
hours = (hours + 12) % 24;
}
year += 2000;
kprintf("RTC: %s %s %d %02d:%02d:%02d %04d\n",
dayOfWeek[weekday - 1], months[month - 1],
day, hours, minutes, seconds, year);
// Convert to UNIX epoch
for (y = 1970; y < year; y++) {
if (RTC_IsLeapYear(y))
days += 366;
else
days += 365;
}
for (m = 0; m < month; m++) {
days += RTC_DaysInMonth(year, month);
}
days += day;
secs = 24 * days + hours;
secs = secs * 60 + minutes;
secs = secs * 60 + seconds;
return secs;
}
void
Debug_Date()
{
RTC_ReadTime();
}
REGISTER_DBGCMD(date, "Print date", Debug_Date);