diff --git a/.vscode/settings.json b/.vscode/settings.json index 529e7021..cfe45b8b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -172,7 +172,8 @@ "cmd_test.h": "c", "cmpxchg.h": "c", "mman.h": "c", - "clocksource.h": "c" + "clocksource.h": "c", + "ata.h": "c" }, "C_Cpp.errorSquiggles": "enabled", "esbonio.sphinx.confDir": "", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index ab3ddf70..c2b0ff96 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -40,7 +40,7 @@ ida = { path = "src/libs/ida" } # 构建时依赖项 [build-dependencies] bindgen = "0.61.0" - +cc = { version = "1.0.83", features = ["parallel"] } [dependencies.lazy_static] version = "1.4.0" diff --git a/kernel/build.rs b/kernel/build.rs index 4587d988..5d80d0d4 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,13 +1,21 @@ extern crate bindgen; +extern crate cc; // use ::std::env; use std::path::PathBuf; +use cc::Build; + fn main() { // Tell cargo to look for shared libraries in the specified directory println!("cargo:rustc-link-search=src"); println!("cargo:rerun-if-changed=src/include/bindings/wrapper.h"); + generate_bindings(); + CFilesBuilder::build(); +} + +fn generate_bindings() { // let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let out_path = PathBuf::from(String::from("src/include/bindings/")); @@ -45,3 +53,58 @@ fn main() { .expect("Couldn't write bindings!"); } } + +/// 构建项目的c文件 +struct CFilesBuilder; + +impl CFilesBuilder { + fn build() { + let mut c = cc::Build::new(); + Self::setup_global_flags(&mut c); + Self::setup_defines(&mut c); + Self::setup_global_include_dir(&mut c); + Self::setup_files(&mut c); + c.compile("dragonos_kernel_cfiles"); + } + + fn setup_global_flags(c: &mut Build) { + c.flag("-mcmodel=large") + .flag("-fno-builtin") + .flag("-nostdlib") + .flag("-fno-stack-protector") + .flag("-fno-pie") + .flag("-Wno-expansion-to-defined") + .flag("-Wno-unused-parameter") + .flag("-m64") + .flag("-O1"); + } + + fn setup_defines(c: &mut Build) { + if let Ok(k) = std::env::var("EMULATOR") { + c.define("EMULATOR", Some(k.as_str())); + } else { + c.define("EMULATOR", "__NO_EMULATION__"); + } + + { + #[cfg(target_arch = "x86_64")] + c.define("__x86_64__", None); + } + + c.define("PIC", "_INTR_APIC_"); + } + + fn setup_global_include_dir(c: &mut Build) { + c.include("src/include"); + c.include("src"); + c.include("."); + + #[cfg(target_arch = "x86_64")] + c.include("src/arch/x86_64/include"); + } + + /// 设置需要编译的文件 + fn setup_files(c: &mut Build) { + c.file("src/arch/x86_64/driver/hpet.c"); + } +} diff --git a/kernel/src/arch/x86_64/c_adapter.rs b/kernel/src/arch/x86_64/c_adapter.rs index db9399df..f6e30141 100644 --- a/kernel/src/arch/x86_64/c_adapter.rs +++ b/kernel/src/arch/x86_64/c_adapter.rs @@ -1,4 +1,6 @@ -use super::setup::setup_arch; +use crate::time::TimeArch; + +use super::{driver::tsc::TSCManager, setup::setup_arch, CurrentTimeArch}; #[no_mangle] unsafe extern "C" fn rs_setup_arch() -> i32 { @@ -6,3 +8,14 @@ unsafe extern "C" fn rs_setup_arch() -> i32 { .map(|_| 0) .unwrap_or_else(|e| e.to_posix_errno()); } + +/// 获取当前的时间戳 +#[no_mangle] +unsafe extern "C" fn rs_get_cycles() -> u64 { + return CurrentTimeArch::get_cycles() as u64; +} + +#[no_mangle] +unsafe extern "C" fn rs_tsc_get_cpu_khz() -> u64 { + return TSCManager::cpu_khz(); +} diff --git a/kernel/src/arch/x86_64/driver/c_adapter.rs b/kernel/src/arch/x86_64/driver/c_adapter.rs new file mode 100644 index 00000000..09c56421 --- /dev/null +++ b/kernel/src/arch/x86_64/driver/c_adapter.rs @@ -0,0 +1,31 @@ +use super::{ + hpet::{hpet_init, hpet_instance}, + tsc::TSCManager, +}; + +#[no_mangle] +unsafe extern "C" fn rs_hpet_init() -> i32 { + hpet_init() + .map(|_| 0) + .unwrap_or_else(|e| e.to_posix_errno()) +} + +#[no_mangle] +unsafe extern "C" fn rs_hpet_enable() -> i32 { + hpet_instance() + .hpet_enable() + .map(|_| 0) + .unwrap_or_else(|e| e.to_posix_errno()) +} + +#[no_mangle] +unsafe extern "C" fn rs_tsc_init() -> i32 { + TSCManager::init() + .map(|_| 0) + .unwrap_or_else(|e| e.to_posix_errno()) +} + +#[no_mangle] +unsafe extern "C" fn rs_handle_hpet_irq(timer_num: u32) { + hpet_instance().handle_irq(timer_num); +} diff --git a/kernel/src/arch/x86_64/driver/hpet.c b/kernel/src/arch/x86_64/driver/hpet.c new file mode 100644 index 00000000..9714eb23 --- /dev/null +++ b/kernel/src/arch/x86_64/driver/hpet.c @@ -0,0 +1,26 @@ +#include +#include +#include + +extern void rs_handle_hpet_irq(uint32_t timer_num); + +hardware_intr_controller HPET_intr_controller = + { + .enable = apic_ioapic_enable, + .disable = apic_ioapic_disable, + .install = apic_ioapic_install, + .uninstall = apic_ioapic_uninstall, + .ack = apic_ioapic_edge_ack, +}; + +void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs) +{ + rs_handle_hpet_irq(param); +} + +void c_hpet_register_irq() +{ + struct apic_IO_APIC_RTE_entry entry; + apic_make_rte_entry(&entry, 34, IO_APIC_FIXED, DEST_PHYSICAL, IDLE, POLARITY_HIGH, IRR_RESET, EDGE_TRIGGER, MASKED, 0); + irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0"); +} diff --git a/kernel/src/arch/x86_64/driver/hpet.rs b/kernel/src/arch/x86_64/driver/hpet.rs new file mode 100644 index 00000000..d389392f --- /dev/null +++ b/kernel/src/arch/x86_64/driver/hpet.rs @@ -0,0 +1,251 @@ +use core::{ + ffi::c_void, + intrinsics::unlikely, + mem::size_of, + ptr::NonNull, + sync::atomic::{AtomicBool, Ordering}, +}; + +use acpi::HpetInfo; + +use crate::{ + driver::{ + acpi::acpi_manager, + timers::hpet::{HpetRegisters, HpetTimerRegisters}, + }, + exception::softirq::{softirq_vectors, SoftirqNumber}, + kdebug, kerror, kinfo, + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + volatile::volwrite, + }, + mm::{ + mmio_buddy::{mmio_pool, MMIOSpaceGuard}, + PhysAddr, + }, + syscall::SystemError, + time::timer::{clock, timer_get_first_expire, update_timer_jiffies}, +}; + +extern "C" { + fn c_hpet_register_irq() -> c_void; +} + +static mut HPET_INSTANCE: Option = None; + +#[inline(always)] +pub fn hpet_instance() -> &'static Hpet { + unsafe { HPET_INSTANCE.as_ref().unwrap() } +} + +pub struct Hpet { + info: HpetInfo, + _mmio_guard: MMIOSpaceGuard, + inner: RwLock, + enabled: AtomicBool, +} + +struct InnerHpet { + registers_ptr: NonNull, + timer_registers_ptr: NonNull, +} + +impl Hpet { + /// HPET0 中断间隔为500us + pub const HPET0_INTERVAL_USEC: u64 = 500; + + fn new(mut hpet_info: HpetInfo) -> Result { + let paddr = PhysAddr::new(hpet_info.base_address); + let map_size = size_of::(); + let mmio = mmio_pool().create_mmio(map_size)?; + unsafe { mmio.map_phys(paddr, map_size)? }; + let hpet = unsafe { + (mmio.vaddr().data() as *const HpetRegisters) + .as_ref() + .unwrap() + }; + let tm_num = hpet.timers_num(); + kinfo!("HPET has {} timers", tm_num); + hpet_info.hpet_number = tm_num as u8; + drop(hpet); + drop(mmio); + if tm_num == 0 { + return Err(SystemError::ENODEV); + } + + let bytes_to_map = size_of::() + + hpet_info.hpet_number as usize * size_of::(); + let mmio = mmio_pool().create_mmio(bytes_to_map)?; + + unsafe { mmio.map_phys(paddr, bytes_to_map)? }; + let ptr = NonNull::new(mmio.vaddr().data() as *mut HpetRegisters).unwrap(); + let timer_ptr = NonNull::new( + (mmio.vaddr().data() + size_of::()) as *mut HpetTimerRegisters, + ) + .unwrap(); + + let hpet = Hpet { + info: hpet_info, + _mmio_guard: mmio, + inner: RwLock::new(InnerHpet { + registers_ptr: ptr, + timer_registers_ptr: timer_ptr, + }), + enabled: AtomicBool::new(false), + }; + + return Ok(hpet); + } + + pub fn enabled(&self) -> bool { + self.enabled.load(Ordering::SeqCst) + } + + /// 使能HPET + pub(super) fn hpet_enable(&self) -> Result<(), SystemError> { + // !!!这里是临时糊代码的,需要在apic重构的时候修改!!! + let (inner_guard, regs) = unsafe { self.hpet_regs_mut() }; + let freq = regs.frequency(); + kdebug!("HPET frequency: {} Hz", freq); + let ticks = Self::HPET0_INTERVAL_USEC * freq / 1000000; + if ticks <= 0 || ticks > freq * 8 { + kerror!("HPET enable: ticks '{ticks}' is invalid"); + return Err(SystemError::EINVAL); + } + if unlikely(regs.timers_num() == 0) { + return Err(SystemError::ENODEV); + } + + unsafe { regs.write_main_counter_value(0) }; + + drop(regs); + drop(inner_guard); + + let (inner_guard, timer_reg) = unsafe { self.timer_mut(0).ok_or(SystemError::ENODEV) }?; + + let timer_reg = NonNull::new(timer_reg as *mut HpetTimerRegisters).unwrap(); + + unsafe { + // 设置定时器0为周期定时,边沿触发,默认投递到IO APIC的2号引脚(看conf寄存器的高32bit,哪一位被置1,则可以投递到哪一个I/O apic引脚) + volwrite!(timer_reg, config, 0x004c); + volwrite!(timer_reg, comparator_value, ticks); + } + drop(timer_reg); + drop(inner_guard); + + // todo!("register irq in C"); + unsafe { c_hpet_register_irq() }; + self.enabled.store(true, Ordering::SeqCst); + + let (inner_guard, regs) = unsafe { self.hpet_regs_mut() }; + + // 置位旧设备中断路由兼容标志位、定时器组使能标志位 + unsafe { regs.write_general_config(3) }; + + drop(regs); + drop(inner_guard); + + kinfo!("HPET enabled"); + return Ok(()); + } + + fn inner(&self) -> RwLockReadGuard { + self.inner.read() + } + + fn inner_mut(&self) -> RwLockWriteGuard { + self.inner.write() + } + + #[allow(dead_code)] + fn timer(&self, index: u8) -> Option<(RwLockReadGuard, &HpetTimerRegisters)> { + let inner = self.inner(); + if index >= self.info.hpet_number { + return None; + } + let timer_regs = unsafe { + inner + .timer_registers_ptr + .as_ptr() + .add(index as usize) + .as_ref() + .unwrap() + }; + return Some((inner, timer_regs)); + } + + unsafe fn timer_mut( + &self, + index: u8, + ) -> Option<(RwLockWriteGuard, &mut HpetTimerRegisters)> { + let inner = self.inner_mut(); + if index >= self.info.hpet_number { + return None; + } + let timer_regs = unsafe { + inner + .timer_registers_ptr + .as_ptr() + .add(index as usize) + .as_mut() + .unwrap() + }; + return Some((inner, timer_regs)); + } + + unsafe fn hpet_regs(&self) -> (RwLockReadGuard, &HpetRegisters) { + let inner = self.inner(); + let regs = unsafe { inner.registers_ptr.as_ref() }; + return (inner, regs); + } + + unsafe fn hpet_regs_mut(&self) -> (RwLockWriteGuard, &mut HpetRegisters) { + let mut inner = self.inner_mut(); + let regs = unsafe { inner.registers_ptr.as_mut() }; + return (inner, regs); + } + + pub fn main_counter_value(&self) -> u64 { + let (inner_guard, regs) = unsafe { self.hpet_regs() }; + let value = regs.main_counter_value(); + drop(regs); + drop(inner_guard); + return value; + } + + pub fn period(&self) -> u64 { + let (inner_guard, regs) = unsafe { self.hpet_regs() }; + let period = regs.counter_clock_period(); + kdebug!("HPET period: {}", period); + drop(regs); + drop(inner_guard); + return period; + } + + /// 处理HPET的中断 + pub(super) fn handle_irq(&self, timer_num: u32) { + if timer_num == 0 { + update_timer_jiffies(Self::HPET0_INTERVAL_USEC); + + if let Ok(first_expire) = timer_get_first_expire() { + if first_expire <= clock() { + softirq_vectors().raise_softirq(SoftirqNumber::TIMER); + } + } + } + } +} + +pub fn hpet_init() -> Result<(), SystemError> { + let hpet_info = HpetInfo::new(acpi_manager().tables().unwrap()).map_err(|e| { + kerror!("Failed to get HPET info: {:?}", e); + SystemError::ENODEV + })?; + + let hpet_instance = Hpet::new(hpet_info)?; + unsafe { + HPET_INSTANCE = Some(hpet_instance); + } + + return Ok(()); +} diff --git a/kernel/src/arch/x86_64/driver/mod.rs b/kernel/src/arch/x86_64/driver/mod.rs new file mode 100644 index 00000000..47ade1d2 --- /dev/null +++ b/kernel/src/arch/x86_64/driver/mod.rs @@ -0,0 +1,3 @@ +mod c_adapter; +pub mod hpet; +pub mod tsc; diff --git a/kernel/src/arch/x86_64/driver/tsc.rs b/kernel/src/arch/x86_64/driver/tsc.rs new file mode 100644 index 00000000..b28c120d --- /dev/null +++ b/kernel/src/arch/x86_64/driver/tsc.rs @@ -0,0 +1,384 @@ +use core::{ + cmp::{max, min}, + intrinsics::unlikely, +}; + +use crate::{ + arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch, CurrentTimeArch}, + driver::acpi::pmtmr::{ACPI_PM_OVERRUN, PMTMR_TICKS_PER_SEC}, + exception::InterruptArch, + kdebug, kerror, kinfo, kwarn, + syscall::SystemError, + time::TimeArch, +}; + +use super::hpet::hpet_instance; + +/// The clock frequency of the i8253/i8254 PIT +const PIT_TICK_RATE: u64 = 1193182; + +#[derive(Debug)] +pub struct TSCManager; + +static mut TSC_KHZ: u64 = 0; +static mut CPU_KHZ: u64 = 0; + +impl TSCManager { + const DEFAULT_THRESHOLD: u64 = 0x20000; + + /// 初始化TSC + /// + /// 目前由于未支持acpi pm timer, 因此调用该函数时,HPET应当完成初始化,否则将无法校准TSC + /// + /// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/arch/x86/kernel/tsc.c#1511 + pub fn init() -> Result<(), SystemError> { + let cpuid = x86::cpuid::CpuId::new(); + let feat = cpuid.get_feature_info().ok_or(SystemError::ENODEV)?; + if !feat.has_tsc() { + kerror!("TSC is not available"); + return Err(SystemError::ENODEV); + } + + if unsafe { TSC_KHZ == 0 } { + if let Err(e) = Self::determine_cpu_tsc_frequency(false) { + kerror!("Failed to determine CPU TSC frequency: {:?}", e); + // todo: mark TSC as unstable clock source + return Err(e); + } + } + + // todo: register TSC as clock source and deal with unstable clock source + + return Ok(()); + } + + /// 获取TSC和CPU总线的频率 + /// + /// ## 参数 + /// + /// - `early`:是否在早期初始化 + /// + /// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/arch/x86/kernel/tsc.c#1438 + fn determine_cpu_tsc_frequency(early: bool) -> Result<(), SystemError> { + if unlikely(Self::cpu_khz() != 0 || Self::tsc_khz() != 0) { + kwarn!("TSC and CPU frequency already determined"); + } + + if early { + // todo: 先根据cpuid或者读取msr或者pit来测量TSC和CPU总线的频率 + todo!("detect TSC and CPU frequency by cpuid or msr or pit"); + } else { + // 使用pit来测量TSC和CPU总线的频率 + Self::set_cpu_khz(Self::calibrate_cpu_by_pit_hpet_ptimer()?); + } + + // 认为非0的TSC频率是可靠的,并且使用它来检查CPU总线的频率 + if Self::tsc_khz() == 0 { + Self::set_tsc_khz(Self::cpu_khz()); + } else if (Self::cpu_khz() as i64 - Self::tsc_khz() as i64).abs() * 10 + > Self::cpu_khz() as i64 + { + // 如果TSC和CPU总线的频率相差太大,那么认为CPU总线的频率是不可靠的,使用TSC的频率 + Self::set_cpu_khz(Self::tsc_khz()); + } + + if Self::cpu_khz() == 0 { + kerror!("Failed to determine CPU frequency"); + return Err(SystemError::ENODEV); + } + + kinfo!( + "Detected {}.{} MHz processor", + Self::cpu_khz() / 1000, + Self::cpu_khz() % 1000 + ); + kinfo!( + "Detected {}.{} MHz TSC", + Self::tsc_khz() / 1000, + Self::tsc_khz() % 1000 + ); + + return Ok(()); + } + + /// 测量CPU总线的频率 + /// + /// 使用pit、hpet、ptimer来测量CPU总线的频率 + fn calibrate_cpu_by_pit_hpet_ptimer() -> Result { + let hpet = hpet_instance().enabled(); + kdebug!( + "Calibrating TSC with {}", + if hpet { "HPET" } else { "PMTIMER" } + ); + + let mut tsc_pit_min = u64::MAX; + let mut tsc_ref_min = u64::MAX; + + // 默认的校准参数 + let cal_ms = 10; + let cal_latch = PIT_TICK_RATE / (1000 / cal_ms); + let cal_pit_loops = 1000; + + // 如果第一轮校准失败,那么使用这些参数(因为虚拟化平台的问题,第一轮校准可能失败) + let cal2_ms = 50; + let cal2_latch = PIT_TICK_RATE / (1000 / cal2_ms); + let cal2_pit_loops = 5000; + + let mut latch = cal_latch; + let mut loopmin = cal_pit_loops; + let mut ms = cal_ms; + + let mut global_ref1 = 0; + let mut global_ref2 = 0; + + for i in 0..3 { + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + + let (tsc1, ref1) = Self::read_refs(hpet); + let tsc_pit_khz = Self::pit_calibrate_tsc(latch, ms, loopmin).unwrap_or(u64::MAX); + let (tsc2, ref2) = Self::read_refs(hpet); + drop(irq_guard); + + global_ref1 = ref1; + global_ref2 = ref2; + + // 选用最小的tsc_pit_khz + tsc_pit_min = min(tsc_pit_min, tsc_pit_khz); + + // HPET或者PTIMER可能是不可用的 + if ref1 == ref2 { + kdebug!("HPET/PMTIMER not available"); + continue; + } + + // 检查采样是否被打断 + if tsc1 == u64::MAX || tsc2 == u64::MAX { + continue; + } + + let mut tsc2 = (tsc2 - tsc1) * 1000000; + + if hpet { + tsc2 = Self::calc_hpet_ref(tsc2, ref1, ref2); + } else { + tsc2 = Self::calc_pmtimer_ref(tsc2, ref1, ref2); + } + + tsc_ref_min = min(tsc_ref_min, tsc2); + + // 检查与参考值的误差 + let mut delta = tsc_pit_min * 100; + delta /= tsc_ref_min; + + // 如果误差在10%以内,那么认为测量成功 + // 返回参考值,因为它是更精确的 + if delta >= 90 && delta <= 110 { + kinfo!( + "PIT calibration matches {}. {} loops", + if hpet { "HPET" } else { "PMTIMER" }, + i + 1 + ); + return Ok(tsc_ref_min); + } + + if i == 1 && tsc_pit_min == u64::MAX { + latch = cal2_latch; + ms = cal2_ms; + loopmin = cal2_pit_loops; + } + } + + if tsc_pit_min == u64::MAX { + kwarn!("Unable to calibrate against PIT"); + + // 如果没有参考值,那么禁用tsc + if (!hpet) && (global_ref1 == 0) && (global_ref2 == 0) { + kwarn!("No reference (HPET/PMTIMER) available"); + return Err(SystemError::ENODEV); + } + + if tsc_ref_min == u64::MAX { + kwarn!("Unable to calibrate against HPET/PMTIMER"); + return Err(SystemError::ENODEV); + } + + kinfo!( + "Using {} reference calibration", + if hpet { "HPET" } else { "PMTIMER" } + ); + return Ok(tsc_ref_min); + } + + // We don't have an alternative source, use the PIT calibration value + if (!hpet) && (global_ref1 == 0) && (global_ref2 == 0) { + kinfo!("Using PIT calibration value"); + return Ok(tsc_pit_min); + } + + // The alternative source failed, use the PIT calibration value + if tsc_ref_min == u64::MAX { + kwarn!("Unable to calibrate against HPET/PMTIMER, using PIT calibration value"); + return Ok(tsc_pit_min); + } + + // The calibration values differ too much. In doubt, we use + // the PIT value as we know that there are PMTIMERs around + // running at double speed. At least we let the user know: + kwarn!( + "PIT calibration deviates from {}: tsc_pit_min={}, tsc_ref_min={}", + if hpet { "HPET" } else { "PMTIMER" }, + tsc_pit_min, + tsc_ref_min + ); + + kinfo!("Using PIT calibration value"); + return Ok(tsc_pit_min); + } + + /// 尝试使用PIT来校准tsc时间,并且返回tsc的频率(khz)。 + /// 如果失败,那么返回None + /// + /// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/arch/x86/kernel/tsc.c#389 + fn pit_calibrate_tsc(latch: u64, ms: u64, loopmin: u64) -> Option { + unsafe { + // Set the Gate high, disable speaker + let d = (CurrentPortIOArch::in8(0x61) & (!0x02)) | 0x01; + CurrentPortIOArch::out8(0x61, d); + + // Setup CTC channel 2* for mode 0, (interrupt on terminal + // count mode), binary count. Set the latch register to 50ms + // (LSB then MSB) to begin countdown. + CurrentPortIOArch::out8(0x43, 0xb0); + CurrentPortIOArch::out8(0x42, (latch & 0xff) as u8); + CurrentPortIOArch::out8(0x42, ((latch >> 8) & 0xff) as u8); + } + + let mut tsc = CurrentTimeArch::get_cycles() as u64; + let t1 = tsc; + let mut t2 = tsc; + let mut pitcnt = 0u64; + let mut tscmax = 0u64; + let mut tscmin = u64::MAX; + while unsafe { (CurrentPortIOArch::in8(0x61) & 0x20) == 0 } { + t2 = CurrentTimeArch::get_cycles() as u64; + let delta = t2 - tsc; + tsc = t2; + + tscmin = min(tscmin, delta); + tscmax = max(tscmax, delta); + + pitcnt += 1; + } + + // Sanity checks: + // + // If we were not able to read the PIT more than loopmin + // times, then we have been hit by a massive SMI + // + // If the maximum is 10 times larger than the minimum, + // then we got hit by an SMI as well. + if pitcnt < loopmin || tscmax > 10 * tscmin { + return None; + } + + let mut delta = t2 - t1; + delta /= ms; + + return Some(delta); + } + + /// 读取tsc和参考值 + /// + /// ## 参数 + /// + /// - `hpet_enabled`:是否启用hpet + /// + /// ## 返回 + /// + /// - `Ok((tsc, ref))`:tsc和参考值 + /// + /// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/arch/x86/kernel/tsc.c#317 + fn read_refs(hpet_enabled: bool) -> (u64, u64) { + let thresh = if Self::tsc_khz() == 0 { + Self::DEFAULT_THRESHOLD + } else { + Self::tsc_khz() >> 5 + }; + + let mut ref_ret = 0; + for _ in 0..5 { + let t1 = CurrentTimeArch::get_cycles() as u64; + if hpet_enabled { + ref_ret = hpet_instance().main_counter_value(); + } else { + todo!("read pmtimer") + } + let t2 = CurrentTimeArch::get_cycles() as u64; + if (t2 - t1) < thresh { + return (t2, ref_ret); + } + } + + kwarn!("TSCManager: Failed to read reference value, tsc delta too high"); + return (u64::MAX, ref_ret); + } + + /// 根据HPET的参考值计算tsc的频率 + /// + /// https://opengrok.ringotek.cn/xref/linux-6.1.9/arch/x86/kernel/tsc.c#339 + fn calc_hpet_ref(mut deltatsc: u64, ref1: u64, mut ref2: u64) -> u64 { + if ref2 <= ref1 { + ref2 += 0x100000000; + } + + ref2 -= ref1; + let mut tmp = ref2 * hpet_instance().period(); + + tmp /= 1000000; + + deltatsc /= tmp; + + return deltatsc; + } + + /// 根据PMtimer的参考值计算tsc的频率 + fn calc_pmtimer_ref(mut deltatsc: u64, ref1: u64, mut ref2: u64) -> u64 { + if unlikely(ref1 == 0 && ref2 == 0) { + return u64::MAX; + } + + if ref2 < ref1 { + ref2 += ACPI_PM_OVERRUN; + } + + ref2 -= ref1; + + let mut tmp = ref2 * 1000000000; + + tmp /= PMTMR_TICKS_PER_SEC; + + deltatsc /= tmp; + + return deltatsc; + } + + pub fn tsc_khz() -> u64 { + unsafe { TSC_KHZ } + } + + pub fn cpu_khz() -> u64 { + unsafe { CPU_KHZ } + } + + fn set_cpu_khz(khz: u64) { + unsafe { + CPU_KHZ = khz; + } + } + + fn set_tsc_khz(khz: u64) { + unsafe { + TSC_KHZ = khz; + } + } +} diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index a0fcbfb9..6e298669 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -3,6 +3,7 @@ pub mod asm; mod acpi; mod c_adapter; pub mod cpu; +pub mod driver; pub mod fpu; pub mod interrupt; pub mod ipc; @@ -17,6 +18,7 @@ pub mod sched; pub mod setup; pub mod smp; pub mod syscall; +pub mod time; pub use self::pci::pci::X86_64PciArch as PciArch; @@ -29,3 +31,4 @@ pub use crate::arch::asm::pio::X86_64PortIOArch as CurrentPortIOArch; pub use kvm::X86_64KVMArch as KVMArch; pub use crate::arch::ipc::signal::X86_64SignalArch as CurrentSignalArch; +pub use crate::arch::time::X86_64TimeArch as CurrentTimeArch; diff --git a/kernel/src/arch/x86_64/time.rs b/kernel/src/arch/x86_64/time.rs new file mode 100644 index 00000000..6bc977e1 --- /dev/null +++ b/kernel/src/arch/x86_64/time.rs @@ -0,0 +1,9 @@ +use crate::time::TimeArch; + +pub struct X86_64TimeArch; + +impl TimeArch for X86_64TimeArch { + fn get_cycles() -> usize { + unsafe { x86::time::rdtsc() as usize } + } +} diff --git a/kernel/src/common/cpu.h b/kernel/src/common/cpu.h index 2e849ee0..0fa33c51 100644 --- a/kernel/src/common/cpu.h +++ b/kernel/src/common/cpu.h @@ -59,17 +59,3 @@ struct cpu_core_info_t }; extern struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM]; - -/** - * @brief 获取当前cpu核心晶振频率 - * - * @return uint32_t 当前cpu核心晶振频率 - */ -uint32_t cpu_get_core_crysral_freq(); - -/** - * @brief 获取处理器的tsc频率(单位:hz) - * - * @return uint64_t - */ -uint64_t cpu_get_tsc_freq(); \ No newline at end of file diff --git a/kernel/src/common/glib.h b/kernel/src/common/glib.h index eac33be0..aa90807d 100644 --- a/kernel/src/common/glib.h +++ b/kernel/src/common/glib.h @@ -5,7 +5,7 @@ #pragma once -//引入对bool类型的支持 +// 引入对bool类型的支持 #include #include #include @@ -13,7 +13,6 @@ #include #include - #include /** @@ -64,7 +63,6 @@ static __always_inline ul ALIGN(const ul addr, const ul _align) return (ul)((addr + _align - 1) & (~(_align - 1))); } - void *memset(void *dst, unsigned char C, ul size) { @@ -189,7 +187,6 @@ void io_out32(unsigned short port, unsigned int value) __asm__ __volatile__("cld;rep;outsw;mfence;" ::"d"(port), "S"(buffer), "c"(nr) \ : "memory") - /** * @brief 验证地址空间是否为用户地址空间 * @@ -245,7 +242,6 @@ static inline uint64_t copy_from_user(void *dst, void *src, uint64_t size) */ static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size) { - uint64_t tmp0, tmp1; if (verify_area((uint64_t)src, size)) return 0; @@ -262,8 +258,8 @@ static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size) // : "=&c"(size), "=&D"(tmp0), "=&S"(tmp1) // : "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src) // : "memory"); - memcpy(dst,src,size); - + memcpy(dst, src, size); + return size; } @@ -285,7 +281,6 @@ static __always_inline void __write8b(uint64_t vaddr, uint64_t value) { asm volatile("movq %%rdx, 0(%%rax)" ::"a"(vaddr), "d"(value) : "memory"); - } /** @@ -299,7 +294,6 @@ static __always_inline void __write4b(uint64_t vaddr, uint32_t value) { asm volatile("movl %%edx, 0(%%rax)" ::"a"(vaddr), "d"(value) : "memory"); - } /** @@ -338,7 +332,7 @@ static __always_inline uint32_t __read4b(uint64_t vaddr) /** * @brief 将数据从src搬运到dst,并能正确处理地址重叠的问题 - * + * * @param dst 目标地址指针 * @param src 源地址指针 * @param size 大小 diff --git a/kernel/src/driver/acpi/mod.rs b/kernel/src/driver/acpi/mod.rs index db1a3157..06b5c4ed 100644 --- a/kernel/src/driver/acpi/mod.rs +++ b/kernel/src/driver/acpi/mod.rs @@ -22,6 +22,7 @@ pub mod bus; mod c_adapter; pub mod glue; pub mod old; +pub mod pmtmr; mod sysfs; static mut __ACPI_TABLE: Option> = None; diff --git a/kernel/src/driver/acpi/pmtmr.rs b/kernel/src/driver/acpi/pmtmr.rs new file mode 100644 index 00000000..92f14840 --- /dev/null +++ b/kernel/src/driver/acpi/pmtmr.rs @@ -0,0 +1,4 @@ +pub const ACPI_PM_OVERRUN: u64 = 1 << 24; + +/// Number of PMTMR ticks expected during calibration run +pub const PMTMR_TICKS_PER_SEC: u64 = 3579545; diff --git a/kernel/src/driver/interrupt/apic/apic_timer.c b/kernel/src/driver/interrupt/apic/apic_timer.c index f164e33a..99288f73 100644 --- a/kernel/src/driver/interrupt/apic/apic_timer.c +++ b/kernel/src/driver/interrupt/apic/apic_timer.c @@ -11,6 +11,9 @@ static spinlock_t apic_timer_init_lock = {1}; // bsp 是否已经完成apic时钟初始化 static bool bsp_initialized = false; +extern uint64_t rs_get_cycles(); +extern uint64_t rs_tsc_get_cpu_khz(); + /** * @brief 初始化AP核的apic时钟 * @@ -59,7 +62,15 @@ uint64_t apic_timer_install(ul irq_num, void *arg) io_mfence(); // 设置初始计数 - apic_timer_set_init_cnt(*(uint64_t *)arg); + + uint64_t cpu_khz = rs_tsc_get_cpu_khz(); + // 疑惑:这里使用khz吗? + // 我觉得应该是hz,但是由于旧的代码是测量出initcnt的,而不是计算的 + // 然后我发现使用hz会导致计算出来的initcnt太大,导致系统卡顿,而khz的却能跑 + // TODO: 这里需要进一步研究 + uint64_t init_cnt = cpu_khz * APIC_TIMER_INTERVAL / (1000 * APIC_TIMER_DIVISOR); + kdebug("cpu_khz: %ld, init_cnt: %ld", cpu_khz, init_cnt); + apic_timer_set_init_cnt(init_cnt); io_mfence(); // 填写LVT apic_timer_set_LVT(APIC_TIMER_IRQ_NUM, 1, APIC_LVT_Timer_Periodic); @@ -101,17 +112,11 @@ void apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs) void apic_timer_init() { - if (apic_timer_ticks_result == 0) - { - kBUG("APIC timer ticks in 5ms is equal to ZERO!"); - while (1) - hlt(); - } uint64_t flags = 0; spin_lock_irqsave(&apic_timer_init_lock, flags); kinfo("Initializing apic timer for cpu %d", rs_current_pcb_cpuid()); io_mfence(); - irq_register(APIC_TIMER_IRQ_NUM, &apic_timer_ticks_result, &apic_timer_handler, 0, &apic_timer_intr_controller, + irq_register(APIC_TIMER_IRQ_NUM, NULL, &apic_timer_handler, 0, &apic_timer_intr_controller, "apic timer"); io_mfence(); if (rs_current_pcb_cpuid() == 0) diff --git a/kernel/src/driver/pci/pci_irq.rs b/kernel/src/driver/pci/pci_irq.rs index 84b28a09..2f7d72b8 100644 --- a/kernel/src/driver/pci/pci_irq.rs +++ b/kernel/src/driver/pci/pci_irq.rs @@ -13,7 +13,7 @@ use crate::include::bindings::bindings::{ c_irq_install, c_irq_uninstall, pt_regs, ul, EAGAIN, EINVAL, }; -use crate::libs::volatile::{volread, volwrite, Volatile, VolatileReadable, VolatileWritable}; +use crate::libs::volatile::{volread, volwrite, Volatile}; /// MSIX表的一项 #[repr(C)] diff --git a/kernel/src/driver/timers/HPET/HPET.c b/kernel/src/driver/timers/HPET/HPET.c deleted file mode 100644 index dd34ce8d..00000000 --- a/kernel/src/driver/timers/HPET/HPET.c +++ /dev/null @@ -1,283 +0,0 @@ -#include "HPET.h" -#include -#include -#include -#include -#include -#include