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
38pub type Chip = QemuRv32VirtChip<'static, QemuRv32VirtDefaultPeripherals<'static>>;
39type RngDriver = components::rng::RngRandomComponentType<
40 qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng<'static, 'static>,
41>;
42pub type ScreenHw = qemu_rv32_virt_chip::virtio::devices::virtio_gpu::VirtIOGPU<'static, 'static>;
43
44kernel::stack_size! {0x8000}
45
46pub struct QemuRv32VirtPlatform {
49 pub pconsole: &'static capsules_core::process_console::ProcessConsole<
50 'static,
51 { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
52 capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
53 'static,
54 qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>,
55 >,
56 components::process_console::Capability,
57 >,
58 console: &'static capsules_core::console::Console<'static>,
59 lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
60 'static,
61 capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
62 >,
63 alarm: &'static capsules_core::alarm::AlarmDriver<
64 'static,
65 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
66 >,
67 pub ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
68 scheduler: &'static CooperativeSched<'static>,
69 scheduler_timer: &'static VirtualSchedulerTimer<
70 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
71 >,
72 rng: Option<&'static RngDriver>,
73 virtio_ethernet_tap: Option<
74 &'static capsules_extra::ethernet_tap::EthernetTapDriver<
75 'static,
76 qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet<'static>,
77 >,
78 >,
79 pub virtio_gpu_screen: Option<
80 &'static capsules_extra::screen::screen_adapters::ScreenARGB8888ToMono8BitPage<
81 'static,
82 ScreenHw,
83 >,
84 >,
85 pub virtio_input_keyboard:
86 Option<&'static qemu_rv32_virt_chip::virtio::devices::virtio_input::VirtIOInput<'static>>,
87}
88
89impl SyscallDriverLookup for QemuRv32VirtPlatform {
91 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
92 where
93 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
94 {
95 match driver_num {
96 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
97 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
98 capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
99 capsules_core::rng::DRIVER_NUM => {
100 if let Some(rng_driver) = self.rng {
101 f(Some(rng_driver))
102 } else {
103 f(None)
104 }
105 }
106 capsules_extra::ethernet_tap::DRIVER_NUM => {
107 if let Some(ethernet_tap_driver) = self.virtio_ethernet_tap {
108 f(Some(ethernet_tap_driver))
109 } else {
110 f(None)
111 }
112 }
113
114 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
115 _ => f(None),
116 }
117 }
118}
119
120impl
121 KernelResources<
122 qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
123 'static,
124 QemuRv32VirtDefaultPeripherals<'static>,
125 >,
126 > for QemuRv32VirtPlatform
127{
128 type SyscallDriverLookup = Self;
129 type SyscallFilter = ();
130 type ProcessFault = ();
131 type Scheduler = CooperativeSched<'static>;
132 type SchedulerTimer = VirtualSchedulerTimer<
133 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
134 >;
135 type WatchDog = ();
136 type ContextSwitchCallback = ();
137
138 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
139 self
140 }
141 fn syscall_filter(&self) -> &Self::SyscallFilter {
142 &()
143 }
144 fn process_fault(&self) -> &Self::ProcessFault {
145 &()
146 }
147 fn scheduler(&self) -> &Self::Scheduler {
148 self.scheduler
149 }
150 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
151 self.scheduler_timer
152 }
153 fn watchdog(&self) -> &Self::WatchDog {
154 &()
155 }
156 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
157 &()
158 }
159}
160
161#[inline(never)]
165#[allow(clippy::large_stack_frames, clippy::large_stack_arrays)]
169pub unsafe fn start() -> (
170 &'static kernel::Kernel,
171 QemuRv32VirtPlatform,
172 &'static qemu_rv32_virt_chip::chip::QemuRv32VirtChip<
173 'static,
174 QemuRv32VirtDefaultPeripherals<'static>,
175 >,
176) {
177 extern "C" {
179 static _stext: u8;
181 static _etext: u8;
183 static _sflash: u8;
185 static _eflash: u8;
187 static _ssram: u8;
189 static _esram: u8;
191 }
192
193 rv32i::configure_trap_handler();
197
198 let epmp = rv32i::pmp::kernel_protection_mml_epmp::KernelProtectionMMLEPMP::new(
202 rv32i::pmp::kernel_protection_mml_epmp::FlashRegion(
203 rv32i::pmp::NAPOTRegionSpec::from_start_end(
204 core::ptr::addr_of!(_sflash),
205 core::ptr::addr_of!(_eflash),
206 )
207 .unwrap(),
208 ),
209 rv32i::pmp::kernel_protection_mml_epmp::RAMRegion(
210 rv32i::pmp::NAPOTRegionSpec::from_start_end(
211 core::ptr::addr_of!(_ssram),
212 core::ptr::addr_of!(_esram),
213 )
214 .unwrap(),
215 ),
216 rv32i::pmp::kernel_protection_mml_epmp::MMIORegion(
217 rv32i::pmp::NAPOTRegionSpec::from_start_size(
218 core::ptr::null::<u8>(), 0x20000000, )
221 .unwrap(),
222 ),
223 rv32i::pmp::kernel_protection_mml_epmp::KernelTextRegion(
224 rv32i::pmp::TORRegionSpec::from_start_end(
225 core::ptr::addr_of!(_stext),
226 core::ptr::addr_of!(_etext),
227 )
228 .unwrap(),
229 ),
230 )
231 .unwrap();
232
233 let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
235
236 let processes = components::process_array::ProcessArrayComponent::new()
240 .finalize(components::process_array_component_static!(NUM_PROCS));
241 PROCESSES = Some(processes);
242
243 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
245
246 let peripherals = static_init!(
249 QemuRv32VirtDefaultPeripherals,
250 QemuRv32VirtDefaultPeripherals::new(),
251 );
252
253 let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
257 .finalize(components::uart_mux_component_static!());
258
259 let hardware_timer = static_init!(
261 qemu_rv32_virt_chip::chip::QemuRv32VirtClint,
262 qemu_rv32_virt_chip::chip::QemuRv32VirtClint::new(&qemu_rv32_virt_chip::clint::CLINT_BASE)
263 );
264
265 let mux_alarm = static_init!(
268 MuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
269 MuxAlarm::new(hardware_timer)
270 );
271 hil::time::Alarm::set_alarm_client(hardware_timer, mux_alarm);
272
273 let systick_virtual_alarm = static_init!(
275 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
276 VirtualMuxAlarm::new(mux_alarm)
277 );
278 systick_virtual_alarm.setup();
279
280 let virtual_alarm_user = static_init!(
282 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
283 VirtualMuxAlarm::new(mux_alarm)
284 );
285 virtual_alarm_user.setup();
286
287 let alarm = static_init!(
288 capsules_core::alarm::AlarmDriver<
289 'static,
290 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint>,
291 >,
292 capsules_core::alarm::AlarmDriver::new(
293 virtual_alarm_user,
294 board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
295 )
296 );
297 hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
298
299 let (mut virtio_gpu_idx, mut virtio_net_idx, mut virtio_rng_idx, mut virtio_input_idx) =
307 (None, None, 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 Ok(VirtIODeviceType::GPUDevice) => {
312 virtio_gpu_idx = Some(i);
313 }
314 Ok(VirtIODeviceType::NetworkCard) => {
315 virtio_net_idx = Some(i);
316 }
317 Ok(VirtIODeviceType::EntropySource) => {
318 virtio_rng_idx = Some(i);
319 }
320 Ok(VirtIODeviceType::InputDevice) => {
321 virtio_input_idx = Some(i);
322 }
323 _ => (),
324 }
325 }
326
327 let virtio_gpu_screen: Option<
330 &'static capsules_extra::screen::screen_adapters::ScreenARGB8888ToMono8BitPage<
331 'static,
332 ScreenHw,
333 >,
334 > = if let Some(gpu_idx) = virtio_gpu_idx {
335 use qemu_rv32_virt_chip::virtio::devices::virtio_gpu::{
336 VirtIOGPU, MAX_REQ_SIZE, MAX_RESP_SIZE, PIXEL_STRIDE,
337 };
338 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
339 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
340 };
341 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
342 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
343
344 const VIDEO_WIDTH: usize = 128;
347 const VIDEO_HEIGHT: usize = 128;
348
349 let descriptors = static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
356 let available_ring =
357 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
358 let used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
359 let control_queue = static_init!(
360 SplitVirtqueue<2>,
361 SplitVirtqueue::new(descriptors, available_ring, used_ring),
362 );
363 control_queue.set_transport(&peripherals.virtio_mmio[gpu_idx]);
364
365 let req_buffer = static_init!([u8; MAX_REQ_SIZE], [0; MAX_REQ_SIZE]);
367 let resp_buffer = static_init!([u8; MAX_RESP_SIZE], [0; MAX_RESP_SIZE]);
368 let gpu = static_init!(
375 VirtIOGPU,
376 VirtIOGPU::new(
377 control_queue,
378 req_buffer,
379 resp_buffer,
380 VIDEO_WIDTH,
381 VIDEO_HEIGHT,
382 )
383 .unwrap()
384 );
385 kernel::deferred_call::DeferredCallClient::register(gpu);
386 control_queue.set_client(gpu);
387
388 let mmio_queues = static_init!([&'static dyn Virtqueue; 1], [control_queue; 1]);
391 peripherals.virtio_mmio[gpu_idx]
392 .initialize(gpu, mmio_queues)
393 .unwrap();
394
395 let screen_argb_8888_to_mono_8bit_page =
399 components::screen_adapters::ScreenAdapterARGB8888ToMono8BitPageComponent::new(gpu)
400 .finalize(
401 components::screen_adapter_argb8888_to_mono8bitpage_component_static!(
402 ScreenHw,
403 VIDEO_WIDTH,
404 VIDEO_HEIGHT,
405 PIXEL_STRIDE
406 ),
407 );
408
409 gpu.initialize().unwrap();
410
411 Some(screen_argb_8888_to_mono_8bit_page)
412 } else {
413 None
415 };
416
417 let virtio_rng: Option<&'static qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng> =
420 if let Some(rng_idx) = virtio_rng_idx {
421 use qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng;
422 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
423 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
424 };
425 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
426 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
427
428 let descriptors =
430 static_init!(VirtqueueDescriptors<1>, VirtqueueDescriptors::default(),);
431 let available_ring =
432 static_init!(VirtqueueAvailableRing<1>, VirtqueueAvailableRing::default(),);
433 let used_ring = static_init!(VirtqueueUsedRing<1>, VirtqueueUsedRing::default(),);
434 let queue = static_init!(
435 SplitVirtqueue<1>,
436 SplitVirtqueue::new(descriptors, available_ring, used_ring),
437 );
438 queue.set_transport(&peripherals.virtio_mmio[rng_idx]);
439
440 let rng = static_init!(VirtIORng, VirtIORng::new(queue));
442 kernel::deferred_call::DeferredCallClient::register(rng);
443 queue.set_client(rng);
444
445 let mmio_queues = static_init!([&'static dyn Virtqueue; 1], [queue; 1]);
448 peripherals.virtio_mmio[rng_idx]
449 .initialize(rng, mmio_queues)
450 .unwrap();
451
452 let rng_buffer = static_init!([u8; 64], [0; 64]);
454 rng.provide_buffer(rng_buffer)
455 .expect("rng: providing initial buffer failed");
456
457 Some(rng)
458 } else {
459 None
461 };
462
463 let virtio_ethernet_tap: Option<
467 &'static capsules_extra::ethernet_tap::EthernetTapDriver<
468 'static,
469 qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet<'static>,
470 >,
471 > = if let Some(net_idx) = virtio_net_idx {
472 use capsules_extra::ethernet_tap::EthernetTapDriver;
473 use kernel::hil::ethernet::EthernetAdapterDatapath;
474 use qemu_rv32_virt_chip::virtio::devices::virtio_net::VirtIONet;
475 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
476 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
477 };
478 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
479 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
480
481 let tx_descriptors =
488 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
489 let tx_available_ring =
490 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
491 let tx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
492 let tx_queue = static_init!(
493 SplitVirtqueue<2>,
494 SplitVirtqueue::new(tx_descriptors, tx_available_ring, tx_used_ring),
495 );
496 tx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
497
498 let rx_descriptors =
500 static_init!(VirtqueueDescriptors<2>, VirtqueueDescriptors::default(),);
501 let rx_available_ring =
502 static_init!(VirtqueueAvailableRing<2>, VirtqueueAvailableRing::default(),);
503 let rx_used_ring = static_init!(VirtqueueUsedRing<2>, VirtqueueUsedRing::default(),);
504 let rx_queue = static_init!(
505 SplitVirtqueue<2>,
506 SplitVirtqueue::new(rx_descriptors, rx_available_ring, rx_used_ring),
507 );
508 rx_queue.set_transport(&peripherals.virtio_mmio[net_idx]);
509
510 let tx_header_buf = static_init!([u8; 12], [0; 12]);
513 let rx_header_buf = static_init!([u8; 12], [0; 12]);
514
515 let rx_buffer = static_init!([u8; 1526], [0; 1526]);
518
519 let virtio_net = static_init!(
521 VirtIONet<'static>,
522 VirtIONet::new(tx_queue, tx_header_buf, rx_queue, rx_header_buf, rx_buffer),
523 );
524 tx_queue.set_client(virtio_net);
525 rx_queue.set_client(virtio_net);
526
527 let mmio_queues = static_init!([&'static dyn Virtqueue; 2], [rx_queue, tx_queue]);
530 peripherals.virtio_mmio[net_idx]
531 .initialize(virtio_net, mmio_queues)
532 .unwrap();
533
534 let virtio_ethernet_tap_tx_buffer = static_init!(
536 [u8; capsules_extra::ethernet_tap::MAX_MTU],
537 [0; capsules_extra::ethernet_tap::MAX_MTU],
538 );
539 let virtio_ethernet_tap = static_init!(
540 EthernetTapDriver<'static, VirtIONet<'static>>,
541 EthernetTapDriver::new(
542 virtio_net,
543 board_kernel.create_grant(
544 capsules_extra::ethernet_tap::DRIVER_NUM,
545 &memory_allocation_cap
546 ),
547 virtio_ethernet_tap_tx_buffer,
548 ),
549 );
550 virtio_net.set_client(virtio_ethernet_tap);
551
552 virtio_ethernet_tap.initialize();
554
555 Some(virtio_ethernet_tap as &'static EthernetTapDriver<'static, VirtIONet<'static>>)
556 } else {
557 None
559 };
560
561 let virtio_input_keyboard: Option<
562 &'static qemu_rv32_virt_chip::virtio::devices::virtio_input::VirtIOInput,
563 > = if let Some(input_idx) = virtio_input_idx {
564 use qemu_rv32_virt_chip::virtio::devices::virtio_input::VirtIOInput;
565 use qemu_rv32_virt_chip::virtio::queues::split_queue::{
566 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
567 };
568 use qemu_rv32_virt_chip::virtio::queues::Virtqueue;
569 use qemu_rv32_virt_chip::virtio::transports::VirtIOTransport;
570
571 let event_descriptors =
573 static_init!(VirtqueueDescriptors<3>, VirtqueueDescriptors::default(),);
574 let event_available_ring =
575 static_init!(VirtqueueAvailableRing<3>, VirtqueueAvailableRing::default(),);
576 let event_used_ring = static_init!(VirtqueueUsedRing<3>, VirtqueueUsedRing::default(),);
577 let event_queue = static_init!(
578 SplitVirtqueue<3>,
579 SplitVirtqueue::new(event_descriptors, event_available_ring, event_used_ring),
580 );
581 event_queue.set_transport(&peripherals.virtio_mmio[input_idx]);
582
583 let status_descriptors =
585 static_init!(VirtqueueDescriptors<1>, VirtqueueDescriptors::default(),);
586 let status_available_ring =
587 static_init!(VirtqueueAvailableRing<1>, VirtqueueAvailableRing::default(),);
588 let status_used_ring = static_init!(VirtqueueUsedRing<1>, VirtqueueUsedRing::default(),);
589 let status_queue = static_init!(
590 SplitVirtqueue<1>,
591 SplitVirtqueue::new(status_descriptors, status_available_ring, status_used_ring),
592 );
593 status_queue.set_transport(&peripherals.virtio_mmio[input_idx]);
594
595 let event_buf1 = static_init!([u8; 8], [0; 8]);
597 let event_buf2 = static_init!([u8; 8], [0; 8]);
598 let event_buf3 = static_init!([u8; 8], [0; 8]);
599 let status_buf = static_init!([u8; 128], [0; 128]);
600
601 let virtio_input = static_init!(
603 VirtIOInput<'static>,
604 VirtIOInput::new(event_queue, status_queue, status_buf),
605 );
606 event_queue.set_client(virtio_input);
607 status_queue.set_client(virtio_input);
608
609 let mmio_queues = static_init!([&'static dyn Virtqueue; 2], [event_queue, status_queue]);
612 peripherals.virtio_mmio[input_idx]
613 .initialize(virtio_input, mmio_queues)
614 .unwrap();
615
616 virtio_input.provide_buffers(event_buf1, event_buf2, event_buf3);
617
618 Some(virtio_input)
619 } else {
620 None
622 };
623
624 let chip = static_init!(
627 QemuRv32VirtChip<QemuRv32VirtDefaultPeripherals>,
628 QemuRv32VirtChip::new(peripherals, hardware_timer, epmp),
629 );
630 CHIP = Some(chip);
631
632 chip.enable_plic_interrupts();
634
635 csr::CSR
637 .mie
638 .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET);
639 csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
640
641 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
645 .finalize(components::process_printer_text_component_static!());
646 PROCESS_PRINTER = Some(process_printer);
647
648 let pconsole = components::process_console::ProcessConsoleComponent::new(
650 board_kernel,
651 uart_mux,
652 mux_alarm,
653 process_printer,
654 None,
655 )
656 .finalize(components::process_console_component_static!(
657 qemu_rv32_virt_chip::chip::QemuRv32VirtClint
658 ));
659
660 let console = components::console::ConsoleComponent::new(
662 board_kernel,
663 capsules_core::console::DRIVER_NUM,
664 uart_mux,
665 )
666 .finalize(components::console_component_static!());
667 components::debug_writer::DebugWriterComponent::new(
669 uart_mux,
670 create_capability!(capabilities::SetDebugWriterCapability),
671 )
672 .finalize(components::debug_writer_component_static!());
673
674 let lldb = components::lldb::LowLevelDebugComponent::new(
675 board_kernel,
676 capsules_core::low_level_debug::DRIVER_NUM,
677 uart_mux,
678 )
679 .finalize(components::low_level_debug_component_static!());
680
681 let rng_driver = virtio_rng.map(|rng| {
685 components::rng::RngRandomComponent::new(board_kernel, capsules_core::rng::DRIVER_NUM, rng)
686 .finalize(components::rng_random_component_static!(
687 qemu_rv32_virt_chip::virtio::devices::virtio_rng::VirtIORng
688 ))
689 });
690
691 let scheduler = components::sched::cooperative::CooperativeComponent::new(processes)
694 .finalize(components::cooperative_component_static!(NUM_PROCS));
695
696 let scheduler_timer = static_init!(
697 VirtualSchedulerTimer<
698 VirtualMuxAlarm<'static, qemu_rv32_virt_chip::chip::QemuRv32VirtClint<'static>>,
699 >,
700 VirtualSchedulerTimer::new(systick_virtual_alarm)
701 );
702
703 let platform = QemuRv32VirtPlatform {
704 pconsole,
705 console,
706 alarm,
707 lldb,
708 scheduler,
709 scheduler_timer,
710 rng: rng_driver,
711 virtio_ethernet_tap,
712 virtio_gpu_screen,
713 virtio_input_keyboard,
714 ipc: kernel::ipc::IPC::new(
715 board_kernel,
716 kernel::ipc::DRIVER_NUM,
717 &memory_allocation_cap,
718 ),
719 };
720
721 debug!("QEMU RISC-V 32-bit \"virt\" machine, initialization complete.");
722
723 if virtio_gpu_screen.is_some() {
727 debug!("- Found VirtIO GPUDevice, enabling video output");
728 } else {
729 debug!("- VirtIO GPUDevice not found, disabling video output");
730 }
731 if virtio_rng.is_some() {
732 debug!("- Found VirtIO EntropySource device, enabling RngDriver");
733 } else {
734 debug!("- VirtIO EntropySource device not found, disabling RngDriver");
735 }
736 if virtio_ethernet_tap.is_some() {
737 debug!("- Found VirtIO NetworkCard device, enabling EthernetTapDriver");
738 } else {
739 debug!("- VirtIO NetworkCard device not found, disabling EthernetTapDriver");
740 }
741 if virtio_input_keyboard.is_some() {
742 debug!("- Found VirtIO Input device, enabling Input");
743 } else {
744 debug!("- VirtIO Input device not found, disabling Input");
745 }
746
747 (board_kernel, platform, chip)
748}