1use core::fmt::Write;
8use core::ptr::addr_of;
9use kernel::debug;
10use kernel::platform::chip::Chip;
11use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
12use rv32i::csr;
13use rv32i::csr::{mcause, mie::mie, mip::mip, CSR};
14use rv32i::pmp::{simple::SimplePMP, PMPUserMPU};
15
16use crate::plic::PLIC;
17use kernel::hil::time::Freq32KHz;
18use kernel::platform::chip::InterruptService;
19use sifive::plic::Plic;
20
21pub type E310xClint<'a> = sifive::clint::Clint<'a, Freq32KHz>;
22
23pub struct E310x<'a, I: InterruptService + 'a> {
24 userspace_kernel_boundary: rv32i::syscall::SysCall,
25 pmp: PMPUserMPU<4, SimplePMP<8>>,
26 plic: &'a Plic,
27 timer: &'a E310xClint<'a>,
28 plic_interrupt_service: &'a I,
29}
30
31pub struct E310xDefaultPeripherals<'a> {
32 pub uart0: sifive::uart::Uart<'a>,
33 pub uart1: sifive::uart::Uart<'a>,
34 pub gpio_port: crate::gpio::Port<'a>,
35 pub prci: sifive::prci::Prci,
36 pub pwm0: sifive::pwm::Pwm,
37 pub pwm1: sifive::pwm::Pwm,
38 pub pwm2: sifive::pwm::Pwm,
39 pub rtc: sifive::rtc::Rtc,
40 pub watchdog: sifive::watchdog::Watchdog,
41}
42
43impl E310xDefaultPeripherals<'_> {
44 pub fn new(clock_frequency: u32) -> Self {
45 Self {
46 uart0: sifive::uart::Uart::new(crate::uart::UART0_BASE, clock_frequency),
47 uart1: sifive::uart::Uart::new(crate::uart::UART1_BASE, clock_frequency),
48 gpio_port: crate::gpio::Port::new(),
49 prci: sifive::prci::Prci::new(crate::prci::PRCI_BASE),
50 pwm0: sifive::pwm::Pwm::new(crate::pwm::PWM0_BASE),
51 pwm1: sifive::pwm::Pwm::new(crate::pwm::PWM1_BASE),
52 pwm2: sifive::pwm::Pwm::new(crate::pwm::PWM2_BASE),
53 rtc: sifive::rtc::Rtc::new(crate::rtc::RTC_BASE),
54 watchdog: sifive::watchdog::Watchdog::new(crate::watchdog::WATCHDOG_BASE),
55 }
56 }
57
58 pub fn init(&'static self) {
60 kernel::deferred_call::DeferredCallClient::register(&self.uart0);
61 kernel::deferred_call::DeferredCallClient::register(&self.uart1);
62 }
63}
64
65impl InterruptService for E310xDefaultPeripherals<'_> {
66 unsafe fn service_interrupt(&self, _interrupt: u32) -> bool {
67 false
68 }
69}
70
71impl<'a, I: InterruptService + 'a> E310x<'a, I> {
72 pub unsafe fn new(plic_interrupt_service: &'a I, timer: &'a E310xClint<'a>) -> Self {
73 Self {
74 userspace_kernel_boundary: rv32i::syscall::SysCall::new(),
75 pmp: PMPUserMPU::new(SimplePMP::new().unwrap()),
76 plic: &*addr_of!(PLIC),
77 timer,
78 plic_interrupt_service,
79 }
80 }
81
82 pub unsafe fn enable_plic_interrupts(&self) {
83 let old_mie = csr::CSR
91 .mstatus
92 .read_and_clear_field(csr::mstatus::mstatus::mie);
93
94 self.plic.enable_all();
95 self.plic.clear_all_pending();
96
97 csr::CSR
99 .mstatus
100 .modify(csr::mstatus::mstatus::mie.val(old_mie));
101 }
102
103 unsafe fn handle_plic_interrupts(&self) {
104 while let Some(interrupt) = self.plic.get_saved_interrupts() {
105 if !self.plic_interrupt_service.service_interrupt(interrupt) {
106 debug!("Pidx {}", interrupt);
107 }
108 self.atomic(|| {
109 self.plic.complete(interrupt);
110 });
111 }
112 }
113}
114
115impl<'a, I: InterruptService + 'a> kernel::platform::chip::Chip for E310x<'a, I> {
116 type MPU = PMPUserMPU<4, SimplePMP<8>>;
117 type UserspaceKernelBoundary = rv32i::syscall::SysCall;
118
119 fn mpu(&self) -> &Self::MPU {
120 &self.pmp
121 }
122
123 fn userspace_kernel_boundary(&self) -> &rv32i::syscall::SysCall {
124 &self.userspace_kernel_boundary
125 }
126
127 fn service_pending_interrupts(&self) {
128 loop {
129 let mip = CSR.mip.extract();
130
131 if mip.is_set(mip::mtimer) {
132 self.timer.handle_interrupt();
133 }
134 if self.plic.get_saved_interrupts().is_some() {
135 unsafe {
136 self.handle_plic_interrupts();
137 }
138 }
139
140 if !mip.any_matching_bits_set(mip::mtimer::SET)
141 && self.plic.get_saved_interrupts().is_none()
142 {
143 break;
144 }
145 }
146
147 CSR.mie.modify(mie::mext::SET + mie::mtimer::SET);
150 }
151
152 fn has_pending_interrupts(&self) -> bool {
153 if CSR.mip.is_set(mip::mtimer) {
157 return true;
158 }
159
160 self.plic.get_saved_interrupts().is_some()
162 }
163
164 fn sleep(&self) {
165 unsafe {
166 rv32i::support::wfi();
167 }
168 }
169
170 unsafe fn atomic<F, R>(&self, f: F) -> R
171 where
172 F: FnOnce() -> R,
173 {
174 rv32i::support::atomic(f)
175 }
176
177 unsafe fn print_state(&self, writer: &mut dyn Write) {
178 rv32i::print_riscv_state(writer);
179 }
180}
181
182fn handle_exception(exception: mcause::Exception) {
183 match exception {
184 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
185
186 mcause::Exception::InstructionMisaligned
187 | mcause::Exception::InstructionFault
188 | mcause::Exception::IllegalInstruction
189 | mcause::Exception::Breakpoint
190 | mcause::Exception::LoadMisaligned
191 | mcause::Exception::LoadFault
192 | mcause::Exception::StoreMisaligned
193 | mcause::Exception::StoreFault
194 | mcause::Exception::MachineEnvCall
195 | mcause::Exception::InstructionPageFault
196 | mcause::Exception::LoadPageFault
197 | mcause::Exception::StorePageFault
198 | mcause::Exception::Unknown => {
199 panic!("fatal exception");
200 }
201 }
202}
203
204unsafe fn handle_interrupt(intr: mcause::Interrupt) {
205 match intr {
206 mcause::Interrupt::UserSoft
207 | mcause::Interrupt::UserTimer
208 | mcause::Interrupt::UserExternal => {
209 panic!("unexpected user-mode interrupt");
210 }
211 mcause::Interrupt::SupervisorExternal
212 | mcause::Interrupt::SupervisorTimer
213 | mcause::Interrupt::SupervisorSoft => {
214 panic!("unexpected supervisor-mode interrupt");
215 }
216
217 mcause::Interrupt::MachineSoft => {
218 CSR.mie.modify(mie::msoft::CLEAR);
219 }
220 mcause::Interrupt::MachineTimer => {
221 CSR.mie.modify(mie::mtimer::CLEAR);
222 }
223 mcause::Interrupt::MachineExternal => {
224 CSR.mie.modify(mie::mext::CLEAR);
226
227 loop {
231 let interrupt = (*addr_of!(PLIC)).next_pending();
232
233 match interrupt {
234 Some(irq) => {
235 (*addr_of!(PLIC)).save_interrupt(irq);
237 }
238 None => {
239 CSR.mie.modify(mie::mext::SET);
241
242 break;
243 }
244 }
245 }
246 }
247
248 mcause::Interrupt::Unknown(_) => {
249 panic!("interrupt of unknown cause");
250 }
251 }
252}
253
254#[export_name = "_start_trap_rust_from_kernel"]
259pub unsafe extern "C" fn start_trap_rust() {
260 match mcause::Trap::from(CSR.mcause.extract()) {
261 mcause::Trap::Interrupt(interrupt) => {
262 handle_interrupt(interrupt);
263 }
264 mcause::Trap::Exception(exception) => {
265 handle_exception(exception);
266 }
267 }
268}
269
270#[export_name = "_disable_interrupt_trap_rust_from_app"]
275pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
276 match mcause::Trap::from(mcause_val as usize) {
277 mcause::Trap::Interrupt(interrupt) => {
278 handle_interrupt(interrupt);
279 }
280 _ => {
281 panic!("unexpected non-interrupt\n");
282 }
283 }
284}