1#![no_std]
8#![cfg_attr(not(doc), no_main)]
11
12use core::ptr::addr_of;
13use core::ptr::addr_of_mut;
14
15use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
16use kernel::capabilities;
17use kernel::component::Component;
18use kernel::hil;
19use kernel::platform::scheduler_timer::VirtualSchedulerTimer;
20use kernel::platform::KernelResources;
21use kernel::platform::SyscallDriverLookup;
22use kernel::scheduler::cooperative::CooperativeSched;
23use kernel::utilities::registers::interfaces::ReadWriteable;
24use kernel::{create_capability, debug, static_init};
25use qemu_rv32_virt_chip::chip::{QemuRv32VirtChip, QemuRv32VirtDefaultPeripherals};
26use rv32i::csr;
27
28pub mod io;
29
30pub const NUM_PROCS: usize = 4;
31
32static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
35 [None; NUM_PROCS];
36
37static mut CHIP: Option<&'static QemuRv32VirtChip<QemuRv32VirtDefaultPeripherals>> = None;
39
40static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
42 None;
43
44const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
46 capsules_system::process_policies::PanicFaultPolicy {};
47
48#[no_mangle]
50#[link_section = ".stack_buffer"]
51pub static mut STACK_MEMORY: [u8; 0x8000] = [0; 0x8000];
52
53struct QemuRv32VirtPlatform {
56 pconsole: &'static capsules_core::process_console::ProcessConsole<
57 'static,
58 { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
59 capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
60 'static,
61 qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>,
62 >,
63 components::process_console::Capability,
64 >,
65 console: &'static capsules_core::console::Console<'static>,
66 lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
67 'static,
68 capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
69 >,
70 alarm: &'static capsules_core::alarm::AlarmDriver<
71 'static,
72 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
73 >,
74 ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
75 scheduler: &'static CooperativeSched<'static>,
76 scheduler_timer: &'static VirtualSchedulerTimer<
77 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
78 >,
79 virtio_rng: Option<
80 &'static capsules_core::rng::RngDriver<
81 'static,
82 qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng<'static, 'static>,
83 >,
84 >,
85}
86
87impl SyscallDriverLookup for QemuRv32VirtPlatform {
89 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
90 where
91 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
92 {
93 match driver_num {
94 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
95 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
96 capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
97 capsules_core::rng::DRIVER_NUM => {
98 if let Some(rng_driver) = self.virtio_rng {
99 f(Some(rng_driver))
100 } else {
101 f(None)
102 }
103 }
104 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
105 _ => f(None),
106 }
107 }
108}
109
110impl
111 KernelResources<
112 qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
113 'static,
114 QemuRv32VirtDefaultPeripherals<'static>,
115 >,
116 > for QemuRv32VirtPlatform
117{
118 type SyscallDriverLookup = Self;
119 type SyscallFilter = ();
120 type ProcessFault = ();
121 type Scheduler = CooperativeSched<'static>;
122 type SchedulerTimer = VirtualSchedulerTimer<
123 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
124 >;
125 type WatchDog = ();
126 type ContextSwitchCallback = ();
127
128 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
129 self
130 }
131 fn syscall_filter(&self) -> &Self::SyscallFilter {
132 &()
133 }
134 fn process_fault(&self) -> &Self::ProcessFault {
135 &()
136 }
137 fn scheduler(&self) -> &Self::Scheduler {
138 self.scheduler
139 }
140 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
141 self.scheduler_timer
142 }
143 fn watchdog(&self) -> &Self::WatchDog {
144 &()
145 }
146 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
147 &()
148 }
149}
150
151#[inline(never)]
155unsafe fn start() -> (
156 &'static kernel::Kernel,
157 QemuRv32VirtPlatform,
158 &'static qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
159 'static,
160 QemuRv32VirtDefaultPeripherals<'static>,
161 >,
162) {
163 extern "C" {
165 static _sapps: u8;
167 static _eapps: u8;
169 static mut _sappmem: u8;
171 static _eappmem: u8;
173 static _stext: u8;
175 static _etext: u8;
177 static _sflash: u8;
179 static _eflash: u8;
181 static _ssram: u8;
183 static _esram: u8;
185 }
186
187 rv32i::configure_trap_handler();
191
192 let epmp = rv32i::pmp::kernel_protection_mml_epmp::KernelProtectionMMLEPMP::new(
196 rv32i::pmp::kernel_protection_mml_epmp::FlashRegion(
197 rv32i::pmp::NAPOTRegionSpec::new(
198 core::ptr::addr_of!(_sflash),
199 core::ptr::addr_of!(_eflash) as usize - core::ptr::addr_of!(_sflash) as usize,
200 )
201 .unwrap(),
202 ),
203 rv32i::pmp::kernel_protection_mml_epmp::RAMRegion(
204 rv32i::pmp::NAPOTRegionSpec::new(
205 core::ptr::addr_of!(_ssram),
206 core::ptr::addr_of!(_esram) as usize - core::ptr::addr_of!(_ssram) as usize,
207 )
208 .unwrap(),
209 ),
210 rv32i::pmp::kernel_protection_mml_epmp::MMIORegion(
211 rv32i::pmp::NAPOTRegionSpec::new(
212 core::ptr::null::<u8>(), 0x20000000, )
215 .unwrap(),
216 ),
217 rv32i::pmp::kernel_protection_mml_epmp::KernelTextRegion(
218 rv32i::pmp::TORRegionSpec::new(
219 core::ptr::addr_of!(_stext),
220 core::ptr::addr_of!(_etext),
221 )
222 .unwrap(),
223 ),
224 )
225 .unwrap();
226
227 let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
229 let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
230
231 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
233
234 let peripherals = static_init!(
237 QemuRv32VirtDefaultPeripherals,
238 QemuRv32VirtDefaultPeripherals::new(),
239 );
240
241 let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
245 .finalize(components::uart_mux_component_static!());
246
247 let hardware_timer = static_init!(
249 qemu_rv32_virt_chip::chip::QemuRv32VirtClint,
250 qemu_rv32_virt_chip::chip::QemuRv32VirtClint::new(&qemu_rv32_virt_chip::clint::CLINT_BASE)
251 );
252
253 let mux_alarm = static_init!(
256 MuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
257 MuxAlarm::new(hardware_timer)
258 );
259 hil::time::Alarm::set_alarm_client(hardware_timer, mux_alarm);
260
261 let systick_virtual_alarm = static_init!(
263 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
264 VirtualMuxAlarm::new(mux_alarm)
265 );
266 systick_virtual_alarm.setup();
267
268 let virtual_alarm_user = static_init!(
270 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
271 VirtualMuxAlarm::new(mux_alarm)
272 );
273 virtual_alarm_user.setup();
274
275 let alarm = static_init!(
276 capsules_core::alarm::AlarmDriver<
277 'static,
278 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
279 >,
280 capsules_core::alarm::AlarmDriver::new(
281 virtual_alarm_user,
282 board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
283 )
284 );
285 hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
286
287 let (mut virtio_net_idx, mut virtio_rng_idx) = (None, None);
295 for (i, virtio_device) in peripherals.virtio_mmio.iter().enumerate() {
296 use qemu_rv32_virt_chip::virtio::devices::VirtIODeviceType;
297 match virtio_device.query() {
298 Some(VirtIODeviceType::NetworkCard) => {
299 virtio_net_idx = Some(i);
300 }
301 Some(VirtIODeviceType::EntropySource) => {
302 virtio_rng_idx = Some(i);
303 }
304 _ => (),
305 }
306 }
307
308 let virtio_rng_driver: Option<
311 &'static capsules_core::rng::RngDriver<
312 'static,
313 qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng<'static, 'static>,
314 >,
315 > = if let Some(rng_idx) = virtio_rng_idx {
316 use kernel::hil::rng::Rng;
317 use qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng;
318 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
319 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
320 };
321 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
322 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
323
324 let descriptors = static_init!(VirtqueueDescriptors<1>, VirtqueueDescriptors::default(),);
326 let available_ring =
327 static_init!(VirtqueueAvailableRing<1>, VirtqueueAvailableRing::default(),);
328 let used_ring = static_init!(VirtqueueUsedRing<1>, VirtqueueUsedRing::default(),);
329 let queue = static_init!(
330 SplitVirtqueue<1>,
331 SplitVirtqueue::new(descriptors, available_ring, used_ring),
332 );
333 queue.set_transport(&peripherals.virtio_mmio[rng_idx]);
334
335 let rng = static_init!(VirtIORng, VirtIORng::new(queue));
337 kernel::deferred_call::DeferredCallClient::register(rng);
338 queue.set_client(rng);
339
340 let mmio_queues = static_init!([&'static dyn Virtqueue; 1], [queue; 1]);
343 peripherals.virtio_mmio[rng_idx]
344 .initialize(rng, mmio_queues)
345 .unwrap();
346
347 let rng_buffer = static_init!([u8; 64], [0; 64]);
349 rng.provide_buffer(rng_buffer)
350 .expect("rng: providing initial buffer failed");
351
352 let rng_driver = static_init!(
354 capsules_core::rng::RngDriver<VirtIORng>,
355 capsules_core::rng::RngDriver::new(
356 rng,
357 board_kernel.create_grant(capsules_core::rng::DRIVER_NUM, &memory_allocation_cap),
358 ),
359 );
360 rng.set_client(rng_driver);
361
362 Some(rng_driver as &'static capsules_core::rng::RngDriver<VirtIORng>)
363 } else {
364 None
366 };
367
368 let _virtio_net_if: Option<
375 &'static qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet<'static>,
376 > = if let Some(net_idx) = virtio_net_idx {
377 use qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet;
378 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
379 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
380 };
381 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
382 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
383
384 let tx_descriptors =
391 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
392 let tx_available_ring =
393 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
394 let tx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
395 let tx_queue = static_init!(
396 SplitVirtqueue<2>,
397 SplitVirtqueue::new(tx_descriptors, tx_available_ring, tx_used_ring),
398 );
399 tx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
400
401 let rx_descriptors =
403 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
404 let rx_available_ring =
405 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
406 let rx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
407 let rx_queue = static_init!(
408 SplitVirtqueue<2>,
409 SplitVirtqueue::new(rx_descriptors, rx_available_ring, rx_used_ring),
410 );
411 rx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
412
413 let tx_header_buf = static_init!([u8; 12], [0; 12]);
416 let rx_header_buf = static_init!([u8; 12], [0; 12]);
417
418 let rx_buffer = static_init!([u8; 1526], [0; 1526]);
421
422 let virtio_net = static_init!(
425 VirtIONet<'static>,
426 VirtIONet::new(
427 0,
428 tx_queue,
429 tx_header_buf,
430 rx_queue,
431 rx_header_buf,
432 rx_buffer,
433 ),
434 );
435 tx_queue.set_client(virtio_net);
436 rx_queue.set_client(virtio_net);
437
438 let mmio_queues = static_init!([&'static dyn Virtqueue; 2], [rx_queue, tx_queue]);
441 peripherals.virtio_mmio[net_idx]
442 .initialize(virtio_net, mmio_queues)
443 .unwrap();
444
445 Some(virtio_net as &'static VirtIONet)
453 } else {
454 None
456 };
457
458 let chip = static_init!(
461 QemuRv32VirtChip<QemuRv32VirtDefaultPeripherals>,
462 QemuRv32VirtChip::new(peripherals, hardware_timer, epmp),
463 );
464 CHIP = Some(chip);
465
466 chip.enable_plic_interrupts();
468
469 csr::CSR
471 .mie
472 .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET);
473 csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
474
475 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
479 .finalize(components::process_printer_text_component_static!());
480 PROCESS_PRINTER = Some(process_printer);
481
482 let pconsole = components::process_console::ProcessConsoleComponent::new(
484 board_kernel,
485 uart_mux,
486 mux_alarm,
487 process_printer,
488 None,
489 )
490 .finalize(components::process_console_component_static!(
491 qemu_rv32_virt_chip::chip::QemuRv32VirtClint
492 ));
493
494 let console = components::console::ConsoleComponent::new(
496 board_kernel,
497 capsules_core::console::DRIVER_NUM,
498 uart_mux,
499 )
500 .finalize(components::console_component_static!());
501 components::debug_writer::DebugWriterComponent::new(uart_mux)
503 .finalize(components::debug_writer_component_static!());
504
505 let lldb = components::lldb::LowLevelDebugComponent::new(
506 board_kernel,
507 capsules_core::low_level_debug::DRIVER_NUM,
508 uart_mux,
509 )
510 .finalize(components::low_level_debug_component_static!());
511
512 let scheduler =
513 components::sched::cooperative::CooperativeComponent::new(&*addr_of!(PROCESSES))
514 .finalize(components::cooperative_component_static!(NUM_PROCS));
515
516 let scheduler_timer = static_init!(
517 VirtualSchedulerTimer<
518 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
519 >,
520 VirtualSchedulerTimer::new(systick_virtual_alarm)
521 );
522
523 let platform = QemuRv32VirtPlatform {
524 pconsole,
525 console,
526 alarm,
527 lldb,
528 scheduler,
529 scheduler_timer,
530 virtio_rng: virtio_rng_driver,
531 ipc: kernel::ipc::IPC::new(
532 board_kernel,
533 kernel::ipc::DRIVER_NUM,
534 &memory_allocation_cap,
535 ),
536 };
537
538 let _ = platform.pconsole.start();
540
541 debug!("QEMU RISC-V 32-bit \"virt\" machine, initialization complete.");
542 debug!("Entering main loop.");
543
544 kernel::process::load_processes(
547 board_kernel,
548 chip,
549 core::slice::from_raw_parts(
550 core::ptr::addr_of!(_sapps),
551 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
552 ),
553 core::slice::from_raw_parts_mut(
554 core::ptr::addr_of_mut!(_sappmem),
555 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
556 ),
557 &mut *addr_of_mut!(PROCESSES),
558 &FAULT_RESPONSE,
559 &process_mgmt_cap,
560 )
561 .unwrap_or_else(|err| {
562 debug!("Error loading processes!");
563 debug!("{:?}", err);
564 });
565
566 (board_kernel, platform, chip)
567}
568
569#[no_mangle]
571pub unsafe fn main() {
572 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
573
574 let (board_kernel, platform, chip) = start();
575 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
576}