aarch64: implement ARM generic timer, can work in qemu

master
equation314 6 years ago
parent 07aa9a0686
commit 3e1d8c5827

@ -3,5 +3,9 @@ name = "bcm2837"
version = "0.1.0"
authors = ["equation314 <equation618@gmail.com>"]
[features]
use_generic_timer = []
[dependencies]
volatile = "0.2.4"
cortex-a = "2.2.2"

@ -0,0 +1,83 @@
extern crate cortex_a;
use self::cortex_a::regs::*;
use volatile::*;
/// The base address for the ARM generic timer, IRQs, mailboxes
const GEN_TIMER_REG_BASE: usize = 0x40000000;
/// Core interrupt sources (ref: QA7 4.10, page 16)
#[repr(u8)]
#[allow(dead_code)]
#[allow(non_snake_case)]
#[derive(Copy, Clone, PartialEq, Debug)]
enum CoreInterrupt {
CNTPSIRQ = 0,
CNTPNSIRQ = 1,
CNTHPIRQ = 2,
CNTVIRQ = 3,
Mailbox0 = 4,
Mailbox1 = 5,
Mailbox2 = 6,
Mailbox3 = 7,
Gpu = 8,
Pmu = 9,
AxiOutstanding = 10,
LocalTimer = 11,
}
/// Timer, IRQs, mailboxes registers (ref: QA7 chapter 4, page 7)
#[allow(non_snake_case)]
#[repr(C)]
struct Registers {
CONTROL: Volatile<u32>,
_unused1: [Volatile<u32>; 8],
LOCAL_IRQ: Volatile<u32>,
_unused2: [Volatile<u32>; 3],
LOCAL_TIMER_CTL: Volatile<u32>,
LOCAL_TIMER_FLAGS: Volatile<u32>,
_unused3: Volatile<u32>,
CORE_TIMER_IRQCNTL: [Volatile<u32>; 4],
CORE_MAILBOX_IRQCNTL: [Volatile<u32>; 4],
CORE_IRQ_SRC: [Volatile<u32>; 4],
}
/// The ARM generic timer.
pub struct Timer {
registers: &'static mut Registers,
}
impl Timer {
/// Returns a new instance of `Timer`.
pub fn new() -> Timer {
Timer {
registers: unsafe { &mut *(GEN_TIMER_REG_BASE as *mut Registers) },
}
}
/// Reads the generic timer's counter and returns the 64-bit counter value.
/// The returned value is the number of elapsed microseconds.
pub fn read(&self) -> u64 {
let cntfrq = CNTFRQ_EL0.get();
(CNTPCT_EL0.get() * 1000000 / (cntfrq as u64)) as u64
}
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
/// interrupt will be issued in `us` microseconds.
pub fn tick_in(&mut self, us: u32) {
let cntfrq = CNTFRQ_EL0.get();
CNTP_TVAL_EL0.set(((cntfrq as f64) * (us as f64) / 1000000.0) as u32);
}
/// Initialization timer
pub fn init(&mut self) {
self.registers.CORE_TIMER_IRQCNTL[0].write(1 << (CoreInterrupt::CNTPNSIRQ as u8));
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET);
}
/// Returns `true` if timer interruption is pending. Otherwise, returns `false`.
pub fn is_pending(&self) -> bool {
self.registers.CORE_IRQ_SRC[0].read() & (1 << (CoreInterrupt::CNTPNSIRQ as u8)) != 0
}
}

@ -0,0 +1,26 @@
#[cfg(feature = "use_generic_timer")]
mod generic_timer;
#[cfg(feature = "use_generic_timer")]
pub use self::generic_timer::Timer;
#[cfg(not(feature = "use_generic_timer"))]
mod system_timer;
#[cfg(not(feature = "use_generic_timer"))]
pub use self::system_timer::Timer;
/// Initialization timer
pub fn init() {
Timer::new().init();
}
/// Returns the current time in microseconds.
pub fn current_time() -> u64 {
Timer::new().read()
}
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
/// interrupt will be issued in `us` microseconds.
pub fn tick_in(us: u32) {
Timer::new().tick_in(us);
}

@ -1,5 +1,6 @@
use super::IO_BASE;
use ::IO_BASE;
use volatile::{ReadOnly, Volatile};
use interrupt::{Controller, Interrupt};
/// The base address for the ARM system timer registers.
const TIMER_REG_BASE: usize = IO_BASE + 0x3000;
@ -15,8 +16,9 @@ struct Registers {
}
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum SystemTimer {
#[allow(dead_code)]
#[derive(Copy, Clone, PartialEq, Debug)]
enum SystemTimer {
Timer0 = 0,
Timer1 = 1,
Timer2 = 2,
@ -47,22 +49,21 @@ impl Timer {
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
/// interrupt will be issued in `us` microseconds.
pub fn tick_in(&mut self, st: SystemTimer, us: u32) {
pub fn tick_in(&mut self, us: u32) {
let current_low = self.registers.CLO.read();
let compare = current_low.wrapping_add(us);
self.registers.COMPARE[st as usize].write(compare);
self.registers.CS.write(1 << (st as usize)); // unmask
self.registers.COMPARE[SystemTimer::Timer1 as usize].write(compare);
self.registers.CS.write(1 << (SystemTimer::Timer1 as usize)); // unmask
}
}
/// Returns the current time in microseconds.
pub fn current_time() -> u64 {
Timer::new().read()
}
/// Initialization timer
pub fn init(&mut self) {
Controller::new().enable(Interrupt::Timer1);
}
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
/// interrupt will be issued in `us` microseconds.
pub fn tick_in(st: SystemTimer, us: u32) {
Timer::new().tick_in(st, us)
/// Returns `true` if timer interruption is pending. Otherwise, returns `false`.
pub fn is_pending(&self) -> bool {
let controller = Controller::new();
controller.is_pending(Interrupt::Timer1)
}
}

25
kernel/Cargo.lock generated

@ -11,6 +11,7 @@ version = "0.1.0"
name = "bcm2837"
version = "0.1.0"
dependencies = [
"cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -57,6 +58,14 @@ name = "cfg-if"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cortex-a"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fixedvec"
version = "0.2.3"
@ -150,6 +159,14 @@ name = "redox_syscall"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "register"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "remove_dir_all"
version = "0.5.1"
@ -204,6 +221,11 @@ dependencies = [
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tock-registers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "uart_16550"
version = "0.1.0"
@ -328,6 +350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1721ced9efc102309bc218c7934d642f60567858faf8d5dd90c0cc6722d97b9"
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b187d0d728b4a99ba1d79f9671b976bcdd71a8a2c719585218fd2dc14a4d08c"
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
@ -341,12 +364,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)" = "<none>"
"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c"
"checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4"
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316"
"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"

@ -44,7 +44,7 @@ riscv = { path = "../crate/riscv" }
bbl = { path = "../crate/bbl" }
[target.'cfg(target_arch = "aarch64")'.dependencies]
bcm2837 = { path = "../crate/bcm2837" }
bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] }
[package.metadata.bootimage]
default-target = "x86_64-blog_os.json"

@ -1,9 +1,10 @@
use super::bcm2837::timer::Timer;
use super::bcm2837::interrupt::{Controller, Interrupt};
pub fn handle_irq() {
let controller = Controller::new();
if controller.is_pending(Interrupt::Timer1) {
println!("Timer tick...");
let controller = Timer::new();
if controller.is_pending() {
println!("Timer tick {}...", super::timer::get_cycle());
super::timer::set_next();
// ::trap::timer();
}

@ -2,8 +2,9 @@ use super::bcm2837::timer;
use super::bcm2837::interrupt::{Controller, Interrupt};
pub fn init() {
Controller::new().enable(Interrupt::Timer1);
timer::init();
set_next();
info!("timer: init end");
}
pub fn get_cycle() -> u64 {
@ -12,5 +13,5 @@ pub fn get_cycle() -> u64 {
pub fn set_next() {
// 1000 ms
timer::tick_in(timer::SystemTimer::Timer1, 1000 * 1000);
timer::tick_in(1000 * 1000);
}

Loading…
Cancel
Save