kernel: add standard clock system

This commit is contained in:
2023-04-28 20:51:51 +01:00
parent 995e364b21
commit 72d8facd47
5 changed files with 123 additions and 35 deletions

View File

@@ -1,4 +1,5 @@
#include <socks/printk.h> #include <socks/printk.h>
#include <socks/clock.h>
#include <socks/vm.h> #include <socks/vm.h>
#include <socks/cpu.h> #include <socks/cpu.h>
#include <arch/acpi/io_apic.hpp> #include <arch/acpi/io_apic.hpp>
@@ -16,6 +17,7 @@
#define IA32_APIC_BASE_MSR_ENABLE 0x800 #define IA32_APIC_BASE_MSR_ENABLE 0x800
static int apic_enabled = 0; static int apic_enabled = 0;
static unsigned int bsp_id = (unsigned int)-1;
using namespace arch::acpi; using namespace arch::acpi;
@@ -118,12 +120,26 @@ static void ioapic_init(uintptr_t base, unsigned int int_base)
queue_push_back(&io_apics, &apic->io_entry); queue_push_back(&io_apics, &apic->io_entry);
} }
static int lapic_clock_irq(void)
{
if (this_cpu() == bsp_id) {
clock_advance(1);
}
return 0;
}
static struct irq_hook lapic_clock_irq_hook = {
{},
lapic_clock_irq,
};
void local_apic_config_timer(void) void local_apic_config_timer(void)
{ {
local_apic lapic(lapic_base); local_apic lapic(lapic_base);
lapic.write(local_apic::TIMER_DIV, 0x3); lapic.write(local_apic::TIMER_DIV, 0x3);
lapic.write(local_apic::TIMER_INITCOUNT, (uint32_t)-1); lapic.write(local_apic::TIMER_INITCOUNT, (uint32_t)-1);
pit_wait(100); clock_wait(10);
lapic.write(local_apic::LVT_TIMER, APIC_LVT_INT_MASKED); lapic.write(local_apic::LVT_TIMER, APIC_LVT_INT_MASKED);
/* mask IRQ0 to block interrupts from the PIT. */ /* mask IRQ0 to block interrupts from the PIT. */
@@ -132,7 +148,8 @@ void local_apic_config_timer(void)
uint32_t total_ticks = 0xFFFFFFFF - lapic.read(local_apic::TIMER_CURCOUNT); uint32_t total_ticks = 0xFFFFFFFF - lapic.read(local_apic::TIMER_CURCOUNT);
total_ticks /= 100; /* convert to LAPIC ticks per kernel clock tick */
total_ticks /= 10;
lapic.write(local_apic::LVT_TIMER, IRQ0 | APIC_LVT_TIMER_MODE_PERIODIC); lapic.write(local_apic::LVT_TIMER, IRQ0 | APIC_LVT_TIMER_MODE_PERIODIC);
lapic.write(local_apic::TIMER_DIV, 0x3); lapic.write(local_apic::TIMER_DIV, 0x3);
@@ -189,8 +206,6 @@ static void init_all_ioapic(struct acpi_madt *madt)
kern_status_t apic_init(void) kern_status_t apic_init(void)
{ {
static unsigned int bsp_id = (unsigned int)-1;
/* the bootstrap processor will be the first one ro call apic_init(). /* the bootstrap processor will be the first one ro call apic_init().
it is responsible for initialising the I/O APICs */ it is responsible for initialising the I/O APICs */
if (bsp_id == (unsigned int)-1) { if (bsp_id == (unsigned int)-1) {
@@ -214,8 +229,13 @@ kern_status_t apic_init(void)
apic_enabled = 1; apic_enabled = 1;
irq_enable(); irq_enable();
pit_start(1000); pit_start(HZ);
return KERN_OK;
local_apic_config_timer(); local_apic_config_timer();
pit_stop();
hook_irq(IRQ0, &lapic_clock_irq_hook);
return KERN_OK; return KERN_OK;
} }

View File

@@ -1,4 +1,5 @@
#include <socks/pmap.h> #include <socks/pmap.h>
#include <socks/clock.h>
#include <socks/types.h> #include <socks/types.h>
#include <socks/object.h> #include <socks/object.h>
#include <arch/e820.h> #include <arch/e820.h>
@@ -46,6 +47,7 @@ int ml_init(uintptr_t arg)
bootstrap_cpu_init(); bootstrap_cpu_init();
vgacon_init(); vgacon_init();
clock_calibrate(500);
print_kernel_banner(); print_kernel_banner();

View File

@@ -1,13 +1,42 @@
#include <socks/printk.h> #include <socks/printk.h>
#include <socks/clock.h>
#include <socks/cpu.h> #include <socks/cpu.h>
#include <arch/ports.h> #include <arch/ports.h>
#include <arch/irq.h> #include <arch/irq.h>
static unsigned long long tick_counter = 0; #define PIT_COUNTER0 0x40
#define PIT_CMD 0x43
#define CMD_BINARY 0x00 // Use Binary counter values
#define CMD_BCD 0x01 // Use Binary Coded Decimal counter values
#define CMD_MODE0 0x00 // Interrupt on Terminal Count
#define CMD_MODE1 0x02 // Hardware Retriggerable One-Shot
#define CMD_MODE2 0x04 // Rate Generator
#define CMD_MODE3 0x06 // Square Wave
#define CMD_MODE4 0x08 // Software Trigerred Strobe
#define CMD_MODE5 0x0a // Hardware Trigerred Strobe
#define CMD_LATCH 0x00
#define CMD_RW_LOW 0x10 // Least Significant Byte
#define CMD_RW_HI 0x20 // Most Significant Byte
#define CMD_RW_BOTH 0x30 // Least followed by Most Significant Byte
#define CMD_COUNTER0 0x00
#define CMD_COUNTER1 0x40
#define CMD_COUNTER2 0x80
#define CMD_READBACK 0xc0
#define PIT_FREQUENCY 1193182
static volatile unsigned long long ticks = 0;
static int pit_callback(void) static int pit_callback(void)
{ {
tick_counter++; clock_advance(1);
ticks++;
return 0; return 0;
} }
@@ -17,39 +46,20 @@ static struct irq_hook pit_irq_hook = {
void pit_start(unsigned int hz) void pit_start(unsigned int hz)
{ {
tick_counter = 0;
unsigned int divisor = 1193180 / hz;
outportb(0x43, 0x36);
uint8_t lo = (uint8_t)(divisor & 0xFF);
uint8_t hi = (uint8_t)((divisor >> 8) & 0xFF);
outportb(0x40, lo);
outportb(0x40, hi);
hook_irq(IRQ0, &pit_irq_hook); hook_irq(IRQ0, &pit_irq_hook);
unsigned int divisor = PIT_FREQUENCY / hz;
outportb(PIT_CMD, CMD_BINARY | CMD_MODE2 | CMD_RW_BOTH | CMD_COUNTER0);
outportb(PIT_COUNTER0, divisor);
outportb(PIT_COUNTER0, divisor >> 8);
} }
void pit_stop(void) void pit_stop(void)
{ {
/* lowest possible frequency */ unsigned int divisor = PIT_FREQUENCY / 20;
unsigned int divisor = 1193180; outportb(PIT_CMD, CMD_BINARY | CMD_MODE4 | CMD_RW_BOTH | CMD_COUNTER0);
outportb(PIT_COUNTER0, divisor);
outportb(0x43, 0x36); outportb(PIT_COUNTER0, divisor >> 8);
uint8_t lo = (uint8_t)(divisor & 0xFF);
uint8_t hi = (uint8_t)((divisor >> 8) & 0xFF);
outportb(0x40, lo);
outportb(0x40, hi);
unhook_irq(IRQ0, &pit_irq_hook); unhook_irq(IRQ0, &pit_irq_hook);
} }
void pit_wait(unsigned int ticks)
{
unsigned long long end = tick_counter + ticks;
while (READ_ONCE(tick_counter) < end) {
}
}

27
include/socks/clock.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef SOCKS_CLOCK_H_
#define SOCKS_CLOCK_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define HZ (clock_hz())
typedef uint64_t clock_ticks_t;
extern volatile clock_ticks_t clock_ticks;
extern clock_ticks_t clock_hz(void);
extern void clock_calibrate(clock_ticks_t hz);
extern void clock_advance(clock_ticks_t ticks);
extern void clock_wait(clock_ticks_t ticks);
#ifdef __cplusplus
}
#endif
#endif

29
kernel/clock.c Normal file
View File

@@ -0,0 +1,29 @@
#include <socks/clock.h>
#include <socks/printk.h>
#include <socks/compiler.h>
static clock_ticks_t ticks_per_sec = 0;
volatile clock_ticks_t clock_ticks = 0;
clock_ticks_t clock_hz(void)
{
return ticks_per_sec;
}
void clock_calibrate(clock_ticks_t hz)
{
ticks_per_sec = hz;
}
void clock_advance(clock_ticks_t ticks)
{
clock_ticks += ticks;
}
void clock_wait(clock_ticks_t ticks)
{
clock_ticks_t end = clock_ticks + ticks;
while (clock_ticks < end) {
}
}