Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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;
}
104 changes: 104 additions & 0 deletions kernel/src/time/pit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
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;