From da152319797436368304cbc3f85a3b9ec049134b Mon Sep 17 00:00:00 2001 From: LoGin Date: Thu, 28 Mar 2024 00:28:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86rtc=E7=9A=84?= =?UTF-8?q?=E6=8A=BD=E8=B1=A1=EF=BC=8C=E5=B9=B6=E4=B8=94=E6=8A=8Ax86?= =?UTF-8?q?=E7=9A=84cmos=20rtc=E6=8E=A5=E5=85=A5=E5=88=B0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E9=A9=B1=E5=8A=A8=E6=A8=A1=E5=9E=8B=20(#674)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型。 --- kernel/Cargo.toml | 1 + kernel/crates/driver_base_macros/Cargo.toml | 8 + kernel/crates/driver_base_macros/src/lib.rs | 20 + kernel/src/arch/x86_64/driver/mod.rs | 1 + kernel/src/arch/x86_64/driver/rtc.rs | 312 ++++++++++++++ kernel/src/arch/x86_64/mm/mod.rs | 9 +- kernel/src/driver/base/device/dd.rs | 6 +- kernel/src/driver/base/device/driver.rs | 18 + kernel/src/driver/base/device/mod.rs | 45 +++ kernel/src/driver/base/kobject.rs | 16 + .../driver/base/platform/platform_device.rs | 1 - .../driver/input/serio/i8042/i8042_device.rs | 6 +- kernel/src/driver/mod.rs | 1 + kernel/src/driver/rtc/class.rs | 109 +++++ kernel/src/driver/rtc/interface.rs | 31 ++ kernel/src/driver/rtc/mod.rs | 169 ++++++++ kernel/src/driver/rtc/rtc_cmos.rs | 227 +++++++++++ kernel/src/driver/rtc/sysfs.rs | 379 ++++++++++++++++++ kernel/src/driver/rtc/utils.rs | 16 + kernel/src/driver/serial/serial8250/mod.rs | 4 - kernel/src/driver/timers/mod.rs | 1 - kernel/src/driver/timers/rtc/mod.rs | 2 - kernel/src/driver/timers/rtc/rtc.rs | 90 ----- .../tty/virtual_terminal/virtual_console.rs | 6 +- kernel/src/driver/video/fbdev/vesafb.rs | 5 - kernel/src/time/mod.rs | 56 +++ kernel/src/time/timekeep.rs | 50 +-- kernel/src/time/timekeeping.rs | 8 + 28 files changed, 1441 insertions(+), 156 deletions(-) create mode 100644 kernel/crates/driver_base_macros/Cargo.toml create mode 100644 kernel/crates/driver_base_macros/src/lib.rs create mode 100644 kernel/src/arch/x86_64/driver/rtc.rs create mode 100644 kernel/src/driver/rtc/class.rs create mode 100644 kernel/src/driver/rtc/interface.rs create mode 100644 kernel/src/driver/rtc/mod.rs create mode 100644 kernel/src/driver/rtc/rtc_cmos.rs create mode 100644 kernel/src/driver/rtc/sysfs.rs create mode 100644 kernel/src/driver/rtc/utils.rs delete mode 100644 kernel/src/driver/timers/rtc/mod.rs delete mode 100644 kernel/src/driver/timers/rtc/rtc.rs diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2f049bf6..8967dd99 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -31,6 +31,7 @@ bit_field = "=0.10" bitfield-struct = "=0.5.3" bitflags = "=1.3.2" bitmap = { path = "crates/bitmap" } +driver_base_macros = { "path" = "crates/driver_base_macros" } # 一个no_std的hashmap、hashset elf = { version = "=0.7.2", default-features = false } hashbrown = "=0.13.2" diff --git a/kernel/crates/driver_base_macros/Cargo.toml b/kernel/crates/driver_base_macros/Cargo.toml new file mode 100644 index 00000000..c9e5799e --- /dev/null +++ b/kernel/crates/driver_base_macros/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "driver_base_macros" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/kernel/crates/driver_base_macros/src/lib.rs b/kernel/crates/driver_base_macros/src/lib.rs new file mode 100644 index 00000000..dee56340 --- /dev/null +++ b/kernel/crates/driver_base_macros/src/lib.rs @@ -0,0 +1,20 @@ +#![no_std] + +/// 获取指定字段 +/// +/// 当weak指针的strong count为0的时候,清除弱引用 +#[macro_export] +macro_rules! get_weak_or_clear { + ($field:expr) => {{ + if let Some(x) = $field.clone() { + if x.strong_count() == 0 { + $field = None; + None + } else { + Some(x) + } + } else { + None + } + }}; +} diff --git a/kernel/src/arch/x86_64/driver/mod.rs b/kernel/src/arch/x86_64/driver/mod.rs index cebddb96..4236ad1c 100644 --- a/kernel/src/arch/x86_64/driver/mod.rs +++ b/kernel/src/arch/x86_64/driver/mod.rs @@ -1,4 +1,5 @@ pub mod apic; pub mod hpet; +pub mod rtc; pub mod tsc; pub mod video; diff --git a/kernel/src/arch/x86_64/driver/rtc.rs b/kernel/src/arch/x86_64/driver/rtc.rs new file mode 100644 index 00000000..0612038e --- /dev/null +++ b/kernel/src/arch/x86_64/driver/rtc.rs @@ -0,0 +1,312 @@ +use core::any::Any; + +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, +}; +use system_error::SystemError; +use unified_init::macros::unified_init; + +use crate::{ + arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch}, + driver::{ + base::{ + class::Class, + device::{ + bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceState, + DeviceType, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + platform::platform_device::{platform_device_manager, PlatformDevice}, + }, + rtc::{RtcClassOps, RtcDevice, RtcTime}, + }, + exception::InterruptArch, + filesystem::kernfs::KernFSInode, + init::initcall::INITCALL_DEVICE, + kerror, + libs::{ + mutex::Mutex, + rwlock::{RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, +}; + +#[derive(Debug)] +#[cast_to([sync] Device, PlatformDevice, RtcDevice)] +struct CmosRtcDevice { + inner: SpinLock, + locked_kobjstate: LockedKObjectState, + ops_mutex: Mutex<()>, +} + +impl CmosRtcDevice { + const NAME: &str = "rtc_cmos"; + pub fn new() -> Arc { + let r = CmosRtcDevice { + inner: SpinLock::new(InnerCmosRtc { + device_common: DeviceCommonData::default(), + kobject_common: KObjectCommonData::default(), + device_state: DeviceState::NotInitialized, + }), + locked_kobjstate: LockedKObjectState::new(None), + ops_mutex: Mutex::new(()), + }; + + r.inner().device_common.can_match = true; + + Arc::new(r) + } + + fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } + + ///置位0x70的第7位,禁止不可屏蔽中断 + #[inline] + fn read_cmos(&self, addr: u8) -> u8 { + unsafe { + CurrentPortIOArch::out8(0x70, 0x80 | addr); + return CurrentPortIOArch::in8(0x71); + } + } +} + +#[derive(Debug)] +struct InnerCmosRtc { + device_common: DeviceCommonData, + kobject_common: KObjectCommonData, + + device_state: DeviceState, +} + +impl RtcDevice for CmosRtcDevice { + fn class_ops(&self) -> &'static dyn RtcClassOps { + &CmosRtcClassOps + } +} + +impl PlatformDevice for CmosRtcDevice { + fn pdev_name(&self) -> &str { + Self::NAME + } + + fn set_pdev_id(&self, _id: i32) { + todo!() + } + + fn set_pdev_id_auto(&self, _id_auto: bool) { + todo!() + } + + fn is_initialized(&self) -> bool { + self.inner().device_state == DeviceState::Initialized + } + + fn set_state(&self, set_state: DeviceState) { + self.inner().device_state = set_state; + } +} + +impl Device for CmosRtcDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Rtc + } + + fn id_table(&self) -> IdTable { + IdTable::new(Self::NAME.to_string(), None) + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn class(&self) -> Option> { + self.inner() + .device_common + .get_class_weak_or_clear() + .and_then(|c| c.upgrade()) + } + + fn driver(&self) -> Option> { + self.inner() + .device_common + .get_driver_weak_or_clear() + .and_then(|d| d.upgrade()) + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + self.inner().device_common.dead + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn bus(&self) -> Option> { + self.inner().device_common.get_bus_weak_or_clear() + } +} + +impl KObject for CmosRtcDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.get_parent_or_clear_weak() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + Self::NAME.to_string() + } + + fn set_name(&self, _name: String) { + // Do nothing + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.locked_kobjstate.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.locked_kobjstate.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobjstate.write() = state; + } +} + +#[derive(Debug)] +pub struct CmosRtcClassOps; + +impl RtcClassOps for CmosRtcClassOps { + fn read_time(&self, dev: &Arc) -> Result { + // 检查是否为cmos rtc + let dev = dev + .as_any_ref() + .downcast_ref::() + .ok_or(SystemError::EINVAL)?; + + let _guard = dev.ops_mutex.lock(); + + // 为防止中断请求打断该过程,需要先关中断 + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + //0x0B + let status_register_b: u8 = dev.read_cmos(0x0B); // 读取状态寄存器B + let is_24h: bool = (status_register_b & 0x02) != 0; + // 判断是否启用24小时模式 + let is_binary: bool = (status_register_b & 0x04) != 0; // 判断是否为二进制码 + let mut res = RtcTime::default(); + + loop { + res.year = dev.read_cmos(CMOSTimeSelector::Year as u8) as i32; + res.month = dev.read_cmos(CMOSTimeSelector::Month as u8) as i32; + res.mday = dev.read_cmos(CMOSTimeSelector::Day as u8) as i32; + res.hour = dev.read_cmos(CMOSTimeSelector::Hour as u8) as i32; + res.minute = dev.read_cmos(CMOSTimeSelector::Minute as u8) as i32; + res.second = dev.read_cmos(CMOSTimeSelector::Second as u8) as i32; + + if res.second == dev.read_cmos(CMOSTimeSelector::Second as u8) as i32 { + break; + } // 若读取时间过程中时间发生跳变则重新读取 + } + + unsafe { + CurrentPortIOArch::out8(0x70, 0x00); + } + + if !is_binary + // 把BCD转为二进制 + { + res.second = (res.second & 0xf) + (res.second >> 4) * 10; + res.minute = (res.minute & 0xf) + (res.minute >> 4) * 10; + res.hour = ((res.hour & 0xf) + ((res.hour & 0x70) >> 4) * 10) | (res.hour & 0x80); + res.mday = (res.mday & 0xf) + ((res.mday / 16) * 10); + res.month = (res.month & 0xf) + (res.month >> 4) * 10; + res.year = (res.year & 0xf) + (res.year >> 4) * 10; + } + res.year += 100; + + if (!is_24h) && (res.hour & 0x80) != 0 { + res.hour = ((res.hour & 0x7f) + 12) % 24; + } // 将十二小时制转为24小时 + + res.month -= 1; + + drop(irq_guard); + + return Ok(res); + } + + fn set_time(&self, _dev: &Arc, _time: &RtcTime) -> Result<(), SystemError> { + kerror!("set_time is not implemented for CmosRtcClassOps"); + Err(SystemError::ENOSYS) + } +} + +/// used in the form of u8 +#[repr(u8)] +enum CMOSTimeSelector { + Second = 0x00, + Minute = 0x02, + Hour = 0x04, + Day = 0x07, + Month = 0x08, + Year = 0x09, +} + +#[unified_init(INITCALL_DEVICE)] +pub fn cmos_rtc_device_init() -> Result<(), SystemError> { + let device = CmosRtcDevice::new(); + device_manager().device_default_initialize(&(device.clone() as Arc)); + platform_device_manager().device_add(device)?; + + return Ok(()); +} diff --git a/kernel/src/arch/x86_64/mm/mod.rs b/kernel/src/arch/x86_64/mm/mod.rs index c1d63f9a..1ef63618 100644 --- a/kernel/src/arch/x86_64/mm/mod.rs +++ b/kernel/src/arch/x86_64/mm/mod.rs @@ -404,10 +404,13 @@ impl VirtAddr { } unsafe fn allocator_init() { - let virt_offset = BOOTSTRAP_MM_INFO.unwrap().start_brk; - let phy_offset = - unsafe { MMArch::virt_2_phys(VirtAddr::new(page_align_up(virt_offset))) }.unwrap(); + let virt_offset = VirtAddr::new(page_align_up(BOOTSTRAP_MM_INFO.unwrap().start_brk)); + let phy_offset = unsafe { MMArch::virt_2_phys(virt_offset) }.unwrap(); + + mem_block_manager() + .reserve_block(PhysAddr::new(0), phy_offset.data()) + .expect("Failed to reserve block"); let mut bump_allocator = BumpAllocator::::new(phy_offset.data()); kdebug!( "BumpAllocator created, offset={:?}", diff --git a/kernel/src/driver/base/device/dd.rs b/kernel/src/driver/base/device/dd.rs index 583ae1e4..a5951d38 100644 --- a/kernel/src/driver/base/device/dd.rs +++ b/kernel/src/driver/base/device/dd.rs @@ -277,16 +277,14 @@ impl DriverManager { .and_then(|bus| bus.upgrade()) .ok_or(SystemError::EINVAL)?; for dev in bus.subsystem().devices().iter() { - if self.do_driver_attach(dev, driver) { - // 匹配成功 - return Ok(()); - } + self.do_driver_attach(dev, driver); } return Ok(()); } /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/dd.c?fi=driver_attach#1134 + #[inline(never)] fn do_driver_attach(&self, device: &Arc, driver: &Arc) -> bool { let r = self.match_device(driver, device).unwrap_or(false); if !r { diff --git a/kernel/src/driver/base/device/driver.rs b/kernel/src/driver/base/device/driver.rs index 10b5cba7..bedee6fb 100644 --- a/kernel/src/driver/base/device/driver.rs +++ b/kernel/src/driver/base/device/driver.rs @@ -109,6 +109,24 @@ pub trait Driver: Sync + Send + Debug + KObject { } } +#[derive(Debug, Default)] +pub struct DriverCommonData { + pub devices: Vec>, + pub bus: Option>, +} + +impl DriverCommonData { + pub fn push_device(&mut self, device: Arc) { + if !self.devices.iter().any(|d| Arc::ptr_eq(d, &device)) { + self.devices.push(device); + } + } + + pub fn delete_device(&mut self, device: &Arc) { + self.devices.retain(|d| !Arc::ptr_eq(d, device)); + } +} + impl dyn Driver { pub fn allows_async_probing(&self) -> bool { match self.probe_type() { diff --git a/kernel/src/driver/base/device/mod.rs b/kernel/src/driver/base/device/mod.rs index fc706ff0..d4d5583c 100644 --- a/kernel/src/driver/base/device/mod.rs +++ b/kernel/src/driver/base/device/mod.rs @@ -201,6 +201,51 @@ impl dyn Device { } } +/// 实现了Device trait的设备需要拥有的数据 +#[derive(Debug)] +pub struct DeviceCommonData { + pub bus: Option>, + pub class: Option>, + pub driver: Option>, + pub dead: bool, + pub can_match: bool, +} + +impl Default for DeviceCommonData { + fn default() -> Self { + Self { + bus: None, + class: None, + driver: None, + dead: false, + can_match: true, + } + } +} + +impl DeviceCommonData { + /// 获取bus字段 + /// + /// 当weak指针的strong count为0的时候,清除弱引用 + pub fn get_bus_weak_or_clear(&mut self) -> Option> { + driver_base_macros::get_weak_or_clear!(self.bus) + } + + /// 获取class字段 + /// + /// 当weak指针的strong count为0的时候,清除弱引用 + pub fn get_class_weak_or_clear(&mut self) -> Option> { + driver_base_macros::get_weak_or_clear!(self.class) + } + + /// 获取driver字段 + /// + /// 当weak指针的strong count为0的时候,清除弱引用 + pub fn get_driver_weak_or_clear(&mut self) -> Option> { + driver_base_macros::get_weak_or_clear!(self.driver) + } +} + // 暂定是不可修改的,在初始化的时候就要确定。以后可能会包括例如硬件中断包含的信息 #[allow(dead_code)] #[derive(Debug, Clone)] diff --git a/kernel/src/driver/base/kobject.rs b/kernel/src/driver/base/kobject.rs index 4cbdf6d2..de45c401 100644 --- a/kernel/src/driver/base/kobject.rs +++ b/kernel/src/driver/base/kobject.rs @@ -4,6 +4,7 @@ use alloc::{ string::String, sync::{Arc, Weak}, }; +use driver_base_macros::get_weak_or_clear; use intertrait::CastFromSync; use crate::{ @@ -73,6 +74,21 @@ impl DowncastArc for dyn KObject { } } +/// kobject的公共数据 +#[derive(Debug, Default)] +pub struct KObjectCommonData { + pub kern_inode: Option>, + pub parent: Option>, + pub kset: Option>, + pub kobj_type: Option<&'static dyn KObjType>, +} + +impl KObjectCommonData { + pub fn get_parent_or_clear_weak(&mut self) -> Option> { + get_weak_or_clear!(self.parent) + } +} + pub trait KObjType: Debug + Send + Sync { /// 当指定的kobject被释放时,设备驱动模型会调用此方法 fn release(&self, _kobj: Arc) {} diff --git a/kernel/src/driver/base/platform/platform_device.rs b/kernel/src/driver/base/platform/platform_device.rs index 88d43eeb..50701f5c 100644 --- a/kernel/src/driver/base/platform/platform_device.rs +++ b/kernel/src/driver/base/platform/platform_device.rs @@ -61,7 +61,6 @@ pub trait PlatformDevice: Device { /// 设置id是否为自动分配 fn set_pdev_id_auto(&self, id_auto: bool); - fn compatible_table(&self) -> CompatibleTable; /// @brief: 判断设备是否初始化 /// @parameter: None /// @return: 如果已经初始化,返回true,否则,返回false diff --git a/kernel/src/driver/input/serio/i8042/i8042_device.rs b/kernel/src/driver/input/serio/i8042/i8042_device.rs index 9ad0be2a..f774c060 100644 --- a/kernel/src/driver/input/serio/i8042/i8042_device.rs +++ b/kernel/src/driver/input/serio/i8042/i8042_device.rs @@ -9,7 +9,7 @@ use crate::{ device::{bus::Bus, driver::Driver, Device, DeviceState, DeviceType, IdTable}, kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, kset::KSet, - platform::{platform_device::PlatformDevice, CompatibleTable}, + platform::platform_device::PlatformDevice, }, filesystem::kernfs::KernFSInode, libs::{ @@ -184,10 +184,6 @@ impl PlatformDevice for I8042PlatformDevice { self.inner.lock().pdev_id_auto = id_auto; } - fn compatible_table(&self) -> CompatibleTable { - todo!() - } - fn is_initialized(&self) -> bool { self.inner.lock().device_state == DeviceState::Initialized } diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 6ca19f10..de767936 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -8,6 +8,7 @@ pub mod keyboard; pub mod net; pub mod open_firmware; pub mod pci; +pub mod rtc; pub mod serial; pub mod timers; pub mod tty; diff --git a/kernel/src/driver/rtc/class.rs b/kernel/src/driver/rtc/class.rs new file mode 100644 index 00000000..357fa4e0 --- /dev/null +++ b/kernel/src/driver/rtc/class.rs @@ -0,0 +1,109 @@ +use alloc::{ + string::ToString, + sync::{Arc, Weak}, +}; +use system_error::SystemError; +use unified_init::macros::unified_init; + +use crate::{ + driver::base::{ + class::{class_manager, Class}, + device::{device_manager, sys_dev_char_kset}, + kobject::KObject, + subsys::SubSysPrivate, + }, + init::initcall::INITCALL_SUBSYS, + time::{timekeeping::do_settimeofday64, TimeSpec}, +}; + +use super::{interface::rtc_read_time, register_default_rtc, sysfs::RtcGeneralDevice}; + +/// `/sys/class/rtc` 的 class 实例 +static mut CLASS_RTC_INSTANCE: Option> = None; + +/// 获取 `/sys/class/rtc` 的 class 实例 +#[inline(always)] +#[allow(dead_code)] +pub fn sys_class_rtc_instance() -> Option<&'static Arc> { + unsafe { CLASS_RTC_INSTANCE.as_ref() } +} + +/// 初始化帧缓冲区子系统 +#[unified_init(INITCALL_SUBSYS)] +pub fn fbmem_init() -> Result<(), SystemError> { + let rtc_class = RtcClass::new(); + class_manager().class_register(&(rtc_class.clone() as Arc))?; + + unsafe { + CLASS_RTC_INSTANCE = Some(rtc_class); + } + + return Ok(()); +} + +/// `/sys/class/rtc` 类 +#[derive(Debug)] +pub struct RtcClass { + subsystem: SubSysPrivate, +} + +impl RtcClass { + const NAME: &'static str = "rtc"; + pub fn new() -> Arc { + let r = Self { + subsystem: SubSysPrivate::new(Self::NAME.to_string(), None, None, &[]), + }; + let r = Arc::new(r); + r.subsystem() + .set_class(Some(Arc::downgrade(&r) as Weak)); + + return r; + } +} + +impl Class for RtcClass { + fn name(&self) -> &'static str { + return Self::NAME; + } + + fn dev_kobj(&self) -> Option> { + Some(sys_dev_char_kset() as Arc) + } + + fn set_dev_kobj(&self, _kobj: Arc) { + unimplemented!("RtcClass::set_dev_kobj"); + } + + fn subsystem(&self) -> &SubSysPrivate { + return &self.subsystem; + } +} + +/// 注册rtc通用设备 +pub(super) fn rtc_register_device(dev: &Arc) -> Result<(), SystemError> { + device_manager().add_device(dev.clone())?; + register_default_rtc(dev.clone()); + // 把硬件时间同步到系统时间 + rtc_hctosys(dev); + return Ok(()); +} + +fn rtc_hctosys(dev: &Arc) { + let r = rtc_read_time(dev); + if let Err(e) = r { + dev.set_hc2sys_result(Err(e)); + return; + } + + let time = r.unwrap(); + let timespec64: TimeSpec = time.into(); + let r = do_settimeofday64(timespec64); + dev.set_hc2sys_result(r); + + kinfo!( + "Setting system clock to {} {} UTC ({})", + time.date_string(), + time.time_string(), + timespec64.tv_sec + ); +} diff --git a/kernel/src/driver/rtc/interface.rs b/kernel/src/driver/rtc/interface.rs new file mode 100644 index 00000000..bcf6d616 --- /dev/null +++ b/kernel/src/driver/rtc/interface.rs @@ -0,0 +1,31 @@ +use alloc::sync::Arc; +use system_error::SystemError; + +use crate::driver::base::kobject::KObject; + +use super::{global_default_rtc, sysfs::RtcGeneralDevice, utils::kobj2rtc_device, RtcTime}; + +/// 根据rtc general device, 读取真实时间 +pub fn rtc_read_time(general_dev: &Arc) -> Result { + let class_ops = general_dev.class_ops().ok_or(SystemError::EINVAL)?; + + let real_dev = general_dev + .parent() + .and_then(|p| p.upgrade()) + .ok_or(SystemError::ENODEV)?; + + let real_dev = kobj2rtc_device(real_dev).ok_or(SystemError::EINVAL)?; + + let time = class_ops.read_time(&real_dev)?; + + if !time.valid() { + return Err(SystemError::EINVAL); + } + + return Ok(time); +} + +/// 从全局默认的rtc时钟那里读取时间 +pub fn rtc_read_time_default() -> Result { + rtc_read_time(&global_default_rtc().ok_or(SystemError::ENODEV)?) +} diff --git a/kernel/src/driver/rtc/mod.rs b/kernel/src/driver/rtc/mod.rs new file mode 100644 index 00000000..9abddaf3 --- /dev/null +++ b/kernel/src/driver/rtc/mod.rs @@ -0,0 +1,169 @@ +use core::fmt::Debug; + +use alloc::{string::String, sync::Arc}; +use system_error::SystemError; + +use crate::{ + libs::rwlock::RwLock, + time::{Instant, TimeSpec, NSEC_PER_SEC}, +}; + +use self::sysfs::RtcGeneralDevice; + +use super::base::device::Device; + +pub mod class; +pub mod interface; +pub mod rtc_cmos; +mod sysfs; +mod utils; + +/// 全局默认rtc +static GLOBAL_DEFAULT_RTC: RwLock>> = RwLock::new(None); + +/// 获取全局的默认的rtc +fn global_default_rtc() -> Option> { + GLOBAL_DEFAULT_RTC.read().clone() +} + +/// 注册默认的rtc +fn register_default_rtc(general_device: Arc) -> bool { + let upg = GLOBAL_DEFAULT_RTC.upgradeable_read(); + if let Some(old_dev) = upg.as_ref() { + if old_dev.priority() >= general_device.priority() { + return false; + } + } + + let mut write = upg.upgrade(); + + write.replace(general_device); + + return true; +} + +/// RTC设备的trait +pub trait RtcDevice: Device { + fn class_ops(&self) -> &'static dyn RtcClassOps; +} + +pub trait RtcClassOps: Send + Sync + Debug { + fn read_time(&self, dev: &Arc) -> Result; + fn set_time(&self, dev: &Arc, time: &RtcTime) -> Result<(), SystemError>; +} + +#[derive(Default, Debug, Clone, Copy)] +pub struct RtcTime { + /// `second`: 秒,范围从 0 到 59 + pub second: i32, + /// `minute`: 分钟,范围从 0 到 59 + pub minute: i32, + /// `hour`: 小时,范围从 0 到 23 + pub hour: i32, + /// `mday`: 一个月中的第几天,范围从 1 到 31 + pub mday: i32, + /// `month`: 月份,范围从 0 到 11 + pub month: i32, + /// `year`: 年份(相对于1900年) + pub year: i32, + /// `wday`: 一周中的第几天,范围从 0(周日)到 6(周六) + pub wday: i32, + /// `yday`: 一年中的第几天,范围从 1 到 366 + pub yday: i32, + /// `isdst`: 表示是否为夏令时,通常如果是夏令时,此值为正,否则为零或负 + pub isdst: i32, +} + +impl RtcTime { + /// 返回一个格式化的日期字符串 + /// + /// 例如,如果日期为2021年1月1日,则返回"2021-01-01" + pub fn date_string(&self) -> String { + format!( + "{:04}-{:02}-{:02}", + self.year_real(), + self.month_real(), + self.mday + ) + } + + /// 返回一个格式化的时间字符串 + /// + /// 例如,如果时间为12:00:00,则返回"12:00:00" + pub fn time_string(&self) -> String { + format!("{:02}:{:02}:{:02}", self.hour, self.minute, self.second) + } + + pub fn valid(&self) -> bool { + !(self.year < 70 + || self.year > (i32::MAX - 1900) + || self.month >= 12 + || self.month < 0 + || self.mday < 1 + || self.mday > self.month_days() + || self.hour >= 24 + || self.hour < 0 + || self.minute >= 60 + || self.minute < 0 + || self.second >= 60 + || self.second < 0) + } + + /// 获取当月有多少天 + pub fn month_days(&self) -> i32 { + let days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + let month = self.month as usize; + let mut days = days_in_month[month]; + + if month == 1 && self.is_leap_year() { + days += 1; + } + + days + } + + /// 判断当前是否为闰年 + pub fn is_leap_year(&self) -> bool { + let year = self.year + 1900; + (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 + } + + pub fn year_real(&self) -> i32 { + self.year + 1900 + } + + pub fn month_real(&self) -> i32 { + self.month + 1 + } +} + +impl From for TimeSpec { + fn from(val: RtcTime) -> Self { + let instant = Instant::mktime64( + val.year_real() as u32, + (val.month + 1) as u32, + (val.mday) as u32, + val.hour as u32, + val.minute as u32, + val.second as u32, + ); + + /* 注意:RTC 仅存储完整的秒数。它是任意的,它存储的是最接近的值还是 + * 分割秒数截断的值。然而,重要的是我们使用它来存储截断的值。这是因为 + * 否则在 RTC 同步函数中,需要读取 both xtime.tv_sec 和 xtime.tv_nsec。 + * 在某些处理器上(例如 ARM),对 >32位的原子读取是不可行的。所以, + * 存储最接近的值会减慢同步 API 的速度。因此,这里我们存储截断的值 + * 并在后面加上 0.5s 的最佳猜测。 + */ + TimeSpec::new(instant.secs(), (NSEC_PER_SEC >> 1).into()) + } +} + +/// 全局默认rtc的优先级 +#[allow(dead_code)] +#[derive(Debug, Default, PartialEq, PartialOrd, Clone, Copy)] +pub enum GeneralRtcPriority { + #[default] + L0 = 0, + L1, +} diff --git a/kernel/src/driver/rtc/rtc_cmos.rs b/kernel/src/driver/rtc/rtc_cmos.rs new file mode 100644 index 00000000..844f5969 --- /dev/null +++ b/kernel/src/driver/rtc/rtc_cmos.rs @@ -0,0 +1,227 @@ +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use intertrait::cast::CastArc; +use system_error::SystemError; +use unified_init::macros::unified_init; + +use super::{ + class::rtc_register_device, + sysfs::{rtc_general_device_create, RtcGeneralDevice}, + RtcClassOps, RtcDevice, RtcTime, +}; +use crate::{ + driver::base::{ + device::{ + bus::Bus, + driver::{Driver, DriverCommonData}, + Device, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + platform::{ + platform_device::PlatformDevice, + platform_driver::{platform_driver_manager, PlatformDriver}, + }, + }, + filesystem::kernfs::KernFSInode, + init::initcall::INITCALL_DEVICE, + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, +}; + +static CMOS_RTC_GENERAL_DEVICE: RwLock>> = RwLock::new(None); + +#[derive(Debug)] +#[cast_to([sync] Driver, PlatformDriver)] +struct CmosPlatformDriver { + inner: SpinLock, + locked_kobjstate: LockedKObjectState, +} + +impl CmosPlatformDriver { + const NAME: &str = "rtc_cmos"; + + fn new() -> Arc { + Arc::new(CmosPlatformDriver { + inner: SpinLock::new(InnerCmosPlatformDriver { + driver_common: DriverCommonData::default(), + kobject_common: KObjectCommonData::default(), + }), + locked_kobjstate: LockedKObjectState::new(None), + }) + } + + fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } +} + +#[derive(Debug)] +struct InnerCmosPlatformDriver { + driver_common: DriverCommonData, + kobject_common: KObjectCommonData, +} + +impl PlatformDriver for CmosPlatformDriver { + fn probe(&self, device: &Arc) -> Result<(), SystemError> { + let dev = device + .clone() + .arc_any() + .cast::() + .map_err(|_| SystemError::ENODEV)?; + + if dev.id_table() != self.id_table().unwrap() { + return Err(SystemError::ENODEV); + } + + if CMOS_RTC_GENERAL_DEVICE.read().is_some() { + return Err(SystemError::EBUSY); + } + + let mut guard = CMOS_RTC_GENERAL_DEVICE.write(); + + // 再次检查 + if guard.is_some() { + return Err(SystemError::EBUSY); + } + + let general_rtc_device: Arc = rtc_general_device_create(&dev, None); + guard.replace(general_rtc_device.clone()); + + general_rtc_device.set_class_ops(&CmosRtcClassOps); + drop(guard); + + rtc_register_device(&general_rtc_device) + .expect("cmos_rtc: register general rtc device failed"); + + return Ok(()); + } + + fn remove(&self, _device: &Arc) -> Result<(), SystemError> { + // todo: remove + Err(SystemError::ENOSYS) + } + + fn shutdown(&self, _device: &Arc) -> Result<(), SystemError> { + unimplemented!("cmos platform driver shutdown") + } + + fn suspend(&self, _device: &Arc) -> Result<(), SystemError> { + todo!("cmos platform driver suspend") + } + + fn resume(&self, _device: &Arc) -> Result<(), SystemError> { + todo!("cmos platform driver resume") + } +} + +impl Driver for CmosPlatformDriver { + fn id_table(&self) -> Option { + Some(IdTable::new(Self::NAME.to_string(), None)) + } + + fn devices(&self) -> Vec> { + self.inner().driver_common.devices.clone() + } + + fn add_device(&self, device: Arc) { + self.inner().driver_common.push_device(device); + } + + fn delete_device(&self, device: &Arc) { + self.inner().driver_common.delete_device(device); + } + + fn set_bus(&self, bus: Option>) { + self.inner().driver_common.bus = bus; + } + + fn bus(&self) -> Option> { + self.inner().driver_common.bus.clone() + } +} + +impl KObject for CmosPlatformDriver { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + Self::NAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.locked_kobjstate.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.locked_kobjstate.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobjstate.write() = state; + } +} + +#[unified_init(INITCALL_DEVICE)] +pub fn cmos_rtc_driver_init() -> Result<(), SystemError> { + let driver = CmosPlatformDriver::new(); + + platform_driver_manager().register(driver)?; + + return Ok(()); +} + +#[derive(Debug)] +struct CmosRtcClassOps; + +impl RtcClassOps for CmosRtcClassOps { + fn read_time(&self, dev: &Arc) -> Result { + dev.class_ops().read_time(dev) + } + + fn set_time(&self, dev: &Arc, time: &RtcTime) -> Result<(), SystemError> { + dev.class_ops().set_time(dev, time) + } +} diff --git a/kernel/src/driver/rtc/sysfs.rs b/kernel/src/driver/rtc/sysfs.rs new file mode 100644 index 00000000..63ba3bd5 --- /dev/null +++ b/kernel/src/driver/rtc/sysfs.rs @@ -0,0 +1,379 @@ +use alloc::{ + string::String, + sync::{Arc, Weak}, +}; +use ida::IdAllocator; +use system_error::SystemError; + +use crate::{ + driver::base::{ + class::Class, + device::{ + bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + }, + filesystem::{ + kernfs::KernFSInode, + sysfs::{ + file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport, SYSFS_ATTR_MODE_RO, + }, + vfs::syscall::ModeType, + }, + libs::{ + rwlock::{RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, +}; + +use super::{ + class::sys_class_rtc_instance, + interface::rtc_read_time, + utils::{kobj2rtc_device, kobj2rtc_general_device}, + GeneralRtcPriority, RtcClassOps, RtcDevice, +}; + +static RTC_GENERAL_DEVICE_IDA: IdAllocator = IdAllocator::new(0, usize::MAX); + +pub(super) const RTC_HCTOSYS_DEVICE: &str = "rtc0"; + +#[derive(Debug)] +#[cast_to([sync] KObject, Device, RtcDevice)] +pub struct RtcGeneralDevice { + name: String, + id: usize, + inner: SpinLock, + kobj_state: LockedKObjectState, + priority: GeneralRtcPriority, +} + +#[derive(Debug)] +struct InnerRtcGeneralDevice { + device_common: DeviceCommonData, + kobject_common: KObjectCommonData, + + class_ops: Option<&'static dyn RtcClassOps>, + /// 上一次调用`rtc_hctosys()`把时间同步到timekeeper的时候的返回值 + hc2sysfs_result: Result<(), SystemError>, +} + +impl RtcGeneralDevice { + /// 创建一个新的通用RTC设备实例 + /// + /// 注意,由于还需要进行其他的初始化操作,因此这个函数并不是公开的构造函数。 + fn new(priority: GeneralRtcPriority) -> Arc { + let id = RTC_GENERAL_DEVICE_IDA.alloc().unwrap(); + let name = format!("rtc{}", id); + Arc::new(Self { + name, + id, + inner: SpinLock::new(InnerRtcGeneralDevice { + device_common: DeviceCommonData::default(), + kobject_common: KObjectCommonData::default(), + class_ops: None, + hc2sysfs_result: Err(SystemError::ENODEV), + }), + kobj_state: LockedKObjectState::new(None), + priority, + }) + } + + fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } + + pub fn set_class_ops(&self, class_ops: &'static dyn RtcClassOps) { + self.inner().class_ops = Some(class_ops); + } + + pub fn class_ops(&self) -> Option<&'static dyn RtcClassOps> { + self.inner().class_ops + } + + pub fn priority(&self) -> GeneralRtcPriority { + self.priority + } + + pub(super) fn set_hc2sys_result(&self, val: Result<(), SystemError>) { + self.inner().hc2sysfs_result = val; + } + + pub(super) fn hc2sysfs_result(&self) -> Result<(), SystemError> { + self.inner().hc2sysfs_result.clone() + } +} + +impl Drop for RtcGeneralDevice { + fn drop(&mut self) { + RTC_GENERAL_DEVICE_IDA.free(self.id); + } +} + +impl RtcDevice for RtcGeneralDevice { + fn class_ops(&self) -> &'static dyn super::RtcClassOps { + todo!() + } +} + +impl Device for RtcGeneralDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Rtc + } + + fn id_table(&self) -> IdTable { + IdTable::new(self.name.clone(), None) + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn bus(&self) -> Option> { + self.inner().device_common.get_bus_weak_or_clear() + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn class(&self) -> Option> { + self.inner() + .device_common + .get_class_weak_or_clear() + .and_then(|x| x.upgrade()) + } + + fn driver(&self) -> Option> { + self.inner() + .device_common + .get_driver_weak_or_clear() + .and_then(|x| x.upgrade()) + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + false + } + + fn set_can_match(&self, _can_match: bool) { + // do nothing + } + + fn state_synced(&self) -> bool { + true + } + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + Some(&[&RtcAttrGroup]) + } +} + +impl KObject for RtcGeneralDevice { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + self.name.clone() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.kobj_state_mut() = state; + } +} + +/// +/// 用于创建一个通用的RTC设备实例。 +/// +/// ## 参数 +/// +/// - `real_dev`: 一个对实际RTC设备的引用,这个设备将作为通用RTC设备的父设备。 +pub fn rtc_general_device_create( + real_dev: &Arc, + priority: Option, +) -> Arc { + let dev = RtcGeneralDevice::new(priority.unwrap_or_default()); + device_manager().device_default_initialize(&(dev.clone() as Arc)); + dev.set_parent(Some(Arc::downgrade(real_dev) as Weak)); + dev.set_class(Some(Arc::downgrade( + &(sys_class_rtc_instance().cloned().unwrap() as Arc), + ))); + + return dev; +} + +#[derive(Debug)] +struct RtcAttrGroup; + +impl AttributeGroup for RtcAttrGroup { + fn name(&self) -> Option<&str> { + None + } + + fn attrs(&self) -> &[&'static dyn Attribute] { + &[&AttrName, &AttrDate, &AttrTime, &AttrHcToSys] + } + + fn is_visible( + &self, + _kobj: Arc, + attr: &'static dyn Attribute, + ) -> Option { + // todo: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/rtc/sysfs.c#280 + + return Some(attr.mode()); + } +} + +#[derive(Debug)] +struct AttrName; + +impl Attribute for AttrName { + fn name(&self) -> &str { + "name" + } + + fn mode(&self) -> ModeType { + SYSFS_ATTR_MODE_RO + } + + fn support(&self) -> SysFSOpsSupport { + SysFSOpsSupport::ATTR_SHOW + } + + fn show(&self, kobj: Arc, buf: &mut [u8]) -> Result { + let rtc_device = kobj + .parent() + .and_then(|x| x.upgrade()) + .ok_or(SystemError::ENODEV)?; + let rtc_device = kobj2rtc_device(rtc_device).ok_or(SystemError::EINVAL)?; + + let driver_name = rtc_device.driver().ok_or(SystemError::ENODEV)?.name(); + let device_name = rtc_device.name(); + sysfs_emit_str(buf, &format!("{} {}\n", driver_name, device_name)) + } +} + +#[derive(Debug)] +struct AttrDate; + +impl Attribute for AttrDate { + fn name(&self) -> &str { + "date" + } + + fn mode(&self) -> ModeType { + SYSFS_ATTR_MODE_RO + } + + fn support(&self) -> SysFSOpsSupport { + SysFSOpsSupport::ATTR_SHOW + } + + fn show(&self, kobj: Arc, buf: &mut [u8]) -> Result { + let rtc_device: Arc = + kobj2rtc_general_device(kobj).ok_or(SystemError::EINVAL)?; + let time = rtc_read_time(&rtc_device)?; + sysfs_emit_str(buf, &time.date_string()) + } +} + +#[derive(Debug)] +struct AttrTime; + +impl Attribute for AttrTime { + fn name(&self) -> &str { + "time" + } + + fn mode(&self) -> ModeType { + SYSFS_ATTR_MODE_RO + } + + fn support(&self) -> SysFSOpsSupport { + SysFSOpsSupport::ATTR_SHOW + } + + fn show(&self, kobj: Arc, buf: &mut [u8]) -> Result { + let rtc_device = kobj2rtc_general_device(kobj).ok_or(SystemError::EINVAL)?; + let time = rtc_read_time(&rtc_device)?; + sysfs_emit_str(buf, &time.time_string()) + } +} + +#[derive(Debug)] +struct AttrHcToSys; + +impl Attribute for AttrHcToSys { + fn name(&self) -> &str { + "hctosys" + } + + fn mode(&self) -> ModeType { + SYSFS_ATTR_MODE_RO + } + + fn support(&self) -> SysFSOpsSupport { + SysFSOpsSupport::ATTR_SHOW + } + + fn show(&self, kobj: Arc, buf: &mut [u8]) -> Result { + let rtc_device = kobj2rtc_general_device(kobj).ok_or(SystemError::EINVAL)?; + if rtc_device.hc2sysfs_result().is_ok() && rtc_device.name().eq(RTC_HCTOSYS_DEVICE) { + return sysfs_emit_str(buf, "1\n"); + } + + return sysfs_emit_str(buf, "0\n"); + } +} diff --git a/kernel/src/driver/rtc/utils.rs b/kernel/src/driver/rtc/utils.rs new file mode 100644 index 00000000..018c8786 --- /dev/null +++ b/kernel/src/driver/rtc/utils.rs @@ -0,0 +1,16 @@ +use alloc::sync::Arc; +use intertrait::cast::CastArc; + +use crate::driver::base::kobject::KObject; + +use super::{sysfs::RtcGeneralDevice, RtcDevice}; + +#[inline] +pub fn kobj2rtc_device(kobj: Arc) -> Option> { + kobj.arc_any().cast::().ok() +} + +#[inline] +pub fn kobj2rtc_general_device(kobj: Arc) -> Option> { + kobj.arc_any().downcast().ok() +} diff --git a/kernel/src/driver/serial/serial8250/mod.rs b/kernel/src/driver/serial/serial8250/mod.rs index cab939d8..620d4b57 100644 --- a/kernel/src/driver/serial/serial8250/mod.rs +++ b/kernel/src/driver/serial/serial8250/mod.rs @@ -177,10 +177,6 @@ impl Serial8250ISADevices { } impl PlatformDevice for Serial8250ISADevices { - fn compatible_table(&self) -> crate::driver::base::platform::CompatibleTable { - unimplemented!() - } - fn pdev_id(&self) -> (i32, bool) { return ( self.id.load(Ordering::SeqCst), diff --git a/kernel/src/driver/timers/mod.rs b/kernel/src/driver/timers/mod.rs index c06ab88f..c8b950a4 100644 --- a/kernel/src/driver/timers/mod.rs +++ b/kernel/src/driver/timers/mod.rs @@ -1,2 +1 @@ pub mod hpet; -pub mod rtc; diff --git a/kernel/src/driver/timers/rtc/mod.rs b/kernel/src/driver/timers/rtc/mod.rs deleted file mode 100644 index 1339763e..00000000 --- a/kernel/src/driver/timers/rtc/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod rtc; diff --git a/kernel/src/driver/timers/rtc/rtc.rs b/kernel/src/driver/timers/rtc/rtc.rs deleted file mode 100644 index 5383f10d..00000000 --- a/kernel/src/driver/timers/rtc/rtc.rs +++ /dev/null @@ -1,90 +0,0 @@ -use system_error::SystemError; - -use crate::{ - arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch}, - exception::InterruptArch, -}; - -#[derive(Default)] -pub struct RtcTime { - pub second: i32, - pub minute: i32, - pub hour: i32, - pub day: i32, - pub month: i32, - pub year: i32, -} - -impl RtcTime { - ///@brief 从主板cmos中获取时间 - /// - ///@param self time结构体 - ///@return int 成功则为0 - pub fn get(&mut self) -> Result { - // 为防止中断请求打断该过程,需要先关中断 - let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - //0x0B - let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B - let is_24h: bool = (status_register_b & 0x02) != 0; - // 判断是否启用24小时模式 - - let is_binary: bool = (status_register_b & 0x04) != 0; // 判断是否为二进制码 - - loop { - self.year = read_cmos(CMOSTimeSelector::Year as u8) as i32; - self.month = read_cmos(CMOSTimeSelector::Month as u8) as i32; - self.day = read_cmos(CMOSTimeSelector::Day as u8) as i32; - self.hour = read_cmos(CMOSTimeSelector::Hour as u8) as i32; - self.minute = read_cmos(CMOSTimeSelector::Minute as u8) as i32; - self.second = read_cmos(CMOSTimeSelector::Second as u8) as i32; - - if self.second == read_cmos(CMOSTimeSelector::Second as u8) as i32 { - break; - } // 若读取时间过程中时间发生跳变则重新读取 - } - - unsafe { - CurrentPortIOArch::out8(0x70, 0x00); - } - - if !is_binary - // 把BCD转为二进制 - { - self.second = (self.second & 0xf) + (self.second >> 4) * 10; - self.minute = (self.minute & 0xf) + (self.minute >> 4) * 10; - self.hour = ((self.hour & 0xf) + ((self.hour & 0x70) >> 4) * 10) | (self.hour & 0x80); - self.day = (self.day & 0xf) + ((self.day / 16) * 10); - self.month = (self.month & 0xf) + (self.month >> 4) * 10; - self.year = (self.year & 0xf) + (self.year >> 4) * 10; - } - self.year += 2000; - - if (!is_24h) && (self.hour & 0x80) != 0 { - self.hour = ((self.hour & 0x7f) + 12) % 24; - } // 将十二小时制转为24小时 - - drop(irq_guard); - - return Ok(0); - } -} - -///置位0x70的第7位,禁止不可屏蔽中断 -#[inline] -fn read_cmos(addr: u8) -> u8 { - unsafe { - CurrentPortIOArch::out8(0x70, 0x80 | addr); - return CurrentPortIOArch::in8(0x71); - } -} - -/// used in the form of u8 -#[repr(u8)] -enum CMOSTimeSelector { - Second = 0x00, - Minute = 0x02, - Hour = 0x04, - Day = 0x07, - Month = 0x08, - Year = 0x09, -} diff --git a/kernel/src/driver/tty/virtual_terminal/virtual_console.rs b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs index 1c85506a..d907c1a7 100644 --- a/kernel/src/driver/tty/virtual_terminal/virtual_console.rs +++ b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs @@ -26,11 +26,13 @@ lazy_static! { /// 是否已经添加了软光标 pub(super) static ref SOFTCURSOR_ORIGINAL: RwLock> = RwLock::new(None); - pub static ref CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1); - pub static ref CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false); } +pub static CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1); + +pub static CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false); + /// ## 虚拟控制台的信息 #[derive(Debug, Clone)] pub struct VirtualConsoleData { diff --git a/kernel/src/driver/video/fbdev/vesafb.rs b/kernel/src/driver/video/fbdev/vesafb.rs index 819b2ff9..2472973d 100644 --- a/kernel/src/driver/video/fbdev/vesafb.rs +++ b/kernel/src/driver/video/fbdev/vesafb.rs @@ -25,7 +25,6 @@ use crate::{ platform::{ platform_device::{platform_device_manager, PlatformDevice}, platform_driver::{platform_driver_manager, PlatformDriver}, - CompatibleTable, }, }, serial::serial8250::send_to_default_serial8250_port, @@ -159,10 +158,6 @@ impl PlatformDevice for VesaFb { self.inner.lock().pdev_id_auto = id_auto; } - fn compatible_table(&self) -> CompatibleTable { - todo!() - } - fn is_initialized(&self) -> bool { self.inner.lock().device_state == DeviceState::Initialized } diff --git a/kernel/src/time/mod.rs b/kernel/src/time/mod.rs index 2dec0150..79e57211 100644 --- a/kernel/src/time/mod.rs +++ b/kernel/src/time/mod.rs @@ -16,6 +16,7 @@ pub mod timeconv; pub mod timekeep; pub mod timekeeping; pub mod timer; + /* Time structures. (Partitially taken from smoltcp) The `time` module contains structures used to represent both @@ -124,6 +125,61 @@ pub struct Instant { impl Instant { pub const ZERO: Instant = Instant::from_micros_const(0); + /// mktime64 - 将日期转换为秒。 + /// + /// ## 参数 + /// + /// - year0: 要转换的年份 + /// - mon0: 要转换的月份 + /// - day: 要转换的天 + /// - hour: 要转换的小时 + /// - min: 要转换的分钟 + /// - sec: 要转换的秒 + /// + /// 将公历日期转换为1970-01-01 00:00:00以来的秒数。 + /// 假设输入为正常的日期格式,即1980-12-31 23:59:59 => 年份=1980, 月=12, 日=31, 时=23, 分=59, 秒=59。 + /// + /// [For the Julian calendar(俄罗斯在1917年之前使用,英国及其殖民地在大西洋1752年之前使用, + /// 其他地方在1582年之前使用,某些社区仍然在使用)省略-year/100+year/400项, + /// 并在结果上加10。] + /// + /// 这个算法最初由高斯(我认为是)发表。 + /// + /// 要表示闰秒,可以通过将sec设为60(在ISO 8601允许)来调用此函数。 + /// 闰秒与随后的秒一样处理,因为它们在UNIX时间中不存在。 + /// + /// 支持将午夜作为当日末尾的24:00:00编码 - 即明天的午夜(在ISO 8601允许)。 + /// + /// ## 返回 + /// + /// 返回:给定输入日期自1970-01-01 00:00:00以来的秒数 + pub fn mktime64(year0: u32, mon0: u32, day: u32, hour: u32, min: u32, sec: u32) -> Self { + let mut mon: i64 = mon0.into(); + let mut year: u64 = year0.into(); + let day: u64 = day.into(); + let hour: u64 = hour.into(); + let min: u64 = min.into(); + let sec: u64 = sec.into(); + + mon -= 2; + /* 1..12 -> 11,12,1..10 */ + if mon <= 0 { + /* Puts Feb last since it has leap day */ + mon += 12; + year -= 1; + } + let mon = mon as u64; + + let secs = ((((year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) + year * 365 + - 719499) + * 24 + hour) /* now have hours - midnight tomorrow handled here */ + * 60 + min)/* now have minutes */ + * 60 + + sec; /* finally seconds */ + + Self::from_secs(secs as i64) + } + /// Create a new `Instant` from a number of microseconds. pub fn from_micros>(micros: T) -> Instant { Instant { diff --git a/kernel/src/time/timekeep.rs b/kernel/src/time/timekeep.rs index 6f2d846c..758064b9 100644 --- a/kernel/src/time/timekeep.rs +++ b/kernel/src/time/timekeep.rs @@ -1,6 +1,10 @@ #![allow(dead_code)] -use crate::driver::timers::rtc::rtc::RtcTime; +use system_error::SystemError; + +use crate::driver::rtc::interface::rtc_read_time_default; + +use super::TimeSpec; #[allow(non_camel_case_types)] pub type ktime_t = i64; @@ -14,48 +18,16 @@ fn ktime_to_ns(kt: ktime_t) -> i64 { /// @brief 从RTC获取当前时间,然后计算时间戳。 /// 时间戳为从UTC+0 1970-01-01 00:00到当前UTC+0时间,所经过的纳秒数。 /// 注意,由于当前未引入时区,因此本函数默认时区为UTC+8来计算 -fn ktime_get_real() -> ktime_t { - let mut rtc_time: RtcTime = RtcTime::default(); - - { - let r = rtc_time.get(); - // 返回错误码 - if let Err(e) = r { - return e as ktime_t; - } - } - - let mut day_count: i32 = 0; - for year in 1970..rtc_time.year { - let leap: bool = (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0); - if leap { - day_count += 366; - } else { - day_count += 365; - } - } - for month in 1..rtc_time.month { - match month { - 1 | 3 | 5 | 7 | 8 | 10 | 12 => day_count += 31, - 2 => day_count += 28, - 4 | 6 | 9 | 11 => day_count += 30, - _ => day_count += 0, - } - } - - day_count += rtc_time.day - 1; - //转换成纳秒 - let timestamp: ktime_t = day_count as i64 * 86_400_000_000_000i64 - + (rtc_time.hour - 8) as i64 * 3_600_000_000_000i64 - + rtc_time.minute as i64 * 60_000_000_000i64 - + rtc_time.second as i64 * 1_000_000_000u64 as ktime_t; - - return timestamp; +fn ktime_get_real() -> Result { + let rtc_time = rtc_read_time_default()?; + let time_spec: TimeSpec = rtc_time.into(); + let r = time_spec.tv_sec * 1_000_000_000 + time_spec.tv_nsec; + return Ok(r); } /// @brief 暴露给外部使用的接口,返回一个时间戳 #[inline] pub fn ktime_get_real_ns() -> i64 { - let kt: ktime_t = ktime_get_real(); + let kt: ktime_t = ktime_get_real().unwrap_or(0); return ktime_to_ns(kt); } diff --git a/kernel/src/time/timekeeping.rs b/kernel/src/time/timekeeping.rs index 7d8fc4ab..bfa753c8 100644 --- a/kernel/src/time/timekeeping.rs +++ b/kernel/src/time/timekeeping.rs @@ -1,5 +1,6 @@ use alloc::sync::Arc; use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, Ordering}; +use system_error::SystemError; use crate::{ arch::CurrentIrqArch, @@ -207,6 +208,13 @@ pub fn do_gettimeofday() -> PosixTimeval { }; } +pub fn do_settimeofday64(time: TimeSpec) -> Result<(), SystemError> { + timekeeper().0.write_irqsave().xtime = time; + // todo: 模仿linux,实现时间误差校准。 + // https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/timekeeping.c?fi=do_settimeofday64#1312 + return Ok(()); +} + /// # 初始化timekeeping模块 #[inline(never)] pub fn timekeeping_init() {