1use core::fmt::Write;
8use core::ptr::addr_of;
9
10use kernel::platform::chip::{Chip, InterruptService};
11use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
12use kernel::utilities::StaticRef;
13
14use rv32i::csr::{self, mcause, mtvec::mtvec, CSR};
15use rv32i::pmp::{simple::SimplePMP, PMPUserMPU};
16use rv32i::syscall::SysCall;
17
18use crate::intc::{Intc, IntcRegisters};
19use crate::interrupts;
20use crate::rng;
21use crate::sysreg;
22use crate::timg;
23
24pub const INTC_BASE: StaticRef<IntcRegisters> =
25 unsafe { StaticRef::new(0x600C_2000 as *const IntcRegisters) };
26
27pub static mut INTC: Intc = Intc::new(INTC_BASE);
28
29pub struct Esp32C3<'a, I: InterruptService + 'a> {
30 userspace_kernel_boundary: SysCall,
31 pub pmp: PMPUserMPU<8, SimplePMP<16>>,
32 intc: &'a Intc,
33 pic_interrupt_service: &'a I,
34}
35
36pub struct Esp32C3DefaultPeripherals<'a> {
37 pub uart0: esp32::uart::Uart<'a>,
38 pub timg0: timg::TimG<'a>,
39 pub timg1: timg::TimG<'a>,
40 pub gpio: esp32::gpio::Port<'a>,
41 pub rtc_cntl: esp32::rtc_cntl::RtcCntl,
42 pub sysreg: sysreg::SysReg,
43 pub rng: rng::Rng<'a>,
44}
45
46impl Esp32C3DefaultPeripherals<'_> {
47 pub fn new() -> Self {
48 Self {
49 uart0: esp32::uart::Uart::new(esp32::uart::UART0_BASE),
50 timg0: timg::TimG::new(timg::TIMG0_BASE, timg::ClockSource::Pll),
51 timg1: timg::TimG::new(timg::TIMG1_BASE, timg::ClockSource::Pll),
52 gpio: esp32::gpio::Port::new(),
53 rtc_cntl: esp32::rtc_cntl::RtcCntl::new(esp32::rtc_cntl::RTC_CNTL_BASE),
54 sysreg: sysreg::SysReg::new(),
55 rng: rng::Rng::new(),
56 }
57 }
58
59 pub fn init(&'static self) {
60 kernel::deferred_call::DeferredCallClient::register(&self.rng);
61 }
62}
63
64impl InterruptService for Esp32C3DefaultPeripherals<'_> {
65 unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
66 match interrupt {
67 interrupts::IRQ_UART0 => self.uart0.handle_interrupt(),
68
69 interrupts::IRQ_TIMER1 => self.timg0.handle_interrupt(),
70 interrupts::IRQ_TIMER2 => self.timg1.handle_interrupt(),
71
72 interrupts::IRQ_GPIO | interrupts::IRQ_GPIO_NMI => self.gpio.handle_interrupt(),
73
74 _ => return false,
75 }
76 true
77 }
78}
79
80impl<'a, I: InterruptService + 'a> Esp32C3<'a, I> {
81 pub unsafe fn new(pic_interrupt_service: &'a I) -> Self {
82 Self {
83 userspace_kernel_boundary: SysCall::new(),
84 pmp: PMPUserMPU::new(SimplePMP::new().unwrap()),
85 intc: &*addr_of!(INTC),
86 pic_interrupt_service,
87 }
88 }
89
90 pub fn map_pic_interrupts(&self) {
91 self.intc.map_interrupts();
92 }
93
94 pub unsafe fn enable_pic_interrupts(&self) {
95 self.intc.enable_all();
96 }
97
98 unsafe fn handle_pic_interrupts(&self) {
99 while let Some(interrupt) = self.intc.get_saved_interrupts() {
100 if !self.pic_interrupt_service.service_interrupt(interrupt) {
101 panic!("Unhandled interrupt {}", interrupt);
102 }
103 self.atomic(|| {
104 self.intc.complete(interrupt);
106 });
107 }
108 }
109}
110
111impl<'a, I: InterruptService + 'a> Chip for Esp32C3<'a, I> {
112 type MPU = PMPUserMPU<8, SimplePMP<16>>;
113 type UserspaceKernelBoundary = SysCall;
114
115 fn service_pending_interrupts(&self) {
116 loop {
117 if self.intc.get_saved_interrupts().is_some() {
118 unsafe {
119 self.handle_pic_interrupts();
120 }
121 }
122
123 if self.intc.get_saved_interrupts().is_none() {
124 break;
125 }
126 }
127
128 self.intc.enable_all();
129 }
130
131 fn has_pending_interrupts(&self) -> bool {
132 self.intc.get_saved_interrupts().is_some()
133 }
134
135 fn mpu(&self) -> &Self::MPU {
136 &self.pmp
137 }
138
139 fn userspace_kernel_boundary(&self) -> &SysCall {
140 &self.userspace_kernel_boundary
141 }
142
143 fn sleep(&self) {
144 unsafe {
145 rv32i::support::wfi();
146 }
147 }
148
149 unsafe fn atomic<F, R>(&self, f: F) -> R
150 where
151 F: FnOnce() -> R,
152 {
153 rv32i::support::atomic(f)
154 }
155
156 unsafe fn print_state(&self, writer: &mut dyn Write) {
157 let mcval: csr::mcause::Trap = core::convert::From::from(csr::CSR.mcause.extract());
158 let _ = writer.write_fmt(format_args!("\r\n---| RISC-V Machine State |---\r\n"));
159 let _ = writer.write_fmt(format_args!("Last cause (mcause): "));
160 rv32i::print_mcause(mcval, writer);
161 let interrupt = csr::CSR.mcause.read(csr::mcause::mcause::is_interrupt);
162 let code = csr::CSR.mcause.read(csr::mcause::mcause::reason);
163 let _ = writer.write_fmt(format_args!(
164 " (interrupt={}, exception code={:#010X})",
165 interrupt, code
166 ));
167 let _ = writer.write_fmt(format_args!(
168 "\r\nLast value (mtval): {:#010X}\
169 \r\n\
170 \r\nSystem register dump:\
171 \r\n mepc: {:#010X} mstatus: {:#010X}\
172 \r\n mtvec: {:#010X}",
173 csr::CSR.mtval.get(),
174 csr::CSR.mepc.get(),
175 csr::CSR.mstatus.get(),
176 csr::CSR.mtvec.get()
177 ));
178 let mstatus = csr::CSR.mstatus.extract();
179 let uie = mstatus.is_set(csr::mstatus::mstatus::uie);
180 let sie = mstatus.is_set(csr::mstatus::mstatus::sie);
181 let mie = mstatus.is_set(csr::mstatus::mstatus::mie);
182 let upie = mstatus.is_set(csr::mstatus::mstatus::upie);
183 let spie = mstatus.is_set(csr::mstatus::mstatus::spie);
184 let mpie = mstatus.is_set(csr::mstatus::mstatus::mpie);
185 let spp = mstatus.is_set(csr::mstatus::mstatus::spp);
186 let _ = writer.write_fmt(format_args!(
187 "\r\n mstatus: {:#010X}\
188 \r\n uie: {:5} upie: {}\
189 \r\n sie: {:5} spie: {}\
190 \r\n mie: {:5} mpie: {}\
191 \r\n spp: {}",
192 mstatus.get(),
193 uie,
194 upie,
195 sie,
196 spie,
197 mie,
198 mpie,
199 spp
200 ));
201 }
202}
203
204fn handle_exception(exception: mcause::Exception) {
205 match exception {
206 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
207
208 mcause::Exception::InstructionMisaligned
209 | mcause::Exception::InstructionFault
210 | mcause::Exception::IllegalInstruction
211 | mcause::Exception::Breakpoint
212 | mcause::Exception::LoadMisaligned
213 | mcause::Exception::LoadFault
214 | mcause::Exception::StoreMisaligned
215 | mcause::Exception::StoreFault
216 | mcause::Exception::MachineEnvCall
217 | mcause::Exception::InstructionPageFault
218 | mcause::Exception::LoadPageFault
219 | mcause::Exception::StorePageFault
220 | mcause::Exception::Unknown => {
221 panic!("fatal exception: {:?}: {:#x}", exception, CSR.mtval.get());
222 }
223 }
224}
225
226unsafe fn handle_interrupt(_intr: mcause::Interrupt) {
227 CSR.mstatus.modify(csr::mstatus::mstatus::mie::CLEAR);
228
229 loop {
233 let interrupt = (*addr_of!(INTC)).next_pending();
234
235 match interrupt {
236 Some(irq) => {
237 (*addr_of!(INTC)).save_interrupt(irq);
239 (*addr_of!(INTC)).disable(irq);
240 }
241 None => {
242 CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
244 break;
245 }
246 }
247 }
248}
249
250#[export_name = "_start_trap_rust_from_kernel"]
255pub unsafe extern "C" fn start_trap_rust() {
256 match mcause::Trap::from(CSR.mcause.extract()) {
257 mcause::Trap::Interrupt(interrupt) => {
258 handle_interrupt(interrupt);
259 }
260 mcause::Trap::Exception(exception) => {
261 handle_exception(exception);
262 }
263 }
264}
265
266#[export_name = "_disable_interrupt_trap_rust_from_app"]
271pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
272 match mcause::Trap::from(mcause_val as usize) {
273 mcause::Trap::Interrupt(interrupt) => {
274 handle_interrupt(interrupt);
275 }
276 _ => {
277 panic!("unexpected non-interrupt\n");
278 }
279 }
280}
281
282pub unsafe fn configure_trap_handler() {
285 CSR.mtvec
286 .write(mtvec::trap_addr.val(_start_trap_vectored as usize >> 2) + mtvec::mode::Vectored)
287}
288
289#[cfg(not(any(doc, all(target_arch = "riscv32", target_os = "none"))))]
293pub extern "C" fn _start_trap_vectored() {
294 use core::hint::unreachable_unchecked;
295 unsafe {
296 unreachable_unchecked();
297 }
298}
299
300#[cfg(any(doc, all(target_arch = "riscv32", target_os = "none")))]
301extern "C" {
302 pub fn _start_trap_vectored();
303}
304
305#[cfg(any(doc, all(target_arch = "riscv32", target_os = "none")))]
306core::arch::global_asm!(
309 "
310 .section .riscv.trap_vectored, \"ax\"
311 .globl _start_trap_vectored
312 _start_trap_vectored:
313 j _start_trap
314 j _start_trap
315 j _start_trap
316 j _start_trap
317 j _start_trap
318 j _start_trap
319 j _start_trap
320 j _start_trap
321 j _start_trap
322 j _start_trap
323 j _start_trap
324 j _start_trap
325 j _start_trap
326 j _start_trap
327 j _start_trap
328 j _start_trap
329 j _start_trap
330 j _start_trap
331 j _start_trap
332 j _start_trap
333 j _start_trap
334 j _start_trap
335 j _start_trap
336 j _start_trap
337 j _start_trap
338 j _start_trap
339 j _start_trap
340 j _start_trap
341 j _start_trap
342 j _start_trap
343 j _start_trap
344 "
345);