Compare commits

...

2 Commits

Author SHA1 Message Date
histausse adc45f6aa2
add logs macro 1 year ago
histausse 1ce4ed7fe9
Add time management 1 year ago

@ -0,0 +1,3 @@
//! Modules specific to the aarch64 architecture.
pub mod time;

@ -0,0 +1,88 @@
//! The implementation of the time management trait for aarch64.
use core::arch::asm;
use core::time::Duration;
use crate::traits::time::TimeManager;
use crate::println;
const NS_PER_S: u64 = 1_000_000_000;
const CNTP_CTL_EL0_ENABLE_MASK: u64 = 0b001;
const CNTP_CTL_EL0_IMASK_MASK: u64 = 0b010;
const CNTP_CTL_EL0_ISTATUS_MASK: u64 = 0b100;
/// AARCH64 Timer.
struct Timer;
/// The global timer.
static TIME_MANAGER: Timer = Timer;
/// Return a reference to the global time manager.
pub fn time_manager() -> &'static impl TimeManager {
&TIME_MANAGER
}
impl TimeManager for Timer {
fn frequency(&self) -> u64 {
let freq: u64;
unsafe {
asm!("mrs {0:x}, CNTFRQ_EL0", out(reg) freq, options(nomem, nostack));
}
freq
}
fn uptime(&self) -> Duration {
let ticks: u64;
unsafe {
// Protect against out of order execution
// https://developer.arm.com/documentation/dui0802/b/CIHGHHIE
// In effect this flush the processor pipeline
asm!("ISB", options(nostack));
asm!("mrs {0:x}, CNTPCT_EL0", out(reg) ticks, options(nomem, nostack));
}
Duration::from_nanos((ticks*NS_PER_S)/self.frequency())
}
fn sleep(&self, duration: Duration) {
if duration.is_zero() {
return;
}
let tmp = match self.frequency().checked_mul(duration.as_nanos() as u64) {
None => {
println!("Cannot sleep this long, skipping");
return;
}
Some(tmp) => tmp,
};
let ticks = tmp / NS_PER_S;
if ticks > u32::max_value().into() {
println!("Cannot wait more than 2^32-1 ticks on aarch64, skipping");
return;
}
if ticks == 0 {
println!("Duration is smaller than a clock tick, skipping.");
return;
}
// Enable the timer and mask (disable) the interrupt
let mut ctl: u64 = CNTP_CTL_EL0_ENABLE_MASK + CNTP_CTL_EL0_IMASK_MASK;
unsafe {
// set the register values for the timer
asm!("msr CNTP_TVAL_EL0, {0:x}", in(reg) ticks, options(nomem, nostack));
asm!("msr CNTP_CTL_EL0, {0:x}", in(reg) ctl, options(nomem, nostack));
}
// Loop waiting for the timer to run out
while (ctl & CNTP_CTL_EL0_ISTATUS_MASK) == 0 {
unsafe {
asm!("mrs {0:x}, CNTP_CTL_EL0", out(reg) ctl, options(nomem, nostack));
}
}
// Disable the counter
ctl &= !CNTP_CTL_EL0_ENABLE_MASK;
unsafe {
asm!("msr CNTP_CTL_EL0, {0:x}", in(reg) ctl, options(nomem, nostack));
}
}
}

@ -6,3 +6,6 @@ pub mod rpi3;
#[cfg(feature = "target_rpi4")]
pub mod rpi4;
#[cfg(target_arch = "aarch64")]
pub mod aarch64;

@ -0,0 +1,121 @@
//! Module implementing the `print!`/`println!` macro.
/// Log an debug info
#[macro_export]
macro_rules! debug {
($string:expr) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] DEBUG: ", $string),
timestamp.as_secs(),
timestamp.subsec_micros(),
));
});
($format_string:expr, $($arg:tt)*) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] DEBUG: ", $format_string),
timestamp.as_secs(),
timestamp.subsec_micros(),
$($arg)*
));
})
}
/// Log an info
#[macro_export]
macro_rules! info {
($string:expr) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] INFO: ", $string),
timestamp.as_secs(),
timestamp.subsec_micros(),
));
});
($format_string:expr, $($arg:tt)*) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] INFO: ", $format_string),
timestamp.as_secs(),
timestamp.subsec_micros(),
$($arg)*
));
})
}
/// Log an warning
#[macro_export]
macro_rules! warn {
($string:expr) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] WARN: ", $string),
timestamp.as_secs(),
timestamp.subsec_micros(),
));
});
($format_string:expr, $($arg:tt)*) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] WARN: ", $format_string),
timestamp.as_secs(),
timestamp.subsec_micros(),
$($arg)*
));
})
}
/// Log an error
#[macro_export]
macro_rules! error {
($string:expr) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] ERR: ", $string),
timestamp.as_secs(),
timestamp.subsec_micros(),
));
});
($format_string:expr, $($arg:tt)*) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] ERR: ", $format_string),
timestamp.as_secs(),
timestamp.subsec_micros(),
$($arg)*
));
})
}
/// Log a fatal error
#[macro_export]
macro_rules! fatal {
($string:expr) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] FATAL: ", $string),
timestamp.as_secs(),
timestamp.subsec_micros(),
));
});
($format_string:expr, $($arg:tt)*) => ({
use $crate::traits::time::TimeManager;
let timestamp = $crate::time_manager().uptime();
$crate::print::_print(format_args_nl!(
concat!("[{:>6}.{:06}] FATAL: ", $format_string),
timestamp.as_secs(),
timestamp.subsec_micros(),
$($arg)*
));
})
}

@ -20,17 +20,25 @@ mod utils;
mod panic;
#[cfg(not(test))]
mod print;
#[cfg(not(test))]
mod log;
#[cfg(not(test))]
use core::arch::global_asm;
#[cfg(not(test))]
use core::arch::asm;
use core::time::Duration;
// TODO: handle this with features
#[cfg(not(test))]
use crate::bsp::rpi3::uart::console;
#[cfg(not(test))]
use crate::bsp::rpi3::gpio;
#[cfg(not(test))]
use crate::bsp::aarch64::time::time_manager;
use crate::traits::time::TimeManager;
// TODO: move this to BSP
/// Pause the core with a infinit loop
@ -68,6 +76,12 @@ pub unsafe fn _start_rust() -> ! {
bsp::rpi3::uart::init();
println!("Hello there");
debug!("debug");
info!("info");
warn!("warn");
error!("error");
fatal!("fatal");
let mut buffer = ['X'; 200];
let mut i = 0;
let mut c = console().read_char();
@ -89,23 +103,22 @@ pub unsafe fn _start_rust() -> ! {
println!("");
match gpio::set_pin_fonction(21, gpio::PinFunction::Output) {
Ok(()) => println!("Successfully set pin to output"),
Err(err) => println!("Failled to set pin: {err}"),
Ok(()) => info!("Successfully set pin to output"),
Err(err) => warn!("Failled to set pin: {}", err),
}
loop {
match gpio::set_pin_output_state(21, gpio::PinOutputState::High) {
Ok(()) => (),
Err(_err) => println!("Failled to set pin 21 to High"),
}
for _ in 0..5000000 {
asm!("nop");
Ok(()) => info!("OUTPUT 21 UP"),
Err(_err) => warn!("Failled to set pin 21 to High"),
}
time_manager().sleep(Duration::from_secs(1));
match gpio::set_pin_output_state(21, gpio::PinOutputState::Low) {
Ok(()) => (),
Err(_err) => println!("Failled to set pin 21 to Low"),
Ok(()) => info!("OUTPUT 21 DOWN"),
Err(_err) => warn!("Failled to set pin 21 to Low"),
}
for _ in 0..5000000 {
asm!("nop");
time_manager().sleep(Duration::from_secs(1));
if time_manager().uptime().as_secs() >= 60 {
panic!("Times out");
}
}
/*

@ -2,7 +2,7 @@
use core::panic::PanicInfo;
use crate::println;
use crate::fatal;
use crate::wait_forever;
/// Avoid nested panic
@ -32,10 +32,11 @@ fn panic(info: &PanicInfo) -> ! {
_ => ("???", 0, 0),
};
println!(
fatal!(
"Kernel panic!\n\n\
Panic location:\n File: '{location}', line {line}, column {column}\n\n\
Panic location:\n File: '{}', line {}, column {}\n\n\
{}",
location, line, column,
info.message().unwrap_or(&format_args!(""))
);
wait_forever()

@ -10,3 +10,4 @@
pub mod console;
pub mod synchronization;
pub mod time;

@ -0,0 +1,16 @@
//! Traits for time management primitives.
use core::time::Duration;
pub trait TimeManager {
/// Return the clock frequency, meaning the resolution of the
/// time mesurement.
fn frequency(&self) -> u64;
/// The uptime since last power-on.
fn uptime(&self) -> Duration;
/// Sleep for the duration.
fn sleep(&self, duration: Duration);
}
Loading…
Cancel
Save