From 4e7918753175dbd8fc38bc7c5b176517e1dbef2f Mon Sep 17 00:00:00 2001 From: Anton Kling Date: Wed, 3 Jul 2024 18:30:51 +0200 Subject: Kernel/Time: Improve time keeping This makes use of TSC and now provides a file system interface for userland programs to change the system time. --- kernel/timer.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 kernel/timer.c (limited to 'kernel/timer.c') diff --git a/kernel/timer.c b/kernel/timer.c new file mode 100644 index 0000000..46a30d3 --- /dev/null +++ b/kernel/timer.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + +i64 start_unix_time; +u64 start_tsc_time; + +void timer_init(void) { + tsc_init(); + start_tsc_time = tsc_get(); + start_unix_time = cmos_get_time(); +} + +u64 timer_get_uptime(void) { + return tsc_calculate_ms(tsc_get()); +} + +void timer_get(struct timespec *tp) { + u64 offset_tsc = tsc_get() - start_tsc_time; + i64 current_unix_time_seconds = + start_unix_time + tsc_calculate_ms(offset_tsc) / 1000; + tp->tv_sec = current_unix_time_seconds; + tp->tv_nsec = tsc_calculate_ms(offset_tsc); +} + +u64 timer_get_ms(void) { + u64 offset_tsc = tsc_get() - start_tsc_time; + return start_unix_time * 1000 + tsc_calculate_ms(offset_tsc); +} + +int clock_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { + (void)offset; + u64 r = timer_get_ms(); + u64 l = min(len, sizeof(u64)); + memcpy(buffer, &r, l); + return l; +} + +int clock_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { + (void)offset; + if (len != sizeof(i64)) { + return 0; + } + + i64 new_value_ms; + memcpy(&new_value_ms, buffer, sizeof(i64)); + i64 new_value_seconds = new_value_ms / 1000; + + u64 offset_tsc = tsc_get() - start_tsc_time; + i64 current_unix_time_seconds = + start_unix_time + tsc_calculate_ms(offset_tsc) / 1000; + + i64 delta = new_value_seconds - current_unix_time_seconds; + start_unix_time += delta; + cmos_set_time(new_value_seconds); + return sizeof(i64); +} + +int always_has_data(vfs_inode_t *inode); +int always_can_write(vfs_inode_t *inode); + +int timer_add_clock(void) { + devfs_add_file("/clock", clock_read, clock_write, NULL, always_has_data, + always_can_write, FS_TYPE_CHAR_DEVICE); + return 1; +} -- cgit v1.2.3