aarch64: implement IRQ & system timer, but don't work in qemu

master
equation314 6 years ago
parent 430bf508e2
commit 07aa9a0686

@ -0,0 +1,61 @@
use super::IO_BASE;
use volatile::{ReadOnly, Volatile};
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
/// Allowed interrupts (ref: peripherals 7.5, page 113)
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Interrupt {
Timer1 = 1,
Timer3 = 3,
Usb = 9,
Aux = 29,
Gpio0 = 49,
Gpio1 = 50,
Gpio2 = 51,
Gpio3 = 52,
Uart = 57,
}
/// Interrupts registers starting from `INT_BASE` (ref: peripherals 7.5, page 112)
#[repr(C)]
#[allow(non_snake_case)]
struct Registers {
IRQBasicPending: ReadOnly<u32>,
IRQPending: [ReadOnly<u32>; 2],
FIQControl: Volatile<u32>,
EnableIRQ: [Volatile<u32>; 2],
EnableBasicIRQ: Volatile<u32>,
DisableIRQ: [Volatile<u32>; 2],
DisableBasicIRQ: Volatile<u32>,
}
/// An interrupt controller. Used to enable and disable interrupts as well as to
/// check if an interrupt is pending.
pub struct Controller {
registers: &'static mut Registers,
}
impl Controller {
/// Returns a new handle to the interrupt controller.
pub fn new() -> Controller {
Controller {
registers: unsafe { &mut *(INT_BASE as *mut Registers) },
}
}
/// Enables the interrupt `int`.
pub fn enable(&mut self, int: Interrupt) {
self.registers.EnableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
}
/// Disables the interrupt `int`.
pub fn disable(&mut self, int: Interrupt) {
self.registers.DisableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
}
/// Returns `true` if `int` is pending. Otherwise, returns `false`.
pub fn is_pending(&self, int: Interrupt) -> bool {
self.registers.IRQPending[int as usize / 32].read() & (1 << (int as usize) % 32) != 0
}
}

@ -6,6 +6,8 @@ extern crate volatile;
mod asm; mod asm;
pub mod gpio; pub mod gpio;
pub mod timer;
pub mod mini_uart; pub mod mini_uart;
pub mod interrupt;
pub const IO_BASE: usize = 0x3F000000; pub const IO_BASE: usize = 0x3F000000;

@ -0,0 +1,68 @@
use super::IO_BASE;
use volatile::{ReadOnly, Volatile};
/// The base address for the ARM system timer registers.
const TIMER_REG_BASE: usize = IO_BASE + 0x3000;
/// System timer registers (ref: peripherals 12.1, page 172)
#[repr(C)]
#[allow(non_snake_case)]
struct Registers {
CS: Volatile<u32>,
CLO: ReadOnly<u32>,
CHI: ReadOnly<u32>,
COMPARE: [Volatile<u32>; 4],
}
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum SystemTimer {
Timer0 = 0,
Timer1 = 1,
Timer2 = 2,
Timer3 = 3,
}
/// The Raspberry Pi ARM system timer.
pub struct Timer {
registers: &'static mut Registers,
}
impl Timer {
/// Returns a new instance of `Timer`.
pub fn new() -> Timer {
Timer {
registers: unsafe { &mut *(TIMER_REG_BASE as *mut Registers) },
}
}
/// Reads the system 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 low = self.registers.CLO.read();
let high = self.registers.CHI.read();
((high as u64) << 32) | (low 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, st: SystemTimer, 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
}
}
/// 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(st: SystemTimer, us: u32) {
Timer::new().tick_in(st, us)
}

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

@ -2,6 +2,8 @@
extern crate bcm2837; extern crate bcm2837;
pub mod irq;
pub mod timer;
pub mod serial; pub mod serial;
pub fn init() { pub fn init() {

@ -0,0 +1,16 @@
use super::bcm2837::timer;
use super::bcm2837::interrupt::{Controller, Interrupt};
pub fn init() {
Controller::new().enable(Interrupt::Timer1);
set_next();
}
pub fn get_cycle() -> u64 {
timer::current_time()
}
pub fn set_next() {
// 1000 ms
timer::tick_in(timer::SystemTimer::Timer1, 1000 * 1000);
}

@ -1,5 +1,6 @@
//! Trap handler //! Trap handler
use arch::board::irq::handle_irq;
use super::context::TrapFrame; use super::context::TrapFrame;
use super::syndrome::Syndrome; use super::syndrome::Syndrome;
@ -48,9 +49,7 @@ pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) {
_ => ::trap::error(tf), _ => ::trap::error(tf),
} }
} }
Kind::Irq => { Kind::Irq => handle_irq(),
// TODO
}
_ => ::trap::error(tf), _ => ::trap::error(tf),
} }
::trap::before_return(); ::trap::before_return();

@ -20,13 +20,13 @@ pub fn init() {
/// Enable the interrupt. /// Enable the interrupt.
#[inline(always)] #[inline(always)]
pub unsafe fn enable() { pub unsafe fn enable() {
// TODO asm!("msr daifclr, #2");
} }
/// Disable the interrupt. /// Disable the interrupt.
#[inline(always)] #[inline(always)]
pub unsafe fn disable() { pub unsafe fn disable() {
// TODO asm!("msr daifset, #2");
} }
/// Disable the interrupt and store the status. /// Disable the interrupt and store the status.

@ -9,6 +9,8 @@ pub mod interrupt;
#[path = "board/raspi3/mod.rs"] #[path = "board/raspi3/mod.rs"]
pub mod board; pub mod board;
pub use self::board::timer;
/// TODO /// TODO
/// The entry point of kernel /// The entry point of kernel
#[no_mangle] // don't mangle the name of this function #[no_mangle] // don't mangle the name of this function
@ -20,6 +22,9 @@ pub extern "C" fn rust_main() -> ! {
// FIXME // FIXME
// ::logging::init(); // ::logging::init();
interrupt::init(); interrupt::init();
timer::init();
unsafe { interrupt::enable(); }
super::fs::show_logo(); super::fs::show_logo();
@ -39,6 +44,9 @@ pub extern "C" fn rust_main() -> ! {
println!("svc 666"); println!("svc 666");
asm!("svc 666"); asm!("svc 666");
}, },
't' => unsafe {
println!("{}", timer::get_cycle());
},
' '...'\u{7e}' => { ' '...'\u{7e}' => {
print!("{}", c); print!("{}", c);
} }

Loading…
Cancel
Save