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