diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs new file mode 100644 index 0000000..664b6bb --- /dev/null +++ b/src/acpi/hpet.rs @@ -0,0 +1,39 @@ +use core::{mem, ptr}; + +use super::sdt::Sdt; + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct GenericAddressStructure { + address_space: u8, + bit_width: u8, + bit_offset: u8, + access_size: u8, + pub address: u64, +} + +#[repr(packed)] +#[derive(Debug)] +pub struct Hpet { + pub header: Sdt, + + pub hw_rev_id: u8, + pub comparator_descriptor: u8, + pub pci_vendor_id: u16, + + pub base_address: GenericAddressStructure, + + pub hpet_number: u8, + pub min_periodic_clk_tick: u16, + pub oem_attribute: u8 +} + +impl Hpet { + pub fn new(sdt: &'static Sdt) -> Option { + if &sdt.signature == b"HPET" && sdt.length as usize >= mem::size_of::() { + Some(unsafe { ptr::read((sdt as *const Sdt) as *const Hpet) }) + } else { + None + } + } +} diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 98d9ba9..f279116 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -18,9 +18,11 @@ use self::madt::{Madt, MadtEntry}; use self::rsdt::Rsdt; use self::sdt::Sdt; use self::xsdt::Xsdt; +use self::hpet::Hpet; use self::aml::{is_aml_table, parse_aml_table, AmlNamespace, AmlError}; +pub mod hpet; mod dmar; mod fadt; mod madt; @@ -195,6 +197,9 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { _ => () } } + } else if let Some(hpet) = Hpet::new(sdt) { + println!(": {}", hpet.hpet_number); + ACPI_TABLE.lock().hpet = Some(hpet); } else if is_aml_table(sdt) { ACPI_TABLE.lock().namespace = match parse_aml_table(sdt) { Ok(res) => { @@ -269,9 +274,10 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { pub struct Acpi { pub fadt: Option, pub namespace: Option, + pub hpet: Option } -pub static ACPI_TABLE: Mutex = Mutex::new(Acpi { fadt: None, namespace: None }); +pub static ACPI_TABLE: Mutex = Mutex::new(Acpi { fadt: None, namespace: None, hpet: None }); /// RSDP #[derive(Copy, Clone, Debug)] diff --git a/src/device/hpet.rs b/src/device/hpet.rs new file mode 100644 index 0000000..3f88f36 --- /dev/null +++ b/src/device/hpet.rs @@ -0,0 +1,82 @@ +use core::intrinsics::{volatile_load, volatile_store}; + +use memory::Frame; +use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress}; + +use acpi::hpet::Hpet; + +pub static mut HPET: HpetDevice = HpetDevice { + capability_addr: 0, + general_config_addr: 0, + general_interrupt_addr: 0, + main_counter_addr: 0, + t0_config_capability_addr: 0, + t0_comparator_addr: 0 +}; + +static LEG_RT_CNF: u64 = 2; +static ENABLE_CNF: u64 = 1; + +static TN_VAL_SET_CNF: u64 = 0x40; +static TN_TYPE_CNF: u64 = 0x08; +static TN_INT_ENB_CNF: u64 = 0x04; + +pub struct HpetDevice { + capability_addr: usize, + general_config_addr: usize, + general_interrupt_addr: usize, + main_counter_addr: usize, + t0_config_capability_addr: usize, + t0_comparator_addr: usize +} + +pub unsafe fn init(hpet: &Hpet, active_table: &mut ActivePageTable) { + HPET.init(hpet, active_table); +} + +impl HpetDevice { + unsafe fn init(&mut self, hpet: &Hpet, active_table: &mut ActivePageTable) { + let base_address = hpet.base_address.address as usize; + + self.capability_addr = base_address; + self.general_config_addr = base_address + 0x10; + self.general_interrupt_addr = base_address + 0x20; + self.main_counter_addr = base_address + 0xF0; + + self.t0_config_capability_addr = base_address + 0x100; + self.t0_comparator_addr = base_address + 0x108; + + { + let page = Page::containing_address(VirtualAddress::new(base_address)); + let frame = Frame::containing_address(PhysicalAddress::new(base_address)); + let result = active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE); + result.flush(active_table); + } + + println!("HPET mapped"); + + let counter_clk_period_fs = self.get_counter_clock_period(); + let desired_fs_period: u64 = 2250286 * 1000000; + + let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs; + + let enable_word: u64 = volatile_load(self.general_config_addr as *const u64) + | LEG_RT_CNF | ENABLE_CNF; + + volatile_store(self.general_config_addr as *mut u64, enable_word); + // Enable interrupts from the HPET + + let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF; + volatile_store(self.t0_config_capability_addr as *mut u64, t0_config_word); + + volatile_store(self.t0_comparator_addr as *mut u64, clk_periods_per_kernel_tick); + } + + pub fn get_counter_clock_period(&self) -> u64 { + unsafe { volatile_load(self.capability_addr as *const u64) >> 32 } + } + + pub fn get_main_counter(&self) -> u64 { + unsafe { volatile_load(self.main_counter_addr as *const u64) } + } +} diff --git a/src/device/mod.rs b/src/device/mod.rs index ef27ccb..965e083 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -1,17 +1,29 @@ use paging::ActivePageTable; +use acpi::ACPI_TABLE; +use syscall::io::{Pio, Io}; pub mod cpu; pub mod local_apic; pub mod pic; +pub mod pit; pub mod rtc; pub mod serial; +pub mod hpet; pub unsafe fn init(active_table: &mut ActivePageTable){ pic::init(); local_apic::init(active_table); } -pub unsafe fn init_noncore() { +pub unsafe fn init_noncore(active_table: &mut ActivePageTable) { + { + if let Some(ref hpet) = ACPI_TABLE.lock().hpet { + hpet::init(hpet, active_table); + } else { + pit::init(); + } + } + rtc::init(); serial::init(); } diff --git a/src/device/pit.rs b/src/device/pit.rs new file mode 100644 index 0000000..4c2fb34 --- /dev/null +++ b/src/device/pit.rs @@ -0,0 +1,20 @@ +use syscall::io::{Io, Pio}; + +pub static mut CHAN0: Pio = Pio::new(0x40); +pub static mut CHAN1: Pio = Pio::new(0x41); +pub static mut CHAN2: Pio = Pio::new(0x42); +pub static mut COMMAND: Pio = Pio::new(0x43); + +static SELECT_CHAN0: u8 = 0; +static LOHI: u8 = 0x30; +static MODE3: u8 = 3; + +static CHAN0_DIVISOR: u16 = 2685; + +pub unsafe fn init() { + COMMAND.write(SELECT_CHAN0 | LOHI | MODE3); + CHAN0.write((CHAN0_DIVISOR & 0xFF) as u8); + CHAN0.write((CHAN0_DIVISOR >> 8) as u8); + + println!("Using PIT"); +} diff --git a/src/start.rs b/src/start.rs index faac4b4..c7a6dd4 100644 --- a/src/start.rs +++ b/src/start.rs @@ -107,7 +107,7 @@ pub unsafe extern fn kstart(kernel_base: usize, kernel_size: usize, stack_base: acpi::init(&mut active_table); // Initialize all of the non-core devices not otherwise needed to complete initialization - device::init_noncore(); + device::init_noncore(&mut active_table); // Initialize memory functions after core has loaded memory::init_noncore();