1#![no_std]
9#![no_main]
10
11use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
12
13use kernel::capabilities;
14use kernel::component::Component;
15use kernel::hil::time::{Alarm, Timer};
16use kernel::platform::chip::InterruptService;
17use kernel::platform::scheduler_timer::VirtualSchedulerTimer;
18use kernel::platform::{KernelResources, SyscallDriverLookup};
19use kernel::process::ProcessArray;
20use kernel::scheduler::mlfq::MLFQSched;
21use kernel::utilities::registers::interfaces::ReadWriteable;
22use kernel::utilities::StaticRef;
23use kernel::{create_capability, debug, static_init};
24use rv32i::csr;
25
26mod io;
27mod litex_generated_constants;
28
29use litex_generated_constants as socc;
36
37struct LiteXArtyInterruptablePeripherals {
45    uart0: &'static litex_vexriscv::uart::LiteXUart<'static, socc::SoCRegisterFmt>,
46    timer0: &'static litex_vexriscv::timer::LiteXTimer<
47        'static,
48        socc::SoCRegisterFmt,
49        socc::ClockFrequency,
50    >,
51    ethmac0: &'static litex_vexriscv::liteeth::LiteEth<
52        'static,
53        { socc::ETHMAC_TX_SLOTS },
54        socc::SoCRegisterFmt,
55    >,
56}
57
58impl LiteXArtyInterruptablePeripherals {
59    pub fn init(&'static self) {
61        kernel::deferred_call::DeferredCallClient::register(self.uart0);
62    }
63}
64
65impl InterruptService for LiteXArtyInterruptablePeripherals {
66    unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
67        match interrupt as usize {
68            socc::UART_INTERRUPT => {
69                self.uart0.service_interrupt();
70                true
71            }
72            socc::TIMER0_INTERRUPT => {
73                self.timer0.service_interrupt();
74                true
75            }
76            socc::ETHMAC_INTERRUPT => {
77                self.ethmac0.service_interrupt();
78                true
79            }
80            _ => false,
81        }
82    }
83}
84
85const NUM_PROCS: usize = 4;
86
87type ChipHw = litex_vexriscv::chip::LiteXVexRiscv<LiteXArtyInterruptablePeripherals>;
88
89static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
91
92struct LiteXArtyPanicReferences {
95    chip: Option<&'static litex_vexriscv::chip::LiteXVexRiscv<LiteXArtyInterruptablePeripherals>>,
96    uart: Option<&'static litex_vexriscv::uart::LiteXUart<'static, socc::SoCRegisterFmt>>,
97    led_controller:
98        Option<&'static litex_vexriscv::led_controller::LiteXLedController<socc::SoCRegisterFmt>>,
99    process_printer: Option<&'static capsules_system::process_printer::ProcessPrinterText>,
100}
101static mut PANIC_REFERENCES: LiteXArtyPanicReferences = LiteXArtyPanicReferences {
102    chip: None,
103    uart: None,
104    led_controller: None,
105    process_printer: None,
106};
107
108const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
110    capsules_system::process_policies::PanicFaultPolicy {};
111
112kernel::stack_size! {0x2000}
113
114struct LiteXArty {
117    led_driver: &'static capsules_core::led::LedDriver<
118        'static,
119        litex_vexriscv::led_controller::LiteXLed<'static, socc::SoCRegisterFmt>,
120        4,
121    >,
122    console: &'static capsules_core::console::Console<'static>,
123    pconsole: &'static capsules_core::process_console::ProcessConsole<
124        'static,
125        { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
126        VirtualMuxAlarm<
127            'static,
128            litex_vexriscv::timer::LiteXAlarm<
129                'static,
130                'static,
131                socc::SoCRegisterFmt,
132                socc::ClockFrequency,
133            >,
134        >,
135        components::process_console::Capability,
136    >,
137    lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
138        'static,
139        capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
140    >,
141    alarm: &'static capsules_core::alarm::AlarmDriver<
142        'static,
143        VirtualMuxAlarm<
144            'static,
145            litex_vexriscv::timer::LiteXAlarm<
146                'static,
147                'static,
148                socc::SoCRegisterFmt,
149                socc::ClockFrequency,
150            >,
151        >,
152    >,
153    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
154    scheduler: &'static MLFQSched<
155        'static,
156        VirtualMuxAlarm<
157            'static,
158            litex_vexriscv::timer::LiteXAlarm<
159                'static,
160                'static,
161                socc::SoCRegisterFmt,
162                socc::ClockFrequency,
163            >,
164        >,
165    >,
166    scheduler_timer: &'static VirtualSchedulerTimer<
167        VirtualMuxAlarm<
168            'static,
169            litex_vexriscv::timer::LiteXAlarm<
170                'static,
171                'static,
172                socc::SoCRegisterFmt,
173                socc::ClockFrequency,
174            >,
175        >,
176    >,
177}
178
179impl SyscallDriverLookup for LiteXArty {
181    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
182    where
183        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
184    {
185        match driver_num {
186            capsules_core::led::DRIVER_NUM => f(Some(self.led_driver)),
187            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
188            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
189            capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
190            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
191            _ => f(None),
192        }
193    }
194}
195
196impl KernelResources<litex_vexriscv::chip::LiteXVexRiscv<LiteXArtyInterruptablePeripherals>>
197    for LiteXArty
198{
199    type SyscallDriverLookup = Self;
200    type SyscallFilter = ();
201    type ProcessFault = ();
202    type Scheduler = MLFQSched<
203        'static,
204        VirtualMuxAlarm<
205            'static,
206            litex_vexriscv::timer::LiteXAlarm<
207                'static,
208                'static,
209                socc::SoCRegisterFmt,
210                socc::ClockFrequency,
211            >,
212        >,
213    >;
214    type SchedulerTimer = VirtualSchedulerTimer<
215        VirtualMuxAlarm<
216            'static,
217            litex_vexriscv::timer::LiteXAlarm<
218                'static,
219                'static,
220                socc::SoCRegisterFmt,
221                socc::ClockFrequency,
222            >,
223        >,
224    >;
225    type WatchDog = ();
226    type ContextSwitchCallback = ();
227
228    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
229        self
230    }
231    fn syscall_filter(&self) -> &Self::SyscallFilter {
232        &()
233    }
234    fn process_fault(&self) -> &Self::ProcessFault {
235        &()
236    }
237    fn scheduler(&self) -> &Self::Scheduler {
238        self.scheduler
239    }
240    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
241        self.scheduler_timer
242    }
243    fn watchdog(&self) -> &Self::WatchDog {
244        &()
245    }
246    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
247        &()
248    }
249}
250
251#[inline(never)]
255unsafe fn start() -> (
256    &'static kernel::Kernel,
257    LiteXArty,
258    &'static litex_vexriscv::chip::LiteXVexRiscv<LiteXArtyInterruptablePeripherals>,
259) {
260    extern "C" {
262        static _sapps: u8;
264        static _eapps: u8;
266        static mut _sappmem: u8;
268        static _eappmem: u8;
270        static _stext: u8;
272        static _etext: u8;
274        static _sflash: u8;
276        static _eflash: u8;
278        static _ssram: u8;
280        static _esram: u8;
282    }
283
284    rv32i::configure_trap_handler();
288
289    let pmp = rv32i::pmp::kernel_protection::KernelProtectionPMP::new(
293        rv32i::pmp::kernel_protection::FlashRegion(
294            rv32i::pmp::NAPOTRegionSpec::from_start_end(
295                core::ptr::addr_of!(_sflash),
296                core::ptr::addr_of!(_eflash),
297            )
298            .unwrap(),
299        ),
300        rv32i::pmp::kernel_protection::RAMRegion(
301            rv32i::pmp::NAPOTRegionSpec::from_start_end(
302                core::ptr::addr_of!(_ssram),
303                core::ptr::addr_of!(_esram),
304            )
305            .unwrap(),
306        ),
307        rv32i::pmp::kernel_protection::MMIORegion(
308            rv32i::pmp::NAPOTRegionSpec::from_start_size(
309                0xf0000000 as *const u8, 0x10000000,              )
312            .unwrap(),
313        ),
314        rv32i::pmp::kernel_protection::KernelTextRegion(
315            rv32i::pmp::TORRegionSpec::from_start_end(
316                core::ptr::addr_of!(_stext),
317                core::ptr::addr_of!(_etext),
318            )
319            .unwrap(),
320        ),
321    )
322    .unwrap();
323
324    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
326    let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
327
328    let processes = components::process_array::ProcessArrayComponent::new()
330        .finalize(components::process_array_component_static!(NUM_PROCS));
331    PROCESSES = Some(processes);
332
333    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
335
336    let led0 = static_init!(
341        litex_vexriscv::led_controller::LiteXLedController<socc::SoCRegisterFmt>,
342        litex_vexriscv::led_controller::LiteXLedController::new(
343            StaticRef::new(
344                socc::CSR_LEDS_BASE
345                    as *const litex_vexriscv::led_controller::LiteXLedRegisters<
346                        socc::SoCRegisterFmt,
347                    >
348            ),
349            4, )
351    );
352    led0.initialize();
353
354    PANIC_REFERENCES.led_controller = Some(led0);
355
356    let timer0 = static_init!(
360        litex_vexriscv::timer::LiteXTimer<'static, socc::SoCRegisterFmt, socc::ClockFrequency>,
361        litex_vexriscv::timer::LiteXTimer::new(StaticRef::new(
362            socc::CSR_TIMER0_BASE
363                as *const litex_vexriscv::timer::LiteXTimerRegisters<socc::SoCRegisterFmt>
364        ),)
365    );
366
367    let timer0_uptime = static_init!(
369        litex_vexriscv::timer::LiteXTimerUptime<
370            'static,
371            socc::SoCRegisterFmt,
372            socc::ClockFrequency,
373        >,
374        litex_vexriscv::timer::LiteXTimerUptime::new(timer0)
375    );
376
377    let litex_alarm = static_init!(
380        litex_vexriscv::timer::LiteXAlarm<
381            'static,
382            'static,
383            socc::SoCRegisterFmt,
384            socc::ClockFrequency,
385        >,
386        litex_vexriscv::timer::LiteXAlarm::new(timer0_uptime, timer0)
387    );
388    timer0.set_timer_client(litex_alarm);
389    litex_alarm.initialize();
390
391    let mux_alarm = static_init!(
394        MuxAlarm<
395            'static,
396            litex_vexriscv::timer::LiteXAlarm<
397                'static,
398                'static,
399                socc::SoCRegisterFmt,
400                socc::ClockFrequency,
401            >,
402        >,
403        MuxAlarm::new(litex_alarm)
404    );
405    litex_alarm.set_alarm_client(mux_alarm);
406
407    let virtual_alarm_user = static_init!(
409        VirtualMuxAlarm<
410            'static,
411            litex_vexriscv::timer::LiteXAlarm<
412                'static,
413                'static,
414                socc::SoCRegisterFmt,
415                socc::ClockFrequency,
416            >,
417        >,
418        VirtualMuxAlarm::new(mux_alarm)
419    );
420    virtual_alarm_user.setup();
421
422    let alarm = static_init!(
423        capsules_core::alarm::AlarmDriver<
424            'static,
425            VirtualMuxAlarm<
426                'static,
427                litex_vexriscv::timer::LiteXAlarm<
428                    'static,
429                    'static,
430                    socc::SoCRegisterFmt,
431                    socc::ClockFrequency,
432                >,
433            >,
434        >,
435        capsules_core::alarm::AlarmDriver::new(
436            virtual_alarm_user,
437            board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
438        )
439    );
440    virtual_alarm_user.set_alarm_client(alarm);
441
442    let systick_virtual_alarm = static_init!(
444        VirtualMuxAlarm<
445            'static,
446            litex_vexriscv::timer::LiteXAlarm<
447                'static,
448                'static,
449                socc::SoCRegisterFmt,
450                socc::ClockFrequency,
451            >,
452        >,
453        VirtualMuxAlarm::new(mux_alarm)
454    );
455    systick_virtual_alarm.setup();
456
457    let scheduler_timer = static_init!(
458        VirtualSchedulerTimer<
459            VirtualMuxAlarm<
460                'static,
461                litex_vexriscv::timer::LiteXAlarm<
462                    'static,
463                    'static,
464                    socc::SoCRegisterFmt,
465                    socc::ClockFrequency,
466                >,
467            >,
468        >,
469        VirtualSchedulerTimer::new(systick_virtual_alarm)
470    );
471
472    let uart0 = static_init!(
476        litex_vexriscv::uart::LiteXUart<socc::SoCRegisterFmt>,
477        litex_vexriscv::uart::LiteXUart::new(
478            StaticRef::new(
479                socc::CSR_UART_BASE
480                    as *const litex_vexriscv::uart::LiteXUartRegisters<socc::SoCRegisterFmt>,
481            ),
482            None,
486        )
487    );
488    uart0.initialize();
489
490    PANIC_REFERENCES.uart = Some(uart0);
491
492    let uart_mux = components::console::UartMuxComponent::new(uart0, socc::UART_BAUDRATE)
494        .finalize(components::uart_mux_component_static!());
495
496    let ethmac0 = static_init!(
500        litex_vexriscv::liteeth::LiteEth<{socc::ETHMAC_TX_SLOTS}, socc::SoCRegisterFmt>,
501        litex_vexriscv::liteeth::LiteEth::new(
502            StaticRef::new(
503                socc::CSR_ETHMAC_BASE
504                    as *const litex_vexriscv::liteeth::LiteEthMacRegisters<socc::SoCRegisterFmt>,
505            ),
506            socc::MEM_ETHMAC_BASE,
507            socc::MEM_ETHMAC_SIZE,
508            socc::ETHMAC_SLOT_SIZE,
509            socc::ETHMAC_RX_SLOTS,
510            socc::ETHMAC_TX_SLOTS,
511        )
512    );
513
514    ethmac0.initialize();
516
517    let led_driver =
521        components::led::LedsComponent::new().finalize(components::led_component_static!(
522            litex_vexriscv::led_controller::LiteXLed<'static, socc::SoCRegisterFmt>,
523            led0.get_led(0).unwrap(),
524            led0.get_led(1).unwrap(),
525            led0.get_led(2).unwrap(),
526            led0.get_led(3).unwrap(),
527        ));
528
529    let interrupt_service = static_init!(
532        LiteXArtyInterruptablePeripherals,
533        LiteXArtyInterruptablePeripherals {
534            uart0,
535            timer0,
536            ethmac0,
537        }
538    );
539    interrupt_service.init();
540
541    let chip = static_init!(
542        litex_vexriscv::chip::LiteXVexRiscv<
543            LiteXArtyInterruptablePeripherals,
544        >,
545        litex_vexriscv::chip::LiteXVexRiscv::new(
546            "LiteX on Arty A7",
547            interrupt_service,
548            pmp,
549        )
550    );
551
552    PANIC_REFERENCES.chip = Some(chip);
553
554    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
555        .finalize(components::process_printer_text_component_static!());
556
557    PANIC_REFERENCES.process_printer = Some(process_printer);
558
559    csr::CSR
561        .mie
562        .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET);
563    csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
564
565    chip.unmask_interrupts();
567
568    let pconsole = components::process_console::ProcessConsoleComponent::new(
570        board_kernel,
571        uart_mux,
572        mux_alarm,
573        process_printer,
574        None,
575    )
576    .finalize(components::process_console_component_static!(
577        litex_vexriscv::timer::LiteXAlarm<
578            'static,
579            'static,
580            socc::SoCRegisterFmt,
581            socc::ClockFrequency,
582        >
583    ));
584
585    let console = components::console::ConsoleComponent::new(
587        board_kernel,
588        capsules_core::console::DRIVER_NUM,
589        uart_mux,
590    )
591    .finalize(components::console_component_static!());
592
593    components::debug_writer::DebugWriterComponent::new_unsafe(
595        uart_mux,
596        create_capability!(capabilities::SetDebugWriterCapability),
597        || unsafe {
598            kernel::debug::initialize_debug_writer_wrapper_unsafe::<
599                <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
600            >();
601        },
602    )
603    .finalize(components::debug_writer_component_static!());
604
605    let lldb = components::lldb::LowLevelDebugComponent::new(
606        board_kernel,
607        capsules_core::low_level_debug::DRIVER_NUM,
608        uart_mux,
609    )
610    .finalize(components::low_level_debug_component_static!());
611
612    let scheduler = components::sched::mlfq::MLFQComponent::new(mux_alarm, processes).finalize(
613        components::mlfq_component_static!(
614            litex_vexriscv::timer::LiteXAlarm<
615                'static,
616                'static,
617                socc::SoCRegisterFmt,
618                socc::ClockFrequency,
619            >,
620            NUM_PROCS
621        ),
622    );
623
624    let litex_arty = LiteXArty {
625        console,
626        pconsole,
627        alarm,
628        lldb,
629        led_driver,
630        scheduler,
631        scheduler_timer,
632        ipc: kernel::ipc::IPC::new(
633            board_kernel,
634            kernel::ipc::DRIVER_NUM,
635            &memory_allocation_cap,
636        ),
637    };
638
639    debug!("LiteX+VexRiscv on ArtyA7: initialization complete, entering main loop.");
640    let _ = litex_arty.pconsole.start();
641
642    kernel::process::load_processes(
643        board_kernel,
644        chip,
645        core::slice::from_raw_parts(
646            core::ptr::addr_of!(_sapps),
647            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
648        ),
649        core::slice::from_raw_parts_mut(
650            core::ptr::addr_of_mut!(_sappmem),
651            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
652        ),
653        &FAULT_RESPONSE,
654        &process_mgmt_cap,
655    )
656    .unwrap_or_else(|err| {
657        debug!("Error loading processes!");
658        debug!("{:?}", err);
659    });
660
661    (board_kernel, litex_arty, chip)
662}
663
664#[no_mangle]
666pub unsafe fn main() {
667    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
668
669    let (board_kernel, board, chip) = start();
670    board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
671}