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 {
25_000_000u64
};
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 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 {
0
}