X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/2804ceee4ce65d49e9d52d0ed817317c0ac9efdc..35a7d633d3f16c1e0539af6ca5d8e7482926cd93:/lunaix-os/kernel/time/timer.c diff --git a/lunaix-os/kernel/time/timer.c b/lunaix-os/kernel/time/timer.c index 989256f..12c8e7f 100644 --- a/lunaix-os/kernel/time/timer.c +++ b/lunaix-os/kernel/time/timer.c @@ -9,174 +9,68 @@ * @copyright Copyright (c) 2022 * */ -#include -#include -#include -#include #include #include #include #include #include #include +#include -#include - -#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector) +#include 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 = NULL; +timer_update(); -// Don't optimize them! Took me an half hour to figure that out... +static DEFINE_LLIST(timers); -static volatile uint32_t rtc_counter = 0; -static volatile uint8_t apic_timer_done = 0; - -static volatile uint32_t sched_ticks = 0; -static volatile uint32_t sched_ticks_counter = 0; +static volatile u32_t sched_ticks = 0; +static volatile u32_t sched_ticks_counter = 0; static struct cake_pile* timer_pile; -#define APIC_CALIBRATION_CONST 0x100000 - void timer_init_context() { timer_pile = cake_new_pile("timer", sizeof(struct lx_timer), 1, 0); - timer_ctx = - (struct lx_timer_context*)valloc(sizeof(struct lx_timer_context)); - - assert_msg(timer_ctx, "Fail to initialize timer contex"); - - timer_ctx->active_timers = (struct lx_timer*)cake_grab(timer_pile); - llist_init_head(&timer_ctx->active_timers->link); } void -timer_init(uint32_t frequency) +timer_init() { timer_init_context(); - cpu_disable_interrupt(); - - // Setup APIC timer - - // Remap the IRQ 8 (rtc timer's vector) to RTC_TIMER_IV in ioapic - // (Remarks IRQ 8 is pin INTIN8) - // See IBM PC/AT Technical Reference 1-10 for old RTC IRQ - // See Intel's Multiprocessor Specification for IRQ - IOAPIC INTIN - // mapping config. - - // grab ourselves these irq numbers - uint32_t iv_rtc = isrm_bindirq(PC_AT_IRQ_RTC, temp_intr_routine_rtc_tick); - uint32_t iv_timer = isrm_ivexalloc(temp_intr_routine_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(iv_timer, 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 - - */ - -#ifdef __LUNAIXOS_DEBUG__ - if (frequency < 1000) { - kprintf(KWARN "Frequency too low. Millisecond timer might be dodgy."); - } -#endif - - timer_ctx->base_frequency = 0; - rtc_counter = 0; - apic_timer_done = 0; - - 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); - - assert_msg(timer_ctx->base_frequency, "Fail to initialize timer (NOFREQ)"); - - kprintf( - KINFO "hw: %u Hz; os: %u Hz\n", timer_ctx->base_frequency, frequency); + hwtimer_init(SYS_TIMER_FREQUENCY_HZ, timer_update); - timer_ctx->running_frequency = frequency; - timer_ctx->tphz = timer_ctx->base_frequency / frequency; - - // cleanup - isrm_ivfree(iv_timer); - isrm_ivfree(iv_rtc); - - apic_write_reg( - APIC_TIMER_LVT, - LVT_ENTRY_TIMER(isrm_ivexalloc(timer_update), LVT_TIMER_PERIODIC)); - - apic_write_reg(APIC_TIMER_ICR, timer_ctx->tphz); - - sched_ticks = timer_ctx->running_frequency / 1000 * SCHED_TIME_SLICE; + sched_ticks = (SYS_TIMER_FREQUENCY_HZ * SCHED_TIME_SLICE) / 1000; sched_ticks_counter = 0; } struct lx_timer* -timer_run_second(uint32_t second, +timer_run_second(u32_t second, void (*callback)(void*), void* payload, - uint8_t flags) + u8_t flags) { - return timer_run( - second * timer_ctx->running_frequency, callback, payload, flags); + ticks_t t = hwtimer_to_ticks(second, TIME_SEC); + return timer_run(t, callback, payload, flags); } struct lx_timer* -timer_run_ms(uint32_t millisecond, +timer_run_ms(u32_t millisecond, void (*callback)(void*), void* payload, - uint8_t flags) + u8_t flags) { - return timer_run(timer_ctx->running_frequency / 1000 * millisecond, - callback, - payload, - flags); + ticks_t t = hwtimer_to_ticks(millisecond, TIME_MS); + return timer_run(t, callback, payload, flags); } struct lx_timer* -timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags) +timer_run(ticks_t ticks, void (*callback)(void*), void* payload, u8_t flags) { struct lx_timer* timer = (struct lx_timer*)cake_grab(timer_pile); @@ -189,18 +83,17 @@ timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags) timer->payload = payload; timer->flags = flags; - llist_append(&timer_ctx->active_timers->link, &timer->link); + llist_append(&timers, &timer->link); return timer; } static void -timer_update(const isr_param* param) +timer_update() { 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) + llist_for_each(pos, n, &timers, link) { if (--(pos->counter)) { continue; @@ -220,32 +113,7 @@ timer_update(const isr_param* param) if (sched_ticks_counter >= sched_ticks) { sched_ticks_counter = 0; + thread_stats_update_entering(false); schedule(); } } - -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(); -} - -struct lx_timer_context* -timer_context() -{ - return timer_ctx; -} \ No newline at end of file