pub(super) fn read_brand_string(out: &mut [u8; 48]) -> u8 {
let mut pos = 0u8;
for leaf in [0x80000002u32, 0x80000003, 0x80000004] {
if let Some((a, b, c, d)) = crate::arch::shim::cpuid_count(leaf, 0) {
for val in [a, b, c, d] {
let bytes = val.to_le_bytes();
for byte in bytes {
if (pos as usize) < 48 {
out[pos as usize] = byte;
pos += 1;
}
}
}
}
}
while pos > 0 && (out[(pos - 1) as usize] == 0 || out[(pos - 1) as usize] == b' ') {
pos -= 1;
}
pos
}
pub fn estimate_frequency() -> u64 {
if let Some((denom, numer, crystal, _)) = crate::arch::shim::cpuid_count(0x15, 0) {
if denom != 0 && numer != 0 {
let crystal_hz = if crystal != 0 {
crystal as u64
} else {
infer_crystal_hz()
};
let tsc_hz = crystal_hz * (numer as u64) / (denom as u64);
if tsc_hz > 100_000_000 {
return tsc_hz;
}
}
}
if let Some(freq) = parse_frequency_from_brand() {
return freq;
}
calibrate_tsc()
}
fn infer_crystal_hz() -> u64 {
if let Some((eax, _, _, _)) = crate::arch::shim::cpuid_count(0x01, 0) {
let family = ((eax >> 8) & 0xF) as u8;
let model = (((eax >> 16) & 0xF) << 4 | ((eax >> 4) & 0xF)) as u8;
if family == 6 {
match model {
0x5C | 0x5F => return 19_200_000,
0x4E | 0x5E | 0x8E | 0x9E | 0xA5 | 0xA6 => return 24_000_000,
0x7E | 0x7D | 0x8C | 0x8D | 0x97 | 0x9A | 0xB7 | 0xBA | 0xBF => return 24_000_000,
_ => {}
}
}
}
0
}
fn parse_frequency_from_brand() -> Option<u64> {
let mut brand = [0u8; 48];
let len = read_brand_string(&mut brand);
if len == 0 {
return None;
}
let s = &brand[..len as usize];
let mut i = 0usize;
while i < s.len() {
if s[i] == b'@' {
let mut j = i + 1;
while j < s.len() && s[j] == b' ' {
j += 1;
}
let start = j;
let mut integer_part: u64 = 0;
let mut frac_part: u64 = 0;
let mut frac_digits: u32 = 0;
let mut in_frac = false;
while j < s.len() && (s[j].is_ascii_digit() || s[j] == b'.') {
if s[j] == b'.' {
in_frac = true;
} else if in_frac {
frac_part = frac_part * 10 + (s[j] - b'0') as u64;
frac_digits += 1;
} else {
integer_part = integer_part * 10 + (s[j] - b'0') as u64;
}
j += 1;
}
if j == start {
i += 1;
continue;
}
let mut multiplier: u64 = 1_000_000;
if j + 2 < s.len() && s[j] == b'G' && s[j + 1] == b'H' && s[j + 2] == b'z' {
multiplier = 1_000_000_000;
} else if j + 2 < s.len() && s[j] == b'M' && s[j + 1] == b'H' && s[j + 2] == b'z' {
multiplier = 1_000_000;
}
let mut hz = integer_part * multiplier;
if frac_digits > 0 {
let mut div = 1u64;
let mut d = 0u32;
while d < frac_digits {
div *= 10;
d += 1;
}
hz += frac_part * multiplier / div;
}
if hz > 100_000_000 {
return Some(hz);
}
}
i += 1;
}
None
}
pub fn calibrate_tsc() -> u64 {
let divisor: u16 = 11932; let pit_hz: u64 = 1_193_182;
unsafe {
crate::arch::x86_64::io::outb(0x43, 0x30);
crate::arch::x86_64::io::outb(0x40, (divisor & 0xFF) as u8);
crate::arch::x86_64::io::outb(0x40, ((divisor >> 8) & 0xFF) as u8);
}
let tsc_start = crate::arch::x86_64::cpu::tsc::read_tsc();
let mut prev = divisor;
let mut spins = 0u32;
loop {
let count = crate::timer::pit::Pit::read_count();
if count > prev && spins > 100 {
break; }
prev = count;
spins += 1;
if spins > 1_000_000 {
break; }
}
let tsc_end = crate::arch::x86_64::cpu::tsc::read_tsc();
let tsc_delta = tsc_end.saturating_sub(tsc_start);
if tsc_delta == 0 {
return 0;
}
tsc_delta * pit_hz / (divisor as u64)
}
pub fn read_cpu_freq_sysfs(cpu_n: u8) -> u64 {
let _ = cpu_n;
0
}