1use core::fmt::Write;
6use kernel::debug;
7use kernel::hil::time::Freq32KHz;
8use kernel::platform::chip::InterruptService;
9use kernel::utilities::registers::interfaces::Readable;
10
11use crate::clint;
12use crate::interrupts;
13use rv32i::pmp::{simple::SimplePMP, PMPUserMPU};
14
15extern "C" {
16 fn _start_trap();
17}
18
19pub type ArtyExxClint<'a> = sifive::clint::Clint<'a, Freq32KHz>;
20
21pub struct ArtyExx<'a, I: InterruptService + 'a> {
22 pmp: PMPUserMPU<2, SimplePMP<4>>,
23 userspace_kernel_boundary: rv32i::syscall::SysCall,
24 clic: rv32i::clic::Clic,
25 machinetimer: &'a ArtyExxClint<'a>,
26 interrupt_service: &'a I,
27}
28
29pub struct ArtyExxDefaultPeripherals<'a> {
30 pub machinetimer: ArtyExxClint<'a>,
31 pub gpio_port: crate::gpio::Port<'a>,
32 pub uart0: sifive::uart::Uart<'a>,
33}
34
35impl ArtyExxDefaultPeripherals<'_> {
36 pub fn new() -> Self {
37 Self {
38 machinetimer: ArtyExxClint::new(&clint::CLINT_BASE),
39 gpio_port: crate::gpio::Port::new(),
40 uart0: sifive::uart::Uart::new(crate::uart::UART0_BASE, 32_000_000),
41 }
42 }
43
44 pub fn init(&'static self) {
46 kernel::deferred_call::DeferredCallClient::register(&self.uart0);
47 }
48}
49
50impl InterruptService for ArtyExxDefaultPeripherals<'_> {
51 unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
52 match interrupt {
53 interrupts::MTIP => self.machinetimer.handle_interrupt(),
54
55 interrupts::GPIO0 => self.gpio_port[0].handle_interrupt(),
56 interrupts::GPIO1 => self.gpio_port[1].handle_interrupt(),
57 interrupts::GPIO2 => self.gpio_port[2].handle_interrupt(),
58 interrupts::GPIO3 => self.gpio_port[3].handle_interrupt(),
59 interrupts::GPIO4 => self.gpio_port[4].handle_interrupt(),
60 interrupts::GPIO5 => self.gpio_port[5].handle_interrupt(),
61 interrupts::GPIO6 => self.gpio_port[6].handle_interrupt(),
62 interrupts::GPIO7 => self.gpio_port[7].handle_interrupt(),
63 interrupts::GPIO8 => self.gpio_port[8].handle_interrupt(),
64 interrupts::GPIO9 => self.gpio_port[9].handle_interrupt(),
65 interrupts::GPIO10 => self.gpio_port[10].handle_interrupt(),
66 interrupts::GPIO11 => self.gpio_port[11].handle_interrupt(),
67 interrupts::GPIO12 => self.gpio_port[12].handle_interrupt(),
68 interrupts::GPIO13 => self.gpio_port[13].handle_interrupt(),
69 interrupts::GPIO14 => self.gpio_port[14].handle_interrupt(),
70 interrupts::GPIO15 => self.gpio_port[15].handle_interrupt(),
71
72 interrupts::UART0 => self.uart0.handle_interrupt(),
73
74 _ => return false,
75 }
76 true
77 }
78}
79
80impl<'a, I: InterruptService + 'a> ArtyExx<'a, I> {
81 pub unsafe fn new(machinetimer: &'a ArtyExxClint<'a>, interrupt_service: &'a I) -> Self {
82 let in_use_interrupts: u64 = 0x1FFFF0080;
86
87 Self {
88 pmp: PMPUserMPU::new(SimplePMP::new().unwrap()),
89 userspace_kernel_boundary: rv32i::syscall::SysCall::new(),
90 clic: rv32i::clic::Clic::new(in_use_interrupts),
91 machinetimer,
92 interrupt_service,
93 }
94 }
95
96 pub fn enable_all_interrupts(&self) {
97 self.clic.enable_all();
98 }
99
100 pub unsafe fn disable_machine_timer(&self) {
105 self.machinetimer.disable_machine_timer();
106 }
107
108 #[cfg(any(doc, all(target_arch = "riscv32", target_os = "none")))]
114 pub unsafe fn configure_trap_handler(&self) {
115 use core::arch::asm;
116 asm!(
117 "
118 // The csrw instruction writes a Control and Status Register (CSR)
119 // with a new value.
120 //
121 // CSR 0x305 (mtvec, 'Machine trap-handler base address.') sets the
122 // address of the trap handler. We do not care about its old value,
123 // so we don't bother reading it. We want to enable direct CLIC mode
124 // so we set the second lowest bit.
125 lui t0, %hi(_start_trap)
126 addi t0, t0, %lo(_start_trap)
127 ori t0, t0, 0x02 // Set CLIC direct mode
128 csrw 0x305, t0 // Write the mtvec CSR.
129 ",
130 out("t0") _
131 );
132 }
133
134 #[cfg(not(any(doc, all(target_arch = "riscv32", target_os = "none"))))]
136 pub unsafe fn configure_trap_handler(&self) {
137 unimplemented!()
138 }
139
140 pub unsafe fn initialize(&self) {
144 self.disable_machine_timer();
145 self.configure_trap_handler();
146 }
147}
148
149impl<'a, I: InterruptService + 'a> kernel::platform::chip::Chip for ArtyExx<'a, I> {
150 type MPU = PMPUserMPU<2, SimplePMP<4>>;
151 type UserspaceKernelBoundary = rv32i::syscall::SysCall;
152
153 fn mpu(&self) -> &Self::MPU {
154 &self.pmp
155 }
156
157 fn userspace_kernel_boundary(&self) -> &rv32i::syscall::SysCall {
158 &self.userspace_kernel_boundary
159 }
160
161 fn service_pending_interrupts(&self) {
162 unsafe {
163 while let Some(interrupt) = self.clic.next_pending() {
164 if !self.interrupt_service.service_interrupt(interrupt) {
165 debug!("unhandled interrupt: {:?}", interrupt);
166 }
167
168 self.clic.complete(interrupt);
171 }
172 }
173 }
174
175 fn has_pending_interrupts(&self) -> bool {
176 self.clic.has_pending()
177 }
178
179 fn sleep(&self) {
180 unsafe {
181 rv32i::support::wfi();
182 }
183 }
184
185 unsafe fn atomic<F, R>(&self, f: F) -> R
186 where
187 F: FnOnce() -> R,
188 {
189 rv32i::support::atomic(f)
190 }
191
192 unsafe fn print_state(&self, write: &mut dyn Write) {
193 rv32i::print_riscv_state(write);
194 }
195}
196
197#[export_name = "_start_trap_rust_from_kernel"]
203pub extern "C" fn start_trap_rust() {
204 let mcause = rv32i::csr::CSR.mcause.extract();
205
206 match rv32i::csr::mcause::Trap::from(mcause) {
207 rv32i::csr::mcause::Trap::Interrupt(_interrupt) => {
208 let interrupt_index = mcause.read(rv32i::csr::mcause::mcause::reason) & 0xFF;
212 unsafe {
213 rv32i::clic::disable_interrupt(interrupt_index as u32);
214 }
215 }
216
217 rv32i::csr::mcause::Trap::Exception(_exception) => {
218 panic!("kernel exception");
220 }
221 }
222}
223
224#[export_name = "_disable_interrupt_trap_rust_from_app"]
229pub extern "C" fn disable_interrupt_trap_handler(mcause: u32) {
230 let interrupt_index = mcause & 0xFF;
233 unsafe {
234 rv32i::clic::disable_interrupt(interrupt_index);
235 }
236}