Skip to content

Commit 76a8d5f

Browse files
committed
mod-inlining
1 parent e0a22e4 commit 76a8d5f

1 file changed

Lines changed: 362 additions & 4 deletions

File tree

tock/chips/arty_e21/src/lib.rs

Lines changed: 362 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,366 @@
66
#![crate_name = "arty_e21"]
77
#![crate_type = "rlib"]
88

9-
mod interrupts;
9+
mod interrupts {
10+
//! Named interrupts for the E21 Arty core.
1011
11-
pub mod chip;
12-
mod gpio;
13-
mod uart;
12+
#![allow(dead_code)]
13+
14+
pub const MTIP: u32 = 7; // Machine Timer
15+
16+
pub const GPIO0: u32 = 18;
17+
pub const GPIO1: u32 = 19;
18+
pub const GPIO2: u32 = 20;
19+
pub const GPIO3: u32 = 21;
20+
pub const GPIO4: u32 = 22;
21+
pub const GPIO5: u32 = 23;
22+
pub const GPIO6: u32 = 24;
23+
pub const GPIO7: u32 = 25;
24+
pub const GPIO8: u32 = 26;
25+
pub const GPIO9: u32 = 27;
26+
pub const GPIO10: u32 = 28;
27+
pub const GPIO11: u32 = 29;
28+
pub const GPIO12: u32 = 30;
29+
pub const GPIO13: u32 = 31;
30+
pub const GPIO14: u32 = 32;
31+
pub const GPIO15: u32 = 33;
32+
pub const UART0: u32 = 16;
33+
}
34+
35+
pub mod chip {
36+
use kernel;
37+
use kernel::debug;
38+
use rv32i;
39+
use rv32i::machine_timer;
40+
41+
use crate::gpio;
42+
use crate::interrupts;
43+
use crate::uart;
44+
45+
extern "C" {
46+
fn _start_trap();
47+
}
48+
49+
pub struct ArtyExx {
50+
userspace_kernel_boundary: rv32i::syscall::SysCall,
51+
clic: rv32i::clic::Clic,
52+
}
53+
54+
impl ArtyExx {
55+
pub unsafe fn new() -> ArtyExx {
56+
// Make a bit-vector of all interrupt locations that we actually intend
57+
// to use on this chip.
58+
// 0001 1111 1111 1111 1111 0000 0000 1000 0000
59+
let in_use_interrupts: u64 = 0x1FFFF0080;
60+
61+
ArtyExx {
62+
userspace_kernel_boundary: rv32i::syscall::SysCall::new(),
63+
clic: rv32i::clic::Clic::new(in_use_interrupts),
64+
}
65+
}
66+
67+
pub fn enable_all_interrupts(&self) {
68+
self.clic.enable_all();
69+
}
70+
71+
/// Configure the PMP to allow all accesses in both machine mode (the
72+
/// default) and in user mode.
73+
///
74+
/// This needs to be replaced with a real PMP driver. See
75+
/// https://github.com/tock/tock/issues/1135
76+
pub unsafe fn disable_pmp(&self) {
77+
asm!("
78+
// PMP PMP PMP
79+
// PMP PMP PMP
80+
// PMP PMP PMP
81+
// PMP PMP PMP
82+
// TODO: Add a real PMP driver!!
83+
// Take some time to disable the PMP.
84+
85+
// Set the first region address to 0xFFFFFFFF. When using top-of-range mode
86+
// this will include the entire address space.
87+
lui t0, %hi(0xFFFFFFFF)
88+
addi t0, t0, %lo(0xFFFFFFFF)
89+
csrw 0x3b0, t0 // CSR=pmpaddr0
90+
91+
// Set the first region to use top-of-range and allow everything.
92+
// This is equivalent to:
93+
// R=1, W=1, X=1, A=01, L=0
94+
li t0, 0x0F
95+
csrw 0x3a0, t0 // CSR=pmpcfg0
96+
"
97+
:
98+
:
99+
:
100+
: "volatile");
101+
}
102+
103+
/// By default the machine timer is enabled and will trigger interrupts. To
104+
/// prevent that we can make the compare register very large to effectively
105+
/// stop the interrupt from triggering, and then the machine timer can be
106+
/// used later as needed.
107+
pub unsafe fn disable_machine_timer(&self) {
108+
asm!("
109+
// Initialize machine timer mtimecmp to disable the machine timer
110+
// interrupt.
111+
li t0, -1 // Set mtimecmp to 0xFFFFFFFF
112+
lui t1, %hi(0x02004000) // Load the address of mtimecmp to t1
113+
addi t1, t1, %lo(0x02004000) // Load the address of mtimecmp to t1
114+
sw t0, 0(t1) // mtimecmp is 64 bits, set to all ones
115+
sw t0, 4(t1) // mtimecmp is 64 bits, set to all ones
116+
"
117+
:
118+
:
119+
:
120+
: "volatile");
121+
}
122+
123+
/// Setup the function that should run when a trap happens.
124+
///
125+
/// This needs to be chip specific because how the CLIC works is configured
126+
/// when the trap handler address is specified in mtvec, and that is only
127+
/// valid for platforms with a CLIC.
128+
pub unsafe fn configure_trap_handler(&self) {
129+
asm!("
130+
// The csrw instruction writes a Control and Status Register (CSR)
131+
// with a new value.
132+
//
133+
// CSR 0x305 (mtvec, 'Machine trap-handler base address.') sets the
134+
// address of the trap handler. We do not care about its old value,
135+
// so we don't bother reading it. We want to enable direct CLIC mode
136+
// so we set the second lowest bit.
137+
lui t0, %hi(_start_trap)
138+
addi t0, t0, %lo(_start_trap)
139+
ori t0, t0, 0x02 // Set CLIC direct mode
140+
csrw 0x305, t0 // Write the mtvec CSR.
141+
"
142+
:
143+
:
144+
:
145+
: "volatile");
146+
}
147+
148+
/// Generic helper initialize function to setup all of the chip specific
149+
/// operations. Different boards can call the functions that `initialize()`
150+
/// calls directly if it needs to use a custom setup operation.
151+
pub unsafe fn initialize(&self) {
152+
self.disable_pmp();
153+
self.disable_machine_timer();
154+
self.configure_trap_handler();
155+
}
156+
}
157+
158+
impl kernel::Chip for ArtyExx {
159+
// While there is initial support for a PMP driver (as of 2019-10-04), it is not
160+
// complete, and while it should disable the PMP, it seems to cause some negative
161+
// side effects (context switching does not work correctly) on the Arty-E21 platform.
162+
//
163+
// TODO: implement the PMP driver and add it here `type MPU = rv32i::pmp::PMPConfig;`.
164+
//
165+
// See https://github.com/tock/tock/pull/1382 for (a little) more information.
166+
type MPU = ();
167+
type UserspaceKernelBoundary = rv32i::syscall::SysCall;
168+
type SysTick = ();
169+
170+
fn mpu(&self) -> &Self::MPU {
171+
&()
172+
}
173+
174+
fn systick(&self) -> &Self::SysTick {
175+
&()
176+
}
177+
178+
fn userspace_kernel_boundary(&self) -> &rv32i::syscall::SysCall {
179+
&self.userspace_kernel_boundary
180+
}
181+
182+
fn service_pending_interrupts(&self) {
183+
unsafe {
184+
while let Some(interrupt) = self.clic.next_pending() {
185+
match interrupt {
186+
interrupts::MTIP => machine_timer::MACHINETIMER.handle_interrupt(),
187+
188+
interrupts::GPIO0 => gpio::PORT[3].handle_interrupt(),
189+
interrupts::GPIO1 => gpio::PORT[3].handle_interrupt(),
190+
interrupts::GPIO2 => gpio::PORT[3].handle_interrupt(),
191+
interrupts::GPIO3 => gpio::PORT[3].handle_interrupt(),
192+
interrupts::GPIO4 => gpio::PORT[4].handle_interrupt(),
193+
interrupts::GPIO5 => gpio::PORT[5].handle_interrupt(),
194+
interrupts::GPIO6 => gpio::PORT[6].handle_interrupt(),
195+
interrupts::GPIO7 => gpio::PORT[7].handle_interrupt(),
196+
interrupts::GPIO8 => gpio::PORT[8].handle_interrupt(),
197+
interrupts::GPIO9 => gpio::PORT[9].handle_interrupt(),
198+
interrupts::GPIO10 => gpio::PORT[10].handle_interrupt(),
199+
interrupts::GPIO11 => gpio::PORT[11].handle_interrupt(),
200+
interrupts::GPIO12 => gpio::PORT[12].handle_interrupt(),
201+
interrupts::GPIO13 => gpio::PORT[13].handle_interrupt(),
202+
interrupts::GPIO14 => gpio::PORT[14].handle_interrupt(),
203+
interrupts::GPIO15 => gpio::PORT[15].handle_interrupt(),
204+
205+
interrupts::UART0 => uart::UART0.handle_interrupt(),
206+
207+
_ => debug!("Pidx {}", interrupt),
208+
}
209+
210+
// Mark that we are done with this interrupt and the hardware
211+
// can clear it.
212+
self.clic.complete(interrupt);
213+
}
214+
}
215+
}
216+
217+
fn has_pending_interrupts(&self) -> bool {
218+
self.clic.has_pending()
219+
}
220+
221+
fn sleep(&self) {
222+
unsafe {
223+
rv32i::support::wfi();
224+
}
225+
}
226+
227+
unsafe fn atomic<F, R>(&self, f: F) -> R
228+
where
229+
F: FnOnce() -> R,
230+
{
231+
rv32i::support::atomic(f)
232+
}
233+
}
234+
235+
/// Trap handler for board/chip specific code.
236+
///
237+
/// For the arty-e21 this gets called when an interrupt occurs while the chip is
238+
/// in kernel mode. All we need to do is check which interrupt occurred and
239+
/// disable it.
240+
#[export_name = "_start_trap_rust"]
241+
pub extern "C" fn start_trap_rust() {
242+
let mut mcause: i32;
243+
244+
unsafe {
245+
asm!("
246+
// Read the mcause CSR to determine why we entered the trap handler.
247+
// Since we are using the CLIC, the hardware includes the interrupt
248+
// index in the mcause register.
249+
csrr $0, 0x342 // CSR=0x342=mcause
250+
"
251+
: "=r"(mcause)
252+
:
253+
:
254+
: "volatile");
255+
}
256+
257+
// Check if the trap was from an interrupt or some other exception.
258+
if mcause < 0 {
259+
// If the most significant bit is set (i.e. mcause is negative) then
260+
// this was an interrupt. The interrupt number is then the lowest 8
261+
// bits.
262+
let interrupt_index = mcause & 0xFF;
263+
unsafe {
264+
rv32i::clic::disable_interrupt(interrupt_index as u32);
265+
}
266+
} else {
267+
// Otherwise, the kernel encountered a fault...so panic!()?
268+
panic!("kernel exception");
269+
}
270+
}
271+
272+
/// Function that gets called if an interrupt occurs while an app was running.
273+
/// mcause is passed in, and this function should correctly handle disabling the
274+
/// interrupt that fired so that it does not trigger again.
275+
#[export_name = "_disable_interrupt_trap_handler"]
276+
pub extern "C" fn disable_interrupt_trap_handler(mcause: u32) {
277+
// The interrupt number is then the lowest 8
278+
// bits.
279+
let interrupt_index = mcause & 0xFF;
280+
unsafe {
281+
rv32i::clic::disable_interrupt(interrupt_index as u32);
282+
}
283+
}
284+
}
285+
mod gpio {
286+
use core::ops::{Index, IndexMut};
287+
288+
use kernel::common::StaticRef;
289+
use sifive::gpio::{pins, GpioPin, GpioRegisters};
290+
291+
const GPIO0_BASE: StaticRef<GpioRegisters> =
292+
unsafe { StaticRef::new(0x2000_2000 as *const GpioRegisters) };
293+
294+
pub struct Port {
295+
pins: [GpioPin; 16],
296+
}
297+
298+
impl Index<usize> for Port {
299+
type Output = GpioPin;
300+
301+
fn index(&self, index: usize) -> &GpioPin {
302+
&self.pins[index]
303+
}
304+
}
305+
306+
impl IndexMut<usize> for Port {
307+
fn index_mut(&mut self, index: usize) -> &mut GpioPin {
308+
&mut self.pins[index]
309+
}
310+
}
311+
312+
pub static mut PORT: Port = Port {
313+
pins: [
314+
GpioPin::new(GPIO0_BASE, pins::pin0, pins::pin0::SET, pins::pin0::CLEAR),
315+
GpioPin::new(GPIO0_BASE, pins::pin1, pins::pin1::SET, pins::pin1::CLEAR),
316+
GpioPin::new(GPIO0_BASE, pins::pin2, pins::pin2::SET, pins::pin2::CLEAR),
317+
GpioPin::new(GPIO0_BASE, pins::pin3, pins::pin3::SET, pins::pin3::CLEAR),
318+
GpioPin::new(GPIO0_BASE, pins::pin4, pins::pin4::SET, pins::pin4::CLEAR),
319+
GpioPin::new(GPIO0_BASE, pins::pin5, pins::pin5::SET, pins::pin5::CLEAR),
320+
GpioPin::new(GPIO0_BASE, pins::pin6, pins::pin6::SET, pins::pin6::CLEAR),
321+
GpioPin::new(GPIO0_BASE, pins::pin7, pins::pin7::SET, pins::pin7::CLEAR),
322+
GpioPin::new(GPIO0_BASE, pins::pin8, pins::pin8::SET, pins::pin8::CLEAR),
323+
GpioPin::new(GPIO0_BASE, pins::pin9, pins::pin9::SET, pins::pin9::CLEAR),
324+
GpioPin::new(
325+
GPIO0_BASE,
326+
pins::pin10,
327+
pins::pin10::SET,
328+
pins::pin10::CLEAR,
329+
),
330+
GpioPin::new(
331+
GPIO0_BASE,
332+
pins::pin11,
333+
pins::pin11::SET,
334+
pins::pin11::CLEAR,
335+
),
336+
GpioPin::new(
337+
GPIO0_BASE,
338+
pins::pin12,
339+
pins::pin12::SET,
340+
pins::pin12::CLEAR,
341+
),
342+
GpioPin::new(
343+
GPIO0_BASE,
344+
pins::pin13,
345+
pins::pin13::SET,
346+
pins::pin13::CLEAR,
347+
),
348+
GpioPin::new(
349+
GPIO0_BASE,
350+
pins::pin14,
351+
pins::pin14::SET,
352+
pins::pin14::CLEAR,
353+
),
354+
GpioPin::new(
355+
GPIO0_BASE,
356+
pins::pin15,
357+
pins::pin15::SET,
358+
pins::pin15::CLEAR,
359+
),
360+
],
361+
};
362+
}
363+
mod uart {
364+
use kernel::common::StaticRef;
365+
use sifive::uart::{Uart, UartRegisters};
366+
367+
pub static mut UART0: Uart = Uart::new(UART0_BASE, 32_000_000);
368+
369+
const UART0_BASE: StaticRef<UartRegisters> =
370+
unsafe { StaticRef::new(0x2000_0000 as *const UartRegisters) };
371+
}

0 commit comments

Comments
 (0)