CeDOS - Commit 076b961a

Time: Switch to RTC interrupt for ticks Previously, the tick counter was increased by the scheduler interrupt. However, this causes changing tick durations when the yield function is called. Instead, we can use the previously unused RTC interrupt, which should as an added benefit have consistent timing across devices.
Celina Sophie Kalus
Tue, 02 Jan 2024 19:51:25 +0100
5 files changed, 73 insertions(+), 11 deletions(-)
M kernel/main.ckernel/main.c

@@ -2,6 +2,7 @@ #include "drivers/console.h"

#include "drivers/keyboard.h" #include "drivers/graphics.h" +#include "time.h" #include "sched/sched.h" #include "sched/process.h"

@@ -61,6 +62,10 @@ printk("done.\n");

printk("Installing syscalls..."); syscall_init(); + printk("done.\n"); + + printk("Initializing RTC..."); + time_init(); printk("done.\n"); printk("Initializing scheduler...");
M kernel/sched/sched.hkernel/sched/sched.h

@@ -11,7 +11,7 @@

#include "mm/paging.h" // 11928 ~ 10ms per interval -#define SCHED_INTERVAL (1193) +#define SCHED_INTERVAL (11928) /*! * Structure of the process stack when the scheduler is executed.
M kernel/sched/sched.skernel/sched/sched.s

@@ -16,7 +16,6 @@ // pass process stack as arguments

push %ebx push %eax xor %eax, %eax - call time_tick call sched_interrupt_c pop %eax pop %ebx
M kernel/time.ckernel/time.c

@@ -1,5 +1,8 @@

#include "time.h" #include "assembly.h" +#include "interrupts.h" +#include "pic.h" +#include "core.h" #define RTC_COMMAND 0x70 #define RTC_DATA 0x71

@@ -9,6 +12,7 @@

#define RTC_REGISTER_A 0x0A #define RTC_REGISTER_B 0x0B #define RTC_REGISTER_C 0x0C +#define RTC_REGISTER_D 0x0D #define RTC_GET_SECONDS 0x00 #define RTC_GET_MINUTES 0x02

@@ -17,6 +21,11 @@

#define RTC_GET_DAY 0x07 #define RTC_GET_MONTH 0x08 #define RTC_GET_YEAR 0x09 + +#define RTC_DISABLE_NMI 0x80 +#define RTC_ENABLE_NMI 0x00 + +#define RTC_ENABLE_INT8 0x40 int ticks = 0;

@@ -30,22 +39,65 @@ }

static uint8_t rtc_get(uint8_t reg) { outb(reg, RTC_COMMAND); + /*nop(); nop(); nop(); + nop();*/ + uint8_t res = inb(RTC_DATA); + return res; +} + +static uint8_t from_BCD(uint8_t bcd_value) { + return (bcd_value >> 4) * 10 + (bcd_value & 0x0F); +} + +static uint8_t rtc_set(uint8_t reg, uint8_t value) { + outb(reg, RTC_COMMAND); + /*nop(); nop(); nop(); - uint8_t res = inb(RTC_DATA); - return (res >> 4) * 10 + (res & 0x0F); + nop();*/ + outb(value, RTC_DATA); } int time_now(datetime_t *buffer) { - buffer->year = 2000 + rtc_get(RTC_GET_YEAR); - buffer->month = rtc_get(RTC_GET_MONTH); - buffer->day = rtc_get(RTC_GET_DAY); + buffer->year = 2000 + from_BCD(rtc_get(RTC_GET_YEAR)); + buffer->month = from_BCD(rtc_get(RTC_GET_MONTH)); + buffer->day = from_BCD(rtc_get(RTC_GET_DAY)); - buffer->hour = rtc_get(RTC_GET_HOURS); - buffer->minute = rtc_get(RTC_GET_MINUTES); - buffer->second = rtc_get(RTC_GET_SECONDS); + buffer->hour = from_BCD(rtc_get(RTC_GET_HOURS)); + buffer->minute = from_BCD(rtc_get(RTC_GET_MINUTES)); + buffer->second = from_BCD(rtc_get(RTC_GET_SECONDS)); return 0; -}+} + +INTERRUPT(rtc_interrupt, frame) { + time_tick(); + + rtc_get(RTC_REGISTER_C); + + pic2_eoi(); +} + +int time_init(void) { + install_interrupt(PIC2_IRQ(0x00), rtc_interrupt, 0x18, INT_GATE); + + // disable all interrupts + cli(); + + uint8_t reg_a = rtc_get(RTC_REGISTER_A | RTC_DISABLE_NMI); + rtc_set(RTC_REGISTER_A | RTC_DISABLE_NMI, (reg_a & 0xF0) | RTC_INT_RATE); + + uint8_t reg_b = rtc_get(RTC_REGISTER_B | RTC_DISABLE_NMI); + rtc_set(RTC_REGISTER_B | RTC_DISABLE_NMI, reg_b | RTC_ENABLE_INT8); + + reg_b = rtc_get(RTC_REGISTER_B); + + rtc_get(RTC_REGISTER_C); + rtc_get(RTC_REGISTER_D); + // enable interrupts again + sti(); + + pic_unmask_interrupt(8); +}
M kernel/time.hkernel/time.h

@@ -1,6 +1,10 @@

#ifndef __TIME_H #define __TIME_H +// frequency = 32768 >> (rate-1); +// rate at least 2 (~8kHz) +#define RTC_INT_RATE 2 + typedef struct { int year; int month;

@@ -10,6 +14,8 @@ int hour;

int minute; int second; } datetime_t; + +int time_init(void); void time_tick(void);