diff --git a/crate/bcm2837/Cargo.toml b/crate/bcm2837/Cargo.toml index 969c995..3fb3e2e 100644 --- a/crate/bcm2837/Cargo.toml +++ b/crate/bcm2837/Cargo.toml @@ -3,5 +3,9 @@ name = "bcm2837" version = "0.1.0" authors = ["equation314 "] +[features] +use_generic_timer = [] + [dependencies] volatile = "0.2.4" +cortex-a = "2.2.2" diff --git a/crate/bcm2837/src/timer/generic_timer.rs b/crate/bcm2837/src/timer/generic_timer.rs new file mode 100644 index 0000000..6c3c0c8 --- /dev/null +++ b/crate/bcm2837/src/timer/generic_timer.rs @@ -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, + _unused1: [Volatile; 8], + LOCAL_IRQ: Volatile, + _unused2: [Volatile; 3], + LOCAL_TIMER_CTL: Volatile, + LOCAL_TIMER_FLAGS: Volatile, + _unused3: Volatile, + CORE_TIMER_IRQCNTL: [Volatile; 4], + CORE_MAILBOX_IRQCNTL: [Volatile; 4], + CORE_IRQ_SRC: [Volatile; 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 + } +} diff --git a/crate/bcm2837/src/timer/mod.rs b/crate/bcm2837/src/timer/mod.rs new file mode 100644 index 0000000..da501cb --- /dev/null +++ b/crate/bcm2837/src/timer/mod.rs @@ -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); +} diff --git a/crate/bcm2837/src/timer.rs b/crate/bcm2837/src/timer/system_timer.rs similarity index 67% rename from crate/bcm2837/src/timer.rs rename to crate/bcm2837/src/timer/system_timer.rs index 3e485b8..cad2af4 100644 --- a/crate/bcm2837/src/timer.rs +++ b/crate/bcm2837/src/timer/system_timer.rs @@ -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) + } } diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 3886b0c..3d0ffa6 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -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)" = "" "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" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index fe19377..476d0c5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -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" diff --git a/kernel/src/arch/aarch64/board/raspi3/irq.rs b/kernel/src/arch/aarch64/board/raspi3/irq.rs index 5f1fb0d..3c3e0b5 100644 --- a/kernel/src/arch/aarch64/board/raspi3/irq.rs +++ b/kernel/src/arch/aarch64/board/raspi3/irq.rs @@ -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(); } diff --git a/kernel/src/arch/aarch64/board/raspi3/timer.rs b/kernel/src/arch/aarch64/board/raspi3/timer.rs index b1a0886..2e54fb3 100644 --- a/kernel/src/arch/aarch64/board/raspi3/timer.rs +++ b/kernel/src/arch/aarch64/board/raspi3/timer.rs @@ -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); }