kernel: add standard clock system
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
27
include/socks/clock.h
Normal 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
29
kernel/clock.c
Normal 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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user