Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型 #674

Merged
merged 4 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 8 additions & 0 deletions kernel/crates/driver_base_macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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]
20 changes: 20 additions & 0 deletions kernel/crates/driver_base_macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
}
}};
}
1 change: 1 addition & 0 deletions kernel/src/arch/x86_64/driver/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod apic;
pub mod hpet;
pub mod rtc;
pub mod tsc;
pub mod video;
312 changes: 312 additions & 0 deletions kernel/src/arch/x86_64/driver/rtc.rs
Original file line number Diff line number Diff line change
@@ -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<InnerCmosRtc>,
locked_kobjstate: LockedKObjectState,
ops_mutex: Mutex<()>,
}

impl CmosRtcDevice {
const NAME: &str = "rtc_cmos";
pub fn new() -> Arc<Self> {
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<InnerCmosRtc> {
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<Weak<dyn Bus>>) {
self.inner().device_common.bus = bus;
}

fn set_class(&self, class: Option<Weak<dyn Class>>) {
self.inner().device_common.class = class;
}

fn class(&self) -> Option<Arc<dyn Class>> {
self.inner()
.device_common
.get_class_weak_or_clear()
.and_then(|c| c.upgrade())
}

fn driver(&self) -> Option<Arc<dyn Driver>> {
self.inner()
.device_common
.get_driver_weak_or_clear()
.and_then(|d| d.upgrade())
}

fn set_driver(&self, driver: Option<Weak<dyn Driver>>) {
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<Weak<dyn Bus>> {
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<Arc<KernFSInode>>) {
self.inner().kobject_common.kern_inode = inode;
}

fn inode(&self) -> Option<Arc<KernFSInode>> {
self.inner().kobject_common.kern_inode.clone()
}

fn parent(&self) -> Option<Weak<dyn KObject>> {
self.inner().kobject_common.get_parent_or_clear_weak()
}

fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
self.inner().kobject_common.parent = parent;
}

fn kset(&self) -> Option<Arc<KSet>> {
self.inner().kobject_common.kset.clone()
}

fn set_kset(&self, kset: Option<Arc<KSet>>) {
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<KObjectState> {
self.locked_kobjstate.read()
}

fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
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<dyn RtcDevice>) -> Result<RtcTime, SystemError> {
// 检查是否为cmos rtc
let dev = dev
.as_any_ref()
.downcast_ref::<CmosRtcDevice>()
.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<dyn RtcDevice>, _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<dyn Device>));
platform_device_manager().device_add(device)?;

return Ok(());
}
9 changes: 6 additions & 3 deletions kernel/src/arch/x86_64/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<X86_64MMArch>::new(phy_offset.data());
kdebug!(
"BumpAllocator created, offset={:?}",
Expand Down
6 changes: 2 additions & 4 deletions kernel/src/driver/base/device/dd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn Device>, driver: &Arc<dyn Driver>) -> bool {
let r = self.match_device(driver, device).unwrap_or(false);
if !r {
Expand Down
Loading
Loading