Skip to content

Commit

Permalink
mod-inlining
Browse files Browse the repository at this point in the history
  • Loading branch information
pnkfelix committed Nov 15, 2019
1 parent e0a22e4 commit 76a8d5f
Showing 1 changed file with 362 additions and 4 deletions.
366 changes: 362 additions & 4 deletions tock/chips/arty_e21/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,366 @@
#![crate_name = "arty_e21"]
#![crate_type = "rlib"]

mod interrupts;
mod interrupts {
//! Named interrupts for the E21 Arty core.

pub mod chip;
mod gpio;
mod uart;
#![allow(dead_code)]

pub const MTIP: u32 = 7; // Machine Timer

pub const GPIO0: u32 = 18;
pub const GPIO1: u32 = 19;
pub const GPIO2: u32 = 20;
pub const GPIO3: u32 = 21;
pub const GPIO4: u32 = 22;
pub const GPIO5: u32 = 23;
pub const GPIO6: u32 = 24;
pub const GPIO7: u32 = 25;
pub const GPIO8: u32 = 26;
pub const GPIO9: u32 = 27;
pub const GPIO10: u32 = 28;
pub const GPIO11: u32 = 29;
pub const GPIO12: u32 = 30;
pub const GPIO13: u32 = 31;
pub const GPIO14: u32 = 32;
pub const GPIO15: u32 = 33;
pub const UART0: u32 = 16;
}

pub mod chip {
use kernel;
use kernel::debug;
use rv32i;
use rv32i::machine_timer;

use crate::gpio;
use crate::interrupts;
use crate::uart;

extern "C" {
fn _start_trap();
}

pub struct ArtyExx {
userspace_kernel_boundary: rv32i::syscall::SysCall,
clic: rv32i::clic::Clic,
}

impl ArtyExx {
pub unsafe fn new() -> ArtyExx {
// Make a bit-vector of all interrupt locations that we actually intend
// to use on this chip.
// 0001 1111 1111 1111 1111 0000 0000 1000 0000
let in_use_interrupts: u64 = 0x1FFFF0080;

ArtyExx {
userspace_kernel_boundary: rv32i::syscall::SysCall::new(),
clic: rv32i::clic::Clic::new(in_use_interrupts),
}
}

pub fn enable_all_interrupts(&self) {
self.clic.enable_all();
}

/// Configure the PMP to allow all accesses in both machine mode (the
/// default) and in user mode.
///
/// This needs to be replaced with a real PMP driver. See
/// https://github.com/tock/tock/issues/1135
pub unsafe fn disable_pmp(&self) {
asm!("
// PMP PMP PMP
// PMP PMP PMP
// PMP PMP PMP
// PMP PMP PMP
// TODO: Add a real PMP driver!!
// Take some time to disable the PMP.
// Set the first region address to 0xFFFFFFFF. When using top-of-range mode
// this will include the entire address space.
lui t0, %hi(0xFFFFFFFF)
addi t0, t0, %lo(0xFFFFFFFF)
csrw 0x3b0, t0 // CSR=pmpaddr0
// Set the first region to use top-of-range and allow everything.
// This is equivalent to:
// R=1, W=1, X=1, A=01, L=0
li t0, 0x0F
csrw 0x3a0, t0 // CSR=pmpcfg0
"
:
:
:
: "volatile");
}

/// By default the machine timer is enabled and will trigger interrupts. To
/// prevent that we can make the compare register very large to effectively
/// stop the interrupt from triggering, and then the machine timer can be
/// used later as needed.
pub unsafe fn disable_machine_timer(&self) {
asm!("
// Initialize machine timer mtimecmp to disable the machine timer
// interrupt.
li t0, -1 // Set mtimecmp to 0xFFFFFFFF
lui t1, %hi(0x02004000) // Load the address of mtimecmp to t1
addi t1, t1, %lo(0x02004000) // Load the address of mtimecmp to t1
sw t0, 0(t1) // mtimecmp is 64 bits, set to all ones
sw t0, 4(t1) // mtimecmp is 64 bits, set to all ones
"
:
:
:
: "volatile");
}

/// Setup the function that should run when a trap happens.
///
/// This needs to be chip specific because how the CLIC works is configured
/// when the trap handler address is specified in mtvec, and that is only
/// valid for platforms with a CLIC.
pub unsafe fn configure_trap_handler(&self) {
asm!("
// The csrw instruction writes a Control and Status Register (CSR)
// with a new value.
//
// CSR 0x305 (mtvec, 'Machine trap-handler base address.') sets the
// address of the trap handler. We do not care about its old value,
// so we don't bother reading it. We want to enable direct CLIC mode
// so we set the second lowest bit.
lui t0, %hi(_start_trap)
addi t0, t0, %lo(_start_trap)
ori t0, t0, 0x02 // Set CLIC direct mode
csrw 0x305, t0 // Write the mtvec CSR.
"
:
:
:
: "volatile");
}

/// Generic helper initialize function to setup all of the chip specific
/// operations. Different boards can call the functions that `initialize()`
/// calls directly if it needs to use a custom setup operation.
pub unsafe fn initialize(&self) {
self.disable_pmp();
self.disable_machine_timer();
self.configure_trap_handler();
}
}

impl kernel::Chip for ArtyExx {
// While there is initial support for a PMP driver (as of 2019-10-04), it is not
// complete, and while it should disable the PMP, it seems to cause some negative
// side effects (context switching does not work correctly) on the Arty-E21 platform.
//
// TODO: implement the PMP driver and add it here `type MPU = rv32i::pmp::PMPConfig;`.
//
// See https://github.com/tock/tock/pull/1382 for (a little) more information.
type MPU = ();
type UserspaceKernelBoundary = rv32i::syscall::SysCall;
type SysTick = ();

fn mpu(&self) -> &Self::MPU {
&()
}

fn systick(&self) -> &Self::SysTick {
&()
}

fn userspace_kernel_boundary(&self) -> &rv32i::syscall::SysCall {
&self.userspace_kernel_boundary
}

fn service_pending_interrupts(&self) {
unsafe {
while let Some(interrupt) = self.clic.next_pending() {
match interrupt {
interrupts::MTIP => machine_timer::MACHINETIMER.handle_interrupt(),

interrupts::GPIO0 => gpio::PORT[3].handle_interrupt(),
interrupts::GPIO1 => gpio::PORT[3].handle_interrupt(),
interrupts::GPIO2 => gpio::PORT[3].handle_interrupt(),
interrupts::GPIO3 => gpio::PORT[3].handle_interrupt(),
interrupts::GPIO4 => gpio::PORT[4].handle_interrupt(),
interrupts::GPIO5 => gpio::PORT[5].handle_interrupt(),
interrupts::GPIO6 => gpio::PORT[6].handle_interrupt(),
interrupts::GPIO7 => gpio::PORT[7].handle_interrupt(),
interrupts::GPIO8 => gpio::PORT[8].handle_interrupt(),
interrupts::GPIO9 => gpio::PORT[9].handle_interrupt(),
interrupts::GPIO10 => gpio::PORT[10].handle_interrupt(),
interrupts::GPIO11 => gpio::PORT[11].handle_interrupt(),
interrupts::GPIO12 => gpio::PORT[12].handle_interrupt(),
interrupts::GPIO13 => gpio::PORT[13].handle_interrupt(),
interrupts::GPIO14 => gpio::PORT[14].handle_interrupt(),
interrupts::GPIO15 => gpio::PORT[15].handle_interrupt(),

interrupts::UART0 => uart::UART0.handle_interrupt(),

_ => debug!("Pidx {}", interrupt),
}

// Mark that we are done with this interrupt and the hardware
// can clear it.
self.clic.complete(interrupt);
}
}
}

fn has_pending_interrupts(&self) -> bool {
self.clic.has_pending()
}

fn sleep(&self) {
unsafe {
rv32i::support::wfi();
}
}

unsafe fn atomic<F, R>(&self, f: F) -> R
where
F: FnOnce() -> R,
{
rv32i::support::atomic(f)
}
}

/// Trap handler for board/chip specific code.
///
/// For the arty-e21 this gets called when an interrupt occurs while the chip is
/// in kernel mode. All we need to do is check which interrupt occurred and
/// disable it.
#[export_name = "_start_trap_rust"]
pub extern "C" fn start_trap_rust() {
let mut mcause: i32;

unsafe {
asm!("
// Read the mcause CSR to determine why we entered the trap handler.
// Since we are using the CLIC, the hardware includes the interrupt
// index in the mcause register.
csrr $0, 0x342 // CSR=0x342=mcause
"
: "=r"(mcause)
:
:
: "volatile");
}

// Check if the trap was from an interrupt or some other exception.
if mcause < 0 {
// If the most significant bit is set (i.e. mcause is negative) then
// this was an interrupt. The interrupt number is then the lowest 8
// bits.
let interrupt_index = mcause & 0xFF;
unsafe {
rv32i::clic::disable_interrupt(interrupt_index as u32);
}
} else {
// Otherwise, the kernel encountered a fault...so panic!()?
panic!("kernel exception");
}
}

/// Function that gets called if an interrupt occurs while an app was running.
/// mcause is passed in, and this function should correctly handle disabling the
/// interrupt that fired so that it does not trigger again.
#[export_name = "_disable_interrupt_trap_handler"]
pub extern "C" fn disable_interrupt_trap_handler(mcause: u32) {
// The interrupt number is then the lowest 8
// bits.
let interrupt_index = mcause & 0xFF;
unsafe {
rv32i::clic::disable_interrupt(interrupt_index as u32);
}
}
}
mod gpio {
use core::ops::{Index, IndexMut};

use kernel::common::StaticRef;
use sifive::gpio::{pins, GpioPin, GpioRegisters};

const GPIO0_BASE: StaticRef<GpioRegisters> =
unsafe { StaticRef::new(0x2000_2000 as *const GpioRegisters) };

pub struct Port {
pins: [GpioPin; 16],
}

impl Index<usize> for Port {
type Output = GpioPin;

fn index(&self, index: usize) -> &GpioPin {
&self.pins[index]
}
}

impl IndexMut<usize> for Port {
fn index_mut(&mut self, index: usize) -> &mut GpioPin {
&mut self.pins[index]
}
}

pub static mut PORT: Port = Port {
pins: [
GpioPin::new(GPIO0_BASE, pins::pin0, pins::pin0::SET, pins::pin0::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin1, pins::pin1::SET, pins::pin1::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin2, pins::pin2::SET, pins::pin2::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin3, pins::pin3::SET, pins::pin3::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin4, pins::pin4::SET, pins::pin4::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin5, pins::pin5::SET, pins::pin5::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin6, pins::pin6::SET, pins::pin6::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin7, pins::pin7::SET, pins::pin7::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin8, pins::pin8::SET, pins::pin8::CLEAR),
GpioPin::new(GPIO0_BASE, pins::pin9, pins::pin9::SET, pins::pin9::CLEAR),
GpioPin::new(
GPIO0_BASE,
pins::pin10,
pins::pin10::SET,
pins::pin10::CLEAR,
),
GpioPin::new(
GPIO0_BASE,
pins::pin11,
pins::pin11::SET,
pins::pin11::CLEAR,
),
GpioPin::new(
GPIO0_BASE,
pins::pin12,
pins::pin12::SET,
pins::pin12::CLEAR,
),
GpioPin::new(
GPIO0_BASE,
pins::pin13,
pins::pin13::SET,
pins::pin13::CLEAR,
),
GpioPin::new(
GPIO0_BASE,
pins::pin14,
pins::pin14::SET,
pins::pin14::CLEAR,
),
GpioPin::new(
GPIO0_BASE,
pins::pin15,
pins::pin15::SET,
pins::pin15::CLEAR,
),
],
};
}
mod uart {
use kernel::common::StaticRef;
use sifive::uart::{Uart, UartRegisters};

pub static mut UART0: Uart = Uart::new(UART0_BASE, 32_000_000);

const UART0_BASE: StaticRef<UartRegisters> =
unsafe { StaticRef::new(0x2000_0000 as *const UartRegisters) };
}

0 comments on commit 76a8d5f

Please sign in to comment.