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.with_interrupts_disabled(|| {
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 type ThreadIdProvider = rv32i::thread_id::RiscvThreadIdProvider;
115
116 fn service_pending_interrupts(&self) {
117 loop {
118 if self.intc.get_saved_interrupts().is_some() {
119 unsafe {
120 self.handle_pic_interrupts();
121 }
122 }
123
124 if self.intc.get_saved_interrupts().is_none() {
125 break;
126 }
127 }
128
129 self.intc.enable_all();
130 }
131
132 fn has_pending_interrupts(&self) -> bool {
133 self.intc.get_saved_interrupts().is_some()
134 }
135
136 fn mpu(&self) -> &Self::MPU {
137 &self.pmp
138 }
139
140 fn userspace_kernel_boundary(&self) -> &SysCall {
141 &self.userspace_kernel_boundary
142 }
143
144 fn sleep(&self) {
145 unsafe {
146 rv32i::support::wfi();
147 }
148 }
149
150 unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
151 where
152 F: FnOnce() -> R,
153 {
154 rv32i::support::with_interrupts_disabled(f)
155 }
156
157 unsafe fn print_state(&self, writer: &mut dyn Write) {
158 let mcval: csr::mcause::Trap = core::convert::From::from(csr::CSR.mcause.extract());
159 let _ = writer.write_fmt(format_args!("\r\n---| RISC-V Machine State |---\r\n"));
160 let _ = writer.write_fmt(format_args!("Last cause (mcause): "));
161 rv32i::print_mcause(mcval, writer);
162 let interrupt = csr::CSR.mcause.read(csr::mcause::mcause::is_interrupt);
163 let code = csr::CSR.mcause.read(csr::mcause::mcause::reason);
164 let _ = writer.write_fmt(format_args!(
165 " (interrupt={}, exception code={:#010X})",
166 interrupt, code
167 ));
168 let _ = writer.write_fmt(format_args!(
169 "\r\nLast value (mtval): {:#010X}\
170 \r\n\
171 \r\nSystem register dump:\
172 \r\n mepc: {:#010X} mstatus: {:#010X}\
173 \r\n mtvec: {:#010X}",
174 csr::CSR.mtval.get(),
175 csr::CSR.mepc.get(),
176 csr::CSR.mstatus.get(),
177 csr::CSR.mtvec.get()
178 ));
179 let mstatus = csr::CSR.mstatus.extract();
180 let uie = mstatus.is_set(csr::mstatus::mstatus::uie);
181 let sie = mstatus.is_set(csr::mstatus::mstatus::sie);
182 let mie = mstatus.is_set(csr::mstatus::mstatus::mie);
183 let upie = mstatus.is_set(csr::mstatus::mstatus::upie);
184 let spie = mstatus.is_set(csr::mstatus::mstatus::spie);
185 let mpie = mstatus.is_set(csr::mstatus::mstatus::mpie);
186 let spp = mstatus.is_set(csr::mstatus::mstatus::spp);
187 let _ = writer.write_fmt(format_args!(
188 "\r\n mstatus: {:#010X}\
189 \r\n uie: {:5} upie: {}\
190 \r\n sie: {:5} spie: {}\
191 \r\n mie: {:5} mpie: {}\
192 \r\n spp: {}",
193 mstatus.get(),
194 uie,
195 upie,
196 sie,
197 spie,
198 mie,
199 mpie,
200 spp
201 ));
202 }
203}
204
205fn handle_exception(exception: mcause::Exception) {
206 match exception {
207 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
208
209 mcause::Exception::InstructionMisaligned
210 | mcause::Exception::InstructionFault
211 | mcause::Exception::IllegalInstruction
212 | mcause::Exception::Breakpoint
213 | mcause::Exception::LoadMisaligned
214 | mcause::Exception::LoadFault
215 | mcause::Exception::StoreMisaligned
216 | mcause::Exception::StoreFault
217 | mcause::Exception::MachineEnvCall
218 | mcause::Exception::InstructionPageFault
219 | mcause::Exception::LoadPageFault
220 | mcause::Exception::StorePageFault
221 | mcause::Exception::Unknown => {
222 panic!("fatal exception: {:?}: {:#x}", exception, CSR.mtval.get());
223 }
224 }
225}
226
227unsafe fn handle_interrupt(_intr: mcause::Interrupt) {
228 CSR.mstatus.modify(csr::mstatus::mstatus::mie::CLEAR);
229
230 loop {
234 let interrupt = (*addr_of!(INTC)).next_pending();
235
236 match interrupt {
237 Some(irq) => {
238 (*addr_of!(INTC)).save_interrupt(irq);
240 (*addr_of!(INTC)).disable(irq);
241 }
242 None => {
243 CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
245 break;
246 }
247 }
248 }
249}
250
251#[export_name = "_start_trap_rust_from_kernel"]
256pub unsafe extern "C" fn start_trap_rust() {
257 match mcause::Trap::from(CSR.mcause.extract()) {
258 mcause::Trap::Interrupt(interrupt) => {
259 handle_interrupt(interrupt);
260 }
261 mcause::Trap::Exception(exception) => {
262 handle_exception(exception);
263 }
264 }
265}
266
267#[export_name = "_disable_interrupt_trap_rust_from_app"]
272pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
273 match mcause::Trap::from(mcause_val as usize) {
274 mcause::Trap::Interrupt(interrupt) => {
275 handle_interrupt(interrupt);
276 }
277 _ => {
278 panic!("unexpected non-interrupt\n");
279 }
280 }
281}
282
283pub unsafe fn configure_trap_handler() {
286 CSR.mtvec
287 .write(mtvec::trap_addr.val(_start_trap_vectored as usize >> 2) + mtvec::mode::Vectored)
288}
289
290#[cfg(not(any(doc, all(target_arch = "riscv32", target_os = "none"))))]
294pub extern "C" fn _start_trap_vectored() {
295 use core::hint::unreachable_unchecked;
296 unsafe {
297 unreachable_unchecked();
298 }
299}
300
301#[cfg(any(doc, all(target_arch = "riscv32", target_os = "none")))]
302#[link_section = ".riscv.trap_vectored"]
303#[unsafe(naked)]
304pub extern "C" fn _start_trap_vectored() -> ! {
305 use core::arch::naked_asm;
306 naked_asm!(
309 "
310 j {start_trap}
311 j {start_trap}
312 j {start_trap}
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 ",
343 start_trap = sym rv32i::_start_trap,
344 );
345}
346
347#[export_name = "_trap_handler_active"]
353static mut TRAP_HANDLER_ACTIVE: [usize; 1] = [0; 1];