1use core::fmt::Write;
8use core::ptr::addr_of;
9use kernel::debug;
10use kernel::platform::chip::InterruptService;
11use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
12use rv32i::csr::{mcause, mie::mie, CSR};
13use rv32i::pmp::{kernel_protection::KernelProtectionPMP, PMPUserMPU};
14use rv32i::syscall::SysCall;
15
16use crate::interrupt_controller::VexRiscvInterruptController;
17
18static mut INTERRUPT_CONTROLLER: VexRiscvInterruptController = VexRiscvInterruptController::new();
21
22pub struct LiteXVexRiscv<I: 'static + InterruptService> {
26 soc_identifier: &'static str,
27 userspace_kernel_boundary: SysCall,
28 interrupt_controller: &'static VexRiscvInterruptController,
29 pmp_mpu: PMPUserMPU<4, KernelProtectionPMP<16>>,
30 interrupt_service: &'static I,
31}
32
33impl<I: 'static + InterruptService> LiteXVexRiscv<I> {
34 pub unsafe fn new(
35 soc_identifier: &'static str,
36 interrupt_service: &'static I,
37 pmp: KernelProtectionPMP<16>,
38 ) -> Self {
39 Self {
40 soc_identifier,
41 userspace_kernel_boundary: SysCall::new(),
42 interrupt_controller: &*addr_of!(INTERRUPT_CONTROLLER),
43 pmp_mpu: PMPUserMPU::new(pmp),
44 interrupt_service,
45 }
46 }
47
48 pub unsafe fn unmask_interrupts(&self) {
49 VexRiscvInterruptController::unmask_all_interrupts();
50 }
51
52 unsafe fn handle_interrupts(&self) {
53 while let Some(interrupt) = self.interrupt_controller.next_saved() {
54 if !self.interrupt_service.service_interrupt(interrupt as u32) {
55 debug!("Unknown interrupt: {}", interrupt);
56 }
57 self.interrupt_controller.complete_saved(interrupt);
58 }
59 }
60}
61
62impl<I: 'static + InterruptService> kernel::platform::chip::Chip for LiteXVexRiscv<I> {
63 type MPU = PMPUserMPU<4, KernelProtectionPMP<16>>;
64 type UserspaceKernelBoundary = SysCall;
65 type ThreadIdProvider = rv32i::thread_id::RiscvThreadIdProvider;
66
67 fn mpu(&self) -> &Self::MPU {
68 &self.pmp_mpu
69 }
70
71 fn userspace_kernel_boundary(&self) -> &SysCall {
72 &self.userspace_kernel_boundary
73 }
74
75 fn service_pending_interrupts(&self) {
76 while self.interrupt_controller.next_saved().is_some() {
77 unsafe {
78 self.handle_interrupts();
79 }
80 }
81
82 CSR.mie.modify(mie::mext::SET);
86 }
87
88 fn has_pending_interrupts(&self) -> bool {
89 self.interrupt_controller.next_saved().is_some()
90 }
91
92 fn sleep(&self) {
93 unsafe {
94 rv32i::support::wfi();
95 }
96 }
97
98 unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
99 where
100 F: FnOnce() -> R,
101 {
102 rv32i::support::with_interrupts_disabled(f)
103 }
104
105 unsafe fn print_state(&self, writer: &mut dyn Write) {
106 let _ = writer.write_fmt(format_args!(
107 "\r\n---| LiteX configuration for {} |---",
108 self.soc_identifier,
109 ));
110 rv32i::print_riscv_state(writer);
111 let _ = writer.write_fmt(format_args!("{}", self.pmp_mpu.pmp));
112 }
113}
114
115fn handle_exception(exception: mcause::Exception) {
116 match exception {
117 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
118
119 mcause::Exception::InstructionMisaligned
120 | mcause::Exception::InstructionFault
121 | mcause::Exception::IllegalInstruction
122 | mcause::Exception::Breakpoint
123 | mcause::Exception::LoadMisaligned
124 | mcause::Exception::LoadFault
125 | mcause::Exception::StoreMisaligned
126 | mcause::Exception::StoreFault
127 | mcause::Exception::MachineEnvCall
128 | mcause::Exception::InstructionPageFault
129 | mcause::Exception::LoadPageFault
130 | mcause::Exception::StorePageFault
131 | mcause::Exception::Unknown => {
132 panic!("fatal exception");
133 }
134 }
135}
136
137unsafe fn handle_interrupt(intr: mcause::Interrupt) {
138 match intr {
139 mcause::Interrupt::UserSoft
140 | mcause::Interrupt::UserTimer
141 | mcause::Interrupt::UserExternal => {
142 debug!("unexpected user-mode interrupt");
143 }
144 mcause::Interrupt::SupervisorExternal
145 | mcause::Interrupt::SupervisorTimer
146 | mcause::Interrupt::SupervisorSoft => {
147 debug!("unexpected supervisor-mode interrupt");
148 }
149
150 mcause::Interrupt::MachineSoft => {
151 CSR.mie.modify(mie::msoft::CLEAR);
152 }
153 mcause::Interrupt::MachineTimer => {
154 CSR.mie.modify(mie::mtimer::CLEAR);
155 }
156 mcause::Interrupt::MachineExternal => {
157 CSR.mie.modify(mie::mext::CLEAR);
159
160 if !(*addr_of!(INTERRUPT_CONTROLLER)).save_pending() {
166 CSR.mie.modify(mie::mext::SET);
167 }
168 }
169
170 mcause::Interrupt::Unknown(_) => {
171 debug!("interrupt of unknown cause");
172 }
173 }
174}
175
176#[export_name = "_start_trap_rust_from_kernel"]
181pub unsafe extern "C" fn start_trap_rust() {
182 match mcause::Trap::from(CSR.mcause.extract()) {
183 mcause::Trap::Interrupt(interrupt) => {
184 handle_interrupt(interrupt);
185 }
186 mcause::Trap::Exception(exception) => {
187 handle_exception(exception);
188 }
189 }
190}
191
192#[export_name = "_disable_interrupt_trap_rust_from_app"]
197pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
198 match mcause::Trap::from(mcause_val as usize) {
199 mcause::Trap::Interrupt(interrupt) => {
200 handle_interrupt(interrupt);
201 }
202 _ => {
203 panic!("unexpected non-interrupt\n");
204 }
205 }
206}
207
208#[export_name = "_trap_handler_active"]
214static mut TRAP_HANDLER_ACTIVE: [usize; 1] = [0; 1];