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(this: Option<&Self>, writer: &mut dyn Write) {
106        let _ = writer.write_fmt(format_args!(
107            "\r\n---| LiteX configuration for {} |---",
108            this.map_or("unknown board (in trap handler thread)", |t| t
109                .soc_identifier),
110        ));
111        rv32i::print_riscv_state(writer);
112        if let Some(t) = this {
113            let _ = writer.write_fmt(format_args!("{}", t.pmp_mpu.pmp));
114        }
115    }
116}
117
118fn handle_exception(exception: mcause::Exception) {
119    match exception {
120        mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
121
122        mcause::Exception::InstructionMisaligned
123        | mcause::Exception::InstructionFault
124        | mcause::Exception::IllegalInstruction
125        | mcause::Exception::Breakpoint
126        | mcause::Exception::LoadMisaligned
127        | mcause::Exception::LoadFault
128        | mcause::Exception::StoreMisaligned
129        | mcause::Exception::StoreFault
130        | mcause::Exception::MachineEnvCall
131        | mcause::Exception::InstructionPageFault
132        | mcause::Exception::LoadPageFault
133        | mcause::Exception::StorePageFault
134        | mcause::Exception::Unknown => {
135            panic!("fatal exception");
136        }
137    }
138}
139
140unsafe fn handle_interrupt(intr: mcause::Interrupt) {
141    match intr {
142        mcause::Interrupt::UserSoft
143        | mcause::Interrupt::UserTimer
144        | mcause::Interrupt::UserExternal => {
145            debug!("unexpected user-mode interrupt");
146        }
147        mcause::Interrupt::SupervisorExternal
148        | mcause::Interrupt::SupervisorTimer
149        | mcause::Interrupt::SupervisorSoft => {
150            debug!("unexpected supervisor-mode interrupt");
151        }
152
153        mcause::Interrupt::MachineSoft => {
154            CSR.mie.modify(mie::msoft::CLEAR);
155        }
156        mcause::Interrupt::MachineTimer => {
157            CSR.mie.modify(mie::mtimer::CLEAR);
158        }
159        mcause::Interrupt::MachineExternal => {
160            CSR.mie.modify(mie::mext::CLEAR);
162
163            if !(*addr_of!(INTERRUPT_CONTROLLER)).save_pending() {
169                CSR.mie.modify(mie::mext::SET);
170            }
171        }
172
173        mcause::Interrupt::Unknown(_) => {
174            debug!("interrupt of unknown cause");
175        }
176    }
177}
178
179#[export_name = "_start_trap_rust_from_kernel"]
184pub unsafe extern "C" fn start_trap_rust() {
185    match mcause::Trap::from(CSR.mcause.extract()) {
186        mcause::Trap::Interrupt(interrupt) => {
187            handle_interrupt(interrupt);
188        }
189        mcause::Trap::Exception(exception) => {
190            handle_exception(exception);
191        }
192    }
193}
194
195#[export_name = "_disable_interrupt_trap_rust_from_app"]
200pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
201    match mcause::Trap::from(mcause_val as usize) {
202        mcause::Trap::Interrupt(interrupt) => {
203            handle_interrupt(interrupt);
204        }
205        _ => {
206            panic!("unexpected non-interrupt\n");
207        }
208    }
209}
210
211#[export_name = "_trap_handler_active"]
217static mut TRAP_HANDLER_ACTIVE: [usize; 1] = [0; 1];