From 541898a69a640bfc3107bdc20d096256b98fb75e Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Wed, 17 Oct 2018 23:29:38 -0700 Subject: [PATCH 1/3] Initialize PIT and install interrupt handler. --- kernel/src/lib.rs | 2 ++ kernel/src/pit.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 kernel/src/pit.rs diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 075614f..e694526 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -34,6 +34,7 @@ use shared::multiboot; mod acpi; mod interrupts; mod mm; +mod pit; mod sched; mod selftest; mod sync; @@ -80,6 +81,7 @@ pub extern "C" fn kinit(_mbinfop: *const multiboot::Info, boot_infop: *const han mm::init(mem_map.clone()); acpi::init(); interrupts::init(); + pit::init(); selftest::run_tests(); diff --git a/kernel/src/pit.rs b/kernel/src/pit.rs new file mode 100644 index 0000000..486390f --- /dev/null +++ b/kernel/src/pit.rs @@ -0,0 +1,26 @@ +use ::interrupts::set_irq_handler; +use ::x86_util::{inb, outb}; + +pub fn init() { + 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); + } + + // The PIT IRQ is 0. Set our handler for that IRQ. + set_irq_handler(0, Some(timer_handler)); +} + +fn timer_handler() { + // Do nothing for now. +} + +// 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 = 20; From 82275d145480bcdbbb771d4069fbd63c788f6887 Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Sun, 21 Oct 2018 15:36:17 -0700 Subject: [PATCH 2/3] Move PIT into new module and define TickSource interface. --- kernel/src/lib.rs | 4 +- kernel/src/pit.rs | 26 ----------- kernel/src/time/mod.rs | 15 ++++++ kernel/src/time/pit.rs | 104 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 28 deletions(-) delete mode 100644 kernel/src/pit.rs create mode 100644 kernel/src/time/mod.rs create mode 100644 kernel/src/time/pit.rs diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index e694526..0c5bffd 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -34,10 +34,10 @@ use shared::multiboot; mod acpi; mod interrupts; mod mm; -mod pit; mod sched; mod selftest; mod sync; +mod time; mod x86_util; #[cfg(not(test))] @@ -81,7 +81,7 @@ pub extern "C" fn kinit(_mbinfop: *const multiboot::Info, boot_infop: *const han mm::init(mem_map.clone()); acpi::init(); interrupts::init(); - pit::init(); + time::init(); selftest::run_tests(); diff --git a/kernel/src/pit.rs b/kernel/src/pit.rs deleted file mode 100644 index 486390f..0000000 --- a/kernel/src/pit.rs +++ /dev/null @@ -1,26 +0,0 @@ -use ::interrupts::set_irq_handler; -use ::x86_util::{inb, outb}; - -pub fn init() { - 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); - } - - // The PIT IRQ is 0. Set our handler for that IRQ. - set_irq_handler(0, Some(timer_handler)); -} - -fn timer_handler() { - // Do nothing for now. -} - -// 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 = 20; diff --git a/kernel/src/time/mod.rs b/kernel/src/time/mod.rs new file mode 100644 index 0000000..d8c48c0 --- /dev/null +++ b/kernel/src/time/mod.rs @@ -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; +} diff --git a/kernel/src/time/pit.rs b/kernel/src/time/pit.rs new file mode 100644 index 0000000..d3db63e --- /dev/null +++ b/kernel/src/time/pit.rs @@ -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, +} + +struct PitData { + ticks: u64, + handler: Option, +} + +impl TickSource for Pit { + fn approx_ticks_per_second(&self) -> u64 { + 1193182 / PIT_RELOAD_VALUE as u64 + } + + 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; From 1667094bc6c71d318ac257eb579eb3c1ae26be86 Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Sun, 21 Oct 2018 15:54:31 -0700 Subject: [PATCH 3/3] Apply rustfmt --- kernel/src/time/pit.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/src/time/pit.rs b/kernel/src/time/pit.rs index d3db63e..e2554c3 100644 --- a/kernel/src/time/pit.rs +++ b/kernel/src/time/pit.rs @@ -55,7 +55,12 @@ impl TickSource for Pit { } } -static PIT: Pit = Pit {data: spin::Mutex::new(PitData { ticks: 0, handler: None })}; +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.