diff options
author | Anton Kling <anton@kling.gg> | 2024-07-03 18:30:51 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-07-03 18:30:51 +0200 |
commit | 4e7918753175dbd8fc38bc7c5b176517e1dbef2f (patch) | |
tree | 723b3b3503d7502f3ce5338aeb6964cb5fa4c246 /kernel | |
parent | 658c4e9645bf46268ed13bf5ef76d0ba60a347b9 (diff) |
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.
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 2 | ||||
-rw-r--r-- | kernel/arch/i386/asm_tsc.s | 8 | ||||
-rw-r--r-- | kernel/arch/i386/tsc.h | 6 | ||||
-rw-r--r-- | kernel/cpu/syscall.c | 11 | ||||
-rw-r--r-- | kernel/drivers/pit.c | 14 | ||||
-rw-r--r-- | kernel/drivers/pit.h | 1 | ||||
-rw-r--r-- | kernel/fs/ext2.c | 5 | ||||
-rw-r--r-- | kernel/init/kernel.c | 8 | ||||
-rw-r--r-- | kernel/sched/scheduler.c | 5 | ||||
-rw-r--r-- | kernel/timer.c | 69 | ||||
-rw-r--r-- | kernel/timer.h | 8 |
11 files changed, 106 insertions, 31 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index 03d2641..a82983b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,6 +1,6 @@ CC="i686-sb-gcc" AS="i686-sb-as" -OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o kubsan.o drivers/serial.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o elf.o ksbrk.o sched/scheduler.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o math.o signal.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o lib/ringbuffer.o lib/relist.o arch/i386/tsc.o arch/i386/asm_tsc.o drivers/cmos.o +OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o kubsan.o drivers/serial.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o elf.o ksbrk.o sched/scheduler.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o math.o signal.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o lib/ringbuffer.o lib/relist.o arch/i386/tsc.o arch/i386/asm_tsc.o drivers/cmos.o timer.o CFLAGS = -std=c99 -O0 -fsanitize=vla-bound,shift-exponent,pointer-overflow,shift,signed-integer-overflow,bounds -ggdb -ffreestanding -Wall -Wextra -Wno-int-conversion -Wno-unused-parameter -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I. -Wno-pointer-sign -DKERNEL LDFLAGS= INCLUDE=-I./includes/ -I../include/ -I./libc/include/ diff --git a/kernel/arch/i386/asm_tsc.s b/kernel/arch/i386/asm_tsc.s index 963687e..5f9d858 100644 --- a/kernel/arch/i386/asm_tsc.s +++ b/kernel/arch/i386/asm_tsc.s @@ -1,17 +1,17 @@ .intel_syntax noprefix -.global get_tsc -.global get_hz +.global tsc_get +.global tsc_get_hz # 1.193182 MHz # So 0xFFFF is roughly 0.05492 seconds # So take the result times 18 and you got your Hz -get_tsc: +tsc_get: rdtsc ret -get_hz: +tsc_get_hz: cli # Disable the gate for channel 2 so the clock can be set. # This should only matter if the channel already has count diff --git a/kernel/arch/i386/tsc.h b/kernel/arch/i386/tsc.h index 2e29cf3..1a9e317 100644 --- a/kernel/arch/i386/tsc.h +++ b/kernel/arch/i386/tsc.h @@ -1,4 +1,6 @@ #include <typedefs.h> -u64 get_tsc(); -u64 get_hz(); +void tsc_init(void); +u64 tsc_get(void); +u64 tsc_get_mhz(void); +u64 tsc_calculate_ms(u64 tsc); diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c index 78d35fe..a74adfd 100644 --- a/kernel/cpu/syscall.c +++ b/kernel/cpu/syscall.c @@ -19,6 +19,7 @@ #include <random.h> #include <socket.h> #include <string.h> +#include <timer.h> #include <typedefs.h> struct two_args { @@ -137,9 +138,7 @@ int syscall_chdir(const char *path) { int syscall_clock_gettime(clockid_t clock_id, struct timespec *tp) { // FIXME: Actually implement this if (tp) { - u64 ms = pit_num_ms(); - tp->tv_sec = ms / 1000; - tp->tv_nsec = ms * 1000 * 1000; + timer_get(tp); } return 0; } @@ -226,7 +225,9 @@ void *syscall_mmap(SYS_MMAP_PARAMS *args) { } void syscall_msleep(u32 ms) { - current_task->sleep_until = pit_num_ms() + ms; + struct timespec t; + timer_get(&t); + current_task->sleep_until = timer_get_ms() + ms; switch_task(); } @@ -371,7 +372,7 @@ int syscall_socket(SYS_SOCKET_PARAMS *args) { } u32 syscall_uptime(void) { - return (u32)pit_num_ms(); + return timer_get_uptime(); } int syscall_write(int fd, const char *buf, size_t count) { diff --git a/kernel/drivers/pit.c b/kernel/drivers/pit.c index ac4e555..70dc0f9 100644 --- a/kernel/drivers/pit.c +++ b/kernel/drivers/pit.c @@ -9,11 +9,6 @@ u32 pit_counter = 0; u32 switch_counter = 0; u16 hertz; -u64 cpu_mhz = 0; -u64 pit_num_ms(void) { - return (get_tsc()) / (cpu_mhz * 1000); -} - u16 read_pit_count(void) { u16 count = 0; @@ -26,8 +21,6 @@ u16 read_pit_count(void) { } void set_pit_count(u16 _hertz) { - cpu_mhz = get_hz() / 10000; - hertz = _hertz; u16 divisor = 1193180 / hertz; @@ -53,13 +46,6 @@ u64 last_tsc = 0; extern int is_switching_tasks; void int_clock(reg_t *regs) { - u64 current_tsc = get_tsc(); - - u64 delta = (current_tsc - last_tsc) / (cpu_mhz * 1000); - - clock_num_ms_ticks += delta; - - last_tsc = current_tsc; switch_counter++; if (clock_num_ms_ticks - last_flush > 50) { diff --git a/kernel/drivers/pit.h b/kernel/drivers/pit.h index ec48cc3..90fddf4 100644 --- a/kernel/drivers/pit.h +++ b/kernel/drivers/pit.h @@ -8,5 +8,4 @@ void pit_install(void); void set_pit_count(u16 hertz); -u64 pit_num_ms(void); #endif diff --git a/kernel/fs/ext2.c b/kernel/fs/ext2.c index 1eeafce..a61d5f2 100644 --- a/kernel/fs/ext2.c +++ b/kernel/fs/ext2.c @@ -6,6 +6,7 @@ #include <math.h> #include <string.h> #include <sys/stat.h> +#include <timer.h> #include <typedefs.h> #define EXT2_SUPERBLOCK_SECTOR 2 @@ -52,7 +53,7 @@ void cached_read_block(u32 block, void *address, size_t size, size_t offset) { continue; } if (cache[i].block_num == block) { - cache[i].last_use = pit_num_ms(); + cache[i].last_use = timer_get_uptime(); memcpy(address, cache[i].block + offset, size); return; } @@ -77,7 +78,7 @@ void cached_read_block(u32 block, void *address, size_t size, size_t offset) { } c->is_used = 1; c->block_num = block; - c->last_use = pit_num_ms(); + c->last_use = timer_get_uptime(); c->has_write = 0; raw_vfs_pread(mount_fd, c->block, block_byte_size, block * block_byte_size); cached_read_block(block, address, size, offset); diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c index 83f4af8..90be3ab 100644 --- a/kernel/init/kernel.c +++ b/kernel/init/kernel.c @@ -28,6 +28,7 @@ #include <stddef.h> #include <stdio.h> #include <string.h> +#include <timer.h> #include <typedefs.h> #if defined(__linux__) @@ -76,6 +77,8 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, ata_init(); klog(LOG_SUCCESS, "ATA Initalized"); + timer_init(); + tasking_init(); klog(LOG_SUCCESS, "Tasking Initalized"); @@ -96,6 +99,9 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, add_stdout(); add_serial(); add_random_devices(); + + timer_add_clock(); + shm_init(); setup_random(); @@ -123,7 +129,7 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, } } for (;;) { - current_task->sleep_until = pit_num_ms() + 100000000; + current_task->sleep_until = timer_get_ms() + 100000000; wait_for_interrupt(); } } diff --git a/kernel/sched/scheduler.c b/kernel/sched/scheduler.c index c8ee0a1..10ecd73 100644 --- a/kernel/sched/scheduler.c +++ b/kernel/sched/scheduler.c @@ -7,7 +7,9 @@ #include <errno.h> #include <fs/vfs.h> #include <interrupts.h> +#include <sched/scheduler.h> #include <signal.h> +#include <timer.h> // FIXME: Use the process_t struct instead or keep this contained in it. TCB *current_task_TCB; @@ -432,6 +434,7 @@ extern PageDirectory *active_directory; process_t *next_task(process_t *s) { process_t *c = s; + u64 ms_time = timer_get_ms(); c = c->next; for (;; c = c->next) { if (!c) { @@ -440,7 +443,7 @@ process_t *next_task(process_t *s) { if (s == c) { // wait_for_interrupt(); } - if (c->sleep_until > pit_num_ms()) { + if (c->sleep_until > ms_time) { continue; } if (c->is_interrupted) { 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 <arch/i386/tsc.h> +#include <drivers/cmos.h> +#include <fs/devfs.h> +#include <math.h> +#include <time.h> +#include <typedefs.h> + +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; +} diff --git a/kernel/timer.h b/kernel/timer.h new file mode 100644 index 0000000..33c04ce --- /dev/null +++ b/kernel/timer.h @@ -0,0 +1,8 @@ +#include <arch/i386/tsc.h> +#include <drivers/cmos.h> + +void timer_init(void); +void timer_get(struct timespec *tp); +u64 timer_get_uptime(void); +u64 timer_get_ms(void); +int timer_add_clock(void); |