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 virtio_ethernet_tap: Option<
86 &'static capsules_extra::ethernet_tap::EthernetTapDriver<
87 'static,
88 qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet<'static>,
89 >,
90 >,
91}
92
93impl SyscallDriverLookup for QemuRv32VirtPlatform {
95 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
96 where
97 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
98 {
99 match driver_num {
100 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
101 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
102 capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
103 capsules_core::rng::DRIVER_NUM => {
104 if let Some(rng_driver) = self.virtio_rng {
105 f(Some(rng_driver))
106 } else {
107 f(None)
108 }
109 }
110 capsules_extra::ethernet_tap::DRIVER_NUM => {
111 if let Some(ethernet_tap_driver) = self.virtio_ethernet_tap {
112 f(Some(ethernet_tap_driver))
113 } else {
114 f(None)
115 }
116 }
117 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
118 _ => f(None),
119 }
120 }
121}
122
123impl
124 KernelResources<
125 qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
126 'static,
127 QemuRv32VirtDefaultPeripherals<'static>,
128 >,
129 > for QemuRv32VirtPlatform
130{
131 type SyscallDriverLookup = Self;
132 type SyscallFilter = ();
133 type ProcessFault = ();
134 type Scheduler = CooperativeSched<'static>;
135 type SchedulerTimer = VirtualSchedulerTimer<
136 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
137 >;
138 type WatchDog = ();
139 type ContextSwitchCallback = ();
140
141 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
142 self
143 }
144 fn syscall_filter(&self) -> &Self::SyscallFilter {
145 &()
146 }
147 fn process_fault(&self) -> &Self::ProcessFault {
148 &()
149 }
150 fn scheduler(&self) -> &Self::Scheduler {
151 self.scheduler
152 }
153 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
154 self.scheduler_timer
155 }
156 fn watchdog(&self) -> &Self::WatchDog {
157 &()
158 }
159 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
160 &()
161 }
162}
163
164#[inline(never)]
168unsafe fn start() -> (
169 &'static kernel::Kernel,
170 QemuRv32VirtPlatform,
171 &'static qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
172 'static,
173 QemuRv32VirtDefaultPeripherals<'static>,
174 >,
175) {
176 extern "C" {
178 static _sapps: u8;
180 static _eapps: u8;
182 static mut _sappmem: u8;
184 static _eappmem: u8;
186 static _stext: u8;
188 static _etext: u8;
190 static _sflash: u8;
192 static _eflash: u8;
194 static _ssram: u8;
196 static _esram: u8;
198 }
199
200 rv32i::configure_trap_handler();
204
205 let epmp = rv32i::pmp::kernel_protection_mml_epmp::KernelProtectionMMLEPMP::new(
209 rv32i::pmp::kernel_protection_mml_epmp::FlashRegion(
210 rv32i::pmp::NAPOTRegionSpec::from_start_end(
211 core::ptr::addr_of!(_sflash),
212 core::ptr::addr_of!(_eflash),
213 )
214 .unwrap(),
215 ),
216 rv32i::pmp::kernel_protection_mml_epmp::RAMRegion(
217 rv32i::pmp::NAPOTRegionSpec::from_start_end(
218 core::ptr::addr_of!(_ssram),
219 core::ptr::addr_of!(_esram),
220 )
221 .unwrap(),
222 ),
223 rv32i::pmp::kernel_protection_mml_epmp::MMIORegion(
224 rv32i::pmp::NAPOTRegionSpec::from_start_size(
225 core::ptr::null::<u8>(), 0x20000000, )
228 .unwrap(),
229 ),
230 rv32i::pmp::kernel_protection_mml_epmp::KernelTextRegion(
231 rv32i::pmp::TORRegionSpec::from_start_end(
232 core::ptr::addr_of!(_stext),
233 core::ptr::addr_of!(_etext),
234 )
235 .unwrap(),
236 ),
237 )
238 .unwrap();
239
240 let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
242 let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
243
244 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
246
247 let peripherals = static_init!(
250 QemuRv32VirtDefaultPeripherals,
251 QemuRv32VirtDefaultPeripherals::new(),
252 );
253
254 let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
258 .finalize(components::uart_mux_component_static!());
259
260 let hardware_timer = static_init!(
262 qemu_rv32_virt_chip::chip::QemuRv32VirtClint,
263 qemu_rv32_virt_chip::chip::QemuRv32VirtClint::new(&qemu_rv32_virt_chip::clint::CLINT_BASE)
264 );
265
266 let mux_alarm = static_init!(
269 MuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
270 MuxAlarm::new(hardware_timer)
271 );
272 hil::time::Alarm::set_alarm_client(hardware_timer, mux_alarm);
273
274 let systick_virtual_alarm = static_init!(
276 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
277 VirtualMuxAlarm::new(mux_alarm)
278 );
279 systick_virtual_alarm.setup();
280
281 let virtual_alarm_user = static_init!(
283 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
284 VirtualMuxAlarm::new(mux_alarm)
285 );
286 virtual_alarm_user.setup();
287
288 let alarm = static_init!(
289 capsules_core::alarm::AlarmDriver<
290 'static,
291 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
292 >,
293 capsules_core::alarm::AlarmDriver::new(
294 virtual_alarm_user,
295 board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
296 )
297 );
298 hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
299
300 let (mut virtio_net_idx, mut virtio_rng_idx) = (None, None);
308 for (i, virtio_device) in peripherals.virtio_mmio.iter().enumerate() {
309 use qemu_rv32_virt_chip::virtio::devices::VirtIODeviceType;
310 match virtio_device.query() {
311 Some(VirtIODeviceType::NetworkCard) => {
312 virtio_net_idx = Some(i);
313 }
314 Some(VirtIODeviceType::EntropySource) => {
315 virtio_rng_idx = Some(i);
316 }
317 _ => (),
318 }
319 }
320
321 let virtio_rng_driver: Option<
324 &'static capsules_core::rng::RngDriver<
325 'static,
326 qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng<'static, 'static>,
327 >,
328 > = if let Some(rng_idx) = virtio_rng_idx {
329 use kernel::hil::rng::Rng;
330 use qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng;
331 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
332 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
333 };
334 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
335 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
336
337 let descriptors = static_init!(VirtqueueDescriptors<1>, VirtqueueDescriptors::default(),);
339 let available_ring =
340 static_init!(VirtqueueAvailableRing<1>, VirtqueueAvailableRing::default(),);
341 let used_ring = static_init!(VirtqueueUsedRing<1>, VirtqueueUsedRing::default(),);
342 let queue = static_init!(
343 SplitVirtqueue<1>,
344 SplitVirtqueue::new(descriptors, available_ring, used_ring),
345 );
346 queue.set_transport(&peripherals.virtio_mmio[rng_idx]);
347
348 let rng = static_init!(VirtIORng, VirtIORng::new(queue));
350 kernel::deferred_call::DeferredCallClient::register(rng);
351 queue.set_client(rng);
352
353 let mmio_queues = static_init!([&'static dyn Virtqueue; 1], [queue; 1]);
356 peripherals.virtio_mmio[rng_idx]
357 .initialize(rng, mmio_queues)
358 .unwrap();
359
360 let rng_buffer = static_init!([u8; 64], [0; 64]);
362 rng.provide_buffer(rng_buffer)
363 .expect("rng: providing initial buffer failed");
364
365 let rng_driver = static_init!(
367 capsules_core::rng::RngDriver<VirtIORng>,
368 capsules_core::rng::RngDriver::new(
369 rng,
370 board_kernel.create_grant(capsules_core::rng::DRIVER_NUM, &memory_allocation_cap),
371 ),
372 );
373 rng.set_client(rng_driver);
374
375 Some(rng_driver as &'static capsules_core::rng::RngDriver<VirtIORng>)
376 } else {
377 None
379 };
380
381 let virtio_ethernet_tap: Option<
385 &'static capsules_extra::ethernet_tap::EthernetTapDriver<
386 'static,
387 qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet<'static>,
388 >,
389 > = if let Some(net_idx) = virtio_net_idx {
390 use capsules_extra::ethernet_tap::EthernetTapDriver;
391 use kernel::hil::ethernet::EthernetAdapterDatapath;
392 use qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet;
393 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
394 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
395 };
396 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
397 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
398
399 let tx_descriptors =
406 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
407 let tx_available_ring =
408 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
409 let tx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
410 let tx_queue = static_init!(
411 SplitVirtqueue<2>,
412 SplitVirtqueue::new(tx_descriptors, tx_available_ring, tx_used_ring),
413 );
414 tx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
415
416 let rx_descriptors =
418 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
419 let rx_available_ring =
420 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
421 let rx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
422 let rx_queue = static_init!(
423 SplitVirtqueue<2>,
424 SplitVirtqueue::new(rx_descriptors, rx_available_ring, rx_used_ring),
425 );
426 rx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
427
428 let tx_header_buf = static_init!([u8; 12], [0; 12]);
431 let rx_header_buf = static_init!([u8; 12], [0; 12]);
432
433 let rx_buffer = static_init!([u8; 1526], [0; 1526]);
436
437 let virtio_net = static_init!(
439 VirtIONet<'static>,
440 VirtIONet::new(tx_queue, tx_header_buf, rx_queue, rx_header_buf, rx_buffer),
441 );
442 tx_queue.set_client(virtio_net);
443 rx_queue.set_client(virtio_net);
444
445 let mmio_queues = static_init!([&'static dyn Virtqueue; 2], [rx_queue, tx_queue]);
448 peripherals.virtio_mmio[net_idx]
449 .initialize(virtio_net, mmio_queues)
450 .unwrap();
451
452 let virtio_ethernet_tap_tx_buffer = static_init!(
454 [u8; capsules_extra::ethernet_tap::MAX_MTU],
455 [0; capsules_extra::ethernet_tap::MAX_MTU],
456 );
457 let virtio_ethernet_tap = static_init!(
458 EthernetTapDriver<'static, VirtIONet<'static>>,
459 EthernetTapDriver::new(
460 virtio_net,
461 board_kernel.create_grant(
462 capsules_extra::ethernet_tap::DRIVER_NUM,
463 &memory_allocation_cap
464 ),
465 virtio_ethernet_tap_tx_buffer,
466 ),
467 );
468 virtio_net.set_client(virtio_ethernet_tap);
469
470 virtio_ethernet_tap.initialize();
472
473 Some(virtio_ethernet_tap as &'static EthernetTapDriver<'static, VirtIONet<'static>>)
474 } else {
475 None
477 };
478
479 let chip = static_init!(
482 QemuRv32VirtChip<QemuRv32VirtDefaultPeripherals>,
483 QemuRv32VirtChip::new(peripherals, hardware_timer, epmp),
484 );
485 CHIP = Some(chip);
486
487 chip.enable_plic_interrupts();
489
490 csr::CSR
492 .mie
493 .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET);
494 csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
495
496 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
500 .finalize(components::process_printer_text_component_static!());
501 PROCESS_PRINTER = Some(process_printer);
502
503 let pconsole = components::process_console::ProcessConsoleComponent::new(
505 board_kernel,
506 uart_mux,
507 mux_alarm,
508 process_printer,
509 None,
510 )
511 .finalize(components::process_console_component_static!(
512 qemu_rv32_virt_chip::chip::QemuRv32VirtClint
513 ));
514
515 let console = components::console::ConsoleComponent::new(
517 board_kernel,
518 capsules_core::console::DRIVER_NUM,
519 uart_mux,
520 )
521 .finalize(components::console_component_static!());
522 components::debug_writer::DebugWriterComponent::new(uart_mux)
524 .finalize(components::debug_writer_component_static!());
525
526 let lldb = components::lldb::LowLevelDebugComponent::new(
527 board_kernel,
528 capsules_core::low_level_debug::DRIVER_NUM,
529 uart_mux,
530 )
531 .finalize(components::low_level_debug_component_static!());
532
533 let scheduler =
534 components::sched::cooperative::CooperativeComponent::new(&*addr_of!(PROCESSES))
535 .finalize(components::cooperative_component_static!(NUM_PROCS));
536
537 let scheduler_timer = static_init!(
538 VirtualSchedulerTimer<
539 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
540 >,
541 VirtualSchedulerTimer::new(systick_virtual_alarm)
542 );
543
544 let platform = QemuRv32VirtPlatform {
545 pconsole,
546 console,
547 alarm,
548 lldb,
549 scheduler,
550 scheduler_timer,
551 virtio_rng: virtio_rng_driver,
552 virtio_ethernet_tap,
553 ipc: kernel::ipc::IPC::new(
554 board_kernel,
555 kernel::ipc::DRIVER_NUM,
556 &memory_allocation_cap,
557 ),
558 };
559
560 let _ = platform.pconsole.start();
562
563 debug!("QEMU RISC-V 32-bit \"virt\" machine, initialization complete.");
564
565 if virtio_rng_driver.is_some() {
569 debug!("- Found VirtIO EntropySource device, enabling RngDriver");
570 } else {
571 debug!("- VirtIO EntropySource device not found, disabling RngDriver");
572 }
573 if virtio_ethernet_tap.is_some() {
574 debug!("- Found VirtIO NetworkCard device, enabling EthernetTapDriver");
575 } else {
576 debug!("- VirtIO NetworkCard device not found, disabling EthernetTapDriver");
577 }
578
579 debug!("Entering main loop.");
580
581 kernel::process::load_processes(
584 board_kernel,
585 chip,
586 core::slice::from_raw_parts(
587 core::ptr::addr_of!(_sapps),
588 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
589 ),
590 core::slice::from_raw_parts_mut(
591 core::ptr::addr_of_mut!(_sappmem),
592 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
593 ),
594 &mut *addr_of_mut!(PROCESSES),
595 &FAULT_RESPONSE,
596 &process_mgmt_cap,
597 )
598 .unwrap_or_else(|err| {
599 debug!("Error loading processes!");
600 debug!("{:?}", err);
601 });
602
603 (board_kernel, platform, chip)
604}
605
606#[no_mangle]
608pub unsafe fn main() {
609 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
610
611 let (board_kernel, platform, chip) = start();
612 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
613}