diff --git a/etc/make/conf.mk b/etc/make/conf.mk index c7e5b8b..fb358ee 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -74,7 +74,8 @@ OBJS+=$(O)/sys/debug.o \ $(O)/sys/random.o \ $(O)/sys/init.o \ $(O)/sys/vfs/vfs_ops.o \ - $(O)/sys/vfs/vfs_access.o + $(O)/sys/vfs/vfs_access.o \ + $(O)/sys/time.o # \ $(O)/sys/vfs/pty.o \ diff --git a/include/sys/amd64/hw/rtc.h b/include/sys/amd64/hw/rtc.h index 7ccca18..1c6c43e 100644 --- a/include/sys/amd64/hw/rtc.h +++ b/include/sys/amd64/hw/rtc.h @@ -1,16 +1,6 @@ #pragma once #include "sys/types.h" -struct rtc_time { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t weekday; - uint8_t day; - uint8_t month; - uint16_t year; -}; - -void rtc_read(struct rtc_time *time); +void rtc_read(struct tm *time); void rtc_set_century(uint8_t c); void rtc_init(void); diff --git a/include/sys/time.h b/include/sys/time.h index b85f317..46de5c7 100644 --- a/include/sys/time.h +++ b/include/sys/time.h @@ -19,5 +19,12 @@ struct timespec { typedef uint64_t time_t; #if defined(__KERNEL__) +struct tm; + +// Nanoseconds since boot extern uint64_t system_time; +// Seconds since epoch +extern time_t system_boot_time; + +time_t mktime(struct tm *tm); #endif diff --git a/include/sys/types.h b/include/sys/types.h index 2a2986a..c06286c 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -5,6 +5,20 @@ #define NULL ((void *) 0) #endif +#if defined(__KERNEL__) +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; +#endif + typedef uint64_t uintptr_t; typedef int64_t intptr_t; diff --git a/sys/amd64/hw/rtc.c b/sys/amd64/hw/rtc.c index 0158fe9..1491000 100644 --- a/sys/amd64/hw/rtc.c +++ b/sys/amd64/hw/rtc.c @@ -50,16 +50,16 @@ static inline uint8_t cmos_read_time(uint8_t reg, uint8_t reg_b) { } } -void rtc_read(struct rtc_time *time) { +void rtc_read(struct tm *time) { uint8_t reg_b = cmos_inb(RTC_REGB_STATUS); - time->second = cmos_read_time(RTC_REG_SECOND, reg_b); - time->minute = cmos_read_time(RTC_REG_MINUTE, reg_b); - time->hour = cmos_read_time(RTC_REG_HOUR, reg_b); - time->weekday = cmos_read_time(RTC_REG_WEEKDAY, reg_b); - time->day = cmos_read_time(RTC_REG_DAY, reg_b); - time->month = cmos_read_time(RTC_REG_MONTH, reg_b); - time->year = cmos_read_time(RTC_REG_YEAR, reg_b) + 100 * rtc_century; + time->tm_sec = cmos_read_time(RTC_REG_SECOND, reg_b); + time->tm_min = cmos_read_time(RTC_REG_MINUTE, reg_b); + time->tm_hour = cmos_read_time(RTC_REG_HOUR, reg_b); + //time->tm_wday = cmos_read_time(RTC_REG_WEEKDAY, reg_b); + time->tm_mday = cmos_read_time(RTC_REG_DAY, reg_b); + time->tm_mon = cmos_read_time(RTC_REG_MONTH, reg_b); + time->tm_year = cmos_read_time(RTC_REG_YEAR, reg_b) + 100 * rtc_century; } static uint32_t rtc_irq(void *ctx) { @@ -94,25 +94,7 @@ void rtc_set_century(uint8_t century) { } void rtc_init(void) { - static const char *day_names[] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const char *month_names[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", - "Aug", "Sep", "Oct", "Nov", "Dec" - }; - - struct rtc_time time; - cmos_inb(RTC_REGC_STATUS); irq_add_leg_handler(8, rtc_irq, NULL); rtc_enable_irq(); - - rtc_read(&time); - kdebug("%s %02u %s %04u %02u:%02u:%02u\n", - day_names[(time.weekday - 1) % 7], - time.day, - month_names[(time.month - 1) % 12], - time.year, - time.hour, time.minute, time.second); } diff --git a/sys/amd64/hw/timer.c b/sys/amd64/hw/timer.c index 4590ddf..43581c1 100644 --- a/sys/amd64/hw/timer.c +++ b/sys/amd64/hw/timer.c @@ -21,7 +21,6 @@ #define PIT_CMD 0x43 uint64_t int_timer_ticks = 0; -uint64_t system_time = 0; static uint32_t timer_tick(void *arg) { switch ((uint64_t) arg) { diff --git a/sys/amd64/kernel.c b/sys/amd64/kernel.c index 30433c4..defdef7 100644 --- a/sys/amd64/kernel.c +++ b/sys/amd64/kernel.c @@ -28,12 +28,7 @@ static multiboot_info_t *multiboot_info; static void amd64_make_random_seed(void) { - struct rtc_time t; - rtc_read(&t); - - uint64_t s = 137831; - s += t.second + t.minute * 60 + t.hour * 3600 + t.day * 86400; - random_init(s + system_time); + random_init(15267 + system_time); } void kernel_main(struct amd64_loader_data *data) { @@ -64,6 +59,14 @@ void kernel_main(struct amd64_loader_data *data) { amd64_apic_init(); rtc_init(); + // Setup system time + struct tm t; + rtc_read(&t); + system_boot_time = mktime(&t); + kinfo("Boot time: %04u-%02u-%02u %02u:%02u:%02u\n", + t.tm_year, t.tm_mon, t.tm_mday, + t.tm_hour, t.tm_min, t.tm_sec); + pci_init(); vfs_init(); diff --git a/sys/amd64/sys_sys.c b/sys/amd64/sys_sys.c index 563f533..28f5292 100644 --- a/sys/amd64/sys_sys.c +++ b/sys/amd64/sys_sys.c @@ -62,14 +62,8 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz) { tz->tz_minuteswest = 0; } - uint64_t secs = system_time / 1000000000ULL; - - struct rtc_time time_rtc; - rtc_read(&time_rtc); - secs += time_rtc.second + time_rtc.minute * 60 + time_rtc.hour * 3600; - + uint64_t secs = system_time / 1000000000ULL + system_boot_time; // System time is in nanos - // TODO: use RTC-provided time for full system time tv->tv_usec = (system_time / 1000) % 1000000; tv->tv_sec = secs; diff --git a/sys/time.c b/sys/time.c new file mode 100644 index 0000000..6b03d51 --- /dev/null +++ b/sys/time.c @@ -0,0 +1,49 @@ +#include "sys/time.h" +#include "sys/types.h" + +#define leap_days_to_1970 477 + +uint64_t system_time = 0; +time_t system_boot_time = 0; + +static const int days_to_month365[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +}; + +static const int days_to_month366[] = { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 +}; + +static inline int is_leap(int year) { + return (year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0))); +} + +static int tm_check(const struct tm *tm) { + return tm->tm_mday < 0 || tm->tm_mday > 31 || + tm->tm_mon < 0 || tm->tm_mon > 12 || + tm->tm_year < 1970 || tm->tm_year > 2500 || + tm->tm_hour < 0 || tm->tm_hour > 23 || + tm->tm_min < 0 || tm->tm_min > 59 || + tm->tm_sec < 0 || tm->tm_sec > 59; +} + +time_t mktime(struct tm *tm) { + if (tm_check(tm) != 0) { + return 0; + } + + // Calculate year day when month starts + int month_startd = (is_leap(tm->tm_year) ? days_to_month366 : days_to_month365)[tm->tm_mon - 1]; + + // Calculate number of days from epoch to year start + int prev_year = tm->tm_year; + int days_before = ((prev_year - 1970) * 365) + (prev_year) / 4 - (prev_year) / 100 + (prev_year / 400) - leap_days_to_1970; + + // Add number of seconds in epoch days + time_t result = days_before + month_startd + tm->tm_mday - 2; + result *= 86400; + + result += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; + + return result; +}