mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 04:56:32 +00:00
Support x2APIC
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
0e8b2aff7b
commit
893b174dc9
@ -3,7 +3,7 @@ use log::info;
|
||||
use spin::{Mutex, Once};
|
||||
use x86::apic::ioapic::IoApic;
|
||||
|
||||
use super::acpi::ACPI_TABLES;
|
||||
use crate::arch::x86::kernel::acpi::ACPI_TABLES;
|
||||
|
||||
pub struct IoApicWrapper {
|
||||
io_apic: IoApic,
|
86
framework/jinux-frame/src/arch/x86/kernel/apic/mod.rs
Normal file
86
framework/jinux-frame/src/arch/x86/kernel/apic/mod.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use alloc::sync::Arc;
|
||||
use log::info;
|
||||
use spin::{Mutex, Once};
|
||||
|
||||
pub mod ioapic;
|
||||
pub mod x2apic;
|
||||
pub mod xapic;
|
||||
|
||||
pub static APIC_INSTANCE: Once<Arc<Mutex<dyn Apic + 'static>>> = Once::new();
|
||||
|
||||
pub trait Apic: ApicTimer + Sync + Send {
|
||||
fn id(&self) -> u32;
|
||||
|
||||
fn version(&self) -> u32;
|
||||
|
||||
/// End of Interrupt, this function will inform APIC that this interrupt has been processed.
|
||||
fn eoi(&mut self);
|
||||
}
|
||||
|
||||
pub trait ApicTimer: Sync + Send {
|
||||
/// Set the initial timer count, the APIC timer will count down from this value.
|
||||
fn set_timer_init_count(&mut self, value: u64);
|
||||
|
||||
/// Get the current count of the timer.
|
||||
/// The interval can be expressed by the expression: `init_count` - `current_count`.
|
||||
fn timer_current_count(&self) -> u64;
|
||||
|
||||
/// Set the timer register in the APIC.
|
||||
/// Bit 0-7: The interrupt vector of timer interrupt.
|
||||
/// Bit 12: Delivery Status, 0 for Idle, 1 for Send Pending.
|
||||
/// Bit 16: Mask bit.
|
||||
/// Bit 17-18: Timer Mode, 0 for One-shot, 1 for Periodic, 2 for TSC-Deadline.
|
||||
fn set_lvt_timer(&mut self, value: u64);
|
||||
|
||||
/// Set timer divide config register.
|
||||
fn set_timer_div_config(&mut self, div_config: DivideConfig);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ApicInitError {
|
||||
/// No x2APIC or xAPIC found.
|
||||
NoApic,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum DivideConfig {
|
||||
Divide1 = 0b1011,
|
||||
Divide2 = 0b0000,
|
||||
Divide4 = 0b0001,
|
||||
Divide8 = 0b0010,
|
||||
Divide16 = 0b0011,
|
||||
Divide32 = 0b1000,
|
||||
Divide64 = 0b1001,
|
||||
Divide128 = 0b1010,
|
||||
}
|
||||
|
||||
pub fn init() -> Result<(), ApicInitError> {
|
||||
crate::arch::x86::kernel::pic::disable_temp();
|
||||
if let Some(mut x2apic) = x2apic::X2Apic::new() {
|
||||
x2apic.enable();
|
||||
let version = x2apic.version();
|
||||
info!(
|
||||
"x2APIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
|
||||
x2apic.id(),
|
||||
version & 0xff,
|
||||
(version >> 16) & 0xff
|
||||
);
|
||||
APIC_INSTANCE.call_once(|| Arc::new(Mutex::new(x2apic)));
|
||||
Ok(())
|
||||
} else if let Some(mut xapic) = xapic::XApic::new() {
|
||||
xapic.enable();
|
||||
let version = xapic.version();
|
||||
info!(
|
||||
"xAPIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
|
||||
xapic.id(),
|
||||
version & 0xff,
|
||||
(version >> 16) & 0xff
|
||||
);
|
||||
APIC_INSTANCE.call_once(|| Arc::new(Mutex::new(xapic)));
|
||||
Ok(())
|
||||
} else {
|
||||
log::warn!("Not found x2APIC or xAPIC");
|
||||
Err(ApicInitError::NoApic)
|
||||
}
|
||||
}
|
78
framework/jinux-frame/src/arch/x86/kernel/apic/x2apic.rs
Normal file
78
framework/jinux-frame/src/arch/x86/kernel/apic/x2apic.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use x86::msr::{
|
||||
rdmsr, wrmsr, IA32_APIC_BASE, IA32_X2APIC_APICID, IA32_X2APIC_CUR_COUNT, IA32_X2APIC_DIV_CONF,
|
||||
IA32_X2APIC_EOI, IA32_X2APIC_INIT_COUNT, IA32_X2APIC_LVT_TIMER, IA32_X2APIC_SIVR,
|
||||
IA32_X2APIC_VERSION,
|
||||
};
|
||||
|
||||
use super::ApicTimer;
|
||||
|
||||
pub struct X2Apic {}
|
||||
|
||||
impl X2Apic {
|
||||
pub(crate) fn new() -> Option<Self> {
|
||||
if !Self::has_x2apic() {
|
||||
return None;
|
||||
}
|
||||
Some(Self {})
|
||||
}
|
||||
|
||||
fn has_x2apic() -> bool {
|
||||
// x2apic::X2APIC::new()
|
||||
let value = unsafe { core::arch::x86_64::__cpuid(1) };
|
||||
value.ecx & 0x20_0000 != 0
|
||||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
// Enable
|
||||
unsafe {
|
||||
// Enable x2APIC mode globally
|
||||
let mut base = rdmsr(IA32_APIC_BASE);
|
||||
base = base | 0b1100_0000_0000; // Enable x2APIC and xAPIC
|
||||
wrmsr(IA32_APIC_BASE, base);
|
||||
|
||||
// Set SVR, Enable APIC and set Spurious Vector to 15 (Reserved irq number)
|
||||
let svr: u64 = 1 << 8 | 15;
|
||||
wrmsr(IA32_X2APIC_SIVR, svr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Apic for X2Apic {
|
||||
fn id(&self) -> u32 {
|
||||
unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
|
||||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
|
||||
}
|
||||
|
||||
fn eoi(&mut self) {
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_EOI, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ApicTimer for X2Apic {
|
||||
fn set_timer_init_count(&mut self, value: u64) {
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_INIT_COUNT, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_current_count(&self) -> u64 {
|
||||
unsafe { rdmsr(IA32_X2APIC_CUR_COUNT) }
|
||||
}
|
||||
|
||||
fn set_lvt_timer(&mut self, value: u64) {
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_LVT_TIMER, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_timer_div_config(&mut self, div_config: super::DivideConfig) {
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_DIV_CONF, div_config as u64);
|
||||
}
|
||||
}
|
||||
}
|
107
framework/jinux-frame/src/arch/x86/kernel/apic/xapic.rs
Normal file
107
framework/jinux-frame/src/arch/x86/kernel/apic/xapic.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use crate::vm;
|
||||
use spin::{Mutex, Once};
|
||||
use x86::apic::xapic;
|
||||
|
||||
use super::ApicTimer;
|
||||
|
||||
const IA32_APIC_BASE_MSR: u32 = 0x1B;
|
||||
const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP
|
||||
const IA32_APIC_BASE_MSR_ENABLE: u64 = 0x800;
|
||||
|
||||
const APIC_LVT_MASK_BITS: u32 = 1 << 16;
|
||||
|
||||
pub static XAPIC_INSTANCE: Once<Mutex<XApic>> = Once::new();
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XApic {
|
||||
mmio_region: &'static mut [u32],
|
||||
}
|
||||
|
||||
impl XApic {
|
||||
pub fn new() -> Option<Self> {
|
||||
if !Self::has_xapic() {
|
||||
return None;
|
||||
}
|
||||
let address = vm::paddr_to_vaddr(get_apic_base_address());
|
||||
let region: &'static mut [u32] = unsafe { &mut *(address as *mut [u32; 256]) };
|
||||
Some(Self {
|
||||
mmio_region: region,
|
||||
})
|
||||
}
|
||||
|
||||
/// Read a register from the MMIO region.
|
||||
fn read(&self, offset: u32) -> u32 {
|
||||
assert!(offset as usize % 4 == 0);
|
||||
let index = offset as usize / 4;
|
||||
unsafe { core::ptr::read_volatile(&self.mmio_region[index]) }
|
||||
}
|
||||
|
||||
/// write a register in the MMIO region.
|
||||
fn write(&mut self, offset: u32, val: u32) {
|
||||
assert!(offset as usize % 4 == 0);
|
||||
let index = offset as usize / 4;
|
||||
unsafe { core::ptr::write_volatile(&mut self.mmio_region[index], val) }
|
||||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
// Enable xAPIC
|
||||
set_apic_base_address(get_apic_base_address());
|
||||
|
||||
// Set SVR, Enable APIC and set Spurious Vector to 15 (Reserved irq number)
|
||||
let svr: u32 = 1 << 8 | 15;
|
||||
self.write(xapic::XAPIC_SVR, svr);
|
||||
}
|
||||
|
||||
pub fn has_xapic() -> bool {
|
||||
let value = unsafe { core::arch::x86_64::__cpuid(1) };
|
||||
value.edx & 0x100 != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Apic for XApic {
|
||||
fn id(&self) -> u32 {
|
||||
self.read(xapic::XAPIC_ID)
|
||||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
self.read(xapic::XAPIC_VERSION)
|
||||
}
|
||||
|
||||
fn eoi(&mut self) {
|
||||
self.write(xapic::XAPIC_EOI, 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl ApicTimer for XApic {
|
||||
fn set_timer_init_count(&mut self, value: u64) {
|
||||
self.write(xapic::XAPIC_TIMER_INIT_COUNT, value as u32);
|
||||
}
|
||||
|
||||
fn timer_current_count(&self) -> u64 {
|
||||
self.read(xapic::XAPIC_TIMER_CURRENT_COUNT) as u64
|
||||
}
|
||||
|
||||
fn set_lvt_timer(&mut self, value: u64) {
|
||||
self.write(xapic::XAPIC_LVT_TIMER, value as u32);
|
||||
}
|
||||
|
||||
fn set_timer_div_config(&mut self, div_config: super::DivideConfig) {
|
||||
self.write(xapic::XAPIC_TIMER_DIV_CONF, div_config as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// set APIC base address and enable it
|
||||
fn set_apic_base_address(address: usize) {
|
||||
unsafe {
|
||||
x86_64::registers::model_specific::Msr::new(IA32_APIC_BASE_MSR)
|
||||
.write(address as u64 | IA32_APIC_BASE_MSR_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/// get APIC base address
|
||||
fn get_apic_base_address() -> usize {
|
||||
unsafe {
|
||||
(x86_64::registers::model_specific::Msr::new(IA32_APIC_BASE_MSR).read() & 0xf_ffff_f000)
|
||||
as usize
|
||||
}
|
||||
}
|
@ -4,6 +4,5 @@
|
||||
//!
|
||||
|
||||
pub mod acpi;
|
||||
pub mod ioapic;
|
||||
pub mod apic;
|
||||
pub mod pic;
|
||||
pub mod xapic;
|
||||
|
@ -1,94 +0,0 @@
|
||||
use crate::vm;
|
||||
use log::debug;
|
||||
use spin::{Mutex, Once};
|
||||
use x86::apic::xapic;
|
||||
|
||||
const IA32_APIC_BASE_MSR: u32 = 0x1B;
|
||||
const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP
|
||||
const IA32_APIC_BASE_MSR_ENABLE: u64 = 0x800;
|
||||
|
||||
const APIC_LVT_MASK_BITS: u32 = 1 << 16;
|
||||
|
||||
pub static XAPIC_INSTANCE: Once<Mutex<Xapic>> = Once::new();
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Xapic {
|
||||
mmio_region: &'static mut [u32],
|
||||
}
|
||||
|
||||
impl Xapic {
|
||||
pub fn new(address: usize) -> Self {
|
||||
let region: &'static mut [u32] = unsafe { &mut *(address as *mut [u32; 256]) };
|
||||
Self {
|
||||
mmio_region: region,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a register from the MMIO region.
|
||||
pub fn read(&self, offset: u32) -> u32 {
|
||||
assert!(offset as usize % 4 == 0);
|
||||
let index = offset as usize / 4;
|
||||
unsafe { core::ptr::read_volatile(&self.mmio_region[index]) }
|
||||
}
|
||||
|
||||
/// write a register in the MMIO region.
|
||||
pub fn write(&mut self, offset: u32, val: u32) {
|
||||
assert!(offset as usize % 4 == 0);
|
||||
let index = offset as usize / 4;
|
||||
unsafe { core::ptr::write_volatile(&mut self.mmio_region[index], val) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_apic() -> bool {
|
||||
let value = unsafe { core::arch::x86_64::__cpuid(1) };
|
||||
value.edx & 0x100 != 0
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
super::pic::disable_temp();
|
||||
|
||||
let mut apic = Xapic::new(vm::paddr_to_vaddr(get_apic_base_address()));
|
||||
// enable apic
|
||||
set_apic_base_address(get_apic_base_address());
|
||||
|
||||
let spurious = apic.read(xapic::XAPIC_SVR);
|
||||
apic.write(xapic::XAPIC_SVR, spurious | (0x100));
|
||||
let apic_id = apic.read(xapic::XAPIC_ID) >> 24;
|
||||
let apic_ver = apic.read(xapic::XAPIC_VERSION);
|
||||
|
||||
debug!(
|
||||
"APIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
|
||||
apic_id,
|
||||
apic_ver & 0xff,
|
||||
(apic_ver >> 16) & 0xff
|
||||
);
|
||||
|
||||
debug!("spurious:{:x}", spurious);
|
||||
|
||||
XAPIC_INSTANCE.call_once(|| Mutex::new(apic));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ack() {
|
||||
XAPIC_INSTANCE
|
||||
.get()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.write(xapic::XAPIC_EOI, 0);
|
||||
}
|
||||
|
||||
/// set APIC base address and enable it
|
||||
fn set_apic_base_address(address: usize) {
|
||||
unsafe {
|
||||
x86_64::registers::model_specific::Msr::new(IA32_APIC_BASE_MSR)
|
||||
.write(address as u64 | IA32_APIC_BASE_MSR_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/// get APIC base address
|
||||
fn get_apic_base_address() -> usize {
|
||||
unsafe {
|
||||
(x86_64::registers::model_specific::Msr::new(IA32_APIC_BASE_MSR).read() & 0xf_ffff_f000)
|
||||
as usize
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ pub(crate) mod timer;
|
||||
|
||||
use alloc::fmt;
|
||||
use core::fmt::Write;
|
||||
use kernel::apic::ioapic;
|
||||
use log::info;
|
||||
|
||||
pub(crate) fn before_all_init() {
|
||||
@ -21,12 +22,14 @@ pub(crate) fn after_all_init() {
|
||||
irq::init();
|
||||
device::serial::callback_init();
|
||||
kernel::acpi::init();
|
||||
if kernel::xapic::has_apic() {
|
||||
kernel::ioapic::init();
|
||||
kernel::xapic::init();
|
||||
} else {
|
||||
info!("No apic exists, using pic instead");
|
||||
kernel::pic::enable();
|
||||
match kernel::apic::init() {
|
||||
Ok(_) => {
|
||||
ioapic::init();
|
||||
}
|
||||
Err(err) => {
|
||||
info!("APIC init error:{:?}", err);
|
||||
kernel::pic::enable();
|
||||
}
|
||||
}
|
||||
timer::init();
|
||||
// Some driver like serial may use PIC
|
||||
@ -35,7 +38,9 @@ pub(crate) fn after_all_init() {
|
||||
|
||||
pub(crate) fn interrupts_ack() {
|
||||
kernel::pic::ack();
|
||||
kernel::xapic::ack();
|
||||
if let Some(apic) = kernel::apic::APIC_INSTANCE.get() {
|
||||
apic.lock().eoi();
|
||||
}
|
||||
}
|
||||
|
||||
struct Stdout;
|
||||
|
@ -1,19 +1,19 @@
|
||||
use log::info;
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
use crate::arch::x86::kernel::{pic, xapic::XAPIC_INSTANCE};
|
||||
use crate::arch::x86::kernel::{
|
||||
apic::{DivideConfig, APIC_INSTANCE},
|
||||
pic,
|
||||
};
|
||||
use crate::config;
|
||||
|
||||
use x86::apic::xapic;
|
||||
|
||||
pub fn init() {
|
||||
let mut apic_lock = XAPIC_INSTANCE.get().unwrap().lock();
|
||||
let mut apic_lock = APIC_INSTANCE.get().unwrap().lock();
|
||||
let handle = unsafe { crate::trap::IrqLine::acquire(super::TIMER_IRQ_NUM) };
|
||||
let a = handle.on_active(init_function);
|
||||
// divide by 64
|
||||
apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001);
|
||||
apic_lock.write(xapic::XAPIC_TIMER_INIT_COUNT, 0xFFFF_FFFF);
|
||||
// apic_lock.lvt_timer_register.write(timer::TIMER_IRQ_NUM as u32);
|
||||
apic_lock.set_timer_div_config(DivideConfig::Divide64);
|
||||
apic_lock.set_timer_init_count(0xFFFF_FFFF);
|
||||
drop(apic_lock);
|
||||
|
||||
// init pic for now, disable it after the APIC Timer init is done
|
||||
@ -34,13 +34,13 @@ pub fn init() {
|
||||
|
||||
fn init_function(trap_frame: &TrapFrame) {
|
||||
static mut IN_TIME: u8 = 0;
|
||||
static mut FIRST_TIME_COUNT: u32 = 0;
|
||||
static mut FIRST_TIME_COUNT: u64 = 0;
|
||||
unsafe {
|
||||
if IS_FINISH || IN_TIME == 0 {
|
||||
// drop the first entry, since it may not be the time we want
|
||||
IN_TIME += 1;
|
||||
let apic_lock = XAPIC_INSTANCE.get().unwrap().lock();
|
||||
let remain_ticks = apic_lock.read(xapic::XAPIC_TIMER_CURRENT_COUNT);
|
||||
let apic_lock = APIC_INSTANCE.get().unwrap().lock();
|
||||
let remain_ticks = apic_lock.timer_current_count();
|
||||
FIRST_TIME_COUNT = 0xFFFF_FFFF - remain_ticks;
|
||||
pic::ack();
|
||||
return;
|
||||
@ -48,17 +48,14 @@ pub fn init() {
|
||||
}
|
||||
pic::disable_temp();
|
||||
// stop APIC Timer, get the number of tick we need
|
||||
let mut apic_lock = XAPIC_INSTANCE.get().unwrap().lock();
|
||||
let remain_ticks = apic_lock.read(xapic::XAPIC_TIMER_CURRENT_COUNT);
|
||||
apic_lock.write(xapic::XAPIC_TIMER_INIT_COUNT, 0);
|
||||
let mut apic_lock = APIC_INSTANCE.get().unwrap().lock();
|
||||
let remain_ticks = apic_lock.timer_current_count();
|
||||
apic_lock.set_timer_init_count(0);
|
||||
let ticks = unsafe { 0xFFFF_FFFF - remain_ticks - FIRST_TIME_COUNT };
|
||||
// periodic mode, divide 64, freq: TIMER_FREQ Hz
|
||||
apic_lock.write(xapic::XAPIC_TIMER_INIT_COUNT, ticks as u32);
|
||||
apic_lock.write(
|
||||
xapic::XAPIC_LVT_TIMER,
|
||||
super::TIMER_IRQ_NUM as u32 | (1 << 17),
|
||||
);
|
||||
apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001);
|
||||
apic_lock.set_timer_init_count(ticks);
|
||||
apic_lock.set_lvt_timer(super::TIMER_IRQ_NUM as u64 | (1 << 17));
|
||||
apic_lock.set_timer_div_config(DivideConfig::Divide64);
|
||||
|
||||
info!(
|
||||
"APIC Timer ticks count:{:x}, remain ticks: {:x},Timer Freq:{} Hz",
|
||||
|
@ -7,7 +7,7 @@ use volatile::{
|
||||
Volatile,
|
||||
};
|
||||
|
||||
use crate::arch::x86::kernel::{acpi::ACPI_TABLES, ioapic};
|
||||
use crate::arch::x86::kernel::{acpi::ACPI_TABLES, apic::ioapic};
|
||||
static HPET_INSTANCE: Once<Hpet> = Once::new();
|
||||
|
||||
const OFFSET_ID_REGISTER: usize = 0x000;
|
||||
|
@ -10,6 +10,7 @@ use spin::{Mutex, Once};
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
use crate::arch::x86::kernel;
|
||||
use crate::config::TIMER_FREQ;
|
||||
use crate::trap::IrqAllocateHandle;
|
||||
|
||||
pub const TIMER_IRQ_NUM: u8 = 32;
|
||||
@ -19,7 +20,7 @@ static TIMER_IRQ: Once<IrqAllocateHandle> = Once::new();
|
||||
|
||||
pub fn init() {
|
||||
TIMEOUT_LIST.call_once(|| Mutex::new(BinaryHeap::new()));
|
||||
if kernel::xapic::has_apic() {
|
||||
if kernel::apic::APIC_INSTANCE.is_completed() {
|
||||
apic::init();
|
||||
} else {
|
||||
pit::init();
|
||||
@ -131,5 +132,5 @@ where
|
||||
/// The time since the system boots up.
|
||||
/// The currently returned results are in milliseconds.
|
||||
pub fn read_monotonic_milli_seconds() -> u64 {
|
||||
TICK.load(Ordering::SeqCst)
|
||||
TICK.load(Ordering::SeqCst) * (1000 / TIMER_FREQ)
|
||||
}
|
||||
|
@ -18,4 +18,4 @@ pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS;
|
||||
|
||||
pub const DEFAULT_LOG_LEVEL: Level = Level::Error;
|
||||
/// This value represent the base timer frequency in Hz
|
||||
pub const TIMER_FREQ: u64 = 1000;
|
||||
pub const TIMER_FREQ: u64 = 500;
|
||||
|
Reference in New Issue
Block a user