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.with_interrupts_disabled(|| {
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 type ThreadIdProvider = rv32i::thread_id::RiscvThreadIdProvider;
118
119 fn mpu(&self) -> &Self::MPU {
120 &self.pmp
121 }
122
123 fn userspace_kernel_boundary(&self) -> &rv32i::syscall::SysCall {
124 &self.userspace_kernel_boundary
125 }
126
127 fn service_pending_interrupts(&self) {
128 loop {
129 let mip = CSR.mip.extract();
130
131 if mip.is_set(mip::mtimer) {
132 self.timer.handle_interrupt();
133 }
134 if self.plic.get_saved_interrupts().is_some() {
135 unsafe {
136 self.handle_plic_interrupts();
137 }
138 }
139
140 if !mip.any_matching_bits_set(mip::mtimer::SET)
141 && self.plic.get_saved_interrupts().is_none()
142 {
143 break;
144 }
145 }
146
147 CSR.mie.modify(mie::mext::SET + mie::mtimer::SET);
150 }
151
152 fn has_pending_interrupts(&self) -> bool {
153 if CSR.mip.is_set(mip::mtimer) {
157 return true;
158 }
159
160 self.plic.get_saved_interrupts().is_some()
162 }
163
164 fn sleep(&self) {
165 unsafe {
166 rv32i::support::wfi();
167 }
168 }
169
170 unsafe fn with_interrupts_disabled<F, R>(&self, f: F) -> R
171 where
172 F: FnOnce() -> R,
173 {
174 rv32i::support::with_interrupts_disabled(f)
175 }
176
177 unsafe fn print_state(&self, writer: &mut dyn Write) {
178 rv32i::print_riscv_state(writer);
179 let _ = writer.write_fmt(format_args!("{}", self.pmp.pmp));
180 }
181}
182
183fn handle_exception(exception: mcause::Exception) {
184 match exception {
185 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
186
187 mcause::Exception::InstructionMisaligned
188 | mcause::Exception::InstructionFault
189 | mcause::Exception::IllegalInstruction
190 | mcause::Exception::Breakpoint
191 | mcause::Exception::LoadMisaligned
192 | mcause::Exception::LoadFault
193 | mcause::Exception::StoreMisaligned
194 | mcause::Exception::StoreFault
195 | mcause::Exception::MachineEnvCall
196 | mcause::Exception::InstructionPageFault
197 | mcause::Exception::LoadPageFault
198 | mcause::Exception::StorePageFault
199 | mcause::Exception::Unknown => {
200 panic!("fatal exception");
201 }
202 }
203}
204
205unsafe fn handle_interrupt(intr: mcause::Interrupt) {
206 match intr {
207 mcause::Interrupt::UserSoft
208 | mcause::Interrupt::UserTimer
209 | mcause::Interrupt::UserExternal => {
210 panic!("unexpected user-mode interrupt");
211 }
212 mcause::Interrupt::SupervisorExternal
213 | mcause::Interrupt::SupervisorTimer
214 | mcause::Interrupt::SupervisorSoft => {
215 panic!("unexpected supervisor-mode interrupt");
216 }
217
218 mcause::Interrupt::MachineSoft => {
219 CSR.mie.modify(mie::msoft::CLEAR);
220 }
221 mcause::Interrupt::MachineTimer => {
222 CSR.mie.modify(mie::mtimer::CLEAR);
223 }
224 mcause::Interrupt::MachineExternal => {
225 CSR.mie.modify(mie::mext::CLEAR);
227
228 loop {
232 let interrupt = (*addr_of!(PLIC)).next_pending();
233
234 match interrupt {
235 Some(irq) => {
236 (*addr_of!(PLIC)).save_interrupt(irq);
238 }
239 None => {
240 CSR.mie.modify(mie::mext::SET);
242
243 break;
244 }
245 }
246 }
247 }
248
249 mcause::Interrupt::Unknown(_) => {
250 panic!("interrupt of unknown cause");
251 }
252 }
253}
254
255#[export_name = "_start_trap_rust_from_kernel"]
260pub unsafe extern "C" fn start_trap_rust() {
261 match mcause::Trap::from(CSR.mcause.extract()) {
262 mcause::Trap::Interrupt(interrupt) => {
263 handle_interrupt(interrupt);
264 }
265 mcause::Trap::Exception(exception) => {
266 handle_exception(exception);
267 }
268 }
269}
270
271#[export_name = "_disable_interrupt_trap_rust_from_app"]
276pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
277 match mcause::Trap::from(mcause_val as usize) {
278 mcause::Trap::Interrupt(interrupt) => {
279 handle_interrupt(interrupt);
280 }
281 _ => {
282 panic!("unexpected non-interrupt\n");
283 }
284 }
285}
286
287#[export_name = "_trap_handler_active"]
298static mut TRAP_HANDLER_ACTIVE: [usize; 1] = [0; 1];