qemu_rv32_virt_chip/
chip.rs1use core::fmt::Write;
8use core::ptr::addr_of;
9
10use kernel::debug;
11use kernel::hil::time::Freq10MHz;
12use kernel::platform::chip::{Chip, InterruptService};
13
14use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
15
16use rv32i::csr::{mcause, mie::mie, mip::mip, CSR};
17
18use crate::plic::PLIC;
19use sifive::plic::Plic;
20
21use crate::interrupts;
22
23use virtio::transports::mmio::VirtIOMMIODevice;
24
25type QemuRv32VirtPMP = rv32i::pmp::PMPUserMPU<
26 5,
27 rv32i::pmp::kernel_protection_mml_epmp::KernelProtectionMMLEPMP<16, 5>,
28>;
29
30pub type QemuRv32VirtClint<'a> = sifive::clint::Clint<'a, Freq10MHz>;
31
32pub struct QemuRv32VirtChip<'a, I: InterruptService + 'a> {
33 userspace_kernel_boundary: rv32i::syscall::SysCall,
34 pmp: QemuRv32VirtPMP,
35 plic: &'a Plic,
36 timer: &'a QemuRv32VirtClint<'a>,
37 plic_interrupt_service: &'a I,
38}
39
40pub struct QemuRv32VirtDefaultPeripherals<'a> {
41 pub uart0: crate::uart::Uart16550<'a>,
42 pub virtio_mmio: [VirtIOMMIODevice; 8],
43}
44
45impl QemuRv32VirtDefaultPeripherals<'_> {
46 pub fn new() -> Self {
47 Self {
48 uart0: crate::uart::Uart16550::new(crate::uart::UART0_BASE),
49 virtio_mmio: [
50 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_0_BASE),
51 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_1_BASE),
52 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_2_BASE),
53 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_3_BASE),
54 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_4_BASE),
55 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_5_BASE),
56 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_6_BASE),
57 VirtIOMMIODevice::new(crate::virtio_mmio::VIRTIO_MMIO_7_BASE),
58 ],
59 }
60 }
61}
62
63impl InterruptService for QemuRv32VirtDefaultPeripherals<'_> {
64 unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
65 match interrupt {
66 interrupts::UART0 => self.uart0.handle_interrupt(),
67 interrupts::VIRTIO_MMIO_0 => self.virtio_mmio[0].handle_interrupt(),
68 interrupts::VIRTIO_MMIO_1 => self.virtio_mmio[1].handle_interrupt(),
69 interrupts::VIRTIO_MMIO_2 => self.virtio_mmio[2].handle_interrupt(),
70 interrupts::VIRTIO_MMIO_3 => self.virtio_mmio[3].handle_interrupt(),
71 interrupts::VIRTIO_MMIO_4 => self.virtio_mmio[4].handle_interrupt(),
72 interrupts::VIRTIO_MMIO_5 => self.virtio_mmio[5].handle_interrupt(),
73 interrupts::VIRTIO_MMIO_6 => self.virtio_mmio[6].handle_interrupt(),
74 interrupts::VIRTIO_MMIO_7 => self.virtio_mmio[7].handle_interrupt(),
75 _ => return false,
76 }
77 true
78 }
79}
80
81impl<'a, I: InterruptService + 'a> QemuRv32VirtChip<'a, I> {
82 pub unsafe fn new(
83 plic_interrupt_service: &'a I,
84 timer: &'a QemuRv32VirtClint<'a>,
85 pmp: rv32i::pmp::kernel_protection_mml_epmp::KernelProtectionMMLEPMP<16, 5>,
86 ) -> Self {
87 Self {
88 userspace_kernel_boundary: rv32i::syscall::SysCall::new(),
89 pmp: rv32i::pmp::PMPUserMPU::new(pmp),
90 plic: &*addr_of!(PLIC),
91 timer,
92 plic_interrupt_service,
93 }
94 }
95
96 pub unsafe fn enable_plic_interrupts(&self) {
97 self.plic.disable_all();
98 self.plic.clear_all_pending();
99 self.plic.enable_all();
100 }
101
102 unsafe fn handle_plic_interrupts(&self) {
103 while let Some(interrupt) = self.plic.get_saved_interrupts() {
104 if !self.plic_interrupt_service.service_interrupt(interrupt) {
105 debug!("Pidx {}", interrupt);
106 }
107 self.atomic(|| {
108 self.plic.complete(interrupt);
109 });
110 }
111 }
112}
113
114impl<'a, I: InterruptService + 'a> Chip for QemuRv32VirtChip<'a, I> {
115 type MPU = QemuRv32VirtPMP;
116 type UserspaceKernelBoundary = rv32i::syscall::SysCall;
117
118 fn mpu(&self) -> &Self::MPU {
119 &self.pmp
120 }
121
122 fn userspace_kernel_boundary(&self) -> &rv32i::syscall::SysCall {
123 &self.userspace_kernel_boundary
124 }
125
126 fn service_pending_interrupts(&self) {
127 loop {
128 let mip = CSR.mip.extract();
129
130 if mip.is_set(mip::mtimer) {
131 self.timer.handle_interrupt();
132 }
133 if self.plic.get_saved_interrupts().is_some() {
134 unsafe {
135 self.handle_plic_interrupts();
136 }
137 }
138
139 if !mip.any_matching_bits_set(mip::mtimer::SET)
140 && self.plic.get_saved_interrupts().is_none()
141 {
142 break;
143 }
144 }
145
146 CSR.mie.modify(mie::mext::SET + mie::mtimer::SET);
149 }
150
151 fn has_pending_interrupts(&self) -> bool {
152 if CSR.mip.is_set(mip::mtimer) {
156 return true;
157 }
158
159 self.plic.get_saved_interrupts().is_some()
161 }
162
163 fn sleep(&self) {
164 unsafe {
165 rv32i::support::wfi();
166 }
167 }
168
169 unsafe fn atomic<F, R>(&self, f: F) -> R
170 where
171 F: FnOnce() -> R,
172 {
173 rv32i::support::atomic(f)
174 }
175
176 unsafe fn print_state(&self, writer: &mut dyn Write) {
177 rv32i::print_riscv_state(writer);
178 let _ = writer.write_fmt(format_args!("{}", self.pmp.pmp));
179 }
180}
181
182fn handle_exception(exception: mcause::Exception) {
183 match exception {
184 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
185
186 mcause::Exception::InstructionMisaligned
187 | mcause::Exception::InstructionFault
188 | mcause::Exception::IllegalInstruction
189 | mcause::Exception::Breakpoint
190 | mcause::Exception::LoadMisaligned
191 | mcause::Exception::LoadFault
192 | mcause::Exception::StoreMisaligned
193 | mcause::Exception::StoreFault
194 | mcause::Exception::MachineEnvCall
195 | mcause::Exception::InstructionPageFault
196 | mcause::Exception::LoadPageFault
197 | mcause::Exception::StorePageFault
198 | mcause::Exception::Unknown => {
199 panic!("fatal exception");
200 }
201 }
202}
203
204unsafe fn handle_interrupt(intr: mcause::Interrupt) {
205 match intr {
206 mcause::Interrupt::UserSoft
207 | mcause::Interrupt::UserTimer
208 | mcause::Interrupt::UserExternal => {
209 panic!("unexpected user-mode interrupt");
210 }
211 mcause::Interrupt::SupervisorExternal
212 | mcause::Interrupt::SupervisorTimer
213 | mcause::Interrupt::SupervisorSoft => {
214 panic!("unexpected supervisor-mode interrupt");
215 }
216
217 mcause::Interrupt::MachineSoft => {
218 CSR.mie.modify(mie::msoft::CLEAR);
219 }
220 mcause::Interrupt::MachineTimer => {
221 CSR.mie.modify(mie::mtimer::CLEAR);
222 }
223 mcause::Interrupt::MachineExternal => {
224 CSR.mie.modify(mie::mext::CLEAR);
226
227 loop {
231 let interrupt = (*addr_of!(PLIC)).next_pending();
232
233 match interrupt {
234 Some(irq) => {
235 (*addr_of!(PLIC)).save_interrupt(irq);
237 }
238 None => {
239 CSR.mie.modify(mie::mext::SET);
241
242 break;
243 }
244 }
245 }
246 }
247
248 mcause::Interrupt::Unknown(_) => {
249 panic!("interrupt of unknown cause");
250 }
251 }
252}
253
254#[export_name = "_start_trap_rust_from_kernel"]
259pub unsafe extern "C" fn start_trap_rust() {
260 match mcause::Trap::from(CSR.mcause.extract()) {
261 mcause::Trap::Interrupt(interrupt) => {
262 handle_interrupt(interrupt);
263 }
264 mcause::Trap::Exception(exception) => {
265 handle_exception(exception);
266 }
267 }
268}
269
270#[export_name = "_disable_interrupt_trap_rust_from_app"]
275pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
276 match mcause::Trap::from(mcause_val as usize) {
277 mcause::Trap::Interrupt(interrupt) => {
278 handle_interrupt(interrupt);
279 }
280 _ => {
281 panic!("unexpected non-interrupt\n");
282 }
283 }
284}