diff options
author | Anton Kling <anton@kling.gg> | 2024-07-03 20:21:59 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-07-04 18:42:46 +0200 |
commit | f7752e37ce29b903e15d2579d25d4ebbaad023e6 (patch) | |
tree | 25d5cd3d1232f8d81c2e51884c6d9dc51190ab6c | |
parent | 6ec139d3ef7c1d2a52bb786779dd1914f125eda4 (diff) |
CMOS: Make read/write calls async
This can speed up boot times since CMOS would otherwise have to wait
before it could perform a read/write call. Now it gets triggered by a
interrupt.
-rw-r--r-- | kernel/drivers/cmos.c | 69 | ||||
-rw-r--r-- | kernel/drivers/cmos.h | 4 | ||||
-rw-r--r-- | kernel/drivers/rtl8139.c | 1 | ||||
-rw-r--r-- | kernel/init/kernel.c | 5 | ||||
-rw-r--r-- | kernel/timer.c | 22 | ||||
-rw-r--r-- | kernel/timer.h | 3 |
6 files changed, 81 insertions, 23 deletions
diff --git a/kernel/drivers/cmos.c b/kernel/drivers/cmos.c index 3df1d97..bdb13cc 100644 --- a/kernel/drivers/cmos.c +++ b/kernel/drivers/cmos.c @@ -1,4 +1,5 @@ #include <assert.h> +#include <cpu/idt.h> #include <cpu/io.h> #include <drivers/cmos.h> @@ -30,6 +31,7 @@ #define CMOS_MONTH 0x08 #define CMOS_YEAR 0x09 #define CMOS_CENTURY 0x32 +#define CMOS_REG_B 0x0B #define NMI_disable_bit 1 @@ -72,29 +74,65 @@ u8 days_in_month[] = { 31, // December: 31 days }; -static int cmos_update_in_progress(void) { - return (cmos_get_register(0x0A) & (1 << 7)); +static i64 cmos_get_time(void); +static void cmos_set_time(i64 time); + +int cmos_has_command = 0; +int cmos_command_is_read = 0; +int *cmos_done_ptr = NULL; +i64 *cmos_time_ptr = NULL; + +void cmos_handler(reg_t *reg) { + (void)reg; + if (!cmos_has_command) { + goto cmos_handler_exit; + } + + if (cmos_command_is_read) { + *cmos_time_ptr = cmos_get_time(); + *cmos_done_ptr = 1; + goto cmos_handler_exit; + } + + if (!cmos_command_is_read) { + cmos_set_time(*cmos_time_ptr); + *cmos_done_ptr = 1; + goto cmos_handler_exit; + } + +cmos_handler_exit: + cmos_has_command = 0; + u8 reg_b = cmos_get_register(CMOS_REG_B); + reg_b &= ~0x40; // Disable interrupts + cmos_set_register(CMOS_REG_B, reg_b); + EOI(0x8); } -// TODO: Optimize by using interrupts as osdev wiki recommends -static void cmos_wait(void) { - // It firsts wait until there is a update - // Then we wait for it to be done. - // This is to avoid race conditions. - for (; !cmos_update_in_progress();) - ; +void cmos_init(void) { + install_handler((interrupt_handler)cmos_handler, INT_32_INTERRUPT_GATE(0x0), + 0x28); +} - for (; cmos_update_in_progress();) - ; +int cmos_start_call(int is_read, int *done, i64 *time) { + if (cmos_has_command) { + return 0; + } + *done = 0; + cmos_done_ptr = done; + cmos_time_ptr = time; + cmos_command_is_read = is_read; + cmos_has_command = 1; + u8 reg_b = cmos_get_register(CMOS_REG_B); + reg_b |= 0x40; // Enable interrupts + cmos_set_register(CMOS_REG_B, reg_b); + return 1; } // This function returns the current unix timestamp from the CMOS RTC // TODO: It currently makes the assumption that time travel is not possible and // as a result will not give negative values. This support should maybe be added // to prepare ourselves for the past. -i64 cmos_get_time(void) { - cmos_wait(); - +static i64 cmos_get_time(void) { u8 seconds = cmos_get_register(CMOS_SECONDS); u8 minutes = cmos_get_register(CMOS_MINUTES); @@ -146,9 +184,8 @@ i64 cmos_get_time(void) { return second_sum; } -void cmos_set_time(i64 time) { +static void cmos_set_time(i64 time) { assert(time > 0); // TODO: Add support for time travelers - cmos_wait(); u8 reg_b = cmos_get_register(0x0B); u8 seconds = 0; diff --git a/kernel/drivers/cmos.h b/kernel/drivers/cmos.h index f985ee3..934b716 100644 --- a/kernel/drivers/cmos.h +++ b/kernel/drivers/cmos.h @@ -1,4 +1,4 @@ #include <typedefs.h> -i64 cmos_get_time(void); -void cmos_set_time(i64 time); +void cmos_init(void); +int cmos_start_call(int is_read, int *done, i64 *time); diff --git a/kernel/drivers/rtl8139.c b/kernel/drivers/rtl8139.c index caacd3c..98d3f22 100644 --- a/kernel/drivers/rtl8139.c +++ b/kernel/drivers/rtl8139.c @@ -7,6 +7,7 @@ #include <mmu.h> #include <network/arp.h> #include <network/ethernet.h> +#include <sched/scheduler.h> #define RBSTART 0x30 #define CMD 0x37 diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c index 90be3ab..6e5c9b4 100644 --- a/kernel/init/kernel.c +++ b/kernel/init/kernel.c @@ -67,6 +67,8 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, idt_init(); klog(LOG_SUCCESS, "IDT Initalized"); + timer_start_init(); + syscalls_init(); klog(LOG_SUCCESS, "Syscalls Initalized"); @@ -77,7 +79,7 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, ata_init(); klog(LOG_SUCCESS, "ATA Initalized"); - timer_init(); + timer_start_init(); tasking_init(); klog(LOG_SUCCESS, "Tasking Initalized"); @@ -100,6 +102,7 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, add_serial(); add_random_devices(); + timer_wait_for_init(); timer_add_clock(); shm_init(); diff --git a/kernel/timer.c b/kernel/timer.c index 46a30d3..d0ef113 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1,17 +1,29 @@ #include <arch/i386/tsc.h> #include <drivers/cmos.h> #include <fs/devfs.h> +#include <interrupts.h> #include <math.h> #include <time.h> +#include <timer.h> #include <typedefs.h> +int has_unix_time; i64 start_unix_time; u64 start_tsc_time; -void timer_init(void) { +void timer_start_init(void) { tsc_init(); start_tsc_time = tsc_get(); - start_unix_time = cmos_get_time(); + enable_interrupts(); + cmos_init(); + cmos_start_call(1, &has_unix_time, &start_unix_time); + enable_interrupts(); +} + +void timer_wait_for_init(void) { + enable_interrupts(); + for (; !has_unix_time;) + ; } u64 timer_get_uptime(void) { @@ -55,7 +67,11 @@ int clock_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { i64 delta = new_value_seconds - current_unix_time_seconds; start_unix_time += delta; - cmos_set_time(new_value_seconds); + int done; + enable_interrupts(); + cmos_start_call(0, &done, &new_value_seconds); + for (; !done;) + ; return sizeof(i64); } diff --git a/kernel/timer.h b/kernel/timer.h index 33c04ce..1e1d6e0 100644 --- a/kernel/timer.h +++ b/kernel/timer.h @@ -1,7 +1,8 @@ #include <arch/i386/tsc.h> #include <drivers/cmos.h> -void timer_init(void); +void timer_start_init(void); +void timer_wait_for_init(); void timer_get(struct timespec *tp); u64 timer_get_uptime(void); u64 timer_get_ms(void); |