mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
feat(driver/acpi_pm): Implement ACPI PM Timer (#772)
* feat: Implement ACPI PM Timer
This commit is contained in:
parent
f75cb0f8ed
commit
dd8e74ef0d
@ -1,8 +1,6 @@
|
|||||||
use system_error::SystemError;
|
|
||||||
|
|
||||||
use crate::{driver::acpi::acpi_manager, kinfo, mm::percpu::PerCpu, smp::cpu::ProcessorId};
|
|
||||||
|
|
||||||
use super::smp::SMP_BOOT_DATA;
|
use super::smp::SMP_BOOT_DATA;
|
||||||
|
use crate::{driver::acpi::acpi_manager, kinfo, mm::percpu::PerCpu, smp::cpu::ProcessorId};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
pub(super) fn early_acpi_boot_init() -> Result<(), SystemError> {
|
pub(super) fn early_acpi_boot_init() -> Result<(), SystemError> {
|
||||||
// 在这里解析madt,初始化smp boot data
|
// 在这里解析madt,初始化smp boot data
|
||||||
|
@ -44,6 +44,14 @@ pub fn hpet_instance() -> &'static Hpet {
|
|||||||
unsafe { HPET_INSTANCE.as_ref().unwrap() }
|
unsafe { HPET_INSTANCE.as_ref().unwrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_hpet_enabled() -> bool {
|
||||||
|
if unsafe { HPET_INSTANCE.as_ref().is_some() } {
|
||||||
|
return unsafe { HPET_INSTANCE.as_ref().unwrap().enabled() };
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Hpet {
|
pub struct Hpet {
|
||||||
info: HpetInfo,
|
info: HpetInfo,
|
||||||
_mmio_guard: MMIOSpaceGuard,
|
_mmio_guard: MMIOSpaceGuard,
|
||||||
@ -254,10 +262,8 @@ impl Hpet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn hpet_init() -> Result<(), SystemError> {
|
pub fn hpet_init() -> Result<(), SystemError> {
|
||||||
let hpet_info = HpetInfo::new(acpi_manager().tables().unwrap()).map_err(|e| {
|
let hpet_info =
|
||||||
kerror!("Failed to get HPET info: {:?}", e);
|
HpetInfo::new(acpi_manager().tables().unwrap()).map_err(|_| SystemError::ENODEV)?;
|
||||||
SystemError::ENODEV
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let hpet_instance = Hpet::new(hpet_info)?;
|
let hpet_instance = Hpet::new(hpet_info)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch, CurrentTimeArch},
|
arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch, CurrentTimeArch},
|
||||||
driver::acpi::pmtmr::{ACPI_PM_OVERRUN, PMTMR_TICKS_PER_SEC},
|
driver::acpi::pmtmr::{acpi_pm_read_early, ACPI_PM_OVERRUN, PMTMR_TICKS_PER_SEC},
|
||||||
exception::InterruptArch,
|
exception::InterruptArch,
|
||||||
kdebug, kerror, kinfo, kwarn,
|
kdebug, kerror, kinfo, kwarn,
|
||||||
time::TimeArch,
|
time::{TimeArch, PIT_TICK_RATE},
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
cmp::{max, min},
|
cmp::{max, min},
|
||||||
@ -11,10 +11,7 @@ use core::{
|
|||||||
};
|
};
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use super::hpet::hpet_instance;
|
use super::hpet::{hpet_instance, is_hpet_enabled};
|
||||||
|
|
||||||
/// The clock frequency of the i8253/i8254 PIT
|
|
||||||
const PIT_TICK_RATE: u64 = 1193182;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TSCManager;
|
pub struct TSCManager;
|
||||||
@ -104,7 +101,7 @@ impl TSCManager {
|
|||||||
///
|
///
|
||||||
/// 使用pit、hpet、ptimer来测量CPU总线的频率
|
/// 使用pit、hpet、ptimer来测量CPU总线的频率
|
||||||
fn calibrate_cpu_by_pit_hpet_ptimer() -> Result<u64, SystemError> {
|
fn calibrate_cpu_by_pit_hpet_ptimer() -> Result<u64, SystemError> {
|
||||||
let hpet = hpet_instance().enabled();
|
let hpet = is_hpet_enabled();
|
||||||
kdebug!(
|
kdebug!(
|
||||||
"Calibrating TSC with {}",
|
"Calibrating TSC with {}",
|
||||||
if hpet { "HPET" } else { "PMTIMER" }
|
if hpet { "HPET" } else { "PMTIMER" }
|
||||||
@ -321,7 +318,7 @@ impl TSCManager {
|
|||||||
if hpet_enabled {
|
if hpet_enabled {
|
||||||
ref_ret = hpet_instance().main_counter_value();
|
ref_ret = hpet_instance().main_counter_value();
|
||||||
} else {
|
} else {
|
||||||
todo!("read pmtimer")
|
ref_ret = acpi_pm_read_early() as u64;
|
||||||
}
|
}
|
||||||
let t2 = CurrentTimeArch::get_cycles() as u64;
|
let t2 = CurrentTimeArch::get_cycles() as u64;
|
||||||
if (t2 - t1) < thresh {
|
if (t2 - t1) < thresh {
|
||||||
|
@ -5,6 +5,7 @@ use x86::dtables::DescriptorTablePointer;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::trap::arch_trap_init, process::table::TSSManager},
|
arch::{interrupt::trap::arch_trap_init, process::table::TSSManager},
|
||||||
|
driver::clocksource::acpi_pm::init_acpi_pm_clocksource,
|
||||||
init::init::start_kernel,
|
init::init::start_kernel,
|
||||||
kdebug,
|
kdebug,
|
||||||
mm::{MemoryManagementArch, PhysAddr},
|
mm::{MemoryManagementArch, PhysAddr},
|
||||||
@ -93,8 +94,12 @@ pub fn setup_arch() -> Result<(), SystemError> {
|
|||||||
/// 架构相关的初始化(在IDLE的最后一个阶段)
|
/// 架构相关的初始化(在IDLE的最后一个阶段)
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn setup_arch_post() -> Result<(), SystemError> {
|
pub fn setup_arch_post() -> Result<(), SystemError> {
|
||||||
hpet_init().expect("hpet init failed");
|
let ret = hpet_init();
|
||||||
hpet_instance().hpet_enable().expect("hpet enable failed");
|
if ret.is_ok() {
|
||||||
|
hpet_instance().hpet_enable().expect("hpet enable failed");
|
||||||
|
} else {
|
||||||
|
init_acpi_pm_clocksource().expect("acpi_pm_timer inits failed");
|
||||||
|
}
|
||||||
TSCManager::init().expect("tsc init failed");
|
TSCManager::init().expect("tsc init failed");
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -1,4 +1,30 @@
|
|||||||
|
use crate::driver::clocksource::acpi_pm::{acpi_pm_read_verified, PMTMR_IO_PORT};
|
||||||
|
use core::sync::atomic::Ordering;
|
||||||
|
|
||||||
pub const ACPI_PM_OVERRUN: u64 = 1 << 24;
|
pub const ACPI_PM_OVERRUN: u64 = 1 << 24;
|
||||||
|
|
||||||
/// Number of PMTMR ticks expected during calibration run
|
/// Number of PMTMR ticks expected during calibration run
|
||||||
pub const PMTMR_TICKS_PER_SEC: u64 = 3579545;
|
pub const PMTMR_TICKS_PER_SEC: u64 = 3579545;
|
||||||
|
|
||||||
|
/// 用于掩码ACPI_PM_READ_ERALY返回值的前24位
|
||||||
|
pub const ACPI_PM_MASK: u64 = 0xffffff;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn acpi_pm_read_early() -> u32 {
|
||||||
|
let port = unsafe { PMTMR_IO_PORT.load(Ordering::SeqCst) };
|
||||||
|
|
||||||
|
// 如果端口为零直接返回
|
||||||
|
if port == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对读取的pmtmr值进行验证并进行掩码处理
|
||||||
|
return acpi_pm_read_verified() & ACPI_PM_MASK as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[cfg(not(target_arch = "x86_64"))]
|
||||||
|
pub fn acpi_pm_read_early() -> u32 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
296
kernel/src/driver/clocksource/acpi_pm.rs
Normal file
296
kernel/src/driver/clocksource/acpi_pm.rs
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
use crate::{
|
||||||
|
alloc::string::ToString,
|
||||||
|
arch::{io::PortIOArch, CurrentPortIOArch},
|
||||||
|
driver::acpi::{
|
||||||
|
acpi_manager,
|
||||||
|
pmtmr::{ACPI_PM_MASK, PMTMR_TICKS_PER_SEC},
|
||||||
|
},
|
||||||
|
libs::spinlock::SpinLock,
|
||||||
|
time::{
|
||||||
|
clocksource::{Clocksource, ClocksourceData, ClocksourceFlags, ClocksourceMask, CycleNum},
|
||||||
|
PIT_TICK_RATE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use acpi::fadt::Fadt;
|
||||||
|
use alloc::sync::{Arc, Weak};
|
||||||
|
use core::intrinsics::unlikely;
|
||||||
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c
|
||||||
|
|
||||||
|
/// acpi_pmtmr所在的I/O端口
|
||||||
|
pub static mut PMTMR_IO_PORT: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
|
/// # 读取acpi_pmtmr当前值,并对齐进行掩码操作
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_pmtmr() -> u32 {
|
||||||
|
return unsafe { CurrentPortIOArch::in32(PMTMR_IO_PORT.load(Ordering::SeqCst) as u16) }
|
||||||
|
& ACPI_PM_MASK as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
//参考: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c#41
|
||||||
|
/// # 读取acpi_pmtmr的值,并进行多次读取以保证获取正确的值
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
/// - u32: 读取到的acpi_pmtmr值
|
||||||
|
pub fn acpi_pm_read_verified() -> u32 {
|
||||||
|
let mut v2: u32;
|
||||||
|
|
||||||
|
// 因为某些损坏芯片组(如ICH4、PIIX4和PIIX4E)可能导致APCI PM时钟源未锁存
|
||||||
|
// 因此需要多次读取以保证获取正确的值
|
||||||
|
loop {
|
||||||
|
let v1 = read_pmtmr();
|
||||||
|
v2 = read_pmtmr();
|
||||||
|
let v3 = read_pmtmr();
|
||||||
|
|
||||||
|
if !(unlikely((v2 > v3 || v1 < v3) && v1 > v2 || v1 < v3 && v2 > v3)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # 作为时钟源的读取函数
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
/// - u64: acpi_pmtmr的当前值
|
||||||
|
fn acpi_pm_read() -> u64 {
|
||||||
|
return read_pmtmr() as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static mut CLOCKSOURCE_ACPI_PM: Option<Arc<Acpipm>> = None;
|
||||||
|
|
||||||
|
pub fn clocksource_acpi_pm() -> Arc<Acpipm> {
|
||||||
|
return unsafe { CLOCKSOURCE_ACPI_PM.as_ref().unwrap().clone() };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Acpipm(SpinLock<InnerAcpipm>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct InnerAcpipm {
|
||||||
|
data: ClocksourceData,
|
||||||
|
self_reaf: Weak<Acpipm>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Acpipm {
|
||||||
|
pub fn new() -> Arc<Self> {
|
||||||
|
let data = ClocksourceData {
|
||||||
|
name: "acpi_pm".to_string(),
|
||||||
|
rating: 200,
|
||||||
|
mask: ClocksourceMask::new(ACPI_PM_MASK),
|
||||||
|
mult: 0,
|
||||||
|
shift: 0,
|
||||||
|
max_idle_ns: Default::default(),
|
||||||
|
flags: ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS,
|
||||||
|
watchdog_last: CycleNum::new(0),
|
||||||
|
uncertainty_margin: 0,
|
||||||
|
maxadj: 0,
|
||||||
|
};
|
||||||
|
let acpi_pm = Arc::new(Acpipm(SpinLock::new(InnerAcpipm {
|
||||||
|
data,
|
||||||
|
self_reaf: Default::default(),
|
||||||
|
})));
|
||||||
|
acpi_pm.0.lock().self_reaf = Arc::downgrade(&acpi_pm);
|
||||||
|
|
||||||
|
return acpi_pm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clocksource for Acpipm {
|
||||||
|
fn read(&self) -> CycleNum {
|
||||||
|
return CycleNum::new(acpi_pm_read());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clocksource_data(&self) -> ClocksourceData {
|
||||||
|
let inner = self.0.lock_irqsave();
|
||||||
|
return inner.data.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clocksource(&self) -> Arc<dyn Clocksource> {
|
||||||
|
return self.0.lock_irqsave().self_reaf.upgrade().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError> {
|
||||||
|
let d = &mut self.0.lock_irqsave().data;
|
||||||
|
d.set_flags(data.flags);
|
||||||
|
d.set_mask(data.mask);
|
||||||
|
d.set_max_idle_ns(data.max_idle_ns);
|
||||||
|
d.set_mult(data.mult);
|
||||||
|
d.set_name(data.name);
|
||||||
|
d.set_rating(data.rating);
|
||||||
|
d.set_shift(data.shift);
|
||||||
|
d.watchdog_last = data.watchdog_last;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/mach_timer.h?fi=mach_prepare_counter
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const CALIBRATE_TIME_MSEC: u64 = 30;
|
||||||
|
pub const CALIBRATE_LATCH: u64 = (PIT_TICK_RATE * CALIBRATE_TIME_MSEC + 1000 / 2) / 1000;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn mach_prepare_counter() {
|
||||||
|
unsafe {
|
||||||
|
// 将Gate位设置为高电平,从而禁用扬声器
|
||||||
|
CurrentPortIOArch::out8(0x61, (CurrentPortIOArch::in8(0x61) & !0x02) | 0x01);
|
||||||
|
|
||||||
|
// 针对计数器/定时器控制器的通道2进行配置,设置为模式0,二进制计数
|
||||||
|
CurrentPortIOArch::out8(0x43, 0xb0);
|
||||||
|
CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH & 0xff) as u8);
|
||||||
|
CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH >> 8) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn mach_countup(count: &mut u32) {
|
||||||
|
let mut tmp: u32 = 0;
|
||||||
|
loop {
|
||||||
|
tmp += 1;
|
||||||
|
if (unsafe { CurrentPortIOArch::in8(0x61) } & 0x20) != 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*count = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const PMTMR_EXPECTED_RATE: u64 =
|
||||||
|
(CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (PIT_TICK_RATE >> 10);
|
||||||
|
|
||||||
|
/// # 验证ACPI PM Timer的运行速率是否在预期范围内(在x86_64架构以外的情况下验证)
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
/// - i32:如果为0则表示在预期范围内,否则不在
|
||||||
|
#[cfg(not(target_arch = "x86_64"))]
|
||||||
|
fn verify_pmtmr_rate() -> bool {
|
||||||
|
let mut count: u32 = 0;
|
||||||
|
|
||||||
|
mach_prepare_counter();
|
||||||
|
let value1 = clocksource_acpi_pm().read().data();
|
||||||
|
mach_countup(&mut count);
|
||||||
|
let value2 = clocksource_acpi_pm().read().data();
|
||||||
|
let delta = (value2 - value1) & ACPI_PM_MASK;
|
||||||
|
|
||||||
|
if (delta < (PMTMR_EXPECTED_RATE * 19) / 20) || (delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
|
||||||
|
kinfo!(
|
||||||
|
"PM Timer running at invalid rate: {}",
|
||||||
|
100 * delta / PMTMR_EXPECTED_RATE
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
fn verify_pmtmr_rate() -> bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ACPI_PM_MONOTONIC_CHECKS: u32 = 10;
|
||||||
|
const ACPI_PM_READ_CHECKS: u32 = 10000;
|
||||||
|
|
||||||
|
/// # 解析fadt
|
||||||
|
fn find_acpi_pm_clock() -> Result<(), SystemError> {
|
||||||
|
let fadt = acpi_manager()
|
||||||
|
.tables()
|
||||||
|
.unwrap()
|
||||||
|
.find_table::<Fadt>()
|
||||||
|
.expect("failed to find FADT table");
|
||||||
|
let pm_timer_block = fadt.pm_timer_block().map_err(|_| SystemError::ENODEV)?;
|
||||||
|
let pm_timer_block = pm_timer_block.ok_or(SystemError::ENODEV)?;
|
||||||
|
let pmtmr_addr = pm_timer_block.address;
|
||||||
|
unsafe {
|
||||||
|
PMTMR_IO_PORT.store(pmtmr_addr as u32, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
kinfo!("apic_pmtmr I/O port: {}", unsafe {
|
||||||
|
PMTMR_IO_PORT.load(Ordering::SeqCst)
|
||||||
|
});
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # 初始化ACPI PM Timer作为系统时钟源
|
||||||
|
// #[unified_init(INITCALL_FS)]
|
||||||
|
pub fn init_acpi_pm_clocksource() -> Result<(), SystemError> {
|
||||||
|
let acpi_pm = Acpipm::new();
|
||||||
|
unsafe {
|
||||||
|
CLOCKSOURCE_ACPI_PM = Some(acpi_pm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析fadt
|
||||||
|
find_acpi_pm_clock()?;
|
||||||
|
|
||||||
|
// 检查pmtmr_io_port是否被设置
|
||||||
|
if unsafe { PMTMR_IO_PORT.load(Ordering::SeqCst) } == 0 {
|
||||||
|
return Err(SystemError::ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证ACPI PM Timer作为时钟源的稳定性和一致性
|
||||||
|
for j in 0..ACPI_PM_MONOTONIC_CHECKS {
|
||||||
|
let mut cnt = 100 * j;
|
||||||
|
while cnt > 0 {
|
||||||
|
cnt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value1 = clocksource_acpi_pm().read().data();
|
||||||
|
let mut i = 0;
|
||||||
|
for _ in 0..ACPI_PM_READ_CHECKS {
|
||||||
|
let value2 = clocksource_acpi_pm().read().data();
|
||||||
|
if value2 == value1 {
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if value2 > value1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (value2 < value1) && (value2 < 0xfff) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kinfo!("PM Timer had inconsistens results: {} {}", value1, value2);
|
||||||
|
unsafe {
|
||||||
|
PMTMR_IO_PORT.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if i == ACPI_PM_READ_CHECKS {
|
||||||
|
kinfo!("PM Timer failed consistency check: {}", value1);
|
||||||
|
unsafe {
|
||||||
|
PMTMR_IO_PORT.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查ACPI PM Timer的频率是否正确
|
||||||
|
if !verify_pmtmr_rate() {
|
||||||
|
unsafe {
|
||||||
|
PMTMR_IO_PORT.store(0, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查TSC时钟源的监视器是否被禁用,如果被禁用则将时钟源的标志设置为CLOCK_SOURCE_MUST_VERIFY
|
||||||
|
// 没有实现clocksource_selecet_watchdog函数,所以这里设置为false
|
||||||
|
let tsc_clocksource_watchdog_disabled = false;
|
||||||
|
if tsc_clocksource_watchdog_disabled {
|
||||||
|
clocksource_acpi_pm().0.lock_irqsave().data.flags |=
|
||||||
|
ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册ACPI PM Timer
|
||||||
|
let acpi_pmtmr = clocksource_acpi_pm() as Arc<dyn Clocksource>;
|
||||||
|
match acpi_pmtmr.register(100, PMTMR_TICKS_PER_SEC as u32) {
|
||||||
|
Ok(_) => {
|
||||||
|
kinfo!("ACPI PM Timer registered as clocksource sccessfully");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
kinfo!("ACPI PM Timer init registered failed");
|
||||||
|
return Err(SystemError::ENOSYS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -1,2 +1,4 @@
|
|||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
pub mod timer_riscv;
|
pub mod timer_riscv;
|
||||||
|
|
||||||
|
pub mod acpi_pm;
|
||||||
|
@ -1069,7 +1069,7 @@ pub fn pci_init() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
HeaderType::PciPciBridge if common_header.status & 0x10 != 0 => {
|
HeaderType::PciPciBridge if common_header.status & 0x10 != 0 => {
|
||||||
kinfo!("Found pci-to-pci bridge device with class code ={} subclass={} status={:#x} cap_pointer={:#x}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_standard_device().unwrap().capabilities_pointer);
|
kinfo!("Found pci-to-pci bridge device with class code ={} subclass={} status={:#x} cap_pointer={:#x}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_pci_to_pci_bridge_device().unwrap().capability_pointer);
|
||||||
}
|
}
|
||||||
HeaderType::PciPciBridge => {
|
HeaderType::PciPciBridge => {
|
||||||
kinfo!(
|
kinfo!(
|
||||||
|
@ -433,7 +433,7 @@ impl CpuRunQueue {
|
|||||||
SchedPolicy::CFS => CompletelyFairScheduler::dequeue(self, pcb, flags),
|
SchedPolicy::CFS => CompletelyFairScheduler::dequeue(self, pcb, flags),
|
||||||
SchedPolicy::FIFO => todo!(),
|
SchedPolicy::FIFO => todo!(),
|
||||||
SchedPolicy::RT => todo!(),
|
SchedPolicy::RT => todo!(),
|
||||||
SchedPolicy::IDLE => todo!(),
|
SchedPolicy::IDLE => IdleScheduler::dequeue(self, pcb, flags),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ use crate::{
|
|||||||
use super::{
|
use super::{
|
||||||
jiffies::clocksource_default_clock,
|
jiffies::clocksource_default_clock,
|
||||||
timer::{clock, Timer, TimerFunction},
|
timer::{clock, Timer, TimerFunction},
|
||||||
NSEC_PER_SEC,
|
NSEC_PER_SEC, NSEC_PER_USEC,
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -58,11 +58,16 @@ pub static mut FINISHED_BOOTING: AtomicBool = AtomicBool::new(false);
|
|||||||
/// Interval: 0.5sec Threshold: 0.0625s
|
/// Interval: 0.5sec Threshold: 0.0625s
|
||||||
/// 系统节拍率
|
/// 系统节拍率
|
||||||
pub const HZ: u64 = 250;
|
pub const HZ: u64 = 250;
|
||||||
|
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/clocksource.c#101
|
||||||
/// watchdog检查间隔
|
/// watchdog检查间隔
|
||||||
pub const WATCHDOG_INTERVAL: u64 = HZ >> 1;
|
pub const WATCHDOG_INTERVAL: u64 = HZ >> 1;
|
||||||
|
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/clocksource.c#108
|
||||||
/// 最大能接受的误差大小
|
/// 最大能接受的误差大小
|
||||||
pub const WATCHDOG_THRESHOLD: u32 = NSEC_PER_SEC >> 4;
|
pub const WATCHDOG_THRESHOLD: u32 = NSEC_PER_SEC >> 4;
|
||||||
|
|
||||||
|
pub const MAX_SKEW_USEC: u64 = 125 * WATCHDOG_INTERVAL / HZ;
|
||||||
|
pub const WATCHDOG_MAX_SKEW: u32 = MAX_SKEW_USEC as u32 * NSEC_PER_USEC;
|
||||||
|
|
||||||
// 时钟周期数
|
// 时钟周期数
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct CycleNum(u64);
|
pub struct CycleNum(u64);
|
||||||
@ -266,6 +271,7 @@ impl dyn Clocksource {
|
|||||||
let cs_data_guard = self.clocksource_data();
|
let cs_data_guard = self.clocksource_data();
|
||||||
|
|
||||||
let mut max_cycles: u64;
|
let mut max_cycles: u64;
|
||||||
|
// 这里我有问题,不知道要不要修改,暂时不修改它
|
||||||
max_cycles = (1 << (63 - (log2(cs_data_guard.mult) + 1))) as u64;
|
max_cycles = (1 << (63 - (log2(cs_data_guard.mult) + 1))) as u64;
|
||||||
max_cycles = max_cycles.min(cs_data_guard.mask.bits);
|
max_cycles = max_cycles.min(cs_data_guard.mask.bits);
|
||||||
let max_nsecs = clocksource_cyc2ns(
|
let max_nsecs = clocksource_cyc2ns(
|
||||||
@ -276,17 +282,95 @@ impl dyn Clocksource {
|
|||||||
return max_nsecs - (max_nsecs >> 5);
|
return max_nsecs - (max_nsecs >> 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # 计算时钟源的mult和shift,以便将一个时钟源的频率转换为另一个时钟源的频率
|
||||||
|
fn clocks_calc_mult_shift(&self, from: u32, to: u32, maxsec: u32) -> (u32, u32) {
|
||||||
|
let mut sftacc: u32 = 32;
|
||||||
|
let mut sft = 1;
|
||||||
|
|
||||||
|
// 计算限制转换范围的shift
|
||||||
|
let mut mult = (maxsec as u64 * from as u64) >> 32;
|
||||||
|
while mult != 0 {
|
||||||
|
mult >>= 1;
|
||||||
|
sftacc -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到最佳的mult和shift
|
||||||
|
for i in (1..=32).rev() {
|
||||||
|
sft = i;
|
||||||
|
mult = (to as u64) << sft;
|
||||||
|
mult += from as u64 / 2;
|
||||||
|
mult /= from as u64;
|
||||||
|
if (mult >> sftacc) == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (mult as u32, sft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # 计算时钟源可以进行的最大调整量
|
||||||
|
fn clocksource_max_adjustment(&self) -> u32 {
|
||||||
|
let cs_data = self.clocksource_data();
|
||||||
|
let ret = cs_data.mult as u64 * 11 / 100;
|
||||||
|
|
||||||
|
return ret as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # 更新时钟源频率,初始化mult/shift 和 max_idle_ns
|
||||||
|
fn clocksource_update_freq_scale(&self, scale: u32, freq: u32) -> Result<(), SystemError> {
|
||||||
|
let mut cs_data = self.clocksource_data();
|
||||||
|
|
||||||
|
if freq != 0 {
|
||||||
|
let mut sec: u64 = cs_data.mask.bits();
|
||||||
|
|
||||||
|
sec /= freq as u64;
|
||||||
|
sec /= scale as u64;
|
||||||
|
if sec == 0 {
|
||||||
|
sec = 1;
|
||||||
|
} else if sec > 600 && cs_data.mask.bits() > u32::MAX as u64 {
|
||||||
|
sec = 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mult, shift) =
|
||||||
|
self.clocks_calc_mult_shift(freq, NSEC_PER_SEC / scale, sec as u32 * scale);
|
||||||
|
cs_data.set_mult(mult);
|
||||||
|
cs_data.set_shift(shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
if scale != 0 && freq != 0 && cs_data.uncertainty_margin == 0 {
|
||||||
|
cs_data.set_uncertainty_margin(NSEC_PER_SEC / (scale * freq));
|
||||||
|
if cs_data.uncertainty_margin < 2 * WATCHDOG_MAX_SKEW {
|
||||||
|
cs_data.set_uncertainty_margin(2 * WATCHDOG_MAX_SKEW);
|
||||||
|
}
|
||||||
|
} else if cs_data.uncertainty_margin == 0 {
|
||||||
|
cs_data.set_uncertainty_margin(WATCHDOG_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保时钟源没有太大的mult值造成溢出
|
||||||
|
cs_data.set_maxadj(self.clocksource_max_adjustment());
|
||||||
|
|
||||||
|
let ns = self.clocksource_max_deferment();
|
||||||
|
cs_data.set_max_idle_ns(ns as u32);
|
||||||
|
|
||||||
|
self.update_clocksource_data(cs_data)?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
/// # 注册时钟源
|
/// # 注册时钟源
|
||||||
///
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - scale: 如果freq单位为0或hz,此值为1,如果为khz,此值为1000
|
||||||
|
/// - freq: 时钟源的频率,jiffies注册时此值为0
|
||||||
|
///
|
||||||
/// ## 返回值
|
/// ## 返回值
|
||||||
///
|
///
|
||||||
/// * `Ok(0)` - 时钟源注册成功。
|
/// * `Ok(0)` - 时钟源注册成功。
|
||||||
/// * `Err(SystemError)` - 时钟源注册失败。
|
/// * `Err(SystemError)` - 时钟源注册失败。
|
||||||
pub fn register(&self) -> Result<i32, SystemError> {
|
pub fn register(&self, scale: u32, freq: u32) -> Result<(), SystemError> {
|
||||||
let ns = self.clocksource_max_deferment();
|
self.clocksource_update_freq_scale(scale, freq)?;
|
||||||
let mut cs_data = self.clocksource_data();
|
|
||||||
cs_data.max_idle_ns = ns as u32;
|
|
||||||
self.update_clocksource_data(cs_data)?;
|
|
||||||
// 将时钟源加入到时钟源队列中
|
// 将时钟源加入到时钟源队列中
|
||||||
self.clocksource_enqueue();
|
self.clocksource_enqueue();
|
||||||
// 将时钟源加入到监视队列中
|
// 将时钟源加入到监视队列中
|
||||||
@ -295,7 +379,7 @@ impl dyn Clocksource {
|
|||||||
// 选择一个最好的时钟源
|
// 选择一个最好的时钟源
|
||||||
clocksource_select();
|
clocksource_select();
|
||||||
kdebug!("clocksource_register successfully");
|
kdebug!("clocksource_register successfully");
|
||||||
return Ok(0);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # 将时钟源插入时钟源队列
|
/// # 将时钟源插入时钟源队列
|
||||||
@ -569,10 +653,15 @@ pub struct ClocksourceData {
|
|||||||
pub max_idle_ns: u32,
|
pub max_idle_ns: u32,
|
||||||
pub flags: ClocksourceFlags,
|
pub flags: ClocksourceFlags,
|
||||||
pub watchdog_last: CycleNum,
|
pub watchdog_last: CycleNum,
|
||||||
|
// 用于描述时钟源的不确定性边界,时钟源读取的时间可能存在的不确定性和误差范围
|
||||||
|
pub uncertainty_margin: u32,
|
||||||
|
// 最大的时间调整量
|
||||||
|
pub maxadj: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClocksourceData {
|
impl ClocksourceData {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: String,
|
name: String,
|
||||||
rating: i32,
|
rating: i32,
|
||||||
@ -581,6 +670,8 @@ impl ClocksourceData {
|
|||||||
shift: u32,
|
shift: u32,
|
||||||
max_idle_ns: u32,
|
max_idle_ns: u32,
|
||||||
flags: ClocksourceFlags,
|
flags: ClocksourceFlags,
|
||||||
|
uncertainty_margin: u32,
|
||||||
|
maxadj: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let csd = ClocksourceData {
|
let csd = ClocksourceData {
|
||||||
name,
|
name,
|
||||||
@ -591,6 +682,8 @@ impl ClocksourceData {
|
|||||||
max_idle_ns,
|
max_idle_ns,
|
||||||
flags,
|
flags,
|
||||||
watchdog_last: CycleNum(0),
|
watchdog_last: CycleNum(0),
|
||||||
|
uncertainty_margin,
|
||||||
|
maxadj,
|
||||||
};
|
};
|
||||||
return csd;
|
return csd;
|
||||||
}
|
}
|
||||||
@ -624,6 +717,12 @@ impl ClocksourceData {
|
|||||||
pub fn insert_flags(&mut self, flags: ClocksourceFlags) {
|
pub fn insert_flags(&mut self, flags: ClocksourceFlags) {
|
||||||
self.flags.insert(flags)
|
self.flags.insert(flags)
|
||||||
}
|
}
|
||||||
|
pub fn set_uncertainty_margin(&mut self, uncertainty_margin: u32) {
|
||||||
|
self.uncertainty_margin = uncertainty_margin;
|
||||||
|
}
|
||||||
|
pub fn set_maxadj(&mut self, maxadj: u32) {
|
||||||
|
self.maxadj = maxadj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// converts clocksource cycles to nanoseconds
|
/// converts clocksource cycles to nanoseconds
|
||||||
@ -733,6 +832,8 @@ pub fn clocksource_watchdog() -> Result<(), SystemError> {
|
|||||||
if cs_dev_nsec.abs_diff(wd_dev_nsec) > WATCHDOG_THRESHOLD.into() {
|
if cs_dev_nsec.abs_diff(wd_dev_nsec) > WATCHDOG_THRESHOLD.into() {
|
||||||
// kdebug!("set_unstable");
|
// kdebug!("set_unstable");
|
||||||
// 误差过大,标记为unstable
|
// 误差过大,标记为unstable
|
||||||
|
kinfo!("cs_dev_nsec = {}", cs_dev_nsec);
|
||||||
|
kinfo!("wd_dev_nsec = {}", wd_dev_nsec);
|
||||||
cs.set_unstable((cs_dev_nsec - wd_dev_nsec).try_into().unwrap())?;
|
cs.set_unstable((cs_dev_nsec - wd_dev_nsec).try_into().unwrap())?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,8 @@ impl ClocksourceJiffies {
|
|||||||
max_idle_ns: Default::default(),
|
max_idle_ns: Default::default(),
|
||||||
flags: ClocksourceFlags::new(0),
|
flags: ClocksourceFlags::new(0),
|
||||||
watchdog_last: CycleNum::new(0),
|
watchdog_last: CycleNum::new(0),
|
||||||
|
uncertainty_margin: 0,
|
||||||
|
maxadj: 0,
|
||||||
};
|
};
|
||||||
let jiffies = Arc::new(ClocksourceJiffies(SpinLock::new(InnerJiffies {
|
let jiffies = Arc::new(ClocksourceJiffies(SpinLock::new(InnerJiffies {
|
||||||
data,
|
data,
|
||||||
@ -92,7 +94,7 @@ pub fn clocksource_default_clock() -> Arc<ClocksourceJiffies> {
|
|||||||
pub fn jiffies_init() {
|
pub fn jiffies_init() {
|
||||||
//注册jiffies
|
//注册jiffies
|
||||||
let jiffies = clocksource_default_clock() as Arc<dyn Clocksource>;
|
let jiffies = clocksource_default_clock() as Arc<dyn Clocksource>;
|
||||||
match jiffies.register() {
|
match jiffies.register(1, 0) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
kinfo!("jiffies_init sccessfully");
|
kinfo!("jiffies_init sccessfully");
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,9 @@ pub const NSEC_PER_SEC: u32 = 1000000000;
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub const FSEC_PER_SEC: u64 = 1000000000000000;
|
pub const FSEC_PER_SEC: u64 = 1000000000000000;
|
||||||
|
|
||||||
|
/// The clock frequency of the i8253/i8254 PIT
|
||||||
|
pub const PIT_TICK_RATE: u64 = 1193182;
|
||||||
|
|
||||||
/// 表示时间的结构体,符合POSIX标准。
|
/// 表示时间的结构体,符合POSIX标准。
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user