From 387cd41e5ebb96517e344a4a2e5b3046617771fc Mon Sep 17 00:00:00 2001 From: Connor Wood Date: Fri, 14 Jul 2017 10:36:27 +0100 Subject: [PATCH 1/4] Implemented ACPI table --- src/acpi/hpet.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/acpi/mod.rs | 4 ++++ 2 files changed, 43 insertions(+) create mode 100644 src/acpi/hpet.rs diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs new file mode 100644 index 0000000..9f76caa --- /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, + 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..7a564af 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}; +mod hpet; mod dmar; mod fadt; mod madt; @@ -195,6 +197,8 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { _ => () } } + } else if let Some(hpet) = Hpet::new(sdt) { + println!(": {:#?}", hpet); } else if is_aml_table(sdt) { ACPI_TABLE.lock().namespace = match parse_aml_table(sdt) { Ok(res) => { From 0cbdb2d0c020d2285babb67ae8cae174d48c2295 Mon Sep 17 00:00:00 2001 From: Connor Wood Date: Fri, 14 Jul 2017 10:39:50 +0100 Subject: [PATCH 2/4] Saved HPET table for global access --- src/acpi/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 7a564af..e67715d 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -198,7 +198,8 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { } } } else if let Some(hpet) = Hpet::new(sdt) { - println!(": {:#?}", hpet); + 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) => { @@ -273,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)] From 0bd6f11a4f91bc580b76338b28735650d2e97fa6 Mon Sep 17 00:00:00 2001 From: Connor Wood Date: Fri, 14 Jul 2017 13:58:06 +0100 Subject: [PATCH 3/4] Implemented HPET driver --- src/acpi/hpet.rs | 2 +- src/acpi/mod.rs | 2 +- src/device/hpet.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++ src/device/mod.rs | 20 ++++++++++- src/start.rs | 2 +- 5 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/device/hpet.rs diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs index 9f76caa..664b6bb 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 e67715d..f279116 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 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..5825ff5 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::::new(0x43); + let mut pit_c0 = Pio::::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 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(); From 0b6bde7c68382ad74b7e16e17595ad5f7f4b1cde Mon Sep 17 00:00:00 2001 From: Connor Wood Date: Fri, 14 Jul 2017 15:26:04 +0100 Subject: [PATCH 4/4] Moved PIT driver into kernel --- src/device/mod.rs | 12 +++--------- src/device/pit.rs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 src/device/pit.rs diff --git a/src/device/mod.rs b/src/device/mod.rs index 5825ff5..965e083 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -5,6 +5,7 @@ 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; @@ -17,16 +18,9 @@ pub unsafe fn init(active_table: &mut ActivePageTable){ 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::::new(0x43); - let mut pit_c0 = Pio::::new(0x40); - - pit_cmd.write(0x30); - pit_c0.write(0); - pit_c0.write(0); - hpet::init(hpet, active_table); + } else { + pit::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"); +}