diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs index 9f76caa6e7679f137d92a8fedf90d52af7e90e9d..664b6bb8d69cd8b32a4ee0770ec4f1ef7fefed71 100644 --- a/src/acpi/hpet.rs +++ b/src/acpi/hpet.rs @@ -9,7 +9,7 @@ pub struct GenericAddressStructure { bit_width: u8, bit_offset: u8, access_size: u8, - address: u64, + pub address: u64, } #[repr(packed)] diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index e67715de9272a4532359b457a4f90727e75a123f..f2791169c6cbfee2c5158e071f1618538b2286fc 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -22,7 +22,7 @@ use self::hpet::Hpet; use self::aml::{is_aml_table, parse_aml_table, AmlNamespace, AmlError}; -mod hpet; +pub mod hpet; mod dmar; mod fadt; mod madt; diff --git a/src/device/hpet.rs b/src/device/hpet.rs new file mode 100644 index 0000000000000000000000000000000000000000..3f88f36896f473f5d651ead3c4a503977a145b0d --- /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 ef27ccb240586d4e76b7d8200d9128dfa29a8ab1..5825ff55d68aef857353addbc7610c6e1b4e3e38 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -1,17 +1,35 @@ use paging::ActivePageTable; +use acpi::ACPI_TABLE; +use syscall::io::{Pio, Io}; pub mod cpu; pub mod local_apic; pub mod pic; 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 { + // Disable the PIT + // TODO: Move PIT driver to kernel, and just don't enable it in the first place if we have an HPET + let mut pit_cmd = Pio::<u8>::new(0x43); + let mut pit_c0 = Pio::<u8>::new(0x40); + + pit_cmd.write(0x30); + pit_c0.write(0); + pit_c0.write(0); + + hpet::init(hpet, active_table); + } + } + rtc::init(); serial::init(); } diff --git a/src/start.rs b/src/start.rs index faac4b42540e64aeab158027fd0c943d9a302e07..c7a6dd435cea68f07d78e33554bf0f7333df801a 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();