From 84046f75826125a4c025dafa2b26587626e19dfc Mon Sep 17 00:00:00 2001 From: Eemeli <eemeli.o.lehtonen@utu.fi> Date: Mon, 22 May 2023 15:35:53 +0300 Subject: [PATCH] WIP: vfs devices lazy init --- src/arch/x86_64/cpu/ints.rs | 3 +- src/driver/acpi/apic.rs | 15 ++-- src/driver/acpi/hpet.rs | 82 ++++++++++++++++---- src/driver/acpi/mod.rs | 8 +- src/driver/rtc.rs | 49 ++---------- src/main.rs | 16 +--- src/scheduler/kshell/shell.rs | 5 +- src/scheduler/mod.rs | 1 + src/scheduler/timer.rs | 21 +++++ src/util/atomic_map.rs | 4 + src/util/mod.rs | 1 + src/util/slice_read.rs | 47 +++++++++++ src/vfs/devices.rs | 11 +++ src/vfs/mod.rs | 142 ++++++++++++++++++++++++++++++++-- 14 files changed, 315 insertions(+), 90 deletions(-) create mode 100644 src/scheduler/timer.rs create mode 100644 src/util/slice_read.rs create mode 100644 src/vfs/devices.rs diff --git a/src/arch/x86_64/cpu/ints.rs b/src/arch/x86_64/cpu/ints.rs index baf95e1..04dd61f 100644 --- a/src/arch/x86_64/cpu/ints.rs +++ b/src/arch/x86_64/cpu/ints.rs @@ -160,7 +160,6 @@ pub extern "x86-interrupt" fn keyboard(_: InterruptStackFrame) { } pub extern "x86-interrupt" fn rtc_tick(_: InterruptStackFrame) { - provide_tick(); RTC.int_ack(); eoi_irq(Irq::PicRtc as _); } @@ -171,7 +170,7 @@ pub extern "x86-interrupt" fn apic_timer(_: InterruptStackFrame) { } pub extern "x86-interrupt" fn apic_spurious(_: InterruptStackFrame) { - provide_tick(); + // spurdo spärde keskeytys eoi(); } diff --git a/src/driver/acpi/apic.rs b/src/driver/acpi/apic.rs index 0bb393a..461e340 100644 --- a/src/driver/acpi/apic.rs +++ b/src/driver/acpi/apic.rs @@ -14,21 +14,25 @@ use crate::{ // enable APIC for this processor pub fn enable() { - crate::debug!("Initializing {:?}", ApicId::current()); write_msr( IA32_APIC_BASE, read_msr(IA32_APIC_BASE) | IA32_APIC_XAPIC_ENABLE, ); let regs = unsafe { &mut *(MADT.local_apic_addr as *mut ApicRegs) }; - LAPICS.insert(ApicId::current(), RwLock::new(Lapic { regs })); - let mut lapic = LAPICS.get(&ApicId::current()).unwrap().write(); + let apic_id = ApicId(regs.lapic_id.read()); + + crate::debug!("Initializing {apic_id:?}"); + LAPICS.insert(apic_id, RwLock::new(Lapic { regs })); + let mut lapic = LAPICS.get(&apic_id).unwrap().write(); reset(lapic.regs); init_lvt_timer(lapic.regs); - crate::debug!("Done Initializing {:?}", ApicId::current()); + crate::debug!("Done Initializing {apic_id:?}"); // trace!("APIC regs: {:#?}", lapic.regs); + // write_msr(IA32_TSC_AUX, apic_id.inner() as _); + INT_CONTROLLER.store(IntController::Apic); } @@ -56,7 +60,7 @@ impl ApicId { pub fn current() -> Self { let regs = unsafe { &*(MADT.local_apic_addr as *const ApicRegs) }; Self(regs.lapic_id.read()) - // Self(read_msr(...) as u32) + /* Self(read_msr(IA32_TSC_AUX) as u32) */ } pub fn lapic(&self) -> RwLockReadGuard<'static, Lapic> { @@ -101,6 +105,7 @@ impl Lapic { static LAPICS: AtomicMap<ApicId, RwLock<Lapic>> = AtomicMap::new(); const IA32_APIC_BASE: u32 = 0x1B; +const IA32_TSC_AUX: u32 = 0xC0000103; // lapic id storage - same as in Theseus const IA32_APIC_XAPIC_ENABLE: u64 = 1 << 11; const _IA32_APIC_X2APIC_ENABLE: u64 = 1 << 10; diff --git a/src/driver/acpi/hpet.rs b/src/driver/acpi/hpet.rs index d3aae34..5dbf8a0 100644 --- a/src/driver/acpi/hpet.rs +++ b/src/driver/acpi/hpet.rs @@ -6,15 +6,18 @@ use core::ptr::{read_volatile, write_volatile}; use bit_field::BitField; use chrono::Duration; -use spin::Lazy; +use spin::{Lazy, Mutex}; -use crate::{debug, trace}; +use crate::{ + debug, trace, + vfs::{FileDevice, IoResult}, +}; use super::{rsdt::RSDT, SdtError}; // -pub static HPET: Lazy<Hpet> = Lazy::new(Hpet::init); +pub static HPET: Lazy<Mutex<Hpet>> = Lazy::new(|| Mutex::new(Hpet::init())); // @@ -55,12 +58,8 @@ pub enum HpetError { // impl Hpet { - pub fn get() -> &'static Self { - &HPET - } - pub fn init() -> Self { - Self::try_init().expect("MADT should be valid") + Self::try_init().expect("HPET should be valid") } pub fn try_init() -> Result<Self, HpetError> { @@ -116,7 +115,7 @@ impl Hpet { } pub fn main_counter_value(&mut self) -> CounterValue { - self.read_reg(0x030) + self.read_reg(0x0F0) } pub fn set_main_counter_value(&mut self, val: CounterValue) { @@ -125,6 +124,40 @@ impl Hpet { // + pub fn femtos(&mut self) -> u128 { + self.period as u128 * self.main_counter_value() as u128 + } + + pub fn picos(&mut self) -> u128 { + self.femtos() / 1_000 + } + + pub fn nanos(&mut self) -> u128 { + self.picos() / 1_000 + } + + pub fn micros(&mut self) -> u128 { + self.nanos() / 1_000 + } + + pub fn millis(&mut self) -> u128 { + self.micros() / 1_000 + } + + pub fn seconds(&mut self) -> u128 { + self.millis() / 1_000 + } + + pub fn minutes(&mut self) -> u128 { + self.millis() / 60 + } + + pub fn now_bytes(&mut self) -> [u8; 16] { + self.femtos().to_le_bytes() + } + + // + fn read_reg(&mut self, reg: u64) -> u64 { unsafe { read_volatile((self.addr + reg) as *const u64) } } @@ -143,11 +176,10 @@ impl Hpet { config.set_enable_cnf(1); self.set_config(config); + debug!("HPET caps: {:#x?}", self.caps()); + debug!("HPET config: {:#x?}", self.config()); + debug!("HPET int status: {:#x?}", self.interrupt_status()); debug!("HPET freq: {}", Self::freq(self.period)); - - /* loop { - println!("main counter: {}", self.main_counter_value()); - } */ } #[allow(unused)] @@ -191,6 +223,28 @@ impl From<SdtError> for HpetError { // +pub struct HpetDevice; + +// + +impl FileDevice for HpetDevice { + fn len(&self) -> usize { + core::mem::size_of::<i64>() + } + + fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize> { + let bytes = &HPET.lock().now_bytes()[..]; + bytes.read(offset, buf) + } + + fn write(&mut self, offset: usize, buf: &[u8]) -> IoResult<usize> { + let mut bytes = &HPET.lock().now_bytes()[..]; + bytes.write(offset, buf) + } +} + +// + macro_rules! bitfield { ($name:ident = $t:ty { $($field:ident : $range:expr),* $(,)? }) => { ::paste::paste! { @@ -211,7 +265,7 @@ macro_rules! bitfield { impl ::core::fmt::Debug for $name { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - f.debug_struct("GeneralCaps") + f.debug_struct(stringify!($name)) $( .field(stringify!($field), &self.$field()) )* diff --git a/src/driver/acpi/mod.rs b/src/driver/acpi/mod.rs index 07b52a8..296db8d 100644 --- a/src/driver/acpi/mod.rs +++ b/src/driver/acpi/mod.rs @@ -243,25 +243,25 @@ pub struct Reserved<T = u32> { // TODO: should be <T: Copy> but it breaks rust-analyzer impl<T> ReadOnly<T> { - fn read(&self) -> T { + pub fn read(&self) -> T { unsafe { ptr::read_volatile(&self.val as _) } } } // TODO: should be <T: Copy> but it breaks rust-analyzer impl<T> ReadWrite<T> { - fn read(&self) -> T { + pub fn read(&self) -> T { unsafe { ptr::read_volatile(&self.val as _) } } - fn write(&mut self, val: T) { + pub fn write(&mut self, val: T) { unsafe { ptr::write_volatile(&mut self.val as _, val) } } } // TODO: should be <T: Copy> but it breaks rust-analyzer impl<T> WriteOnly<T> { - fn write(&mut self, val: T) { + pub fn write(&mut self, val: T) { unsafe { ptr::write_volatile(&mut self.val as _, val) } } } diff --git a/src/driver/rtc.rs b/src/driver/rtc.rs index 1daae31..5bd0d56 100644 --- a/src/driver/rtc.rs +++ b/src/driver/rtc.rs @@ -2,7 +2,6 @@ use crate::{ debug, error, vfs::{self, FileDevice}, }; -use alloc::sync::Arc; use chrono::{DateTime, TimeZone, Utc}; use core::{ mem, @@ -37,10 +36,6 @@ impl Rtc { } } - pub fn install_device() { - _ = vfs::create_device("/dev/rtc", true, Arc::new(Mutex::new(RtcDevice)) as _); - } - pub fn enable_ints(&self) { without_interrupts(|| { let mut ports = self.ports.lock(); @@ -108,49 +103,21 @@ impl Rtc { } } -struct RtcDevice; +pub struct RtcDevice; impl FileDevice for RtcDevice { - fn len(&mut self) -> usize { + fn len(&self) -> usize { mem::size_of::<i64>() } - fn read(&mut self, offset: usize, buf: &mut [u8]) -> vfs::IoResult<usize> { - let bytes = RTC.now_bytes(); - - let len = self - .len() - .checked_sub(offset) - .ok_or(vfs::IoError::UnexpectedEOF)? - .min(buf.len()); - - buf[..len].copy_from_slice( - bytes - .get(offset..offset + len) - .ok_or(vfs::IoError::UnexpectedEOF)?, - ); - - Ok(len) - } - - fn read_exact(&mut self, offset: usize, buf: &mut [u8]) -> vfs::IoResult<()> { - let bytes = RTC.now_bytes(); - - buf.copy_from_slice( - bytes - .get(offset..offset + buf.len()) - .ok_or(vfs::IoError::UnexpectedEOF)?, - ); - - Ok(()) - } - - fn write(&mut self, _: usize, _: &mut [u8]) -> vfs::IoResult<usize> { - Err(vfs::IoError::PermissionDenied) + fn read(&self, offset: usize, buf: &mut [u8]) -> vfs::IoResult<usize> { + let bytes = &RTC.now_bytes()[..]; + bytes.read(offset, buf) } - fn write_exact(&mut self, _: usize, _: &mut [u8]) -> vfs::IoResult<()> { - Err(vfs::IoError::PermissionDenied) + fn write(&mut self, offset: usize, buf: &[u8]) -> vfs::IoResult<usize> { + let mut bytes = &RTC.now_bytes()[..]; + bytes.write(offset, buf) } } diff --git a/src/main.rs b/src/main.rs index 2673477..fd91494 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,10 +26,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use crate::{ arch::cpu::idt::Irq, driver::{ - acpi::{ - apic::ApicId, - ioapic::{IoApic, IO_APICS}, - }, + acpi::{apic::ApicId, ioapic::IoApic}, rtc, }, scheduler::kshell::kshell, @@ -102,17 +99,6 @@ fn kernel_main() -> ! { #[cfg(test)] test_main(); - if let Some(time) = rtc::RTC.now() { - debug!("RTC time: {time:?}"); - } - - rtc::RTC.enable_ints(); - rtc::Rtc::install_device(); - debug!( - "ints enabled?: {}", - x86_64::instructions::interrupts::are_enabled() - ); - // main task(s) scheduler::spawn(kshell()); diff --git a/src/scheduler/kshell/shell.rs b/src/scheduler/kshell/shell.rs index dfd37d6..34f8360 100644 --- a/src/scheduler/kshell/shell.rs +++ b/src/scheduler/kshell/shell.rs @@ -1,4 +1,5 @@ use crate::{ + driver::acpi::hpet::HPET, mem::pmm::PageFrameAllocator, util::fmt::NumberPostfix, vfs::{ @@ -67,7 +68,9 @@ impl<'fbo> Shell<'fbo> { self.term.flush(); } - pub fn tick(&mut self) {} + pub fn tick(&mut self) { + // crate::debug!("tick : {}", HPET.lock().main_counter_value()); + } fn prompt(&mut self) { _ = write!(self.term, "\n[kshell {}]# ", self.current_dir.as_str()); diff --git a/src/scheduler/mod.rs b/src/scheduler/mod.rs index 9d8f69d..4abe4e5 100644 --- a/src/scheduler/mod.rs +++ b/src/scheduler/mod.rs @@ -3,6 +3,7 @@ pub mod keyboard; pub mod kshell; pub mod task; pub mod tick; +pub mod timer; // diff --git a/src/scheduler/timer.rs b/src/scheduler/timer.rs new file mode 100644 index 0000000..3707dba --- /dev/null +++ b/src/scheduler/timer.rs @@ -0,0 +1,21 @@ +use alloc::collections::BinaryHeap; +use spin::Mutex; + +use crate::{driver::acpi::apic::ApicId, util::atomic_map::AtomicMap}; + +// + +/* pub static DEADLINES: BinaryHeap<TimerEntry>; */ + +// + +/* pub struct TimerEntry { + // deadline: +} */ + +// + +pub fn test() { + let lapic = ApicId::current().lapic_mut(); + lapic.regs().timer_current.read(); +} diff --git a/src/util/atomic_map.rs b/src/util/atomic_map.rs index e57528e..7d91daf 100644 --- a/src/util/atomic_map.rs +++ b/src/util/atomic_map.rs @@ -65,6 +65,10 @@ impl<K, V> AtomicMap<K, V> { self.len.load(Ordering::Acquire) } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> { let mut cur = &self.head; core::iter::from_fn(move || { diff --git a/src/util/mod.rs b/src/util/mod.rs index b13c840..a536c11 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,4 +1,5 @@ pub mod atomic_map; pub mod bitmap; pub mod fmt; +pub mod slice_read; pub mod stack_str; diff --git a/src/util/slice_read.rs b/src/util/slice_read.rs new file mode 100644 index 0000000..64bfaef --- /dev/null +++ b/src/util/slice_read.rs @@ -0,0 +1,47 @@ +use crate::vfs::{FileDevice, IoError, IoResult}; + +// + +impl FileDevice for &'_ [u8] { + fn len(&self) -> usize { + self.len() + } + + fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize> { + let len = self + .len() + .checked_sub(offset) + .ok_or(IoError::UnexpectedEOF)? + .min(buf.len()); + + buf[..len].copy_from_slice(&self[offset..offset + len]); + + Ok(len) + } + + fn write(&mut self, offset: usize, buf: &[u8]) -> IoResult<usize> { + Err(IoError::PermissionDenied) + } +} + +impl FileDevice for &'_ mut [u8] { + fn len(&self) -> usize { + self.len() + } + + fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize> { + self.as_ref().read(offset, buf) + } + + fn write(&mut self, offset: usize, buf: &[u8]) -> IoResult<usize> { + let len = self + .len() + .checked_sub(offset) + .ok_or(IoError::UnexpectedEOF)? + .min(buf.len()); + + self[offset..offset + len].copy_from_slice(&buf[..len]); + + Ok(len) + } +} diff --git a/src/vfs/devices.rs b/src/vfs/devices.rs new file mode 100644 index 0000000..7ea9798 --- /dev/null +++ b/src/vfs/devices.rs @@ -0,0 +1,11 @@ +use crate::{ + driver::{acpi::hpet::HpetDevice, rtc::RtcDevice}, + vfs, +}; + +// + +pub fn install() { + vfs::install_dev("/dev/rtc", RtcDevice); + vfs::install_dev("/dev/hpet", HpetDevice); +} diff --git a/src/vfs/mod.rs b/src/vfs/mod.rs index 1531956..55b6a0c 100644 --- a/src/vfs/mod.rs +++ b/src/vfs/mod.rs @@ -13,11 +13,17 @@ use self::path::Path; // +pub mod devices; pub mod path; // -pub static ROOT: Lazy<Root> = Lazy::new(|| Directory::from("")); +static _ROOT_NODE: Lazy<Root> = Lazy::new(|| Directory::from("")); +pub static ROOT: Lazy<Root> = Lazy::new(|| { + debug!("Initializing VFS"); + devices::install(); + _ROOT_NODE.clone() +}); // @@ -120,19 +126,51 @@ pub struct Directory { } pub trait FileDevice { - fn len(&mut self) -> usize; + fn len(&self) -> usize; - fn is_empty(&mut self) -> bool { + fn is_empty(&self) -> bool { self.len() == 0 } - fn read(&mut self, offset: usize, buf: &mut [u8]) -> IoResult<usize>; - - fn read_exact(&mut self, offset: usize, buf: &mut [u8]) -> IoResult<()>; + fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize>; + + fn read_exact(&self, mut offset: usize, mut buf: &mut [u8]) -> IoResult<()> { + while !buf.is_empty() { + match self.read(offset, buf) { + Ok(0) => break, + Ok(n) => { + offset += n; + let tmp = buf; + buf = &mut tmp[n..]; + } + Err(IoError::Interrupted) => {} + Err(err) => return Err(err), + } + } - fn write(&mut self, offset: usize, bytes: &mut [u8]) -> IoResult<usize>; + if !buf.is_empty() { + Err(IoError::UnexpectedEOF) + } else { + Ok(()) + } + } - fn write_exact(&mut self, offset: usize, bytes: &mut [u8]) -> IoResult<()>; + fn write(&mut self, offset: usize, buf: &[u8]) -> IoResult<usize>; + + fn write_exact(&mut self, mut offset: usize, mut buf: &[u8]) -> IoResult<()> { + while !buf.is_empty() { + match self.write(offset, buf) { + Ok(0) => return Err(IoError::WriteZero), + Ok(n) => { + offset += n; + buf = &buf[n..]; + } + Err(IoError::Interrupted) => {} + Err(err) => return Err(err), + } + } + Ok(()) + } } pub trait DirectoryDevice { @@ -165,6 +203,12 @@ pub enum IoError { #[snafu(display("unexpected end of file"))] UnexpectedEOF, + + #[snafu(display("interrupted"))] + Interrupted, + + #[snafu(display("wrote nothing"))] + WriteZero, } pub type IoResult<T> = Result<T, IoError>; @@ -215,12 +259,94 @@ impl IoError { IoError::FilesystemError => "filesystem error", IoError::PermissionDenied => "permission denied", IoError::UnexpectedEOF => "unexpected eof", + IoError::Interrupted => "interrupted", + IoError::WriteZero => "wrote nothing", } } } // +fn get_node_with(mut node: Node, path: impl AsRef<Path>, make_dirs: bool) -> IoResult<Node> { + for part in path.as_ref().iter() { + match node { + Node::File(_) => return Err(IoError::NotADirectory), + Node::Directory(_dir) => { + let mut dir = _dir.lock(); + // TODO: only Node::Directory should be cloned + + node = if let Ok(node) = dir.get_node(part) { + node + } else if make_dirs { + let node = Node::Directory(Directory::from(part)); + dir.create_node(part, node.clone())?; + node + } else { + return Err(IoError::NotFound); + }; + } + } + } + + Ok(node) +} + +fn get_dir_with(node: Node, path: impl AsRef<Path>, make_dirs: bool) -> IoResult<DirRef> { + let node = get_node_with(node, path, make_dirs)?; + match node { + Node::File(_) => Err(IoError::NotADirectory), + Node::Directory(dir) => Ok(dir), + } +} + +fn get_file_with( + node: Node, + path: impl AsRef<Path>, + make_dirs: bool, + _create: bool, +) -> IoResult<FileRef> { + let node = get_node_with(node, path, make_dirs)?; + match node { + Node::File(file) => Ok(file), + Node::Directory(_) => Err(IoError::IsADirectory), + } +} + +fn create_device_with( + node: Node, + path: impl AsRef<Path>, + make_dirs: bool, + dev: FileRef, +) -> IoResult<()> { + create_node_with(node, path, make_dirs, Node::File(dev)) +} + +fn install_dev_with( + node: Node, + path: impl AsRef<Path>, + dev: impl FileDevice + Send + Sync + 'static, +) { + let path = path.as_ref(); + debug!("installing VFS device at {path:?}"); + if let Err(err) = create_device_with(node, path, true, Arc::new(Mutex::new(dev)) as _) { + error!("failed to install VFS device at {path:?} : {err:?}"); + } +} + +fn create_node_with( + node: Node, + path: impl AsRef<Path>, + make_dirs: bool, + node: Node, +) -> IoResult<()> { + let (parent_dir, file_name) = path.as_ref().split().ok_or(IoError::NotFound)?; + let parent_dir = get_dir(parent_dir, make_dirs)?; + + let mut parent_dir = parent_dir.lock(); + parent_dir.create_node_with(node, file_name, node)?; + + Ok(()) +} fn create_node(path: impl AsRef<Path>, make_dirs: bool, node: Node) -> IoResult<()> { let (parent_dir, file_name) = path.as_ref().split().ok_or(IoError::NotFound)?; let parent_dir = get_dir(parent_dir, make_dirs)?; -- GitLab