1#![no_std]
9#![no_main]
10
11use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
12use kernel::capabilities;
13use kernel::component::Component;
14use kernel::debug::PanicResources;
15use kernel::hil::time::{Alarm, Timer};
16use kernel::platform::chip::InterruptService;
17use kernel::platform::{KernelResources, SyscallDriverLookup};
18use kernel::scheduler::mlfq::MLFQSched;
19use kernel::utilities::registers::interfaces::ReadWriteable;
20use kernel::utilities::single_thread_value::SingleThreadValue;
21use kernel::utilities::StaticRef;
22use kernel::{create_capability, debug, static_init};
23use rv32i::csr;
24
25mod io;
26mod litex_generated_constants;
27
28use litex_generated_constants as socc;
35
36struct LiteXArtyInterruptablePeripherals {
44 uart0: &'static litex_vexriscv::uart::LiteXUart<'static, socc::SoCRegisterFmt>,
45 timer0: &'static litex_vexriscv::timer::LiteXTimer<
46 'static,
47 socc::SoCRegisterFmt,
48 socc::ClockFrequency,
49 >,
50 ethmac0: &'static litex_vexriscv::liteeth::LiteEth<
51 'static,
52 { socc::ETHMAC_TX_SLOTS },
53 socc::SoCRegisterFmt,
54 >,
55}
56
57impl LiteXArtyInterruptablePeripherals {
58 pub fn init(&'static self) {
60 kernel::deferred_call::DeferredCallClient::register(self.uart0);
61 }
62}
63
64impl InterruptService for LiteXArtyInterruptablePeripherals {
65 unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
66 match interrupt as usize {
67 socc::UART_INTERRUPT => {
68 self.uart0.service_interrupt();
69 true
70 }
71 socc::TIMER0_INTERRUPT => {
72 self.timer0.service_interrupt();
73 true
74 }
75 socc::ETHMAC_INTERRUPT => {
76 self.ethmac0.service_interrupt();
77 true
78 }
79 _ => false,
80 }
81 }
82}
83
84const NUM_PROCS: usize = 4;
85
86type ChipHw = litex_vexriscv::chip::LiteXVexRiscv<LiteXArtyInterruptablePeripherals>;
87type AlarmHw =
88 litex_vexriscv::timer::LiteXAlarm<'static, 'static, socc::SoCRegisterFmt, socc::ClockFrequency>;
89type SchedulerTimerHw =
90 components::virtual_scheduler_timer::VirtualSchedulerTimerComponentType<AlarmHw>;
91type ProcessPrinterInUse = capsules_system::process_printer::ProcessPrinterText;
92
93static PANIC_RESOURCES: SingleThreadValue<PanicResources<ChipHw, ProcessPrinterInUse>> =
95 SingleThreadValue::new(PanicResources::new());
96
97const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
99 capsules_system::process_policies::PanicFaultPolicy {};
100
101kernel::stack_size! {0x2000}
102
103struct LiteXArty {
106 led_driver: &'static capsules_core::led::LedDriver<
107 'static,
108 litex_vexriscv::led_controller::LiteXLed<'static, socc::SoCRegisterFmt>,
109 4,
110 >,
111 console: &'static capsules_core::console::Console<'static>,
112 pconsole: &'static capsules_core::process_console::ProcessConsole<
113 'static,
114 { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
115 VirtualMuxAlarm<'static, AlarmHw>,
116 components::process_console::Capability,
117 >,
118 lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
119 'static,
120 capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
121 >,
122 alarm: &'static capsules_core::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, AlarmHw>>,
123 ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
124 scheduler: &'static MLFQSched<'static, VirtualMuxAlarm<'static, AlarmHw>>,
125 scheduler_timer: &'static SchedulerTimerHw,
126}
127
128impl SyscallDriverLookup for LiteXArty {
130 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
131 where
132 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
133 {
134 match driver_num {
135 capsules_core::led::DRIVER_NUM => f(Some(self.led_driver)),
136 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
137 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
138 capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
139 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
140 _ => f(None),
141 }
142 }
143}
144
145impl KernelResources<litex_vexriscv::chip::LiteXVexRiscv<LiteXArtyInterruptablePeripherals>>
146 for LiteXArty
147{
148 type SyscallDriverLookup = Self;
149 type SyscallFilter = ();
150 type ProcessFault = ();
151 type Scheduler = MLFQSched<'static, VirtualMuxAlarm<'static, AlarmHw>>;
152 type SchedulerTimer = SchedulerTimerHw;
153 type WatchDog = ();
154 type ContextSwitchCallback = ();
155
156 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
157 self
158 }
159 fn syscall_filter(&self) -> &Self::SyscallFilter {
160 &()
161 }
162 fn process_fault(&self) -> &Self::ProcessFault {
163 &()
164 }
165 fn scheduler(&self) -> &Self::Scheduler {
166 self.scheduler
167 }
168 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
169 self.scheduler_timer
170 }
171 fn watchdog(&self) -> &Self::WatchDog {
172 &()
173 }
174 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
175 &()
176 }
177}
178
179#[inline(never)]
183unsafe fn start() -> (
184 &'static kernel::Kernel,
185 LiteXArty,
186 &'static litex_vexriscv::chip::LiteXVexRiscv<LiteXArtyInterruptablePeripherals>,
187) {
188 extern "C" {
190 static _sapps: u8;
192 static _eapps: u8;
194 static mut _sappmem: u8;
196 static _eappmem: u8;
198 static _stext: u8;
200 static _etext: u8;
202 static _sflash: u8;
204 static _eflash: u8;
206 static _ssram: u8;
208 static _esram: u8;
210 }
211
212 rv32i::configure_trap_handler();
216
217 kernel::deferred_call::initialize_deferred_call_state_unsafe::<
219 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
220 >();
221
222 PANIC_RESOURCES
224 .bind_to_thread_unsafe::<<ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider>();
225
226 let pmp = rv32i::pmp::kernel_protection::KernelProtectionPMP::new(
230 rv32i::pmp::kernel_protection::FlashRegion(
231 rv32i::pmp::NAPOTRegionSpec::from_start_end(
232 core::ptr::addr_of!(_sflash),
233 core::ptr::addr_of!(_eflash),
234 )
235 .unwrap(),
236 ),
237 rv32i::pmp::kernel_protection::RAMRegion(
238 rv32i::pmp::NAPOTRegionSpec::from_start_end(
239 core::ptr::addr_of!(_ssram),
240 core::ptr::addr_of!(_esram),
241 )
242 .unwrap(),
243 ),
244 rv32i::pmp::kernel_protection::MMIORegion(
245 rv32i::pmp::NAPOTRegionSpec::from_start_size(
246 0xf0000000 as *const u8, 0x10000000, )
249 .unwrap(),
250 ),
251 rv32i::pmp::kernel_protection::KernelTextRegion(
252 rv32i::pmp::TORRegionSpec::from_start_end(
253 core::ptr::addr_of!(_stext),
254 core::ptr::addr_of!(_etext),
255 )
256 .unwrap(),
257 ),
258 )
259 .unwrap();
260
261 let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
263 let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
264
265 let processes = components::process_array::ProcessArrayComponent::new()
267 .finalize(components::process_array_component_static!(NUM_PROCS));
268 PANIC_RESOURCES.get().map(|resources| {
269 resources.processes.put(processes.as_slice());
270 });
271
272 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
274
275 let led0 = static_init!(
280 litex_vexriscv::led_controller::LiteXLedController<socc::SoCRegisterFmt>,
281 litex_vexriscv::led_controller::LiteXLedController::new(
282 StaticRef::new(
283 socc::CSR_LEDS_BASE
284 as *const litex_vexriscv::led_controller::LiteXLedRegisters<
285 socc::SoCRegisterFmt,
286 >
287 ),
288 4, )
290 );
291 led0.initialize();
292
293 let timer0 = static_init!(
297 litex_vexriscv::timer::LiteXTimer<'static, socc::SoCRegisterFmt, socc::ClockFrequency>,
298 litex_vexriscv::timer::LiteXTimer::new(StaticRef::new(
299 socc::CSR_TIMER0_BASE
300 as *const litex_vexriscv::timer::LiteXTimerRegisters<socc::SoCRegisterFmt>
301 ),)
302 );
303
304 let timer0_uptime = static_init!(
306 litex_vexriscv::timer::LiteXTimerUptime<
307 'static,
308 socc::SoCRegisterFmt,
309 socc::ClockFrequency,
310 >,
311 litex_vexriscv::timer::LiteXTimerUptime::new(timer0)
312 );
313
314 let litex_alarm = static_init!(
317 AlarmHw,
318 litex_vexriscv::timer::LiteXAlarm::new(timer0_uptime, timer0)
319 );
320 timer0.set_timer_client(litex_alarm);
321 litex_alarm.initialize();
322
323 let mux_alarm = static_init!(MuxAlarm<'static, AlarmHw>, MuxAlarm::new(litex_alarm));
326 litex_alarm.set_alarm_client(mux_alarm);
327
328 let virtual_alarm_user = static_init!(
330 VirtualMuxAlarm<'static, AlarmHw>,
331 VirtualMuxAlarm::new(mux_alarm)
332 );
333 virtual_alarm_user.setup();
334
335 let alarm = static_init!(
336 capsules_core::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, AlarmHw>>,
337 capsules_core::alarm::AlarmDriver::new(
338 virtual_alarm_user,
339 board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
340 )
341 );
342 virtual_alarm_user.set_alarm_client(alarm);
343
344 let scheduler_timer =
345 components::virtual_scheduler_timer::VirtualSchedulerTimerComponent::new(mux_alarm)
346 .finalize(components::virtual_scheduler_timer_component_static!(
347 AlarmHw
348 ));
349
350 let uart0 = static_init!(
354 litex_vexriscv::uart::LiteXUart<socc::SoCRegisterFmt>,
355 litex_vexriscv::uart::LiteXUart::new(
356 StaticRef::new(
357 socc::CSR_UART_BASE
358 as *const litex_vexriscv::uart::LiteXUartRegisters<socc::SoCRegisterFmt>,
359 ),
360 None,
364 )
365 );
366 uart0.initialize();
367
368 let uart_mux = components::console::UartMuxComponent::new(uart0, socc::UART_BAUDRATE)
370 .finalize(components::uart_mux_component_static!());
371
372 let ethmac0 = static_init!(
376 litex_vexriscv::liteeth::LiteEth<{socc::ETHMAC_TX_SLOTS}, socc::SoCRegisterFmt>,
377 litex_vexriscv::liteeth::LiteEth::new(
378 StaticRef::new(
379 socc::CSR_ETHMAC_BASE
380 as *const litex_vexriscv::liteeth::LiteEthMacRegisters<socc::SoCRegisterFmt>,
381 ),
382 socc::MEM_ETHMAC_BASE,
383 socc::MEM_ETHMAC_SIZE,
384 socc::ETHMAC_SLOT_SIZE,
385 socc::ETHMAC_RX_SLOTS,
386 socc::ETHMAC_TX_SLOTS,
387 )
388 );
389
390 ethmac0.initialize();
392
393 let led_driver =
397 components::led::LedsComponent::new().finalize(components::led_component_static!(
398 litex_vexriscv::led_controller::LiteXLed<'static, socc::SoCRegisterFmt>,
399 led0.get_led(0).unwrap(),
400 led0.get_led(1).unwrap(),
401 led0.get_led(2).unwrap(),
402 led0.get_led(3).unwrap(),
403 ));
404
405 let interrupt_service = static_init!(
408 LiteXArtyInterruptablePeripherals,
409 LiteXArtyInterruptablePeripherals {
410 uart0,
411 timer0,
412 ethmac0,
413 }
414 );
415 interrupt_service.init();
416
417 let chip = static_init!(
418 litex_vexriscv::chip::LiteXVexRiscv<
419 LiteXArtyInterruptablePeripherals,
420 >,
421 litex_vexriscv::chip::LiteXVexRiscv::new(
422 "LiteX on Arty A7",
423 interrupt_service,
424 pmp,
425 )
426 );
427 PANIC_RESOURCES.get().map(|resources| {
428 resources.chip.put(chip);
429 });
430
431 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
432 .finalize(components::process_printer_text_component_static!());
433 PANIC_RESOURCES.get().map(|resources| {
434 resources.printer.put(process_printer);
435 });
436
437 csr::CSR
439 .mie
440 .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET);
441 csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
442
443 chip.unmask_interrupts();
445
446 let pconsole = components::process_console::ProcessConsoleComponent::new(
448 board_kernel,
449 uart_mux,
450 mux_alarm,
451 process_printer,
452 None,
453 )
454 .finalize(components::process_console_component_static!(AlarmHw));
455
456 let console = components::console::ConsoleComponent::new(
458 board_kernel,
459 capsules_core::console::DRIVER_NUM,
460 uart_mux,
461 )
462 .finalize(components::console_component_static!());
463
464 components::debug_writer::DebugWriterComponent::new_unsafe(
466 uart_mux,
467 create_capability!(capabilities::SetDebugWriterCapability),
468 || unsafe {
469 kernel::debug::initialize_debug_writer_wrapper_unsafe::<
470 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
471 >();
472 },
473 )
474 .finalize(components::debug_writer_component_static!());
475
476 let lldb = components::lldb::LowLevelDebugComponent::new(
477 board_kernel,
478 capsules_core::low_level_debug::DRIVER_NUM,
479 uart_mux,
480 )
481 .finalize(components::low_level_debug_component_static!());
482
483 let scheduler = components::sched::mlfq::MLFQComponent::new(mux_alarm, processes).finalize(
484 components::mlfq_component_static!(
485 litex_vexriscv::timer::LiteXAlarm<
486 'static,
487 'static,
488 socc::SoCRegisterFmt,
489 socc::ClockFrequency,
490 >,
491 NUM_PROCS
492 ),
493 );
494
495 let litex_arty = LiteXArty {
496 console,
497 pconsole,
498 alarm,
499 lldb,
500 led_driver,
501 scheduler,
502 scheduler_timer,
503 ipc: kernel::ipc::IPC::new(
504 board_kernel,
505 kernel::ipc::DRIVER_NUM,
506 &memory_allocation_cap,
507 ),
508 };
509
510 debug!("LiteX+VexRiscv on ArtyA7: initialization complete, entering main loop.");
511 let _ = litex_arty.pconsole.start();
512
513 kernel::process::load_processes(
514 board_kernel,
515 chip,
516 core::slice::from_raw_parts(
517 core::ptr::addr_of!(_sapps),
518 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
519 ),
520 core::slice::from_raw_parts_mut(
521 core::ptr::addr_of_mut!(_sappmem),
522 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
523 ),
524 &FAULT_RESPONSE,
525 &process_mgmt_cap,
526 )
527 .unwrap_or_else(|err| {
528 debug!("Error loading processes!");
529 debug!("{:?}", err);
530 });
531
532 (board_kernel, litex_arty, chip)
533}
534
535#[no_mangle]
537pub unsafe fn main() {
538 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
539
540 let (board_kernel, board, chip) = start();
541 board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
542}