1use crate::machine_timer::Clint;
9use core::fmt::Write;
10use core::ptr::addr_of;
11use kernel::platform::chip::{Chip, InterruptService};
12use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
13use kernel::utilities::StaticRef;
14use rv32i::csr::{mcause, mie::mie, mip::mip, CSR};
15use rv32i::pmp::{simple::SimplePMP, PMPUserMPU};
16use rv32i::syscall::SysCall;
17
18use crate::pic::Pic;
19use crate::pic::PicRegisters;
20
21pub const PIC_BASE: StaticRef<PicRegisters> =
22 unsafe { StaticRef::new(0xf00c_0000 as *const PicRegisters) };
23
24pub static mut PIC: Pic = Pic::new(PIC_BASE);
25
26pub struct VeeR<'a, I: InterruptService + 'a> {
27 userspace_kernel_boundary: SysCall,
28 pic: &'a Pic,
29 mtimer: &'static Clint<'static>,
30 pic_interrupt_service: &'a I,
31 pmp: PMPUserMPU<4, SimplePMP<8>>,
32}
33
34pub struct VeeRDefaultPeripherals {
35 pub sim_uart: crate::uart::SimUartType,
36}
37
38impl VeeRDefaultPeripherals {
39 pub fn new() -> Self {
40 Self {
41 sim_uart: crate::uart::SimUartType::new(),
42 }
43 }
44
45 pub fn init(&'static self) {
46 kernel::deferred_call::DeferredCallClient::register(&self.sim_uart);
47 }
48}
49
50impl Default for VeeRDefaultPeripherals {
51 fn default() -> Self {
52 Self::new()
53 }
54}
55
56impl InterruptService for VeeRDefaultPeripherals {
57 unsafe fn service_interrupt(&self, _interrupt: u32) -> bool {
58 true
59 }
60}
61
62impl<'a, I: InterruptService + 'a> VeeR<'a, I> {
63 pub unsafe fn new(pic_interrupt_service: &'a I, mtimer: &'static Clint) -> Self {
66 Self {
67 userspace_kernel_boundary: SysCall::new(),
68 pic: &*addr_of!(PIC),
69 mtimer,
70 pic_interrupt_service,
71 pmp: PMPUserMPU::new(SimplePMP::new().unwrap()),
72 }
73 }
74
75 pub fn enable_pic_interrupts(&self) {
76 self.pic.enable_all();
77 }
78
79 unsafe fn handle_pic_interrupts(&self) {
80 while let Some(interrupt) = self.pic.get_saved_interrupts() {
81 if !self.pic_interrupt_service.service_interrupt(interrupt) {
82 panic!("Unhandled interrupt {}", interrupt);
83 }
84 self.with_interrupts_disabled(|| {
85 self.pic.complete(interrupt);
87 });
88 }
89 }
90}
91
92impl<'a, I: InterruptService + 'a> kernel::platform::chip::Chip for VeeR<'a, I> {
93 type MPU = PMPUserMPU<4, SimplePMP<8>>;
94 type UserspaceKernelBoundary = SysCall;
95 type ThreadIdProvider = rv32i::thread_id::RiscvThreadIdProvider;
96
97 fn init() {}
98
99 fn mpu(&self) -> &Self::MPU {
100 &self.pmp
101 }
102
103 fn userspace_kernel_boundary(&self) -> &SysCall {
104 &self.userspace_kernel_boundary
105 }
106
107 fn service_pending_interrupts(&self) {
108 loop {
109 let mip = CSR.mip.extract();
110
111 if mip.is_set(mip::mtimer) {
113 self.mtimer.handle_interrupt();
114 }
115 if self.pic.get_saved_interrupts().is_some() {
116 unsafe {
117 self.handle_pic_interrupts();
118 }
119 }
120
121 if !mip.any_matching_bits_set(mip::mtimer::SET)
122 && self.pic.get_saved_interrupts().is_none()
123 {
124 break;
125 }
126 }
127
128 CSR.mie.modify(mie::mext::SET + mie::mtimer::SET);
131 }
132
133 fn has_pending_interrupts(&self) -> bool {
134 let mip = CSR.mip.extract();
135 self.pic.get_saved_interrupts().is_some() || mip.any_matching_bits_set(mip::mtimer::SET)
136 }
137
138 fn sleep(&self) {
139 unsafe {
140 rv32i::support::wfi();
141 }
142 }
143
144 unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
145 where
146 F: FnOnce() -> R,
147 {
148 rv32i::support::with_interrupts_disabled(f)
149 }
150
151 unsafe fn print_state(_this: Option<&Self>, writer: &mut dyn Write) {
152 rv32i::print_riscv_state(writer);
153 }
154}
155
156fn handle_exception(exception: mcause::Exception) {
157 match exception {
158 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
159
160 mcause::Exception::InstructionMisaligned
161 | mcause::Exception::InstructionFault
162 | mcause::Exception::IllegalInstruction
163 | mcause::Exception::Breakpoint
164 | mcause::Exception::LoadMisaligned
165 | mcause::Exception::LoadFault
166 | mcause::Exception::StoreMisaligned
167 | mcause::Exception::StoreFault
168 | mcause::Exception::MachineEnvCall
169 | mcause::Exception::InstructionPageFault
170 | mcause::Exception::LoadPageFault
171 | mcause::Exception::StorePageFault
172 | mcause::Exception::Unknown => {
173 panic!("fatal exception: {:?}: {:#x}", exception, CSR.mtval.get());
174 }
175 }
176}
177
178unsafe fn handle_interrupt(intr: mcause::Interrupt) {
179 match intr {
180 mcause::Interrupt::UserSoft
181 | mcause::Interrupt::UserTimer
182 | mcause::Interrupt::UserExternal => {
183 panic!("unexpected user-mode interrupt");
184 }
185 mcause::Interrupt::SupervisorExternal
186 | mcause::Interrupt::SupervisorTimer
187 | mcause::Interrupt::SupervisorSoft => {
188 panic!("unexpected supervisor-mode interrupt");
189 }
190
191 mcause::Interrupt::MachineSoft => {
192 CSR.mie.modify(mie::msoft::CLEAR);
193 }
194 mcause::Interrupt::MachineTimer => {
195 CSR.mie.modify(mie::mtimer::CLEAR);
196 }
197 mcause::Interrupt::MachineExternal => {
198 CSR.mie.modify(mie::mext::CLEAR);
200
201 loop {
205 let interrupt = (*addr_of!(PIC)).next_pending();
206
207 match interrupt {
208 Some(irq) => {
209 (*addr_of!(PIC)).save_interrupt(irq);
211 }
212 None => {
213 CSR.mie.modify(mie::mext::SET);
215 break;
216 }
217 }
218 }
219 }
220
221 mcause::Interrupt::Unknown(_) => {
222 panic!("interrupt of unknown cause");
223 }
224 }
225}
226
227#[export_name = "_start_trap_rust_from_kernel"]
235pub unsafe extern "C" fn start_trap_rust() {
236 match mcause::Trap::from(CSR.mcause.extract()) {
237 mcause::Trap::Interrupt(interrupt) => {
238 handle_interrupt(interrupt);
239 }
240 mcause::Trap::Exception(exception) => {
241 handle_exception(exception);
242 }
243 }
244}
245
246#[export_name = "_disable_interrupt_trap_rust_from_app"]
251pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
252 match mcause::Trap::from(mcause_val as usize) {
253 mcause::Trap::Interrupt(interrupt) => unsafe {
254 handle_interrupt(interrupt);
255 },
256 _ => {
257 panic!("unexpected non-interrupt\n");
258 }
259 }
260}
261
262#[export_name = "_trap_handler_active"]
268static mut TRAP_HANDLER_ACTIVE: [usize; 1] = [0; 1];