1#![no_std]
8#![cfg_attr(not(doc), no_main)]
11
12use capsules_core::alarm;
13use capsules_core::console::{self, Console};
14use capsules_core::rng::RngDriver;
15use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
16use components::console::ConsoleComponent;
17use components::debug_writer::DebugWriterComponent;
18use core::ptr;
19use kernel::capabilities;
20use kernel::component::Component;
21use kernel::debug;
22use kernel::deferred_call::DeferredCallClient;
23use kernel::hil;
24use kernel::ipc::IPC;
25use kernel::platform::chip::{Chip, InterruptService};
26use kernel::platform::scheduler_timer::VirtualSchedulerTimer;
27use kernel::platform::{KernelResources, SyscallDriverLookup};
28use kernel::process::ProcessArray;
29use kernel::scheduler::cooperative::CooperativeSched;
30use kernel::syscall::SyscallDriver;
31use kernel::utilities::cells::OptionalCell;
32use kernel::{create_capability, static_init};
33use virtio::devices::virtio_rng::VirtIORng;
34use virtio::devices::VirtIODeviceType;
35use virtio_pci_x86::VirtIOPCIDevice;
36use x86::registers::bits32::paging::{PDEntry, PTEntry, PD, PT};
37use x86::registers::irq;
38use x86_q35::pit::{Pit, RELOAD_1KHZ};
39use x86_q35::{Pc, PcComponent};
40
41mod multiboot;
42use multiboot::MultibootV1Header;
43
44mod io;
45
46#[link_section = ".multiboot"]
48#[used]
49static MULTIBOOT_V1_HEADER: MultibootV1Header = MultibootV1Header::new(0);
50
51const NUM_PROCS: usize = 4;
52
53static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
55
56static mut CHIP: Option<&'static Pc<'static, ()>> = None;
58
59static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
61 None;
62
63const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
65 capsules_system::process_policies::PanicFaultPolicy {};
66
67kernel::stack_size! {0x1000}
68
69#[no_mangle]
73#[link_section = ".pde"]
74pub static mut PAGE_DIR: PD = [PDEntry(0); 1024];
75#[no_mangle]
76#[link_section = ".pte"]
77pub static mut PAGE_TABLE: PT = [PTEntry(0); 1024];
78
79fn init_virtio_dev(
91 dev: pci_x86::Device,
92 dev_type: VirtIODeviceType,
93) -> Option<(u8, VirtIOPCIDevice)> {
94 use pci_x86::cap::Cap;
95
96 let int_line = dev.int_line()?;
97
98 for cap in dev.capabilities() {
99 match cap {
100 Cap::Msi(cap) => {
101 cap.disable();
102 }
103 Cap::Msix(cap) => {
104 cap.disable();
105 }
106 _ => {}
107 }
108 }
109
110 let dev = VirtIOPCIDevice::from_pci_device(dev, dev_type)?;
111
112 Some((int_line, dev))
113}
114
115struct VirtioDevices {
118 rng: OptionalCell<(u8, &'static VirtIOPCIDevice)>,
119}
120
121impl InterruptService for VirtioDevices {
122 unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
123 let mut handled = false;
124
125 self.rng.map(|(int_line, dev)| {
126 if interrupt == (int_line as u32) {
127 dev.handle_interrupt();
128 handled = true;
129 }
130 });
131
132 handled
133 }
134}
135
136pub struct QemuI386Q35Platform {
137 pconsole: &'static capsules_core::process_console::ProcessConsole<
138 'static,
139 { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
140 VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>,
141 components::process_console::Capability,
142 >,
143 console: &'static Console<'static>,
144 lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
145 'static,
146 capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
147 >,
148 alarm: &'static capsules_core::alarm::AlarmDriver<
149 'static,
150 VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>,
151 >,
152 ipc: IPC<{ NUM_PROCS as u8 }>,
153 scheduler: &'static CooperativeSched<'static>,
154 scheduler_timer:
155 &'static VirtualSchedulerTimer<VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>>,
156 rng: Option<&'static RngDriver<'static, VirtIORng<'static, 'static>>>,
157}
158
159impl SyscallDriverLookup for QemuI386Q35Platform {
160 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
161 where
162 F: FnOnce(Option<&dyn SyscallDriver>) -> R,
163 {
164 match driver_num {
165 console::DRIVER_NUM => f(Some(self.console)),
166 alarm::DRIVER_NUM => f(Some(self.alarm)),
167 capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
168 capsules_core::rng::DRIVER_NUM => {
169 if let Some(rng) = self.rng {
170 f(Some(rng))
171 } else {
172 f(None)
173 }
174 }
175 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
176 _ => f(None),
177 }
178 }
179}
180
181impl<C: Chip> KernelResources<C> for QemuI386Q35Platform {
182 type SyscallDriverLookup = Self;
183 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
184 self
185 }
186
187 type SyscallFilter = ();
188 fn syscall_filter(&self) -> &Self::SyscallFilter {
189 &()
190 }
191
192 type ProcessFault = ();
193 fn process_fault(&self) -> &Self::ProcessFault {
194 &()
195 }
196
197 type Scheduler = CooperativeSched<'static>;
198 fn scheduler(&self) -> &Self::Scheduler {
199 self.scheduler
200 }
201
202 type SchedulerTimer =
203 VirtualSchedulerTimer<VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>>;
204 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
205 self.scheduler_timer
206 }
207
208 type WatchDog = ();
209 fn watchdog(&self) -> &Self::WatchDog {
210 &()
211 }
212
213 type ContextSwitchCallback = ();
214 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
215 &()
216 }
217}
218#[no_mangle]
219unsafe extern "cdecl" fn main() {
220 let virtio_devs = static_init!(
224 VirtioDevices,
225 VirtioDevices {
226 rng: OptionalCell::empty(),
227 }
228 );
229 let chip = PcComponent::new(
230 &mut *ptr::addr_of_mut!(PAGE_DIR),
231 &mut *ptr::addr_of_mut!(PAGE_TABLE),
232 virtio_devs,
233 )
234 .finalize(x86_q35::x86_q35_component_static!(VirtioDevices));
235
236 let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
238 let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
239 let main_loop_cap = create_capability!(capabilities::MainLoopCapability);
240
241 let processes = components::process_array::ProcessArrayComponent::new()
243 .finalize(components::process_array_component_static!(NUM_PROCS));
244 PROCESSES = Some(processes);
245
246 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
248
249 let uart_mux = components::console::UartMuxComponent::new(chip.com1, 115_200)
254 .finalize(components::uart_mux_component_static!());
255
256 let vga_uart_mux = components::console::UartMuxComponent::new(chip.vga, 115_200)
258 .finalize(components::uart_mux_component_static!());
259
260 let debug_uart_device = vga_uart_mux;
266
267 let mux_alarm = static_init!(
272 MuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>,
273 MuxAlarm::new(&chip.pit),
274 );
275 hil::time::Alarm::set_alarm_client(&chip.pit, mux_alarm);
276
277 let systick_virtual_alarm = static_init!(
279 VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>,
280 VirtualMuxAlarm::new(mux_alarm)
281 );
282 systick_virtual_alarm.setup();
283
284 let virtual_alarm_user = static_init!(
286 VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>,
287 VirtualMuxAlarm::new(mux_alarm)
288 );
289 virtual_alarm_user.setup();
290
291 let alarm = static_init!(
292 capsules_core::alarm::AlarmDriver<
293 'static,
294 VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>,
295 >,
296 capsules_core::alarm::AlarmDriver::new(
297 virtual_alarm_user,
298 board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
299 )
300 );
301 hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
302
303 let mut virtio_rng_dev = None;
310 for dev in pci_x86::iter() {
311 use virtio::devices::VirtIODeviceType;
312 use virtio_pci_x86::{DEVICE_ID_BASE, VENDOR_ID};
313
314 if dev.vendor_id() != VENDOR_ID {
316 continue;
317 }
318 let dev_id = dev.device_id();
319 if dev_id < DEVICE_ID_BASE {
320 continue;
321 }
322
323 let dev_id = (dev_id - DEVICE_ID_BASE) as u32;
325 let Some(dev_type) = VirtIODeviceType::from_device_id(dev_id) else {
326 continue;
327 };
328
329 if dev_type == VirtIODeviceType::EntropySource {
330 if virtio_rng_dev.is_some() {
332 continue;
333 }
334
335 virtio_rng_dev = Some(dev);
336 }
337 }
338
339 let virtio_rng: Option<&'static VirtIORng> = if let Some(rng_dev) = virtio_rng_dev {
342 use virtio::queues::split_queue::{
343 SplitVirtqueue, VirtqueueAvailableRing, VirtqueueDescriptors, VirtqueueUsedRing,
344 };
345 use virtio::queues::Virtqueue;
346 use virtio::transports::VirtIOTransport;
347
348 let (int_line, transport) = init_virtio_dev(rng_dev, VirtIODeviceType::EntropySource)
350 .expect("virtio pci init failed");
351 let transport = static_init!(VirtIOPCIDevice, transport);
352
353 let descriptors = static_init!(VirtqueueDescriptors<1>, VirtqueueDescriptors::default(),);
355 let available_ring =
356 static_init!(VirtqueueAvailableRing<1>, VirtqueueAvailableRing::default(),);
357 let used_ring = static_init!(VirtqueueUsedRing<1>, VirtqueueUsedRing::default(),);
358 let queue = static_init!(
359 SplitVirtqueue<1>,
360 SplitVirtqueue::new(descriptors, available_ring, used_ring),
361 );
362 queue.set_transport(transport);
363
364 let rng = static_init!(VirtIORng, VirtIORng::new(queue));
366 DeferredCallClient::register(rng);
367 queue.set_client(rng);
368
369 let queues = static_init!([&'static dyn Virtqueue; 1], [queue; 1]);
372 transport.initialize(rng, queues).unwrap();
373
374 let rng_buffer = static_init!([u8; 64], [0; 64]);
376 rng.provide_buffer(rng_buffer)
377 .expect("rng: providing initial buffer failed");
378
379 virtio_devs.rng.set((int_line, transport));
382
383 Some(rng)
384 } else {
385 None
386 };
387
388 chip.pit.start();
392
393 irq::enable();
395
396 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
400 .finalize(components::process_printer_text_component_static!());
401 PROCESS_PRINTER = Some(process_printer);
402
403 let console_uart_device = uart_mux;
413
414 let pconsole = components::process_console::ProcessConsoleComponent::new(
416 board_kernel,
417 console_uart_device,
418 mux_alarm,
419 process_printer,
420 None,
421 )
422 .finalize(components::process_console_component_static!(
423 Pit<'static, RELOAD_1KHZ>
424 ));
425
426 let console = ConsoleComponent::new(board_kernel, console::DRIVER_NUM, console_uart_device)
428 .finalize(components::console_component_static!());
429
430 DebugWriterComponent::new(
432 debug_uart_device,
433 create_capability!(capabilities::SetDebugWriterCapability),
434 )
435 .finalize(components::debug_writer_component_static!());
436
437 let lldb = components::lldb::LowLevelDebugComponent::new(
438 board_kernel,
439 capsules_core::low_level_debug::DRIVER_NUM,
440 uart_mux,
441 )
442 .finalize(components::low_level_debug_component_static!());
443
444 let rng_driver = virtio_rng.map(|rng| {
448 components::rng::RngRandomComponent::new(board_kernel, capsules_core::rng::DRIVER_NUM, rng)
449 .finalize(components::rng_random_component_static!(VirtIORng))
450 });
451
452 let scheduler = components::sched::cooperative::CooperativeComponent::new(processes)
453 .finalize(components::cooperative_component_static!(NUM_PROCS));
454
455 let scheduler_timer = static_init!(
456 VirtualSchedulerTimer<VirtualMuxAlarm<'static, Pit<'static, RELOAD_1KHZ>>>,
457 VirtualSchedulerTimer::new(systick_virtual_alarm)
458 );
459
460 let platform = QemuI386Q35Platform {
461 pconsole,
462 console,
463 alarm,
464 lldb,
465 scheduler,
466 scheduler_timer,
467 rng: rng_driver,
468 ipc: kernel::ipc::IPC::new(
469 board_kernel,
470 kernel::ipc::DRIVER_NUM,
471 &memory_allocation_cap,
472 ),
473 };
474
475 let _ = platform.pconsole.start();
477
478 debug!("QEMU i486 \"Q35\" machine, initialization complete.");
479 debug!("Entering main loop.");
480
481 extern "C" {
483 static _sapps: u8;
485 static _eapps: u8;
487 static mut _sappmem: u8;
489 static _eappmem: u8;
491 }
492
493 kernel::process::load_processes(
496 board_kernel,
497 chip,
498 core::slice::from_raw_parts(
499 ptr::addr_of!(_sapps),
500 ptr::addr_of!(_eapps) as usize - ptr::addr_of!(_sapps) as usize,
501 ),
502 core::slice::from_raw_parts_mut(
503 ptr::addr_of_mut!(_sappmem),
504 ptr::addr_of!(_eappmem) as usize - ptr::addr_of!(_sappmem) as usize,
505 ),
506 &FAULT_RESPONSE,
507 &process_mgmt_cap,
508 )
509 .unwrap_or_else(|err| {
510 debug!("Error loading processes!");
511 debug!("{:?}", err);
512 });
513
514 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_cap);
515}