From: Minep Date: Sat, 12 Mar 2022 18:55:50 +0000 (+0000) Subject: Timer re-worked! X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/fef29e9e993e62f025d8cbfeb6b8d51588083b7e?ds=sidebyside Timer re-worked! Renamings some header files. A linked list implementation stolen from Linux. --- diff --git a/lunaix-os/arch/x86/hhk.c b/lunaix-os/arch/x86/hhk.c index ed3709f..c6797c8 100644 --- a/lunaix-os/arch/x86/hhk.c +++ b/lunaix-os/arch/x86/hhk.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #define PT_ADDR(ptd, pt_index) ((ptd_t*)ptd + (pt_index + 1) * 1024) #define SET_PDE(ptd, pde_index, pde) *((ptd_t*)ptd + pde_index) = pde; diff --git a/lunaix-os/hal/acpi/acpi.c b/lunaix-os/hal/acpi/acpi.c index 4781219..a37466a 100644 --- a/lunaix-os/hal/acpi/acpi.c +++ b/lunaix-os/hal/acpi/acpi.c @@ -8,7 +8,7 @@ #include "parser/madt_parser.h" -acpi_context* toc = NULL; +static acpi_context* toc = NULL; LOG_MODULE("ACPI") @@ -51,7 +51,7 @@ acpi_init(multiboot_info_t* mb_info) kprintf(KINFO "OEM: %s\n", toc->oem_id); kprintf(KINFO "IOAPIC address: %p\n", toc->madt.ioapic->ioapic_addr); kprintf(KINFO "APIC address: %p\n", toc->madt.apic_addr); - + for (size_t i = 0; i < 24; i++) { acpi_intso_t* intso = toc->madt.irq_exception[i]; if (!intso) diff --git a/lunaix-os/hal/apic.c b/lunaix-os/hal/apic.c index c74d3f9..32bfed5 100644 --- a/lunaix-os/hal/apic.c +++ b/lunaix-os/hal/apic.c @@ -27,7 +27,7 @@ void apic_setup_lvts(); void -init_apic() +apic_init() { // ensure that external interrupt is disabled cpu_disable_interrupt(); @@ -77,9 +77,6 @@ init_apic() // install our handler for spurious interrupt. spiv = (spiv & ~0xff) | APIC_SPIV_APIC_ENABLE | APIC_SPIV_IV; apic_write_reg(APIC_SPIVR, spiv); - - // setup timer and performing calibrations - apic_setup_timer(); } #define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector) @@ -89,7 +86,6 @@ init_apic() // LINT#1 *must* be edge trigged (Intel manual vol3. 10-14) #define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE) #define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector) -#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) void apic_setup_lvts() @@ -98,124 +94,3 @@ apic_setup_lvts() apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1); apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV)); } - -void -temp_intr_routine_rtc_tick(const isr_param* param); - -void -temp_intr_routine_apic_timer(const isr_param* param); - -void -test_timer(const isr_param* param); - -uint32_t apic_timer_base_freq = 0; - -// Don't optimize them! Took me an half hour to figure that out... - -volatile uint32_t rtc_counter = 0; -volatile uint8_t apic_timer_done = 0; - -#define APIC_CALIBRATION_CONST 0x100000 - -void -apic_setup_timer() -{ - cpu_disable_interrupt(); - - // Setup APIC timer - - // Setup a one-shot timer, we will use this to measure the bus speed. So we can - // then calibrate apic timer to work at *nearly* accurate hz - apic_write_reg(APIC_TIMER_LVT, LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_ONESHOT)); - - // Set divider to 64 - apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64); - - /* - Timer calibration process - measure the APIC timer base frequency - - step 1: setup a temporary isr for RTC timer which trigger at each tick (1024Hz) - step 2: setup a temporary isr for #APIC_TIMER_IV - step 3: setup the divider, APIC_TIMER_DCR - step 4: Startup RTC timer - step 5: Write a large value, v, to APIC_TIMER_ICR to start APIC timer - (this must be followed immediately after step 4) - step 6: issue a write to EOI and clean up. - - When the APIC ICR counting down to 0 #APIC_TIMER_IV triggered, save the rtc timer's - counter, k, and disable RTC timer immediately (although the RTC interrupts should be - blocked by local APIC as we are currently busy on handling #APIC_TIMER_IV) - - So the apic timer frequency F_apic in Hz can be calculate as - v / F_apic = k / 1024 - => F_apic = v / k * 1024 - - */ - - apic_timer_base_freq = 0; - rtc_counter = 0; - apic_timer_done = 0; - - intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); - intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); - - - rtc_enable_timer(); // start RTC timer - apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); // start APIC timer - - // enable interrupt, just for our RTC start ticking! - cpu_enable_interrupt(); - - wait_until(apic_timer_done); - - // cpu_disable_interrupt(); - - assert_msg(apic_timer_base_freq, "Fail to initialize timer"); - - kprintf(KINFO "Timer base frequency: %u Hz\n", apic_timer_base_freq); - - // cleanup - intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); - intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); - - // TODO: now setup timer with our custom frequency which we can derived from the base frequency - // we measured - - apic_write_reg(APIC_TIMER_LVT, LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC)); - intr_subscribe(APIC_TIMER_IV, test_timer); - - apic_write_reg(APIC_TIMER_ICR, apic_timer_base_freq); -} - -volatile rtc_datetime datetime; - -void -test_timer(const isr_param* param) { - - rtc_get_datetime(&datetime); - - kprintf(KWARN "%u/%02u/%02u %02u:%02u:%02u\r", - datetime.year, - datetime.month, - datetime.day, - datetime.hour, - datetime.minute, - datetime.second); -} - -void -temp_intr_routine_rtc_tick(const isr_param* param) { - rtc_counter++; - - // dummy read on register C so RTC can send anther interrupt - // This strange behaviour observed in virtual box & bochs - (void) rtc_read_reg(RTC_REG_C); -} - -void -temp_intr_routine_apic_timer(const isr_param* param) { - apic_timer_base_freq = APIC_CALIBRATION_CONST / rtc_counter * RTC_TIMER_BASE_FREQUENCY; - apic_timer_done = 1; - - rtc_disable_timer(); -} \ No newline at end of file diff --git a/lunaix-os/hal/rtc.c b/lunaix-os/hal/rtc.c index 60a1aed..0e3673c 100644 --- a/lunaix-os/hal/rtc.c +++ b/lunaix-os/hal/rtc.c @@ -9,6 +9,7 @@ * */ #include +#include #include void @@ -42,7 +43,7 @@ bcd2dec(uint8_t bcd) } int -rtc_date_same(rtc_datetime* a, rtc_datetime* b) { +rtc_date_same(datetime_t* a, datetime_t* b) { return a->year == b->year && a->month == b->month && a->day == b->day && @@ -52,14 +53,14 @@ rtc_date_same(rtc_datetime* a, rtc_datetime* b) { } void -rtc_get_datetime(rtc_datetime* datetime) +time_getdatetime(datetime_t* datetime) { - rtc_datetime current; + datetime_t current; do { while (rtc_read_reg(RTC_REG_A) & 0x80); - memcpy(¤t, datetime, sizeof(rtc_datetime)); + memcpy(¤t, datetime, sizeof(datetime_t)); datetime->year = rtc_read_reg(RTC_REG_YRS); datetime->month = rtc_read_reg(RTC_REG_MTH); diff --git a/lunaix-os/includes/hal/apic.h b/lunaix-os/includes/hal/apic.h index 851e75e..f4ab92c 100644 --- a/lunaix-os/includes/hal/apic.h +++ b/lunaix-os/includes/hal/apic.h @@ -67,7 +67,7 @@ #define apic_write_reg(reg, val) (*(uint32_t*)(APIC_BASE_VADDR + (reg)) = (val)) void -init_apic(); +apic_init(); /** * @brief Tell the APIC that the handler for current interrupt is finished. diff --git a/lunaix-os/includes/hal/rtc.h b/lunaix-os/includes/hal/rtc.h index 0092171..0742f0c 100644 --- a/lunaix-os/includes/hal/rtc.h +++ b/lunaix-os/includes/hal/rtc.h @@ -32,17 +32,6 @@ #define RTC_FREQUENCY_1024HZ 0b110 #define RTC_DIVIDER_33KHZ (0b010 << 4) -typedef struct -{ - uint32_t year; // use int32 as we need to store the 4-digit year - uint8_t month; - uint8_t day; - uint8_t weekday; - uint8_t hour; - uint8_t minute; - uint8_t second; -} rtc_datetime; - void rtc_init(); @@ -52,9 +41,6 @@ rtc_read_reg(uint8_t reg_selector); void rtc_write_reg(uint8_t reg_selector, uint8_t val); -void -rtc_get_datetime(rtc_datetime* datetime); - void rtc_enable_timer(); diff --git a/lunaix-os/includes/lunaix/common.h b/lunaix-os/includes/lunaix/common.h new file mode 100644 index 0000000..d9ffeae --- /dev/null +++ b/lunaix-os/includes/lunaix/common.h @@ -0,0 +1,31 @@ +#ifndef __LUNAIX_CONSTANTS_H +#define __LUNAIX_CONSTANTS_H + +#include + +#define K_STACK_SIZE (64 << 10) +#define K_STACK_START ((0xFFBFFFFFU - K_STACK_SIZE) + 1) +#define HIGHER_HLF_BASE 0xC0000000UL +#define MEM_1MB 0x100000UL + +#define VGA_BUFFER_VADDR 0xB0000000UL +#define VGA_BUFFER_PADDR 0xB8000UL +#define VGA_BUFFER_SIZE 4096 + +#define SYS_TIMER_FREQUENCY_HZ 2048 + + +// From Linux kernel v2.6.0 +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#endif /* __LUNAIX_CONSTANTS_H */ diff --git a/lunaix-os/includes/lunaix/constants.h b/lunaix-os/includes/lunaix/constants.h deleted file mode 100644 index 6fc0c48..0000000 --- a/lunaix-os/includes/lunaix/constants.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LUNAIX_CONSTANTS_H -#define __LUNAIX_CONSTANTS_H - -#define K_STACK_SIZE (64 << 10) -#define K_STACK_START ((0xFFBFFFFFU - K_STACK_SIZE) + 1) -#define HIGHER_HLF_BASE 0xC0000000UL -#define MEM_1MB 0x100000UL - -#define VGA_BUFFER_VADDR 0xB0000000UL -#define VGA_BUFFER_PADDR 0xB8000UL -#define VGA_BUFFER_SIZE 4096 - -#endif /* __LUNAIX_CONSTANTS_H */ diff --git a/lunaix-os/includes/lunaix/ds/llist.h b/lunaix-os/includes/lunaix/ds/llist.h new file mode 100644 index 0000000..effee95 --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/llist.h @@ -0,0 +1,82 @@ +/** + * @file llist.h + * @author Lunaixsky + * @brief This doubly linked cyclic list is adopted from Linux kernel + * @version 0.1 + * @date 2022-03-12 + * + * @copyright Copyright (c) 2022 + * + */ +#ifndef __LUNAIX_LLIST_H +#define __LUNAIX_LLIST_H + +#include + +struct llist_header +{ + struct llist_header* prev; + struct llist_header* next; +}; + +static inline void +__llist_add(struct llist_header* elem, + struct llist_header* prev, + struct llist_header* next) +{ + next->prev = elem; + elem->next = next; + elem->prev = prev; + prev->next = elem; +} + +static inline void +llist_init_head(struct llist_header* head) { + head->next = head; + head->prev = head; +} + +static inline void +llist_append(struct llist_header* head, struct llist_header* elem) +{ + __llist_add(elem, head, head->next); +} + +static inline void +llist_prepend(struct llist_header* head, struct llist_header* elem) +{ + __llist_add(elem, head->prev, head); +} + +static inline void +llist_delete(struct llist_header* elem) { + elem->prev->next = elem->next; + elem->next->prev = elem->next; + + // make elem orphaned + elem->prev = elem; + elem->next = elem; +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define llist_for_each(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif /* __LUNAIX_LLIST_H */ diff --git a/lunaix-os/includes/lunaix/mm/page.h b/lunaix-os/includes/lunaix/mm/page.h index c202184..415ea9e 100644 --- a/lunaix-os/includes/lunaix/mm/page.h +++ b/lunaix-os/includes/lunaix/mm/page.h @@ -1,7 +1,7 @@ #ifndef __LUNAIX_PAGE_H #define __LUNAIX_PAGE_H #include -#include +#include #define PG_SIZE_BITS 12 #define PG_SIZE (1 << PG_SIZE_BITS) diff --git a/lunaix-os/includes/lunaix/time.h b/lunaix-os/includes/lunaix/time.h new file mode 100644 index 0000000..522cc1f --- /dev/null +++ b/lunaix-os/includes/lunaix/time.h @@ -0,0 +1,20 @@ +#ifndef __LUNAIX_TIME_H +#define __LUNAIX_TIME_H + +#include + +typedef struct +{ + uint32_t year; // use int32 as we need to store the 4-digit year + uint8_t month; + uint8_t day; + uint8_t weekday; + uint8_t hour; + uint8_t minute; + uint8_t second; +} datetime_t; + +void +time_getdatetime(datetime_t* datetime); + +#endif /* __LUNAIX_TIME_H */ diff --git a/lunaix-os/includes/lunaix/timer.h b/lunaix-os/includes/lunaix/timer.h new file mode 100644 index 0000000..5c40696 --- /dev/null +++ b/lunaix-os/includes/lunaix/timer.h @@ -0,0 +1,42 @@ +#ifndef __LUNAIX_TIMER_H +#define __LUNAIX_TIMER_H + +#include +#include + +#define SYS_TIMER_FREQUENCY_HZ 2048UL + +#define TIMER_MODE_PERIODIC 0x1 + +struct lx_timer_context { + struct lx_timer *active_timers; + uint32_t base_frequency; + uint32_t running_frequency; + uint32_t tick_interval; +}; + +struct lx_timer { + struct llist_header link; + uint32_t deadline; + uint32_t counter; + void* payload; + void (*callback)(void*); + uint8_t flags; +}; + + +/** + * @brief Initialize the system timer that runs at specified frequency + * + * @param frequency The frequency that timer should run in Hz. + */ +void +timer_init(uint32_t frequency); + +int +timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags); + +int +timer_run(uint32_t ticks, void (*callback)(void*), void* payload, uint8_t flags); + +#endif /* __LUNAIX_TIMER_H */ diff --git a/lunaix-os/kernel/asm/x86/interrupts.c b/lunaix-os/kernel/asm/x86/interrupts.c index 869569f..a7ac25a 100644 --- a/lunaix-os/kernel/asm/x86/interrupts.c +++ b/lunaix-os/kernel/asm/x86/interrupts.c @@ -4,7 +4,7 @@ #include #include -int_subscriber subscribers[256]; +static int_subscriber subscribers[256]; static int_subscriber fallback = (int_subscriber) 0; diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 2dbd64e..5e6cc99 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,8 @@ extern uint8_t __kernel_start; extern uint8_t __kernel_end; extern uint8_t __init_hhk_end; + +// Set remotely by kernel/asm/x86/prologue.S multiboot_info_t* _k_init_mb_info; LOG_MODULE("INIT"); @@ -93,7 +96,8 @@ _kernel_post_init() { vmm_set_mapping(IOAPIC_BASE_VADDR, ioapic_addr, PG_PREM_RW); ioapic_init(); - init_apic(); + apic_init(); + timer_init(SYS_TIMER_FREQUENCY_HZ); for (size_t i = 256; i < hhk_init_pg_count; i++) { vmm_unmap_page((void*)(i << PG_SIZE_BITS)); diff --git a/lunaix-os/kernel/k_main.c b/lunaix-os/kernel/k_main.c index 8104408..a78562a 100644 --- a/lunaix-os/kernel/k_main.c +++ b/lunaix-os/kernel/k_main.c @@ -1,15 +1,19 @@ #include -#include #include #include #include #include +#include +#include #include extern uint8_t __kernel_start; LOG_MODULE("LX") +void +test_timer(void* payload); + void _kernel_main() { @@ -47,5 +51,21 @@ _kernel_main() lxfree(arr); lxfree(big_); + timer_run_second(1, test_timer, NULL, TIMER_MODE_PERIODIC); + spin(); +} + +static datetime_t datetime; + +void test_timer(void* payload) { + time_getdatetime(&datetime); + + kprintf(KWARN "%u/%02u/%02u %02u:%02u:%02u\r", + datetime.year, + datetime.month, + datetime.day, + datetime.hour, + datetime.minute, + datetime.second); } \ No newline at end of file diff --git a/lunaix-os/kernel/kprintf.c b/lunaix-os/kernel/kprintf.c index 82202ba..3bae867 100644 --- a/lunaix-os/kernel/kprintf.c +++ b/lunaix-os/kernel/kprintf.c @@ -5,7 +5,7 @@ #define MAX_KPRINTF_BUF_SIZE 1024 #define MAX_XFMT_SIZE 1024 -char buf[MAX_KPRINTF_BUF_SIZE]; +static char buf[MAX_KPRINTF_BUF_SIZE]; void __kprintf(const char* component, const char* fmt, va_list args) { diff --git a/lunaix-os/kernel/mm/kalloc.c b/lunaix-os/kernel/mm/kalloc.c index 6f04e2e..e9f0564 100644 --- a/lunaix-os/kernel/mm/kalloc.c +++ b/lunaix-os/kernel/mm/kalloc.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -23,7 +23,7 @@ extern uint8_t __kernel_heap_start; -heap_context_t __kalloc_kheap; +static heap_context_t __kalloc_kheap; void* lx_malloc_internal(heap_context_t* heap, size_t size); diff --git a/lunaix-os/kernel/mm/pmm.c b/lunaix-os/kernel/mm/pmm.c index 304d19d..054b247 100644 --- a/lunaix-os/kernel/mm/pmm.c +++ b/lunaix-os/kernel/mm/pmm.c @@ -13,9 +13,9 @@ uint32_t leading_shifts = \ (page_count + offset) < 8 ? page_count : 8 - offset; -uint8_t pm_bitmap[PM_BMP_MAX_SIZE]; +static uint8_t pm_bitmap[PM_BMP_MAX_SIZE]; -uintptr_t max_pg; +static uintptr_t max_pg; // ... |xxxx xxxx | // ... |-->| diff --git a/lunaix-os/kernel/timer.c b/lunaix-os/kernel/timer.c new file mode 100644 index 0000000..bf3e699 --- /dev/null +++ b/lunaix-os/kernel/timer.c @@ -0,0 +1,196 @@ +/** + * @file timer.c + * @author Lunaixsky + * @brief A simple timer implementation based on APIC with adjustable frequency and subscribable "timerlets" + * @version 0.1 + * @date 2022-03-12 + * + * @copyright Copyright (c) 2022 + * + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) + + +LOG_MODULE("TIMER"); + +static void +temp_intr_routine_rtc_tick(const isr_param* param); + +static void +temp_intr_routine_apic_timer(const isr_param* param); + +static void +timer_update(const isr_param* param); + +static volatile struct lx_timer_context* timer_ctx; + +// Don't optimize them! Took me an half hour to figure that out... + +static volatile uint32_t rtc_counter = 0; +static volatile uint8_t apic_timer_done = 0; + +#define APIC_CALIBRATION_CONST 0x100000 + +void +timer_init_context() +{ + timer_ctx = + (struct lx_timer_context*)lxmalloc(sizeof(struct lx_timer_context)); + + assert_msg(timer_ctx, "Fail to initialize timer contex"); + + timer_ctx->active_timers = + (struct lx_timer*)lxmalloc(sizeof(struct lx_timer)); + llist_init_head(timer_ctx->active_timers); +} + +void +timer_init(uint32_t frequency) +{ + timer_init_context(); + + cpu_disable_interrupt(); + + // Setup APIC timer + + // Setup a one-shot timer, we will use this to measure the bus speed. So we + // can + // then calibrate apic timer to work at *nearly* accurate hz + apic_write_reg(APIC_TIMER_LVT, + LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_ONESHOT)); + + // Set divider to 64 + apic_write_reg(APIC_TIMER_DCR, APIC_TIMER_DIV64); + + /* + Timer calibration process - measure the APIC timer base frequency + + step 1: setup a temporary isr for RTC timer which trigger at each tick + (1024Hz) step 2: setup a temporary isr for #APIC_TIMER_IV step 3: setup + the divider, APIC_TIMER_DCR step 4: Startup RTC timer step 5: Write a + large value, v, to APIC_TIMER_ICR to start APIC timer (this must be + followed immediately after step 4) step 6: issue a write to EOI and clean + up. + + When the APIC ICR counting down to 0 #APIC_TIMER_IV triggered, save the + rtc timer's counter, k, and disable RTC timer immediately (although the + RTC interrupts should be blocked by local APIC as we are currently busy + on handling #APIC_TIMER_IV) + + So the apic timer frequency F_apic in Hz can be calculate as + v / F_apic = k / 1024 + => F_apic = v / k * 1024 + + */ + + timer_ctx->base_frequency = 0; + rtc_counter = 0; + apic_timer_done = 0; + + intr_subscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); + intr_subscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); + + rtc_enable_timer(); // start RTC timer + apic_write_reg(APIC_TIMER_ICR, APIC_CALIBRATION_CONST); // start APIC timer + + // enable interrupt, just for our RTC start ticking! + cpu_enable_interrupt(); + + wait_until(apic_timer_done); + + // cpu_disable_interrupt(); + + assert_msg(timer_ctx->base_frequency, "Fail to initialize timer (NOFREQ)"); + + kprintf(KINFO "Base frequency: %u Hz\n", timer_ctx->base_frequency); + + timer_ctx->running_frequency = frequency; + timer_ctx->tick_interval = timer_ctx->base_frequency / frequency; + + // cleanup + intr_unsubscribe(APIC_TIMER_IV, temp_intr_routine_apic_timer); + intr_unsubscribe(RTC_TIMER_IV, temp_intr_routine_rtc_tick); + + apic_write_reg(APIC_TIMER_LVT, + LVT_ENTRY_TIMER(APIC_TIMER_IV, LVT_TIMER_PERIODIC)); + intr_subscribe(APIC_TIMER_IV, timer_update); + + apic_write_reg(APIC_TIMER_ICR, timer_ctx->tick_interval); +} + +int +timer_run_second(uint32_t second, void (*callback)(void*), void* payload, uint8_t flags) +{ + return timer_run(second * timer_ctx->running_frequency, callback, payload, flags); +} + +int +timer_run(uint32_t ticks, void (*callback)(void*), void* payload, uint8_t flags) +{ + struct lx_timer* timer = (struct lx_timer*)lxmalloc(sizeof(struct lx_timer)); + + if (!timer) return 0; + + timer->callback = callback; + timer->counter = ticks; + timer->deadline = ticks; + timer->payload = payload; + timer->flags = flags; + + llist_append(timer_ctx->active_timers, timer); + + return 1; +} + +static void +timer_update(const isr_param* param) +{ + struct lx_timer *pos, *n; + struct lx_timer* timer_list_head = timer_ctx->active_timers; + + llist_for_each(pos, n, &timer_list_head->link, link) + { + if (--pos->counter) { + continue; + } + + pos->callback ? pos->callback(pos->payload) : 1; + + if (pos->flags & TIMER_MODE_PERIODIC) { + pos->counter = pos->deadline; + } else { + llist_delete(pos); + lxfree(pos); + } + } +} + +static void +temp_intr_routine_rtc_tick(const isr_param* param) +{ + rtc_counter++; + + // dummy read on register C so RTC can send anther interrupt + // This strange behaviour observed in virtual box & bochs + (void)rtc_read_reg(RTC_REG_C); +} + +static void +temp_intr_routine_apic_timer(const isr_param* param) +{ + timer_ctx->base_frequency = + APIC_CALIBRATION_CONST / rtc_counter * RTC_TIMER_BASE_FREQUENCY; + apic_timer_done = 1; + + rtc_disable_timer(); +} \ No newline at end of file diff --git a/lunaix-os/kernel/tty/tty.c b/lunaix-os/kernel/tty/tty.c index e9aa42a..cc70087 100644 --- a/lunaix-os/kernel/tty/tty.c +++ b/lunaix-os/kernel/tty/tty.c @@ -1,17 +1,17 @@ #include #include -#include +#include #include #define TTY_WIDTH 80 #define TTY_HEIGHT 25 -vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR; +static vga_attribute* tty_vga_buffer = (vga_attribute*)VGA_BUFFER_PADDR; -vga_attribute tty_theme_color = VGA_COLOR_BLACK; +static vga_attribute tty_theme_color = VGA_COLOR_BLACK; -uint32_t tty_x = 0; -uint16_t tty_y = 0; +static uint32_t tty_x = 0; +static uint16_t tty_y = 0; void tty_init(void* vga_buf) { tty_vga_buffer = (vga_attribute*)vga_buf;