84 lines
1.8 KiB
C
84 lines
1.8 KiB
C
/*
|
|
* AsterOS Kernel
|
|
* Autor: Pavel Kalaš
|
|
* Rok: 2026
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Tento soubor implementuje ovladac PIT casovace.
|
|
* Nastavuje frekvenci hardwaroveho casovace, drzi globalni citac tiku
|
|
* a poskytuje blokujici uspani jadra na zadany pocet milisekund.
|
|
*/
|
|
|
|
#include "timer.h"
|
|
|
|
static volatile unsigned long g_ticks = 0;
|
|
|
|
static inline unsigned long long read_tsc(void) {
|
|
unsigned int lo;
|
|
unsigned int hi;
|
|
__asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi));
|
|
return ((unsigned long long)hi << 32) | (unsigned long long)lo;
|
|
}
|
|
|
|
static int interrupts_enabled(void) {
|
|
unsigned long long rflags;
|
|
__asm__ volatile ("pushfq; popq %0" : "=r"(rflags));
|
|
return (rflags & (1ULL << 9)) != 0;
|
|
}
|
|
|
|
static void busy_delay_ms(unsigned long ms) {
|
|
unsigned long long start = read_tsc();
|
|
unsigned long long wait_cycles = (unsigned long long)ms * 1000000ULL;
|
|
unsigned long long end = start + wait_cycles;
|
|
|
|
while (read_tsc() < end) {
|
|
__asm__ volatile ("pause");
|
|
}
|
|
}
|
|
|
|
static inline void outb(unsigned short port, unsigned char value) {
|
|
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
|
|
}
|
|
|
|
void timer_init(unsigned int hz) {
|
|
unsigned int divisor;
|
|
|
|
if (hz == 0) {
|
|
hz = 100;
|
|
}
|
|
|
|
divisor = 1193180U / hz;
|
|
|
|
outb(0x43, 0x36);
|
|
outb(0x40, (unsigned char)(divisor & 0xFF));
|
|
outb(0x40, (unsigned char)((divisor >> 8) & 0xFF));
|
|
}
|
|
|
|
unsigned long timer_ticks(void) {
|
|
return g_ticks;
|
|
}
|
|
|
|
void timer_tick_advance(void) {
|
|
++g_ticks;
|
|
}
|
|
|
|
void timer_sleep_ms(unsigned long ms) {
|
|
if (!interrupts_enabled()) {
|
|
busy_delay_ms(ms);
|
|
return;
|
|
}
|
|
|
|
unsigned long start = timer_ticks();
|
|
unsigned long wait_ticks = (ms + 9UL) / 10UL;
|
|
|
|
if (wait_ticks == 0) {
|
|
wait_ticks = 1;
|
|
}
|
|
|
|
while ((timer_ticks() - start) < wait_ticks) {
|
|
__asm__ volatile ("hlt");
|
|
}
|
|
}
|