summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-07-03 20:21:59 +0200
committerAnton Kling <anton@kling.gg>2024-07-04 18:42:46 +0200
commitf7752e37ce29b903e15d2579d25d4ebbaad023e6 (patch)
tree25d5cd3d1232f8d81c2e51884c6d9dc51190ab6c
parent6ec139d3ef7c1d2a52bb786779dd1914f125eda4 (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.c69
-rw-r--r--kernel/drivers/cmos.h4
-rw-r--r--kernel/drivers/rtl8139.c1
-rw-r--r--kernel/init/kernel.c5
-rw-r--r--kernel/timer.c22
-rw-r--r--kernel/timer.h3
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);