Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod rtc;
mod sched;
mod selftest;
mod sync;
mod time;
mod x86_util;

#[cfg(not(test))]
Expand Down Expand Up @@ -81,6 +82,7 @@ pub extern "C" fn kinit(_mbinfop: *const multiboot::Info, boot_infop: *const han
mm::init(mem_map.clone());
acpi::init();
interrupts::init();
time::init();
rtc::init();

selftest::run_tests();
Expand Down
15 changes: 15 additions & 0 deletions kernel/src/time/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
mod pit;

pub fn init() {
pit::init();
}

/// Represents a periodic tick generator.
trait TickSource {
/// Get an estimation of the ticks emitted per second.
fn approx_ticks_per_second(&self) -> u64;
// Set a function to be called for each tick.
fn set_tick_handler(&mut self, fn(u64));
// Get the current number of elapsed ticks.
fn get_ticks(&self) -> u64;
}
109 changes: 109 additions & 0 deletions kernel/src/time/pit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use spin::Mutex;

use interrupts::set_irq_handler;
use x86_util::{inb, outb};

use super::TickSource;

/// A `TickSource` adapter for the programmable interval timer.
pub struct Pit {
data: spin::Mutex<PitData>,
}

struct PitData {
ticks: u64,
handler: Option<fn(u64)>,
}

impl TickSource for Pit {
fn approx_ticks_per_second(&self) -> u64 {
1193182 / PIT_RELOAD_VALUE as u64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably document this number some how, either a constant or a comment

}

fn set_tick_handler(&mut self, tick_handler: fn(u64)) {
unsafe {
asm!("cli");
}

{
let mut data = self.data.lock();
data.handler = Some(tick_handler);
}

unsafe {
asm!("sti");
}
}

fn get_ticks(&self) -> u64 {
let ticks;

unsafe {
asm!("cli");
}

{
let mut data = self.data.lock();
ticks = data.ticks;
}

unsafe {
asm!("sti");
}

ticks
}
}

static PIT: Pit = Pit {
data: spin::Mutex::new(PitData {
ticks: 0,
handler: None,
}),
};

pub fn init() {
// The PIT IRQ is 0. Set our handler for that IRQ.
set_irq_handler(0, Some(timer_handler));

unsafe {
// Set channel 0 to lobyte/hibyte access mode and rate
// generator operating mode.
outb(0x43, 0b00_11_010_0);
// Output our desired reload value.
outb(0x40, PIT_RELOAD_VALUE as u8);
outb(0x40, (PIT_RELOAD_VALUE >> 8) as u8);
}
}

fn timer_handler() {
let now_ticks;
let maybe_handler;

{
unsafe {
asm!("cli");
}

let mut pit_data = PIT.data.lock();
pit_data.ticks += 1;

now_ticks = pit_data.ticks;
maybe_handler = pit_data.handler;

unsafe {
asm!("sti");
}
}

match maybe_handler {
Some(handler) => handler(now_ticks),
None => (),
};
}

// The counter value at which we want the PIT to generate an
// interrupt. The interrupt frequency is
// 1193182 / `PIT_RELOAD_VALUE`. For an interrupt about every
// 10 microseconds, we use a value of 20.
const PIT_RELOAD_VALUE: u16 = 1193;