1#![no_std]
8#![no_main]
9
10use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
11use kernel::capabilities;
12use kernel::component::Component;
13use kernel::hil;
14use kernel::platform::scheduler_timer::VirtualSchedulerTimer;
15use kernel::platform::KernelResources;
16use kernel::platform::SyscallDriverLookup;
17use kernel::process::ProcessArray;
18use kernel::scheduler::cooperative::CooperativeSched;
19use kernel::utilities::registers::interfaces::ReadWriteable;
20use kernel::{create_capability, debug, static_init};
21use qemu_rv32_virt_chip::chip::{QemuRv32VirtChip, QemuRv32VirtDefaultPeripherals};
22use rv32i::csr;
23
24pub mod io;
25
26pub const NUM_PROCS: usize = 4;
27
28static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
30
31static mut CHIP: Option<&'static QemuRv32VirtChip<QemuRv32VirtDefaultPeripherals>> = None;
33
34static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
36 None;
37
38const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
40 capsules_system::process_policies::PanicFaultPolicy {};
41
42#[no_mangle]
44#[link_section = ".stack_buffer"]
45static mut STACK_MEMORY: [u8; 0x8000] = [0; 0x8000];
46
47struct QemuRv32VirtPlatform {
50 pconsole: &'static capsules_core::process_console::ProcessConsole<
51 'static,
52 { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
53 capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
54 'static,
55 qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>,
56 >,
57 components::process_console::Capability,
58 >,
59 console: &'static capsules_core::console::Console<'static>,
60 lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
61 'static,
62 capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
63 >,
64 alarm: &'static capsules_core::alarm::AlarmDriver<
65 'static,
66 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
67 >,
68 ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
69 scheduler: &'static CooperativeSched<'static>,
70 scheduler_timer: &'static VirtualSchedulerTimer<
71 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
72 >,
73 virtio_rng: Option<
74 &'static capsules_core::rng::RngDriver<
75 'static,
76 qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng<'static, 'static>,
77 >,
78 >,
79 virtio_ethernet_tap: Option<
80 &'static capsules_extra::ethernet_tap::EthernetTapDriver<
81 'static,
82 qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet<'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 capsules_extra::ethernet_tap::DRIVER_NUM => {
105 if let Some(ethernet_tap_driver) = self.virtio_ethernet_tap {
106 f(Some(ethernet_tap_driver))
107 } else {
108 f(None)
109 }
110 }
111 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
112 _ => f(None),
113 }
114 }
115}
116
117impl
118 KernelResources<
119 qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
120 'static,
121 QemuRv32VirtDefaultPeripherals<'static>,
122 >,
123 > for QemuRv32VirtPlatform
124{
125 type SyscallDriverLookup = Self;
126 type SyscallFilter = ();
127 type ProcessFault = ();
128 type Scheduler = CooperativeSched<'static>;
129 type SchedulerTimer = VirtualSchedulerTimer<
130 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
131 >;
132 type WatchDog = ();
133 type ContextSwitchCallback = ();
134
135 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
136 self
137 }
138 fn syscall_filter(&self) -> &Self::SyscallFilter {
139 &()
140 }
141 fn process_fault(&self) -> &Self::ProcessFault {
142 &()
143 }
144 fn scheduler(&self) -> &Self::Scheduler {
145 self.scheduler
146 }
147 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
148 self.scheduler_timer
149 }
150 fn watchdog(&self) -> &Self::WatchDog {
151 &()
152 }
153 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
154 &()
155 }
156}
157
158#[inline(never)]
162unsafe fn start() -> (
163 &'static kernel::Kernel,
164 QemuRv32VirtPlatform,
165 &'static qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
166 'static,
167 QemuRv32VirtDefaultPeripherals<'static>,
168 >,
169) {
170 extern "C" {
172 static _sapps: u8;
174 static _eapps: u8;
176 static mut _sappmem: u8;
178 static _eappmem: u8;
180 static _stext: u8;
182 static _etext: u8;
184 static _sflash: u8;
186 static _eflash: u8;
188 static _ssram: u8;
190 static _esram: u8;
192 }
193
194 rv32i::configure_trap_handler();
198
199 let epmp = rv32i::pmp::kernel_protection_mml_epmp::KernelProtectionMMLEPMP::new(
203 rv32i::pmp::kernel_protection_mml_epmp::FlashRegion(
204 rv32i::pmp::NAPOTRegionSpec::from_start_end(
205 core::ptr::addr_of!(_sflash),
206 core::ptr::addr_of!(_eflash),
207 )
208 .unwrap(),
209 ),
210 rv32i::pmp::kernel_protection_mml_epmp::RAMRegion(
211 rv32i::pmp::NAPOTRegionSpec::from_start_end(
212 core::ptr::addr_of!(_ssram),
213 core::ptr::addr_of!(_esram),
214 )
215 .unwrap(),
216 ),
217 rv32i::pmp::kernel_protection_mml_epmp::MMIORegion(
218 rv32i::pmp::NAPOTRegionSpec::from_start_size(
219 core::ptr::null::<u8>(), 0x20000000, )
222 .unwrap(),
223 ),
224 rv32i::pmp::kernel_protection_mml_epmp::KernelTextRegion(
225 rv32i::pmp::TORRegionSpec::from_start_end(
226 core::ptr::addr_of!(_stext),
227 core::ptr::addr_of!(_etext),
228 )
229 .unwrap(),
230 ),
231 )
232 .unwrap();
233
234 let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
236 let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
237
238 let processes = components::process_array::ProcessArrayComponent::new()
242 .finalize(components::process_array_component_static!(NUM_PROCS));
243 PROCESSES = Some(processes);
244
245 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
247
248 let peripherals = static_init!(
251 QemuRv32VirtDefaultPeripherals,
252 QemuRv32VirtDefaultPeripherals::new(),
253 );
254
255 let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
259 .finalize(components::uart_mux_component_static!());
260
261 let hardware_timer = static_init!(
263 qemu_rv32_virt_chip::chip::QemuRv32VirtClint,
264 qemu_rv32_virt_chip::chip::QemuRv32VirtClint::new(&qemu_rv32_virt_chip::clint::CLINT_BASE)
265 );
266
267 let mux_alarm = static_init!(
270 MuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
271 MuxAlarm::new(hardware_timer)
272 );
273 hil::time::Alarm::set_alarm_client(hardware_timer, mux_alarm);
274
275 let systick_virtual_alarm = static_init!(
277 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
278 VirtualMuxAlarm::new(mux_alarm)
279 );
280 systick_virtual_alarm.setup();
281
282 let virtual_alarm_user = static_init!(
284 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
285 VirtualMuxAlarm::new(mux_alarm)
286 );
287 virtual_alarm_user.setup();
288
289 let alarm = static_init!(
290 capsules_core::alarm::AlarmDriver<
291 'static,
292 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
293 >,
294 capsules_core::alarm::AlarmDriver::new(
295 virtual_alarm_user,
296 board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
297 )
298 );
299 hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
300
301 let (mut virtio_net_idx, mut virtio_rng_idx) = (None, None);
309 for (i, virtio_device) in peripherals.virtio_mmio.iter().enumerate() {
310 use qemu_rv32_virt_chip::virtio::devices::VirtIODeviceType;
311 match virtio_device.query() {
312 Some(VirtIODeviceType::NetworkCard) => {
313 virtio_net_idx = Some(i);
314 }
315 Some(VirtIODeviceType::EntropySource) => {
316 virtio_rng_idx = Some(i);
317 }
318 _ => (),
319 }
320 }
321
322 let virtio_rng_driver: Option<
325 &'static capsules_core::rng::RngDriver<
326 'static,
327 qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng<'static, 'static>,
328 >,
329 > = if let Some(rng_idx) = virtio_rng_idx {
330 use kernel::hil::rng::Rng;
331 use qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng;
332 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
333 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
334 };
335 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
336 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
337
338 let descriptors = static_init!(VirtqueueDescriptors<1>, VirtqueueDescriptors::default(),);
340 let available_ring =
341 static_init!(VirtqueueAvailableRing<1>, VirtqueueAvailableRing::default(),);
342 let used_ring = static_init!(VirtqueueUsedRing<1>, VirtqueueUsedRing::default(),);
343 let queue = static_init!(
344 SplitVirtqueue<1>,
345 SplitVirtqueue::new(descriptors, available_ring, used_ring),
346 );
347 queue.set_transport(&peripherals.virtio_mmio[rng_idx]);
348
349 let rng = static_init!(VirtIORng, VirtIORng::new(queue));
351 kernel::deferred_call::DeferredCallClient::register(rng);
352 queue.set_client(rng);
353
354 let mmio_queues = static_init!([&'static dyn Virtqueue; 1], [queue; 1]);
357 peripherals.virtio_mmio[rng_idx]
358 .initialize(rng, mmio_queues)
359 .unwrap();
360
361 let rng_buffer = static_init!([u8; 64], [0; 64]);
363 rng.provide_buffer(rng_buffer)
364 .expect("rng: providing initial buffer failed");
365
366 let rng_driver = static_init!(
368 capsules_core::rng::RngDriver<VirtIORng>,
369 capsules_core::rng::RngDriver::new(
370 rng,
371 board_kernel.create_grant(capsules_core::rng::DRIVER_NUM, &memory_allocation_cap),
372 ),
373 );
374 rng.set_client(rng_driver);
375
376 Some(rng_driver as &'static capsules_core::rng::RngDriver<VirtIORng>)
377 } else {
378 None
380 };
381
382 let virtio_ethernet_tap: Option<
386 &'static capsules_extra::ethernet_tap::EthernetTapDriver<
387 'static,
388 qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet<'static>,
389 >,
390 > = if let Some(net_idx) = virtio_net_idx {
391 use capsules_extra::ethernet_tap::EthernetTapDriver;
392 use kernel::hil::ethernet::EthernetAdapterDatapath;
393 use qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet;
394 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
395 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
396 };
397 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
398 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
399
400 let tx_descriptors =
407 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
408 let tx_available_ring =
409 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
410 let tx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
411 let tx_queue = static_init!(
412 SplitVirtqueue<2>,
413 SplitVirtqueue::new(tx_descriptors, tx_available_ring, tx_used_ring),
414 );
415 tx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
416
417 let rx_descriptors =
419 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
420 let rx_available_ring =
421 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
422 let rx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
423 let rx_queue = static_init!(
424 SplitVirtqueue<2>,
425 SplitVirtqueue::new(rx_descriptors, rx_available_ring, rx_used_ring),
426 );
427 rx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
428
429 let tx_header_buf = static_init!([u8; 12], [0; 12]);
432 let rx_header_buf = static_init!([u8; 12], [0; 12]);
433
434 let rx_buffer = static_init!([u8; 1526], [0; 1526]);
437
438 let virtio_net = static_init!(
440 VirtIONet<'static>,
441 VirtIONet::new(tx_queue, tx_header_buf, rx_queue, rx_header_buf, rx_buffer),
442 );
443 tx_queue.set_client(virtio_net);
444 rx_queue.set_client(virtio_net);
445
446 let mmio_queues = static_init!([&'static dyn Virtqueue; 2], [rx_queue, tx_queue]);
449 peripherals.virtio_mmio[net_idx]
450 .initialize(virtio_net, mmio_queues)
451 .unwrap();
452
453 let virtio_ethernet_tap_tx_buffer = static_init!(
455 [u8; capsules_extra::ethernet_tap::MAX_MTU],
456 [0; capsules_extra::ethernet_tap::MAX_MTU],
457 );
458 let virtio_ethernet_tap = static_init!(
459 EthernetTapDriver<'static, VirtIONet<'static>>,
460 EthernetTapDriver::new(
461 virtio_net,
462 board_kernel.create_grant(
463 capsules_extra::ethernet_tap::DRIVER_NUM,
464 &memory_allocation_cap
465 ),
466 virtio_ethernet_tap_tx_buffer,
467 ),
468 );
469 virtio_net.set_client(virtio_ethernet_tap);
470
471 virtio_ethernet_tap.initialize();
473
474 Some(virtio_ethernet_tap as &'static EthernetTapDriver<'static, VirtIONet<'static>>)
475 } else {
476 None
478 };
479
480 let chip = static_init!(
483 QemuRv32VirtChip<QemuRv32VirtDefaultPeripherals>,
484 QemuRv32VirtChip::new(peripherals, hardware_timer, epmp),
485 );
486 CHIP = Some(chip);
487
488 chip.enable_plic_interrupts();
490
491 csr::CSR
493 .mie
494 .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET);
495 csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
496
497 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
501 .finalize(components::process_printer_text_component_static!());
502 PROCESS_PRINTER = Some(process_printer);
503
504 let pconsole = components::process_console::ProcessConsoleComponent::new(
506 board_kernel,
507 uart_mux,
508 mux_alarm,
509 process_printer,
510 None,
511 )
512 .finalize(components::process_console_component_static!(
513 qemu_rv32_virt_chip::chip::QemuRv32VirtClint
514 ));
515
516 let console = components::console::ConsoleComponent::new(
518 board_kernel,
519 capsules_core::console::DRIVER_NUM,
520 uart_mux,
521 )
522 .finalize(components::console_component_static!());
523 components::debug_writer::DebugWriterComponent::new(
525 uart_mux,
526 create_capability!(capabilities::SetDebugWriterCapability),
527 )
528 .finalize(components::debug_writer_component_static!());
529
530 let lldb = components::lldb::LowLevelDebugComponent::new(
531 board_kernel,
532 capsules_core::low_level_debug::DRIVER_NUM,
533 uart_mux,
534 )
535 .finalize(components::low_level_debug_component_static!());
536
537 let scheduler = components::sched::cooperative::CooperativeComponent::new(processes)
538 .finalize(components::cooperative_component_static!(NUM_PROCS));
539
540 let scheduler_timer = static_init!(
541 VirtualSchedulerTimer<
542 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
543 >,
544 VirtualSchedulerTimer::new(systick_virtual_alarm)
545 );
546
547 let platform = QemuRv32VirtPlatform {
548 pconsole,
549 console,
550 alarm,
551 lldb,
552 scheduler,
553 scheduler_timer,
554 virtio_rng: virtio_rng_driver,
555 virtio_ethernet_tap,
556 ipc: kernel::ipc::IPC::new(
557 board_kernel,
558 kernel::ipc::DRIVER_NUM,
559 &memory_allocation_cap,
560 ),
561 };
562
563 let _ = platform.pconsole.start();
565
566 debug!("QEMU RISC-V 32-bit \"virt\" machine, initialization complete.");
567
568 if virtio_rng_driver.is_some() {
572 debug!("- Found VirtIO EntropySource device, enabling RngDriver");
573 } else {
574 debug!("- VirtIO EntropySource device not found, disabling RngDriver");
575 }
576 if virtio_ethernet_tap.is_some() {
577 debug!("- Found VirtIO NetworkCard device, enabling EthernetTapDriver");
578 } else {
579 debug!("- VirtIO NetworkCard device not found, disabling EthernetTapDriver");
580 }
581
582 debug!("Entering main loop.");
583
584 kernel::process::load_processes(
587 board_kernel,
588 chip,
589 core::slice::from_raw_parts(
590 core::ptr::addr_of!(_sapps),
591 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
592 ),
593 core::slice::from_raw_parts_mut(
594 core::ptr::addr_of_mut!(_sappmem),
595 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
596 ),
597 &FAULT_RESPONSE,
598 &process_mgmt_cap,
599 )
600 .unwrap_or_else(|err| {
601 debug!("Error loading processes!");
602 debug!("{:?}", err);
603 });
604
605 (board_kernel, platform, chip)
606}
607
608#[no_mangle]
610pub unsafe fn main() {
611 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
612
613 let (board_kernel, platform, chip) = start();
614 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
615}