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(this: Option<&Self>, writer: &mut dyn Write) {
178 rv32i::print_riscv_state(writer);
179 if let Some(t) = this {
180 let _ = writer.write_fmt(format_args!("{}", t.pmp.pmp));
181 }
182 }
183}
184
185fn handle_exception(exception: mcause::Exception) {
186 match exception {
187 mcause::Exception::UserEnvCall | mcause::Exception::SupervisorEnvCall => (),
188
189 mcause::Exception::InstructionMisaligned
190 | mcause::Exception::InstructionFault
191 | mcause::Exception::IllegalInstruction
192 | mcause::Exception::Breakpoint
193 | mcause::Exception::LoadMisaligned
194 | mcause::Exception::LoadFault
195 | mcause::Exception::StoreMisaligned
196 | mcause::Exception::StoreFault
197 | mcause::Exception::MachineEnvCall
198 | mcause::Exception::InstructionPageFault
199 | mcause::Exception::LoadPageFault
200 | mcause::Exception::StorePageFault
201 | mcause::Exception::Unknown => {
202 panic!("fatal exception");
203 }
204 }
205}
206
207unsafe fn handle_interrupt(intr: mcause::Interrupt) {
208 match intr {
209 mcause::Interrupt::UserSoft
210 | mcause::Interrupt::UserTimer
211 | mcause::Interrupt::UserExternal => {
212 panic!("unexpected user-mode interrupt");
213 }
214 mcause::Interrupt::SupervisorExternal
215 | mcause::Interrupt::SupervisorTimer
216 | mcause::Interrupt::SupervisorSoft => {
217 panic!("unexpected supervisor-mode interrupt");
218 }
219
220 mcause::Interrupt::MachineSoft => {
221 CSR.mie.modify(mie::msoft::CLEAR);
222 }
223 mcause::Interrupt::MachineTimer => {
224 CSR.mie.modify(mie::mtimer::CLEAR);
225 }
226 mcause::Interrupt::MachineExternal => {
227 CSR.mie.modify(mie::mext::CLEAR);
229
230 loop {
234 let interrupt = (*addr_of!(PLIC)).next_pending();
235
236 match interrupt {
237 Some(irq) => {
238 (*addr_of!(PLIC)).save_interrupt(irq);
240 }
241 None => {
242 CSR.mie.modify(mie::mext::SET);
244
245 break;
246 }
247 }
248 }
249 }
250
251 mcause::Interrupt::Unknown(_) => {
252 panic!("interrupt of unknown cause");
253 }
254 }
255}
256
257#[export_name = "_start_trap_rust_from_kernel"]
262pub unsafe extern "C" fn start_trap_rust() {
263 match mcause::Trap::from(CSR.mcause.extract()) {
264 mcause::Trap::Interrupt(interrupt) => {
265 handle_interrupt(interrupt);
266 }
267 mcause::Trap::Exception(exception) => {
268 handle_exception(exception);
269 }
270 }
271}
272
273#[export_name = "_disable_interrupt_trap_rust_from_app"]
278pub unsafe extern "C" fn disable_interrupt_trap_handler(mcause_val: u32) {
279 match mcause::Trap::from(mcause_val as usize) {
280 mcause::Trap::Interrupt(interrupt) => {
281 handle_interrupt(interrupt);
282 }
283 _ => {
284 panic!("unexpected non-interrupt\n");
285 }
286 }
287}
288
289#[export_name = "_trap_handler_active"]
300static mut TRAP_HANDLER_ACTIVE: [usize; 1] = [0; 1];