summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-04 00:10:16 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-04 00:10:16 -0400
commit3a44b8da250ffafec26a1c61cf41eeb5978f4549 (patch)
tree809bec6f8dd8a953d27708bf27d99e551997138e
parentserial and tty (diff)
downloadcomus-3a44b8da250ffafec26a1c61cf41eeb5978f4549.tar.gz
comus-3a44b8da250ffafec26a1c61cf41eeb5978f4549.tar.bz2
comus-3a44b8da250ffafec26a1c61cf41eeb5978f4549.zip
real time clock
Diffstat (limited to '')
-rw-r--r--build.zig2
-rw-r--r--include/time.h63
-rw-r--r--kernel/drivers/clock.c159
-rw-r--r--kernel/drivers/drivers.c2
-rw-r--r--kernel/include/comus/drivers/clock.h14
-rw-r--r--kernel/kernel.c9
-rw-r--r--lib/timetostr.c144
7 files changed, 393 insertions, 0 deletions
diff --git a/build.zig b/build.zig
index e673d1d..487681f 100644
--- a/build.zig
+++ b/build.zig
@@ -30,6 +30,7 @@ const kernel_src = &[_][]const u8{
"kernel/cpu/idt.c",
"kernel/cpu/idt.S",
"kernel/cpu/pic.c",
+ "kernel/drivers/clock.c",
"kernel/drivers/drivers.c",
"kernel/drivers/pci.c",
"kernel/drivers/tty.c",
@@ -71,6 +72,7 @@ const lib_src = &[_][]const u8{
"lib/strncpy.c",
"lib/strtoux.c",
"lib/strtox.c",
+ "lib/timetostr.c",
"lib/uxtoa.c",
"lib/xtoa.c",
};
diff --git a/include/time.h b/include/time.h
new file mode 100644
index 0000000..b3b0fc1
--- /dev/null
+++ b/include/time.h
@@ -0,0 +1,63 @@
+/**
+ * @file time.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * System time structure
+ */
+
+#ifndef TIME_H_
+#define TIME_H_
+
+#include <stddef.h>
+
+typedef struct {
+ int sec; /// Seconds [0,59]
+ int min; /// Minutes [0,59]
+ int hour; /// Hour [0,23]
+ int mday; /// Day of month [1,31]
+ int mon; /// Month of year [0,11]
+ int year; /// Years since 1900
+ int wday; /// Day of week [0,6] (Sunday = 0)
+ int yday; /// Day of year [0,365]
+ int yn; /// Year number [0,99]
+ int cen; /// Century [19,20]
+ int leap; /// If year is a leap year (True == 1)
+} time_t;
+
+typedef enum {
+ TZ_UTC = 0,
+ TZ_EST = -5,
+ TZ_EDT = -4,
+} timezone_t;
+
+/**
+ * Sets the current timezone
+ */
+extern void set_timezone(timezone_t tz);
+
+/**
+ * Returns current time in UTC
+ */
+extern time_t get_utctime(void);
+
+/**
+ * Returns current time from current Timezone
+ */
+extern time_t get_localtime(void);
+
+/**
+ * Return the time on the system clock
+ */
+extern size_t get_systemtime(void);
+
+/**
+ * Converts the time into a string format
+ *
+ * @param time - the current time
+ * @param format - see manpage for date
+ * @param buf - the buffer to store it in
+ */
+extern void timetostr(time_t *time, char *format, char *buf, size_t n);
+
+#endif /* time.h */
diff --git a/kernel/drivers/clock.c b/kernel/drivers/clock.c
new file mode 100644
index 0000000..80a44df
--- /dev/null
+++ b/kernel/drivers/clock.c
@@ -0,0 +1,159 @@
+#include <lib.h>
+#include <time.h>
+#include <comus/asm.h>
+#include <comus/drivers/clock.h>
+
+#define CMOS_WRITE_PORT 0x70
+#define CMOS_READ_PORT 0x71
+
+#define CMOS_REG_SEC 0x00
+#define CMOS_REG_MIN 0x02
+#define CMOS_REG_HOUR 0x04
+#define CMOS_REG_WDAY 0x06
+#define CMOS_REG_MDAY 0x07
+#define CMOS_REG_MON 0x08
+#define CMOS_REG_YEAR 0x09
+#define CMOS_REG_CEN 0x32
+
+// Live buffers to work on data
+static time_t time;
+static time_t localtime;
+
+// Front buffers so interupts dont request data that is half done
+static time_t curr_time;
+static time_t curr_localtime;
+
+// Current set time Zone
+static timezone_t curr_timezone = TZ_UTC;
+static timezone_t last_timezone = TZ_UTC;
+
+static uint8_t cmos_read(uint8_t reg) {
+ uint8_t hex, ret;
+
+ outb(CMOS_WRITE_PORT, reg);
+ hex = inb(CMOS_READ_PORT);
+
+ ret = hex & 0x0F;
+ ret += (hex & 0xF0) / 16 * 10;
+
+ return ret;
+}
+
+static int mday_offset[12] = {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
+static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static void update_localtime(void) {
+
+ int change, max;
+
+ // set localtime
+ localtime = time;
+
+ // if tz is UTC, we dont need to do anythin
+ if (last_timezone == TZ_UTC) return;
+
+ localtime.hour += last_timezone;
+
+ // check if day rolled over
+ change = localtime.hour < 0 ? -1 : localtime.hour >= 24 ? 1 : 0;
+ if (!change) return;
+
+ // roll over day
+ localtime.hour = (localtime.hour + 24) % 24;
+ localtime.wday = (localtime.wday + change + 7) % 7;
+ localtime.mday += change;
+ localtime.yday += change;
+
+ // check if month rolled over
+ max = month_days[localtime.mon];
+ if (localtime.leap && localtime.mon == 1) max++;
+ change = localtime.mday < 0 ? -1 : localtime.mday >= max ? 1 : 0;
+ if (!change) return;
+
+ // roll over month
+ localtime.mon = (localtime.mon + change + 12) % 12;
+
+ // check if year rolled over
+ max = localtime.leap ? 366 : 365;
+ change = localtime.yday < 0 ? -1 : localtime.yday >= max ? 1 : 0;
+ if (!change) return;
+
+ // roll over year
+ localtime.yn += change;
+
+ // check if cen rolled over
+ change = localtime.yn < 0 ? -1 : localtime.yn >= 100 ? 1 : 0;
+ if (!change) goto year;
+
+ // roll over cen
+ localtime.cen += change;
+
+
+year:
+
+ localtime.year = localtime.yn + localtime.cen * 100;
+ localtime.leap = localtime.year % 4 == 0 && localtime.year % 100 != 0;
+
+ if (localtime.leap && localtime.yday == -1)
+ localtime.yday = 365;
+ else if (localtime.yday == -1)
+ localtime.yday = 364;
+ else
+ localtime.yday = 0;
+
+ localtime.year -= 1900;
+
+}
+
+void clock_update(void) {
+ time.sec = cmos_read(CMOS_REG_SEC);
+ time.min = cmos_read(CMOS_REG_MIN);
+ time.hour = cmos_read(CMOS_REG_HOUR);
+ time.wday = cmos_read(CMOS_REG_WDAY) - 1;
+ time.mday = cmos_read(CMOS_REG_MDAY);
+ time.mon = cmos_read(CMOS_REG_MON) - 1;
+ time.yn = cmos_read(CMOS_REG_YEAR);
+ time.cen = 20;
+
+ time.year = time.yn + time.cen * 100;
+
+ time.leap = time.year % 4 == 0 && time.year % 100 != 0;
+
+ time.yday = mday_offset[time.mon] + time.mday;
+
+ if (time.leap && time.mon > 2)
+ time.yday++;
+
+ time.year -= 1900;
+
+ update_localtime();
+
+ curr_time = time;
+ curr_localtime = localtime;
+}
+
+void set_timezone(timezone_t tz) {
+ curr_timezone = tz;
+}
+
+time_t get_utctime(void) {
+ return curr_time;
+}
+
+time_t get_localtime(void) {
+ if (curr_timezone != last_timezone) {
+ last_timezone = curr_timezone;
+ update_localtime();
+ curr_localtime = localtime;
+ }
+ return curr_localtime;
+}
+
+size_t get_systemtime(void) {
+ return 0;
+}
diff --git a/kernel/drivers/drivers.c b/kernel/drivers/drivers.c
index 4790c3a..b4c2c90 100644
--- a/kernel/drivers/drivers.c
+++ b/kernel/drivers/drivers.c
@@ -2,10 +2,12 @@
#include <comus/drivers/uart.h>
#include <comus/drivers/tty.h>
#include <comus/drivers/pci.h>
+#include <comus/drivers/clock.h>
void drivers_init(void)
{
uart_init();
tty_init();
pci_init();
+ clock_update();
}
diff --git a/kernel/include/comus/drivers/clock.h b/kernel/include/comus/drivers/clock.h
new file mode 100644
index 0000000..35f26c6
--- /dev/null
+++ b/kernel/include/comus/drivers/clock.h
@@ -0,0 +1,14 @@
+/**
+ * @file clock.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * CMOS real time clock driver
+ */
+
+#ifndef CLOCK_H_
+#define CLOCK_H_
+
+extern void clock_update(void);
+
+#endif /* clock.h */
diff --git a/kernel/kernel.c b/kernel/kernel.c
index 4896b38..0b411be 100644
--- a/kernel/kernel.c
+++ b/kernel/kernel.c
@@ -3,6 +3,8 @@
#include <comus/mboot.h>
#include <comus/drivers.h>
#include <lib.h>
+#include <stdio.h>
+#include <time.h>
struct memory_map mmap;
@@ -23,6 +25,13 @@ void main(long magic, volatile void *mboot)
// initalize devices
drivers_init();
+ // print current time
+ char date[40];
+ set_timezone(TZ_EDT);
+ time_t time = get_localtime();
+ timetostr(&time, "%a %b %d %Y %H:%M:%S", date, 40);
+ printf("The date is: %s\n\n", date);
+
// halt
printf("halting...\n");
}
diff --git a/lib/timetostr.c b/lib/timetostr.c
new file mode 100644
index 0000000..0d4e9a5
--- /dev/null
+++ b/lib/timetostr.c
@@ -0,0 +1,144 @@
+#include <lib.h>
+#include <time.h>
+
+static char* ABB_WEEKDAY[7] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+static char* FULL_WEEKDAY[7] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturady"
+};
+
+static char* ABB_MONTH[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static char* FULL_MONTH[12] = {
+ "January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+};
+
+static char *write_num(unsigned int num, unsigned int pad, char *buf, size_t n) {
+ size_t digits = 1;
+ unsigned int x = num;
+
+ while (x /= 10, x > 0) digits++;
+ if (pad == 0) pad = digits;
+
+ for (size_t i = 0; i < pad; i++) {
+
+ size_t digit;
+ if (i >= digits) {
+ digit = 0;
+ } else {
+ digit = num % 10;
+ num /= 10;
+ }
+
+ if (pad - i - 1 >= n) continue;
+ buf[pad - i - 1] = '0' + digit;
+
+ }
+
+ if (pad > n) pad = n;
+
+ return buf + pad;
+}
+
+void timetostr(time_t *time, char *format, char *buf, size_t n) {
+ char *index = buf;
+ char c;
+ int space;
+
+ while (
+ c = *format++,
+ space = (buf + n) - index,
+ c != '\0' && space > 0
+ ) {
+ if (c != '%') {
+ *index++ = c;
+ continue;
+ } else {
+ c = *format++;
+ }
+
+ switch (c) {
+ case '%':
+ *index++ = '%';
+ break;
+ case 'a':
+ index = strncpy(index, ABB_WEEKDAY[time->wday], space);
+ break;
+ case 'A':
+ index = strncpy(index, FULL_WEEKDAY[time->wday], space);
+ break;
+ case 'b':
+ case 'h':
+ index = strncpy(index, ABB_MONTH[time->mon], space);
+ break;
+ case 'B':
+ index = strncpy(index, FULL_MONTH[time->mon], space);
+ break;
+ case 'C':
+ index = write_num(time->cen, 0, index, space);
+ break;
+ case 'd':
+ index = write_num(time->mday, 2, index, space);
+ break;
+ case 'H':
+ index = write_num(time->hour, 2, index, space);
+ break;
+ case 'I':
+ index = write_num((time->hour + 12) % 12 + 1, 2, index, space);
+ break;
+ case 'j':
+ index = write_num(time->yday, 3, index, space);
+ break;
+ case 'm':
+ index = write_num(time->mon + 1, 2, index, space);
+ break;
+ case 'M':
+ index = write_num(time->min, 2, index, space);
+ break;
+ case 'n':
+ *index++ = '\n';
+ break;
+ case 'p':
+ index = strncpy(index, time->hour > 11 ? "PM" : "AM", space);
+ break;
+ case 'P':
+ index = strncpy(index, time->hour > 11 ? "pm" : "am", space);
+ break;
+ case 'q':
+ index = write_num((time->mon + 3) / 3, 0, index, space);
+ break;
+ case 'S':
+ index = write_num(time->sec, 2, index, space);
+ break;
+ case 't':
+ *index++ = '\t';
+ break;
+ case 'u':
+ index = write_num(((time->wday + 1 )% 7) + 1, 0, index, space);
+ break;
+ case 'w':
+ index = write_num(time->wday, 0, index, space);
+ break;
+ case 'y':
+ index = write_num(time->yn, 2, index, space);
+ break;
+ case 'Y':
+ index = write_num(time->year + 1900, 0, index, space);
+ break;
+ default: {
+ char b[3] = {'%', c, '\0'};
+ index = strncpy(index, b, space);
+ break;
+ }
+ }
+ }
+
+ if (space < 1)
+ buf[n - 1] = '\0';
+ else
+ *index = '\0';
+}