1 use crate::{ 2 alloc::string::ToString, 3 arch::{io::PortIOArch, CurrentPortIOArch}, 4 driver::acpi::{ 5 acpi_manager, 6 pmtmr::{ACPI_PM_MASK, PMTMR_TICKS_PER_SEC}, 7 }, 8 libs::spinlock::SpinLock, 9 time::{ 10 clocksource::{Clocksource, ClocksourceData, ClocksourceFlags, ClocksourceMask, CycleNum}, 11 PIT_TICK_RATE, 12 }, 13 }; 14 use acpi::fadt::Fadt; 15 use alloc::sync::{Arc, Weak}; 16 use core::intrinsics::unlikely; 17 use core::sync::atomic::{AtomicU32, Ordering}; 18 use log::info; 19 use system_error::SystemError; 20 21 // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c 22 23 /// acpi_pmtmr所在的I/O端口 24 pub static PMTMR_IO_PORT: AtomicU32 = AtomicU32::new(0); 25 26 /// # 读取acpi_pmtmr当前值,并对齐进行掩码操作 27 #[inline(always)] 28 fn read_pmtmr() -> u32 { 29 return unsafe { CurrentPortIOArch::in32(PMTMR_IO_PORT.load(Ordering::SeqCst) as u16) } 30 & ACPI_PM_MASK as u32; 31 } 32 33 //参考: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c#41 34 /// # 读取acpi_pmtmr的值,并进行多次读取以保证获取正确的值 35 /// 36 /// ## 返回值 37 /// - u32: 读取到的acpi_pmtmr值 38 #[allow(dead_code)] 39 pub fn acpi_pm_read_verified() -> u32 { 40 let mut v2: u32; 41 42 // 因为某些损坏芯片组(如ICH4、PIIX4和PIIX4E)可能导致APCI PM时钟源未锁存 43 // 因此需要多次读取以保证获取正确的值 44 loop { 45 let v1 = read_pmtmr(); 46 v2 = read_pmtmr(); 47 let v3 = read_pmtmr(); 48 49 if !(unlikely((v2 > v3 || v1 < v3) && v1 > v2 || v1 < v3 && v2 > v3)) { 50 break; 51 } 52 } 53 54 return v2; 55 } 56 57 /// # 作为时钟源的读取函数 58 /// 59 /// ## 返回值 60 /// - u64: acpi_pmtmr的当前值 61 fn acpi_pm_read() -> u64 { 62 return read_pmtmr() as u64; 63 } 64 65 pub static mut CLOCKSOURCE_ACPI_PM: Option<Arc<Acpipm>> = None; 66 67 pub fn clocksource_acpi_pm() -> Arc<Acpipm> { 68 return unsafe { CLOCKSOURCE_ACPI_PM.as_ref().unwrap().clone() }; 69 } 70 71 #[derive(Debug)] 72 pub struct Acpipm(SpinLock<InnerAcpipm>); 73 74 #[derive(Debug)] 75 struct InnerAcpipm { 76 data: ClocksourceData, 77 self_reaf: Weak<Acpipm>, 78 } 79 80 impl Acpipm { 81 pub fn new() -> Arc<Self> { 82 let data = ClocksourceData { 83 name: "acpi_pm".to_string(), 84 rating: 200, 85 mask: ClocksourceMask::new(ACPI_PM_MASK), 86 mult: 0, 87 shift: 0, 88 max_idle_ns: Default::default(), 89 flags: ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS, 90 watchdog_last: CycleNum::new(0), 91 cs_last: CycleNum::new(0), 92 uncertainty_margin: 0, 93 maxadj: 0, 94 cycle_last: CycleNum::new(0), 95 }; 96 let acpi_pm = Arc::new(Acpipm(SpinLock::new(InnerAcpipm { 97 data, 98 self_reaf: Default::default(), 99 }))); 100 acpi_pm.0.lock().self_reaf = Arc::downgrade(&acpi_pm); 101 102 return acpi_pm; 103 } 104 } 105 106 impl Clocksource for Acpipm { 107 fn read(&self) -> CycleNum { 108 return CycleNum::new(acpi_pm_read()); 109 } 110 111 fn clocksource_data(&self) -> ClocksourceData { 112 let inner = self.0.lock_irqsave(); 113 return inner.data.clone(); 114 } 115 116 fn clocksource(&self) -> Arc<dyn Clocksource> { 117 return self.0.lock_irqsave().self_reaf.upgrade().unwrap(); 118 } 119 120 fn update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError> { 121 let d = &mut self.0.lock_irqsave().data; 122 d.set_name(data.name); 123 d.set_rating(data.rating); 124 d.set_mask(data.mask); 125 d.set_mult(data.mult); 126 d.set_shift(data.shift); 127 d.set_max_idle_ns(data.max_idle_ns); 128 d.set_flags(data.flags); 129 d.watchdog_last = data.watchdog_last; 130 d.cs_last = data.cs_last; 131 d.set_uncertainty_margin(data.uncertainty_margin); 132 d.set_maxadj(data.maxadj); 133 d.cycle_last = data.cycle_last; 134 return Ok(()); 135 } 136 } 137 138 // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/mach_timer.h?fi=mach_prepare_counter 139 #[allow(dead_code)] 140 pub const CALIBRATE_TIME_MSEC: u64 = 30; 141 pub const CALIBRATE_LATCH: u64 = (PIT_TICK_RATE * CALIBRATE_TIME_MSEC + 1000 / 2) / 1000; 142 143 #[inline(always)] 144 #[allow(dead_code)] 145 pub fn mach_prepare_counter() { 146 unsafe { 147 // 将Gate位设置为高电平,从而禁用扬声器 148 CurrentPortIOArch::out8(0x61, (CurrentPortIOArch::in8(0x61) & !0x02) | 0x01); 149 150 // 针对计数器/定时器控制器的通道2进行配置,设置为模式0,二进制计数 151 CurrentPortIOArch::out8(0x43, 0xb0); 152 CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH & 0xff) as u8); 153 CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH >> 8) as u8); 154 } 155 } 156 157 #[allow(dead_code)] 158 pub fn mach_countup(count: &mut u32) { 159 let mut tmp: u32 = 0; 160 loop { 161 tmp += 1; 162 if (unsafe { CurrentPortIOArch::in8(0x61) } & 0x20) != 0 { 163 break; 164 } 165 } 166 *count = tmp; 167 } 168 169 #[allow(dead_code)] 170 const PMTMR_EXPECTED_RATE: u64 = 171 (CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (PIT_TICK_RATE >> 10); 172 173 /// # 验证ACPI PM Timer的运行速率是否在预期范围内(在x86_64架构以外的情况下验证) 174 /// 175 /// ## 返回值 176 /// - i32:如果为0则表示在预期范围内,否则不在 177 #[cfg(not(target_arch = "x86_64"))] 178 #[allow(dead_code)] 179 fn verify_pmtmr_rate() -> bool { 180 use log::info; 181 182 let mut count: u32 = 0; 183 184 mach_prepare_counter(); 185 let value1 = clocksource_acpi_pm().read().data(); 186 mach_countup(&mut count); 187 let value2 = clocksource_acpi_pm().read().data(); 188 let delta = (value2 - value1) & ACPI_PM_MASK; 189 190 if (delta < (PMTMR_EXPECTED_RATE * 19) / 20) || (delta > (PMTMR_EXPECTED_RATE * 21) / 20) { 191 info!( 192 "PM Timer running at invalid rate: {}", 193 100 * delta / PMTMR_EXPECTED_RATE 194 ); 195 return false; 196 } 197 198 return true; 199 } 200 #[cfg(target_arch = "x86_64")] 201 fn verify_pmtmr_rate() -> bool { 202 return true; 203 } 204 205 const ACPI_PM_MONOTONIC_CHECKS: u32 = 10; 206 const ACPI_PM_READ_CHECKS: u32 = 10000; 207 208 /// # 解析fadt 209 fn find_acpi_pm_clock() -> Result<(), SystemError> { 210 let fadt = acpi_manager() 211 .tables() 212 .unwrap() 213 .find_table::<Fadt>() 214 .expect("failed to find FADT table"); 215 let pm_timer_block = fadt.pm_timer_block().map_err(|_| SystemError::ENODEV)?; 216 let pm_timer_block = pm_timer_block.ok_or(SystemError::ENODEV)?; 217 let pmtmr_addr = pm_timer_block.address; 218 219 PMTMR_IO_PORT.store(pmtmr_addr as u32, Ordering::SeqCst); 220 221 info!( 222 "apic_pmtmr I/O port: {}", 223 PMTMR_IO_PORT.load(Ordering::SeqCst) 224 ); 225 226 return Ok(()); 227 } 228 229 /// # 初始化ACPI PM Timer作为系统时钟源 230 // #[unified_init(INITCALL_FS)] 231 #[inline(never)] 232 #[allow(dead_code)] 233 pub fn init_acpi_pm_clocksource() -> Result<(), SystemError> { 234 let acpi_pm = Acpipm::new(); 235 236 // 解析fadt 237 find_acpi_pm_clock()?; 238 239 // 检查pmtmr_io_port是否被设置 240 if PMTMR_IO_PORT.load(Ordering::SeqCst) == 0 { 241 return Err(SystemError::ENODEV); 242 } 243 244 unsafe { 245 CLOCKSOURCE_ACPI_PM = Some(acpi_pm); 246 } 247 248 // 验证ACPI PM Timer作为时钟源的稳定性和一致性 249 for j in 0..ACPI_PM_MONOTONIC_CHECKS { 250 let mut cnt = 100 * j; 251 while cnt > 0 { 252 cnt -= 1; 253 } 254 255 let value1 = clocksource_acpi_pm().read().data(); 256 let mut i = 0; 257 for _ in 0..ACPI_PM_READ_CHECKS { 258 let value2 = clocksource_acpi_pm().read().data(); 259 if value2 == value1 { 260 i += 1; 261 continue; 262 } 263 if value2 > value1 { 264 break; 265 } 266 if (value2 < value1) && (value2 < 0xfff) { 267 break; 268 } 269 info!("PM Timer had inconsistens results: {} {}", value1, value2); 270 271 PMTMR_IO_PORT.store(0, Ordering::SeqCst); 272 273 return Err(SystemError::EINVAL); 274 } 275 if i == ACPI_PM_READ_CHECKS { 276 info!("PM Timer failed consistency check: {}", value1); 277 278 PMTMR_IO_PORT.store(0, Ordering::SeqCst); 279 280 return Err(SystemError::EINVAL); 281 } 282 } 283 284 // 检查ACPI PM Timer的频率是否正确 285 if !verify_pmtmr_rate() { 286 PMTMR_IO_PORT.store(0, Ordering::SeqCst); 287 } 288 289 // 检查TSC时钟源的监视器是否被禁用,如果被禁用则将时钟源的标志设置为CLOCK_SOURCE_MUST_VERIFY 290 // 是因为jiffies精度小于acpi pm,所以不需要被jiffies监视 291 let tsc_clocksource_watchdog_disabled = false; 292 if tsc_clocksource_watchdog_disabled { 293 clocksource_acpi_pm().0.lock_irqsave().data.flags |= 294 ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY; 295 } 296 297 // 注册ACPI PM Timer 298 let acpi_pmtmr = clocksource_acpi_pm() as Arc<dyn Clocksource>; 299 match acpi_pmtmr.register(1, PMTMR_TICKS_PER_SEC as u32) { 300 Ok(_) => { 301 info!("ACPI PM Timer registered as clocksource sccessfully"); 302 return Ok(()); 303 } 304 Err(_) => { 305 info!("ACPI PM Timer init registered failed"); 306 return Err(SystemError::ENOSYS); 307 } 308 }; 309 } 310