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