39
src/acpi/hpet.rs
Normal file
39
src/acpi/hpet.rs
Normal file
@@ -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<Hpet> {
|
||||
if &sdt.signature == b"HPET" && sdt.length as usize >= mem::size_of::<Hpet>() {
|
||||
Some(unsafe { ptr::read((sdt as *const Sdt) as *const Hpet) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Fadt>,
|
||||
pub namespace: Option<AmlNamespace>,
|
||||
pub hpet: Option<Hpet>
|
||||
}
|
||||
|
||||
pub static ACPI_TABLE: Mutex<Acpi> = Mutex::new(Acpi { fadt: None, namespace: None });
|
||||
pub static ACPI_TABLE: Mutex<Acpi> = Mutex::new(Acpi { fadt: None, namespace: None, hpet: None });
|
||||
|
||||
/// RSDP
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
||||
82
src/device/hpet.rs
Normal file
82
src/device/hpet.rs
Normal file
@@ -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) }
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
20
src/device/pit.rs
Normal file
20
src/device/pit.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use syscall::io::{Io, Pio};
|
||||
|
||||
pub static mut CHAN0: Pio<u8> = Pio::new(0x40);
|
||||
pub static mut CHAN1: Pio<u8> = Pio::new(0x41);
|
||||
pub static mut CHAN2: Pio<u8> = Pio::new(0x42);
|
||||
pub static mut COMMAND: Pio<u8> = 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");
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user