aarch64: move crate bcm2837 to remote

master
equation314 6 years ago
parent 68b967b48e
commit f3d47f4b02

@ -15,6 +15,7 @@ dependencies = [
[[package]]
name = "bcm2837"
version = "0.1.0"
source = "git+https://github.com/equation314/bcm2837#446f0ea04deb5216ba5e08f10af36e5c1729e6fd"
dependencies = [
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -98,7 +99,7 @@ name = "rcore-bootloader"
version = "0.1.0"
dependencies = [
"aarch64 2.2.2 (git+https://github.com/equation314/aarch64)",
"bcm2837 0.1.0",
"bcm2837 0.1.0 (git+https://github.com/equation314/bcm2837)",
"cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
"fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -205,6 +206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aarch64 2.2.2 (git+https://github.com/equation314/aarch64)" = "<none>"
"checksum bcm2837 0.1.0 (git+https://github.com/equation314/bcm2837)" = "<none>"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92"

@ -10,7 +10,7 @@ fixedvec = "0.2.3"
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64 = { git = "https://github.com/equation314/aarch64" }
bcm2837 = { path = "../crate/bcm2837" }
bcm2837 = { git = "https://github.com/equation314/bcm2837" }
[build-dependencies]
cc = "1.0"

@ -1,13 +0,0 @@
[package]
name = "bcm2837"
version = "0.1.0"
authors = ["equation314 <equation618@gmail.com>"]
edition = "2018"
[features]
zero_kernel_offset = []
use_generic_timer = ["aarch64"]
[dependencies]
volatile = "0.2.4"
aarch64= { git = "https://github.com/equation314/aarch64", optional = true }

@ -1,65 +0,0 @@
use super::raw;
use core::slice;
use core::str;
/// An ATAG.
#[derive(Debug, Copy, Clone)]
pub enum Atag {
Core(raw::Core),
Mem(raw::Mem),
Cmd(&'static str),
Unknown(u32),
None,
}
impl Atag {
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
pub fn core(self) -> Option<raw::Core> {
match self {
Atag::Core(x) => Some(x),
_ => None,
}
}
/// Returns `Some` if this is a `Mem` ATAG. Otherwise returns `None`.
pub fn mem(self) -> Option<raw::Mem> {
match self {
Atag::Mem(x) => Some(x),
_ => None,
}
}
/// Returns `Some` with the command line string if this is a `Cmd` ATAG.
/// Otherwise returns `None`.
pub fn cmd(self) -> Option<&'static str> {
match self {
Atag::Cmd(x) => Some(x),
_ => None,
}
}
}
// Convert between raw::* types and Atag wrapper.
impl<'a> From<&'a raw::Atag> for Atag {
fn from(atag: &raw::Atag) -> Atag {
unsafe {
match (atag.tag, &atag.kind) {
(raw::Atag::CORE, &raw::Kind { core }) => Atag::Core(core),
(raw::Atag::MEM, &raw::Kind { mem }) => Atag::Mem(mem),
(raw::Atag::CMDLINE, &raw::Kind { ref cmd }) => {
let cmd_ptr: *const u8 = &cmd.cmd as *const u8;
let mut len: usize = 0;
while *cmd_ptr.add(len) != 0 {
len += 1;
}
let cmd_slice = slice::from_raw_parts(cmd_ptr, len);
Atag::Cmd(str::from_utf8_unchecked(cmd_slice))
}
(raw::Atag::NONE, _) => Atag::None,
(id, _) => Atag::Unknown(id),
}
}
}
}

@ -1,41 +0,0 @@
mod atag;
mod raw;
use super::consts::KERNEL_OFFSET;
pub use self::atag::*;
pub use self::raw::{Cmd, Core, Mem};
/// The address at which the firmware loads the ATAGS.
const ATAG_BASE: usize = KERNEL_OFFSET + 0x100;
/// An iterator over the ATAGS on this system.
pub struct Atags {
ptr: &'static raw::Atag,
}
impl Atags {
/// Returns an instance of `Atags`, an iterator over ATAGS on this system.
pub fn get() -> Atags {
Atags {
ptr: unsafe { &*(ATAG_BASE as *const raw::Atag) },
}
}
}
impl Iterator for Atags {
type Item = Atag;
/// Iterate over Atags. Returns a valid Atag until the iterator hits the
/// Atag::None.
fn next(&mut self) -> Option<Atag> {
let cur = self.ptr;
match cur.next() {
Some(next) => {
let result = Some(Atag::from(cur));
self.ptr = next;
result
}
None => None,
}
}
}

@ -1,65 +0,0 @@
/// A raw `ATAG` as laid out in memory.
#[repr(C)]
pub struct Atag {
pub dwords: u32,
pub tag: u32,
pub kind: Kind,
}
impl Atag {
pub const NONE: u32 = 0x00000000;
pub const CORE: u32 = 0x54410001;
pub const MEM: u32 = 0x54410002;
pub const VIDEOTEXT: u32 = 0x54410003;
pub const RAMDISK: u32 = 0x54410004;
pub const INITRD2: u32 = 0x54420005;
pub const SERIAL: u32 = 0x54410006;
pub const REVISION: u32 = 0x54410007;
pub const VIDEOLFB: u32 = 0x54410008;
pub const CMDLINE: u32 = 0x54410009;
/// Returns the ATAG following `self`, if there is one.
pub fn next(&self) -> Option<&Atag> {
if self.tag == Atag::NONE {
None
} else {
let current = self as *const Atag as *const u32;
let next: &Atag = unsafe { &*(current.add(self.dwords as usize) as *const Atag) };
Some(next)
}
}
}
/// The possible variant of an ATAG.
#[repr(C)]
pub union Kind {
pub core: Core,
pub mem: Mem,
pub cmd: Cmd,
}
/// A `CORE` ATAG.
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Core {
pub flags: u32,
pub page_size: u32,
pub root_dev: u32,
}
/// A `MEM` ATAG.
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Mem {
pub size: u32,
pub start: u32,
}
/// A `CMDLINE` ATAG.
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Cmd {
/// The first byte of the command line string.
pub cmd: u8,
}

@ -1,7 +0,0 @@
#[cfg(feature = "zero_kernel_offset")]
pub const KERNEL_OFFSET: usize = 0;
#[cfg(not(feature = "zero_kernel_offset"))]
pub const KERNEL_OFFSET: usize = 0xFFFF_0000_0000_0000;
pub const RAW_IO_BASE: usize = 0x3F00_0000;
pub const IO_BASE: usize = KERNEL_OFFSET + RAW_IO_BASE;

@ -1,163 +0,0 @@
use crate::consts::IO_BASE;
use crate::timer::delay;
use core::marker::PhantomData;
use volatile::{ReadOnly, Volatile, WriteOnly};
/// The base address of the `GPIO` registers.
const GPIO_BASE: usize = IO_BASE + 0x200000;
/// An alternative GPIO function. (ref: peripherals 6.1, page 92)
#[repr(u8)]
pub enum Function {
Input = 0b000,
Output = 0b001,
Alt0 = 0b100,
Alt1 = 0b101,
Alt2 = 0b110,
Alt3 = 0b111,
Alt4 = 0b011,
Alt5 = 0b010,
}
/// GPIO registers starting from `GPIO_BASE` (ref: peripherals 6.1, page 90)
#[repr(C)]
#[allow(non_snake_case)]
struct Registers {
FSEL: [Volatile<u32>; 6],
__reserved0: u32,
SET: [WriteOnly<u32>; 2],
__reserved1: u32,
CLR: [WriteOnly<u32>; 2],
__reserved2: u32,
LEV: [ReadOnly<u32>; 2],
__reserved3: u32,
EDS: [Volatile<u32>; 2],
__reserved4: u32,
REN: [Volatile<u32>; 2],
__reserved5: u32,
FEN: [Volatile<u32>; 2],
__reserved6: u32,
HEN: [Volatile<u32>; 2],
__reserved7: u32,
LEN: [Volatile<u32>; 2],
__reserved8: u32,
AREN: [Volatile<u32>; 2],
__reserved9: u32,
AFEN: [Volatile<u32>; 2],
__reserved10: u32,
PUD: Volatile<u32>,
PUDCLK: [Volatile<u32>; 2],
}
/// Possible states for a GPIO pin.
pub enum Uninitialized {}
pub enum Input {}
pub enum Output {}
pub enum Alt {}
/// A GPIO pin in state `State`.
///
/// The `State` generic always corresponds to an uninstantiatable type that is
/// use solely to mark and track the state of a given GPIO pin. A `Gpio`
/// structure starts in the `Uninitialized` state and must be transitions into
/// one of `Input`, `Output`, or `Alt` via the `into_input`, `into_output`, and
/// `into_alt` methods before it can be used.
pub struct Gpio<State> {
pin: u8,
registers: &'static mut Registers,
_state: PhantomData<State>,
}
impl<T> Gpio<T> {
/// Transitions `self` to state `S`, consuming `self` and returning a new
/// `Gpio` instance in state `S`. This method should _never_ be exposed to
/// the public!
#[inline(always)]
fn transition<S>(self) -> Gpio<S> {
Gpio {
pin: self.pin,
registers: self.registers,
_state: PhantomData,
}
}
/// Set the Gpio pull-up/pull-down state for values in `pin_value`
/// (ref: peripherals 6.1, page 101)
pub fn set_gpio_pd(&mut self, pud_value: u8) {
let index = if self.pin >= 32 { 1 } else { 0 };
self.registers.PUD.write(pud_value as u32);
delay(150);
self.registers.PUDCLK[index as usize].write((1 << self.pin) as u32);
delay(150);
self.registers.PUD.write(0);
self.registers.PUDCLK[index as usize].write(0);
}
}
impl Gpio<Uninitialized> {
/// Returns a new `GPIO` structure for pin number `pin`.
///
/// # Panics
///
/// Panics if `pin` > `53`.
pub fn new(pin: u8) -> Gpio<Uninitialized> {
if pin > 53 {
panic!("Gpio::new(): pin {} exceeds maximum of 53", pin);
}
Gpio {
registers: unsafe { &mut *(GPIO_BASE as *mut Registers) },
pin: pin,
_state: PhantomData,
}
}
/// Enables the alternative function `function` for `self`. Consumes self
/// and returns a `Gpio` structure in the `Alt` state.
pub fn into_alt(self, function: Function) -> Gpio<Alt> {
let select = (self.pin / 10) as usize;
let offset = 3 * (self.pin % 10) as usize;
self.registers.FSEL[select].update(|value| {
*value &= !(0b111 << offset);
*value |= (function as u32) << offset;
});
self.transition()
}
/// Sets this pin to be an _output_ pin. Consumes self and returns a `Gpio`
/// structure in the `Output` state.
pub fn into_output(self) -> Gpio<Output> {
self.into_alt(Function::Output).transition()
}
/// Sets this pin to be an _input_ pin. Consumes self and returns a `Gpio`
/// structure in the `Input` state.
pub fn into_input(self) -> Gpio<Input> {
self.into_alt(Function::Input).transition()
}
}
impl Gpio<Output> {
/// Sets (turns on) the pin.
pub fn set(&mut self) {
let index = if self.pin >= 32 { 1 } else { 0 };
self.registers.SET[index as usize].write(1 << (self.pin - index * 32));
}
/// Clears (turns off) the pin.
pub fn clear(&mut self) {
let index = if self.pin >= 32 { 1 } else { 0 };
self.registers.CLR[index as usize].write(1 << (self.pin - index * 32));
}
}
impl Gpio<Input> {
/// Reads the pin's value. Returns `true` if the level is high and `false`
/// if the level is low.
pub fn level(&mut self) -> bool {
let index = if self.pin >= 32 { 1 } else { 0 };
let high = 1 << (self.pin - index * 32);
(self.registers.LEV[index as usize].read() & high) == high
}
}

@ -1,88 +0,0 @@
use crate::consts::IO_BASE;
use volatile::{ReadOnly, Volatile};
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
/// Allowed interrupts (ref: peripherals 7.5, page 113)
#[repr(u8)]
#[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>,
}
/// Pending interrupts
pub struct PendingInterrupts(u64);
impl Iterator for PendingInterrupts {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let int = self.0.trailing_zeros();
if int < 64 {
self.0 &= !(1 << int);
Some(int as usize)
} else {
None
}
}
}
/// 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.
#[inline]
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
}
/// Return all pending interrupts.
pub fn pending_interrupts(&self) -> PendingInterrupts {
let irq1 = self.registers.IRQPending[0].read() as u64;
let irq2 = self.registers.IRQPending[1].read() as u64;
PendingInterrupts((irq2 << 32) | irq1)
}
}

@ -1,12 +0,0 @@
#![no_std]
#![feature(asm)]
extern crate volatile;
pub mod atags;
pub mod consts;
pub mod gpio;
pub mod interrupt;
pub mod mailbox;
pub mod mini_uart;
pub mod timer;

@ -1,80 +0,0 @@
use crate::consts::IO_BASE;
use volatile::{ReadOnly, Volatile, WriteOnly};
/// The base address for the `MU` registers.
const MAILBOX_BASE: usize = IO_BASE + 0xB000 + 0x880;
/// Available mailbox channels
///
/// (ref: https://github.com/raspberrypi/firmware/wiki/Mailboxes)
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum MailboxChannel {
Framebuffer = 1,
Property = 8,
}
/// Read from mailbox status register (MAILx_STA).
#[repr(u32)]
enum MailboxStatus {
MailboxEmpty = 1 << 30,
MailboxFull = 1 << 31,
}
/// Mailbox registers. We basically only support mailbox 0 & 1. We
/// deliver to the VC in mailbox 1, it delivers to us in mailbox 0. See
/// BCM2835-ARM-Peripherals.pdf section 1.3 for an explanation about
/// the placement of memory barriers.
///
/// (ref: https://github.com/raspberrypi/firmware/wiki/Mailboxes)
#[repr(C)]
#[allow(non_snake_case)]
struct Registers {
MAIL0_RD: ReadOnly<u32>, // 0x00
__reserved0: [u32; 3],
MAIL0_POL: ReadOnly<u32>, // 0x10
MAIL0_SND: ReadOnly<u32>, // 0x14
MAIL0_STA: ReadOnly<u32>, // 0x18
MAIL0_CNF: Volatile<u32>, // 0x1c
MAIL1_WRT: WriteOnly<u32>, // 0x20
__reserved1: [u32; 3],
_MAIL1_POL: ReadOnly<u32>, // 0x30
_MAIL1_SND: ReadOnly<u32>, // 0x34
MAIL1_STA: ReadOnly<u32>, // 0x38
_MAIL1_CNF: Volatile<u32>, // 0x3c
}
/// The Raspberry Pi's mailbox.
///
/// (ref: https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes)
pub struct Mailbox {
registers: &'static mut Registers,
}
impl Mailbox {
/// Returns a new instance of `Mailbox`.
#[inline]
pub fn new() -> Mailbox {
Mailbox {
registers: unsafe { &mut *(MAILBOX_BASE as *mut Registers) },
}
}
/// Read from the requested channel of mailbox 0.
pub fn read(&self, channel: MailboxChannel) -> u32 {
loop {
while self.registers.MAIL0_STA.read() & (MailboxStatus::MailboxEmpty as u32) != 0 {}
let data = self.registers.MAIL0_RD.read();
if data & 0xF == channel as u32 {
return data & !0xF;
}
}
}
/// Write to the requested channel of mailbox 1.
pub fn write(&mut self, channel: MailboxChannel, data: u32) {
while self.registers.MAIL1_STA.read() & (MailboxStatus::MailboxFull as u32) != 0 {}
self.registers.MAIL1_WRT.write((data & !0xF) | (channel as u32));
}
}

@ -1,133 +0,0 @@
use crate::consts::IO_BASE;
use crate::gpio::{Function, Gpio};
use volatile::{ReadOnly, Volatile};
/// The `AUXENB` register from page 9 of the BCM2837 documentation.
const AUX_ENABLES: *mut Volatile<u8> = (IO_BASE + 0x215004) as *mut Volatile<u8>;
/// The base address for the `MU` registers.
const MU_REG_BASE: usize = IO_BASE + 0x215040;
/// Enum representing bit fields of the `AUX_MU_IIR_REG` register.
#[repr(u8)]
pub enum MiniUartInterruptId {
Transmit = 0b010,
Recive = 0b100,
}
/// Enum representing bit fields of the `AUX_MU_LSR_REG` register.
#[repr(u8)]
enum LsrStatus {
DataReady = 1,
TxAvailable = 1 << 5,
}
/// MU registers starting from `MU_REG_BASE` (ref: peripherals 2.1, page 8)
#[repr(C)]
#[allow(non_snake_case)]
struct Registers {
AUX_MU_IO_REG: Volatile<u8>,
__r0: [u8; 3],
AUX_MU_IER_REG: Volatile<u8>,
__r1: [u8; 3],
AUX_MU_IIR_REG: Volatile<u8>,
__r2: [u8; 3],
AUX_MU_LCR_REG: Volatile<u8>,
__r3: [u8; 3],
AUX_MU_MCR_REG: Volatile<u8>,
__r4: [u8; 3],
AUX_MU_LSR_REG: ReadOnly<u8>,
__r5: [u8; 3],
AUX_MU_MSR_REG: ReadOnly<u8>,
__r6: [u8; 3],
AUX_MU_SCRATCH: Volatile<u8>,
__r7: [u8; 3],
AUX_MU_CNTL_REG: Volatile<u8>,
__r8: [u8; 3],
AUX_MU_STAT_REG: ReadOnly<u32>,
AUX_MU_BAUD_REG: Volatile<u16>,
}
/// The Raspberry Pi's "mini UART".
pub struct MiniUart {
registers: &'static mut Registers,
timeout: Option<u32>,
}
impl MiniUart {
/// Returns a new instance of `MiniUart`.
#[inline]
pub fn new() -> MiniUart {
let registers = unsafe { &mut *(MU_REG_BASE as *mut Registers) };
MiniUart {
registers: registers,
timeout: None,
}
}
/// Initializes the mini UART by enabling it as an auxiliary peripheral,
/// setting the data size to 8 bits, setting the BAUD rate to ~115200 (baud
/// divider of 270), setting GPIO pins 14 and 15 to alternative function 5
/// (TXD1/RDXD1), and finally enabling the UART transmitter and receiver.
///
/// By default, reads will never time out. To set a read timeout, use
/// `set_read_timeout()`.
pub fn init(&mut self) {
// Enable the mini UART as an auxiliary device.
unsafe { (*AUX_ENABLES).write(1) }
Gpio::new(14).into_alt(Function::Alt5).set_gpio_pd(0);
Gpio::new(15).into_alt(Function::Alt5).set_gpio_pd(0);
self.registers.AUX_MU_CNTL_REG.write(0); // Disable auto flow control and disable receiver and transmitter (for now)
self.registers.AUX_MU_IER_REG.write(1); // Enable receive interrupts and disable transmit interrupts
self.registers.AUX_MU_LCR_REG.write(3); // Enable 8 bit mode
self.registers.AUX_MU_MCR_REG.write(0); // Set RTS line to be always high
self.registers.AUX_MU_BAUD_REG.write(270); // Set baud rate to 115200
self.registers.AUX_MU_CNTL_REG.write(3); // Finally, enable transmitter and receiver
}
/// Set the read timeout to `milliseconds` milliseconds.
pub fn set_read_timeout(&mut self, milliseconds: u32) {
self.timeout = Some(milliseconds)
}
/// Write the byte `byte`. This method blocks until there is space available
/// in the output FIFO.
pub fn write_byte(&mut self, byte: u8) {
while self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::TxAvailable as u8) == 0 {}
self.registers.AUX_MU_IO_REG.write(byte);
}
/// Returns `true` if there is at least one byte ready to be read. If this
/// method returns `true`, a subsequent call to `read_byte` is guaranteed to
/// return immediately. This method does not block.
pub fn has_byte(&self) -> bool {
self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::DataReady as u8) != 0
}
/// Blocks until there is a byte ready to read. If a read timeout is set,
/// this method blocks for at most that amount of time. Otherwise, this
/// method blocks indefinitely until there is a byte to read.
///
/// Returns `Ok(())` if a byte is ready to read. Returns `Err(())` if the
/// timeout expired while waiting for a byte to be ready. If this method
/// returns `Ok(())`, a subsequent call to `read_byte` is guaranteed to
/// return immediately.
pub fn wait_for_byte(&self) -> Result<(), ()> {
unimplemented!()
}
/// Reads a byte. Blocks indefinitely until a byte is ready to be read.
pub fn read_byte(&self) -> u8 {
while !self.has_byte() {}
self.registers.AUX_MU_IO_REG.read()
}
// Read `AUX_MU_IIR_REG` and determine if the interrupt `id` is pending.
pub fn interrupt_is_pending(&self, id: MiniUartInterruptId) -> bool {
self.registers.AUX_MU_IIR_REG.read() & 0b110 == id as u8
}
}

@ -1,77 +0,0 @@
extern crate aarch64;
use super::BasicTimer;
use crate::consts::KERNEL_OFFSET;
use aarch64::regs::*;
use volatile::*;
/// The base address for the ARM generic timer, IRQs, mailboxes
const GEN_TIMER_REG_BASE: usize = KERNEL_OFFSET + 0x4000_0000;
/// 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 GenericTimer {
registers: &'static mut Registers,
}
impl BasicTimer for GenericTimer {
fn new() -> Self {
GenericTimer {
registers: unsafe { &mut *(GEN_TIMER_REG_BASE as *mut Registers) },
}
}
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);
}
fn read(&self) -> u64 {
let cntfrq = CNTFRQ_EL0.get(); // 62500000
(CNTPCT_EL0.get() * 1000000 / (cntfrq as u64)) as u64
}
fn tick_in(&mut self, us: u32) {
let cntfrq = CNTFRQ_EL0.get(); // 62500000
CNTP_TVAL_EL0.set(((cntfrq as f64) * (us as f64) / 1000000.0) as u32);
}
fn is_pending(&self) -> bool {
self.registers.CORE_IRQ_SRC[0].read() & (1 << (CoreInterrupt::CNTPNSIRQ as u8)) != 0
}
}

@ -1,38 +0,0 @@
#[cfg(feature = "use_generic_timer")]
mod generic_timer;
#[cfg(feature = "use_generic_timer")]
pub use self::generic_timer::GenericTimer as Timer;
#[cfg(not(feature = "use_generic_timer"))]
mod system_timer;
#[cfg(not(feature = "use_generic_timer"))]
pub use self::system_timer::SystemTimer as Timer;
/// The Raspberry Pi timer.
pub trait BasicTimer {
/// Returns a new instance.
fn new() -> Self;
/// Initialization timer.
fn init(&mut self);
/// Reads the timer's counter and returns the 64-bit counter value.
/// The returned value is the number of elapsed microseconds.
fn read(&self) -> 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.
fn tick_in(&mut self, us: u32);
/// Returns `true` if timer interruption is pending. Otherwise, returns `false`.
fn is_pending(&self) -> bool;
}
/// wait for `cycle` CPU cycles
#[inline(always)]
pub fn delay(cycle: u32) {
for _ in 0..cycle {
unsafe { asm!("nop") }
}
}

@ -1,62 +0,0 @@
use super::BasicTimer;
use crate::consts::IO_BASE;
use crate::interrupt::{Controller, Interrupt};
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)]
#[allow(dead_code)]
#[derive(Copy, Clone, PartialEq, Debug)]
enum SystemTimerId {
Timer0 = 0,
Timer1 = 1,
Timer2 = 2,
Timer3 = 3,
}
/// The Raspberry Pi ARM system timer.
pub struct SystemTimer {
registers: &'static mut Registers,
}
impl BasicTimer for SystemTimer {
fn new() -> Self {
SystemTimer {
registers: unsafe { &mut *(TIMER_REG_BASE as *mut Registers) },
}
}
fn init(&mut self) {
Controller::new().enable(Interrupt::Timer1);
}
fn read(&self) -> u64 {
let low = self.registers.CLO.read();
let high = self.registers.CHI.read();
((high as u64) << 32) | (low as u64)
}
fn tick_in(&mut self, us: u32) {
let current_low = self.registers.CLO.read();
let compare = current_low.wrapping_add(us);
self.registers.COMPARE[SystemTimerId::Timer1 as usize].write(compare);
self.registers.CS.write(1 << (SystemTimerId::Timer1 as usize)); // unmask
}
fn is_pending(&self) -> bool {
let controller = Controller::new();
controller.is_pending(Interrupt::Timer1)
}
}

4
kernel/Cargo.lock generated

@ -45,6 +45,7 @@ version = "0.1.0"
[[package]]
name = "bcm2837"
version = "0.1.0"
source = "git+https://github.com/equation314/bcm2837#446f0ea04deb5216ba5e08f10af36e5c1729e6fd"
dependencies = [
"aarch64 2.2.2 (git+https://github.com/equation314/aarch64)",
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -248,7 +249,7 @@ dependencies = [
"aarch64 2.2.2 (git+https://github.com/equation314/aarch64)",
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
"bbl 0.1.0",
"bcm2837 0.1.0",
"bcm2837 0.1.0 (git+https://github.com/equation314/bcm2837)",
"bit-allocator 0.1.0",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -525,6 +526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)" = "<none>"
"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72"
"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a"
"checksum bcm2837 0.1.0 (git+https://github.com/equation314/bcm2837)" = "<none>"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfadef5c4e2c2e64067b9ecc061179f12ac7ec65ba613b1f60f3972bbada1f5b"

@ -72,7 +72,7 @@ bbl = { path = "../crate/bbl" }
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64 = { git = "https://github.com/equation314/aarch64" }
bcm2837 = { path = "../crate/bcm2837", optional = true }
bcm2837 = { git = "https://github.com/equation314/bcm2837", optional = true }
[package.metadata.bootimage]
default-target = "targets/x86_64.json"

Loading…
Cancel
Save