新的ipi功能&kick_cpu功能的重写 (#274)

This commit is contained in:
LoGin 2023-05-30 10:21:11 +08:00 committed by GitHub
parent bb24249faa
commit aa0367d69e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 272 additions and 68 deletions

View File

@ -0,0 +1,127 @@
use crate::exception::ipi::{IpiKind, IpiTarget};
extern "C" {
pub fn apic_write_icr(value: u64);
pub fn apic_x2apic_enabled() -> bool;
}
/// IPI的种类(架构相关,指定了向量号)
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum ArchIpiKind {
KickCpu = 200,
FlushTLB = 201,
}
impl From<IpiKind> for ArchIpiKind {
fn from(kind: IpiKind) -> Self {
match kind {
IpiKind::KickCpu => ArchIpiKind::KickCpu,
IpiKind::FlushTLB => ArchIpiKind::FlushTLB,
}
}
}
/// IPI投递目标
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ArchIpiTarget {
/// 当前CPU
Current,
/// 所有CPU
All,
/// 除了当前CPU以外的所有CPU
Other,
/// 指定的CPU
Specified(usize),
}
impl From<IpiTarget> for ArchIpiTarget {
fn from(target: IpiTarget) -> Self {
match target {
IpiTarget::Current => ArchIpiTarget::Current,
IpiTarget::All => ArchIpiTarget::All,
IpiTarget::Other => ArchIpiTarget::Other,
IpiTarget::Specified(cpu_id) => ArchIpiTarget::Specified(cpu_id),
}
}
}
impl ArchIpiTarget {
pub fn shorthand(&self) -> u8 {
match self {
ArchIpiTarget::Specified(_) => 0,
ArchIpiTarget::Current => 1,
ArchIpiTarget::All => 2,
ArchIpiTarget::Other => 3,
}
}
}
impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
fn into(self) -> x86::apic::DestinationShorthand {
match self {
ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
}
}
}
impl Into<x86::apic::ApicId> for ArchIpiTarget {
fn into(self) -> x86::apic::ApicId {
let id = match self {
ArchIpiTarget::Specified(cpu_id) => cpu_id,
_ => 0,
};
if unsafe { apic_x2apic_enabled() } {
return x86::apic::ApicId::X2Apic(id as u32);
} else {
return x86::apic::ApicId::XApic(id as u8);
}
}
}
#[inline(always)]
pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
// kdebug!("send_ipi: {:?} {:?}", kind, target);
let ipi_vec = ArchIpiKind::from(kind) as u8;
let target = ArchIpiTarget::from(target);
let shorthand: x86::apic::DestinationShorthand = target.into();
let destination: x86::apic::ApicId = target.into();
if unsafe { apic_x2apic_enabled() } {
// kdebug!("send_ipi: x2apic");
let icr = x86::apic::Icr::for_x2apic(
ipi_vec,
destination,
shorthand,
x86::apic::DeliveryMode::Fixed,
x86::apic::DestinationMode::Physical,
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Assert,
x86::apic::TriggerMode::Edge,
);
unsafe {
apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
}
} else {
// kdebug!("send_ipi: xapic");
let icr = x86::apic::Icr::for_xapic(
ipi_vec,
destination,
shorthand,
x86::apic::DeliveryMode::Fixed,
x86::apic::DestinationMode::Physical,
x86::apic::DeliveryStatus::Idle,
x86::apic::Level::Assert,
x86::apic::TriggerMode::Edge,
);
unsafe {
apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
}
}
}

View File

@ -1,4 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
pub mod ipi;
use core::{ use core::{
arch::asm, arch::asm,
sync::atomic::{compiler_fence, Ordering}, sync::atomic::{compiler_fence, Ordering},

View File

@ -9,10 +9,7 @@ use crate::{
syscall::{Syscall, SystemError, SYS_EXECVE, SYS_FORK, SYS_RT_SIGRETURN, SYS_VFORK}, syscall::{Syscall, SystemError, SYS_EXECVE, SYS_FORK, SYS_RT_SIGRETURN, SYS_VFORK},
}; };
use super::{ use super::{asm::ptrace::user_mode, mm::barrier::mfence};
asm::{ptrace::user_mode},
mm::barrier::mfence,
};
extern "C" { extern "C" {
fn do_fork(regs: *mut pt_regs, clone_flags: u64, stack_start: u64, stack_size: u64) -> u64; fn do_fork(regs: *mut pt_regs, clone_flags: u64, stack_start: u64, stack_size: u64) -> u64;

View File

@ -147,6 +147,9 @@ void apic_init_ap_core_local_apic()
__local_apic_x2apic_init(); __local_apic_x2apic_init();
else // 当前为xapic else // 当前为xapic
__local_apic_xapic_init(); __local_apic_xapic_init();
barrier();
kdebug("AP-core's local apic initialized.");
barrier();
} }
/** /**
@ -160,15 +163,15 @@ static void __local_apic_xapic_init()
uint64_t qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR); uint64_t qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR);
qword |= (1 << 8); qword |= (1 << 8);
*(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR) = qword; *(volatile uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR) = qword;
qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR); qword = *(volatile uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR);
if (qword & 0x100) if (qword & 0x100)
kinfo("APIC Software Enabled."); kinfo("APIC Software Enabled.");
if (qword & 0x1000) if (qword & 0x1000)
kinfo("EOI-Broadcast Suppression Enabled."); kinfo("EOI-Broadcast Suppression Enabled.");
barrier();
// 从 Local APIC Version register 获取Local APIC Version // 从 Local APIC Version register 获取Local APIC Version
qword = *(uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_Version); qword = *(volatile uint64_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_Version);
qword &= 0xffffffff; qword &= 0xffffffff;
local_apic_max_LVT_entries = ((qword >> 16) & 0xff) + 1; local_apic_max_LVT_entries = ((qword >> 16) & 0xff) + 1;
@ -188,19 +191,19 @@ static void __local_apic_xapic_init()
// 如果写入这里的话,在有的机器上面会报错 // 如果写入这里的话,在有的机器上面会报错
// *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI) = APIC_LVT_INT_MASKED; // *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI) = APIC_LVT_INT_MASKED;
io_mfence(); io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER) = APIC_LVT_INT_MASKED; *(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER) = APIC_LVT_INT_MASKED;
io_mfence(); io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL) = APIC_LVT_INT_MASKED; *(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL) = APIC_LVT_INT_MASKED;
io_mfence(); io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR) = *(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR) =
APIC_LVT_INT_MASKED; APIC_LVT_INT_MASKED;
io_mfence(); io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0) = APIC_LVT_INT_MASKED; *(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0) = APIC_LVT_INT_MASKED;
io_mfence(); io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1) = APIC_LVT_INT_MASKED; *(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1) = APIC_LVT_INT_MASKED;
io_mfence(); io_mfence();
*(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR) = APIC_LVT_INT_MASKED; *(volatile uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR) = APIC_LVT_INT_MASKED;
io_mfence(); io_mfence();
kdebug("All LVT Masked"); kdebug("All LVT Masked");
@ -692,4 +695,37 @@ uint32_t apic_get_local_apic_id()
return x; return x;
} }
} }
/**
* icr寄存器
*
* @param value
*/
void apic_write_icr(uint64_t value)
{
if (flag_support_x2apic)
{
wrmsr(0x830, value);
}
else
{
// kdebug("to write icr: %#018lx", value);
const uint64_t PENDING = 1UL << 12;
while (*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) & PENDING)
;
// kdebug("write icr: %#018lx", value);
*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32) = (value >> 32) & 0xffffffff;
*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) = value & 0xffffffff;
while (*(volatile uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) & PENDING)
;
// kdebug("write icr done");
}
}
// 查询是否启用了x2APIC
bool apic_x2apic_enabled()
{
return flag_support_x2apic;
}
#pragma GCC pop_options #pragma GCC pop_options

View File

@ -8,7 +8,6 @@
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize("O0") #pragma GCC optimize("O0")
#define APIC_SUCCESS 0 #define APIC_SUCCESS 0
#define APIC_E_NOTFOUND 1 #define APIC_E_NOTFOUND 1
@ -19,7 +18,7 @@
extern uint8_t __apic_enable_state; extern uint8_t __apic_enable_state;
#define APIC_XAPIC_ENABLED 0 #define APIC_XAPIC_ENABLED 0
#define APIC_X2APIC_ENABLED 1 #define APIC_X2APIC_ENABLED 1
#define CURRENT_APIC_STATE (__apic_enable_state ) #define CURRENT_APIC_STATE (__apic_enable_state)
// ======== local apic 寄存器虚拟地址偏移量表 ======= // ======== local apic 寄存器虚拟地址偏移量表 =======
// 0x00~0x10 Reserved. // 0x00~0x10 Reserved.
@ -331,4 +330,6 @@ void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, u
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID); uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask, uint8_t dest_apicID);
uint32_t apic_get_local_apic_id(); uint32_t apic_get_local_apic_id();
void apic_write_icr(uint64_t value);
bool apic_x2apic_enabled();
#pragma GCC pop_options #pragma GCC pop_options

View File

@ -0,0 +1,21 @@
#[allow(dead_code)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum IpiKind {
KickCpu,
FlushTLB,
}
/// IPI投递目标
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[allow(dead_code)]
pub enum IpiTarget {
/// 当前CPU
Current,
/// 所有CPU
All,
/// 除了当前CPU以外的所有CPU
Other,
/// 指定的CPU
Specified(usize),
}

View File

@ -1,5 +1,6 @@
use crate::arch::CurrentIrqArch; use crate::arch::CurrentIrqArch;
pub mod ipi;
pub mod softirq; pub mod softirq;
/// @brief 中断相关的操作 /// @brief 中断相关的操作

View File

@ -1,12 +1,9 @@
use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloc::{boxed::Box, sync::Arc, vec::Vec};
use crate::{ use crate::{
arch::asm::{current::current_pcb}, arch::asm::current::current_pcb,
filesystem::vfs::file::FileDescriptorVec, filesystem::vfs::file::FileDescriptorVec,
include::bindings::bindings::{ include::bindings::bindings::{verify_area, AT_REMOVEDIR, PAGE_4K_SIZE, PROC_MAX_FD_NUM},
verify_area, AT_REMOVEDIR, PAGE_4K_SIZE, PROC_MAX_FD_NUM,
},
io::SeekFrom, io::SeekFrom,
kerror, kerror,
syscall::{Syscall, SystemError}, syscall::{Syscall, SystemError},

View File

@ -35,12 +35,10 @@ use crate::{
use super::signal_types::{ use super::signal_types::{
si_code_val, sig_is_member, sigaction, sigaction__union_u, sigcontext, sigframe, si_code_val, sig_is_member, sigaction, sigaction__union_u, sigcontext, sigframe,
sighand_struct, siginfo, signal_struct, sigpending, sigset_clear, sigset_del, sigset_delmask, sighand_struct, siginfo, signal_struct, sigpending, sigset_clear, sigset_del, sigset_delmask,
sigset_equal, sigset_t, SigQueue, SignalNumber, MAX_SIG_NUM, SA_ALL_FLAGS, sigset_equal, sigset_t, SigQueue, SignalNumber, MAX_SIG_NUM, SA_ALL_FLAGS, SA_FLAG_DFL,
SA_FLAG_DFL, SA_FLAG_IGN, SA_FLAG_IMMUTABLE, SA_FLAG_RESTORER, STACK_ALIGN, _NSIG_U64_CNT, SA_FLAG_IGN, SA_FLAG_IMMUTABLE, SA_FLAG_RESTORER, STACK_ALIGN, _NSIG_U64_CNT,
}; };
/// 默认信号处理程序占位符用于在sighand结构体中的action数组中占位 /// 默认信号处理程序占位符用于在sighand结构体中的action数组中占位
pub static DEFAULT_SIGACTION: sigaction = sigaction { pub static DEFAULT_SIGACTION: sigaction = sigaction {
_u: sigaction__union_u { _u: sigaction__union_u {

View File

@ -55,7 +55,7 @@ macro_rules! int_like {
#[allow(dead_code)] #[allow(dead_code)]
pub const fn new(x: $new_type_name) -> Self { pub const fn new(x: $new_type_name) -> Self {
$new_atomic_type_name { $new_atomic_type_name {
container: $backing_atomic_type::new(x.into()) container: $backing_atomic_type::new(x.into()),
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -71,37 +71,60 @@ macro_rules! int_like {
self.container.store(val.into(), order) self.container.store(val.into(), order)
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn swap(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) -> $new_type_name { pub fn swap(
&self,
val: $new_type_name,
order: ::core::sync::atomic::Ordering,
) -> $new_type_name {
$new_type_name::from(self.container.swap(val.into(), order)) $new_type_name::from(self.container.swap(val.into(), order))
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn compare_exchange(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> { pub fn compare_exchange(
match self.container.compare_exchange(current.into(), new.into(), success, failure) { &self,
current: $new_type_name,
new: $new_type_name,
success: ::core::sync::atomic::Ordering,
failure: ::core::sync::atomic::Ordering,
) -> ::core::result::Result<$new_type_name, $new_type_name> {
match self
.container
.compare_exchange(current.into(), new.into(), success, failure)
{
Ok(result) => Ok($new_type_name::from(result)), Ok(result) => Ok($new_type_name::from(result)),
Err(result) => Err($new_type_name::from(result)) Err(result) => Err($new_type_name::from(result)),
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn compare_exchange_weak(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> { pub fn compare_exchange_weak(
match self.container.compare_exchange_weak(current.into(), new.into(), success, failure) { &self,
current: $new_type_name,
new: $new_type_name,
success: ::core::sync::atomic::Ordering,
failure: ::core::sync::atomic::Ordering,
) -> ::core::result::Result<$new_type_name, $new_type_name> {
match self.container.compare_exchange_weak(
current.into(),
new.into(),
success,
failure,
) {
Ok(result) => Ok($new_type_name::from(result)), Ok(result) => Ok($new_type_name::from(result)),
Err(result) => Err($new_type_name::from(result)) Err(result) => Err($new_type_name::from(result)),
}
} }
} }
} }
};
} }
#[test] #[test]
fn test() { fn test() {
use core::mem::size_of;
use ::core::sync::atomic::AtomicUsize; use ::core::sync::atomic::AtomicUsize;
use core::mem::size_of;
// Generate type `usize_like`. // Generate type `usize_like`.
int_like!(UsizeLike, usize); int_like!(UsizeLike, usize);
assert_eq!(size_of::<UsizeLike>(), size_of::<usize>()); assert_eq!(size_of::<UsizeLike>(), size_of::<usize>());
// Generate types `usize_like` and `AtomicUsize`. // Generate types `usize_like` and `AtomicUsize`.
int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize); int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize);
assert_eq!(size_of::<UsizeLike2>(), size_of::<usize>()); assert_eq!(size_of::<UsizeLike2>(), size_of::<usize>());

View File

@ -1,5 +1,3 @@
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
#[repr(u8)] #[repr(u8)]

View File

@ -775,7 +775,7 @@ int process_wakeup_immediately(struct process_control_block *pcb)
if (pcb->cpu_id == current_pcb->cpu_id) if (pcb->cpu_id == current_pcb->cpu_id)
sched(); sched();
else else
kick_cpu(pcb->cpu_id); rs_kick_cpu(pcb->cpu_id);
return 0; return 0;
} }

View File

@ -1 +1,21 @@
use crate::{
arch::interrupt::ipi::send_ipi,
exception::ipi::{IpiKind, IpiTarget},
syscall::SystemError,
};
pub mod core; pub mod core;
pub fn kick_cpu(cpu_id: usize) -> Result<(), SystemError> {
// todo: 增加对cpu_id的有效性检查
send_ipi(IpiKind::KickCpu, IpiTarget::Specified(cpu_id));
return Ok(());
}
#[no_mangle]
pub extern "C" fn rs_kick_cpu(cpu_id: usize) -> usize {
return kick_cpu(cpu_id)
.map(|_| 0usize)
.unwrap_or_else(|e| e.to_posix_errno() as usize);
}

View File

@ -222,21 +222,6 @@ static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_r
sched(); sched();
} }
/**
* @brief 使cpu核心立即运行调度
*
* @param cpu_id cpu核心号
*/
int kick_cpu(uint32_t cpu_id)
{
if (cpu_id >= MAX_CPU_NUM)
{
return -EINVAL;
}
ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, KICK_CPU_IRQ_NUM, ICR_APIC_FIXED,
ICR_ALL_EXCLUDE_Self, 0);
return 0;
}
/** /**
* @brief cpu数目 * @brief cpu数目

View File

@ -15,6 +15,6 @@ extern uchar _apu_boot_end[];
*/ */
void smp_init(); void smp_init();
int kick_cpu(uint32_t cpu_id); extern int64_t rs_kick_cpu(uint32_t cpu_id);
uint32_t smp_get_total_cpu(); uint32_t smp_get_total_cpu();

View File

@ -13,7 +13,8 @@ use crate::{
MAX_PATHLEN, MAX_PATHLEN,
}, },
include::bindings::bindings::{mm_stat_t, pid_t, verify_area, PAGE_2M_SIZE, PAGE_4K_SIZE}, include::bindings::bindings::{mm_stat_t, pid_t, verify_area, PAGE_2M_SIZE, PAGE_4K_SIZE},
io::SeekFrom, kinfo, io::SeekFrom,
kinfo,
net::syscall::SockAddr, net::syscall::SockAddr,
time::TimeSpec, time::TimeSpec,
}; };

View File

@ -3,11 +3,7 @@ use core::{arch::x86_64::_rdtsc, hint::spin_loop};
use alloc::{boxed::Box, sync::Arc}; use alloc::{boxed::Box, sync::Arc};
use crate::{ use crate::{
arch::{ arch::{asm::current::current_pcb, sched::sched, CurrentIrqArch},
asm::current::current_pcb,
sched::sched,
CurrentIrqArch,
},
exception::InterruptArch, exception::InterruptArch,
include::bindings::bindings::{useconds_t, Cpu_tsc_freq}, include::bindings::bindings::{useconds_t, Cpu_tsc_freq},
syscall::SystemError, syscall::SystemError,