litex_sim/
main.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Board file for a LiteX SoC running in a Verilated simulation
6
7#![no_std]
8#![no_main]
9
10use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
11use kernel::capabilities;
12use kernel::component::Component;
13use kernel::hil::led::LedHigh;
14use kernel::hil::time::{Alarm, Timer};
15use kernel::platform::chip::InterruptService;
16use kernel::platform::{KernelResources, SyscallDriverLookup};
17use kernel::process::ProcessArray;
18use kernel::scheduler::mlfq::MLFQSched;
19use kernel::utilities::registers::interfaces::ReadWriteable;
20use kernel::utilities::StaticRef;
21use kernel::{create_capability, debug, static_init};
22use rv32i::csr;
23
24mod io;
25mod litex_generated_constants;
26
27// This module contains the LiteX SoC configuration options, register
28// positions, interrupt mappings and other implementation details of
29// the generated bitstream.
30//
31// Its values are used throughout the file, hence import it under a
32// short name.
33use litex_generated_constants as socc;
34
35/// Structure for dynamic interrupt mapping, depending on the SoC
36/// configuration
37///
38/// This struct is deliberately kept in the board crate. Because of
39/// the configurable nature of LiteX, it does not make sense to define
40/// a default interrupt mapping, as the interrupt numbers are
41/// generated sequentially for all softcores.
42struct LiteXSimInterruptablePeripherals {
43    gpio0: &'static litex_vexriscv::gpio::LiteXGPIOController<'static, socc::SoCRegisterFmt>,
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 LiteXSimInterruptablePeripherals {
58    // Resolve any recursive dependencies and set up deferred calls:
59    pub fn init(&'static self) {
60        kernel::deferred_call::DeferredCallClient::register(self.uart0);
61    }
62}
63
64impl InterruptService for LiteXSimInterruptablePeripherals {
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            socc::GPIO_INTERRUPT => {
80                self.gpio0.service_interrupt();
81                true
82            }
83            _ => false,
84        }
85    }
86}
87
88const NUM_PROCS: usize = 4;
89
90type ChipHw = litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>;
91type AlarmHw =
92    litex_vexriscv::timer::LiteXAlarm<'static, 'static, socc::SoCRegisterFmt, socc::ClockFrequency>;
93type SchedulerTimerHw =
94    components::virtual_scheduler_timer::VirtualSchedulerTimerComponentType<AlarmHw>;
95
96/// Static variables used by io.rs.
97static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
98
99// Reference to the chip and UART hardware for panic dumps
100struct LiteXSimPanicReferences {
101    chip: Option<&'static litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>>,
102    uart: Option<&'static litex_vexriscv::uart::LiteXUart<'static, socc::SoCRegisterFmt>>,
103    process_printer: Option<&'static capsules_system::process_printer::ProcessPrinterText>,
104}
105static mut PANIC_REFERENCES: LiteXSimPanicReferences = LiteXSimPanicReferences {
106    chip: None,
107    uart: None,
108    process_printer: None,
109};
110
111// How should the kernel respond when a process faults.
112const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
113    capsules_system::process_policies::PanicFaultPolicy {};
114
115kernel::stack_size! {0x2000}
116
117/// A structure representing this platform that holds references to all
118/// capsules for this platform.
119struct LiteXSim {
120    gpio_driver: &'static capsules_core::gpio::GPIO<
121        'static,
122        litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
123    >,
124    button_driver: &'static capsules_core::button::Button<
125        'static,
126        litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
127    >,
128    led_driver: &'static capsules_core::led::LedDriver<
129        'static,
130        LedHigh<
131            'static,
132            litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>,
133        >,
134        8,
135    >,
136    console: &'static capsules_core::console::Console<'static>,
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<'static, VirtualMuxAlarm<'static, AlarmHw>>,
142    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
143    scheduler: &'static MLFQSched<'static, VirtualMuxAlarm<'static, AlarmHw>>,
144    scheduler_timer: &'static SchedulerTimerHw,
145}
146
147/// Mapping of integer syscalls to objects that implement syscalls.
148impl SyscallDriverLookup for LiteXSim {
149    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
150    where
151        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
152    {
153        match driver_num {
154            capsules_core::button::DRIVER_NUM => f(Some(self.button_driver)),
155            capsules_core::led::DRIVER_NUM => f(Some(self.led_driver)),
156            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio_driver)),
157            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
158            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
159            capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
160            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
161            _ => f(None),
162        }
163    }
164}
165
166impl KernelResources<litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>>
167    for LiteXSim
168{
169    type SyscallDriverLookup = Self;
170    type SyscallFilter = ();
171    type ProcessFault = ();
172    type Scheduler = MLFQSched<'static, VirtualMuxAlarm<'static, AlarmHw>>;
173    type SchedulerTimer = SchedulerTimerHw;
174    type WatchDog = ();
175    type ContextSwitchCallback = ();
176
177    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
178        self
179    }
180    fn syscall_filter(&self) -> &Self::SyscallFilter {
181        &()
182    }
183    fn process_fault(&self) -> &Self::ProcessFault {
184        &()
185    }
186    fn scheduler(&self) -> &Self::Scheduler {
187        self.scheduler
188    }
189    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
190        self.scheduler_timer
191    }
192    fn watchdog(&self) -> &Self::WatchDog {
193        &()
194    }
195    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
196        &()
197    }
198}
199
200/// This is in a separate, inline(never) function so that its stack frame is
201/// removed when this function returns. Otherwise, the stack space used for
202/// these static_inits is wasted.
203#[inline(never)]
204unsafe fn start() -> (
205    &'static kernel::Kernel,
206    LiteXSim,
207    &'static litex_vexriscv::chip::LiteXVexRiscv<LiteXSimInterruptablePeripherals>,
208) {
209    // These symbols are defined in the linker script.
210    extern "C" {
211        /// Beginning of the ROM region containing app images.
212        static _sapps: u8;
213        /// End of the ROM region containing app images.
214        static _eapps: u8;
215        /// Beginning of the RAM region for app memory.
216        static mut _sappmem: u8;
217        /// End of the RAM region for app memory.
218        static _eappmem: u8;
219        /// The start of the kernel text (Included only for kernel PMP)
220        static _stext: u8;
221        /// The end of the kernel text (Included only for kernel PMP)
222        static _etext: u8;
223        /// The start of the kernel / app / storage flash (Included only for kernel PMP)
224        static _sflash: u8;
225        /// The end of the kernel / app / storage flash (Included only for kernel PMP)
226        static _eflash: u8;
227        /// The start of the kernel / app RAM (Included only for kernel PMP)
228        static _ssram: u8;
229        /// The end of the kernel / app RAM (Included only for kernel PMP)
230        static _esram: u8;
231    }
232
233    // ---------- BASIC INITIALIZATION ----------
234
235    // Basic setup of the riscv platform.
236    rv32i::configure_trap_handler();
237
238    // Initialize deferred calls very early.
239    kernel::deferred_call::initialize_deferred_call_state_unsafe::<
240        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
241    >();
242
243    // Set up memory protection immediately after setting the trap handler, to
244    // ensure that much of the board initialization routine runs with PMP kernel
245    // memory protection.
246    let pmp = rv32i::pmp::kernel_protection::KernelProtectionPMP::new(
247        rv32i::pmp::kernel_protection::FlashRegion(
248            rv32i::pmp::NAPOTRegionSpec::from_start_end(
249                core::ptr::addr_of!(_sflash),
250                core::ptr::addr_of!(_eflash),
251            )
252            .unwrap(),
253        ),
254        rv32i::pmp::kernel_protection::RAMRegion(
255            rv32i::pmp::NAPOTRegionSpec::from_start_end(
256                core::ptr::addr_of!(_ssram),
257                core::ptr::addr_of!(_esram),
258            )
259            .unwrap(),
260        ),
261        rv32i::pmp::kernel_protection::MMIORegion(
262            rv32i::pmp::NAPOTRegionSpec::from_start_size(
263                0xf0000000 as *const u8, // start
264                0x10000000,              // size
265            )
266            .unwrap(),
267        ),
268        rv32i::pmp::kernel_protection::KernelTextRegion(
269            rv32i::pmp::TORRegionSpec::from_start_end(
270                core::ptr::addr_of!(_stext),
271                core::ptr::addr_of!(_etext),
272            )
273            .unwrap(),
274        ),
275    )
276    .unwrap();
277
278    // initialize capabilities
279    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
280    let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
281
282    // Create an array to hold process references.
283    let processes = components::process_array::ProcessArrayComponent::new()
284        .finalize(components::process_array_component_static!(NUM_PROCS));
285    PROCESSES = Some(processes);
286
287    // Setup space to store the core kernel data structure.
288    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
289
290    // --------- TIMER & UPTIME CORE; ALARM INITIALIZATION ----------
291
292    // Initialize the hardware timer
293    let timer0 = static_init!(
294        litex_vexriscv::timer::LiteXTimer<'static, socc::SoCRegisterFmt, socc::ClockFrequency>,
295        litex_vexriscv::timer::LiteXTimer::new(StaticRef::new(
296            socc::CSR_TIMER0_BASE
297                as *const litex_vexriscv::timer::LiteXTimerRegisters<socc::SoCRegisterFmt>
298        ),)
299    );
300
301    // The SoC is expected to feature the 64-bit uptime extension to the timer hardware
302    let timer0_uptime = static_init!(
303        litex_vexriscv::timer::LiteXTimerUptime<
304            'static,
305            socc::SoCRegisterFmt,
306            socc::ClockFrequency,
307        >,
308        litex_vexriscv::timer::LiteXTimerUptime::new(timer0)
309    );
310
311    // Create the LiteXAlarm based on the hardware LiteXTimer core and
312    // the uptime peripheral
313    let litex_alarm = static_init!(
314        AlarmHw,
315        litex_vexriscv::timer::LiteXAlarm::new(timer0_uptime, timer0)
316    );
317    timer0.set_timer_client(litex_alarm);
318    litex_alarm.initialize();
319
320    // Create a shared virtualization mux layer on top of a single hardware
321    // alarm.
322    let mux_alarm = static_init!(MuxAlarm<'static, AlarmHw>, MuxAlarm::new(litex_alarm));
323    litex_alarm.set_alarm_client(mux_alarm);
324
325    // Userspace alarm driver
326    let virtual_alarm_user = static_init!(
327        VirtualMuxAlarm<'static, AlarmHw>,
328        VirtualMuxAlarm::new(mux_alarm)
329    );
330    virtual_alarm_user.setup();
331
332    let alarm = static_init!(
333        capsules_core::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, AlarmHw>>,
334        capsules_core::alarm::AlarmDriver::new(
335            virtual_alarm_user,
336            board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
337        )
338    );
339    virtual_alarm_user.set_alarm_client(alarm);
340
341    let scheduler_timer =
342        components::virtual_scheduler_timer::VirtualSchedulerTimerComponent::new(mux_alarm)
343            .finalize(components::virtual_scheduler_timer_component_static!(
344                AlarmHw
345            ));
346
347    // ---------- UART ----------
348
349    // Initialize the HW UART
350    let uart0 = static_init!(
351        litex_vexriscv::uart::LiteXUart<socc::SoCRegisterFmt>,
352        litex_vexriscv::uart::LiteXUart::new(
353            StaticRef::new(
354                socc::CSR_UART_BASE
355                    as *const litex_vexriscv::uart::LiteXUartRegisters<socc::SoCRegisterFmt>,
356            ),
357            None, // LiteX simulator has no UART phy
358        )
359    );
360    uart0.initialize();
361
362    PANIC_REFERENCES.uart = Some(uart0);
363
364    // Create a shared UART channel for the console and for kernel debug.
365    //
366    // The baudrate is ingnored, as no UART phy is present in the
367    // verilated simulation.
368    let uart_mux = components::console::UartMuxComponent::new(uart0, 115200)
369        .finalize(components::uart_mux_component_static!());
370
371    // ---------- ETHERNET ----------
372
373    // ETHMAC peripheral
374    let ethmac0 = static_init!(
375        litex_vexriscv::liteeth::LiteEth<{socc::ETHMAC_TX_SLOTS}, socc::SoCRegisterFmt>,
376        litex_vexriscv::liteeth::LiteEth::new(
377            StaticRef::new(
378                socc::CSR_ETHMAC_BASE
379                    as *const litex_vexriscv::liteeth::LiteEthMacRegisters<socc::SoCRegisterFmt>,
380            ),
381            socc::MEM_ETHMAC_BASE,
382            socc::MEM_ETHMAC_SIZE,
383            socc::ETHMAC_SLOT_SIZE,
384            socc::ETHMAC_RX_SLOTS,
385            socc::ETHMAC_TX_SLOTS,
386        )
387    );
388
389    // Initialize the ETHMAC controller
390    ethmac0.initialize();
391
392    // --------- GPIO CONTROLLER ----------
393    type GPIOPin = litex_vexriscv::gpio::LiteXGPIOPin<'static, 'static, socc::SoCRegisterFmt>;
394
395    // GPIO hardware controller
396    let gpio0 = static_init!(
397        litex_vexriscv::gpio::LiteXGPIOController<'static, socc::SoCRegisterFmt>,
398        litex_vexriscv::gpio::LiteXGPIOController::new(
399            StaticRef::new(
400                socc::CSR_GPIO_BASE
401                    as *const litex_vexriscv::gpio::LiteXGPIORegisters<socc::SoCRegisterFmt>
402            ),
403            32, // 32 GPIOs in the simulation
404        ),
405    );
406    gpio0.initialize();
407
408    // --------- GPIO DRIVER ----------
409
410    let gpio_driver = components::gpio::GpioComponent::new(
411        board_kernel,
412        capsules_core::gpio::DRIVER_NUM,
413        components::gpio_component_helper_owned!(
414            GPIOPin,
415            16 => gpio0.get_gpio_pin(16).unwrap(),
416            17 => gpio0.get_gpio_pin(17).unwrap(),
417            18 => gpio0.get_gpio_pin(18).unwrap(),
418            19 => gpio0.get_gpio_pin(19).unwrap(),
419            20 => gpio0.get_gpio_pin(20).unwrap(),
420            21 => gpio0.get_gpio_pin(21).unwrap(),
421            22 => gpio0.get_gpio_pin(22).unwrap(),
422            23 => gpio0.get_gpio_pin(23).unwrap(),
423            24 => gpio0.get_gpio_pin(24).unwrap(),
424            25 => gpio0.get_gpio_pin(25).unwrap(),
425            26 => gpio0.get_gpio_pin(26).unwrap(),
426            27 => gpio0.get_gpio_pin(27).unwrap(),
427            28 => gpio0.get_gpio_pin(28).unwrap(),
428            29 => gpio0.get_gpio_pin(29).unwrap(),
429            30 => gpio0.get_gpio_pin(30).unwrap(),
430            31 => gpio0.get_gpio_pin(31).unwrap(),
431        ),
432    )
433    .finalize(components::gpio_component_static!(GPIOPin));
434
435    // ---------- LED DRIVER ----------
436
437    let led_gpios = static_init!(
438        [GPIOPin; 8],
439        [
440            gpio0.get_gpio_pin(0).unwrap(),
441            gpio0.get_gpio_pin(1).unwrap(),
442            gpio0.get_gpio_pin(2).unwrap(),
443            gpio0.get_gpio_pin(3).unwrap(),
444            gpio0.get_gpio_pin(4).unwrap(),
445            gpio0.get_gpio_pin(5).unwrap(),
446            gpio0.get_gpio_pin(6).unwrap(),
447            gpio0.get_gpio_pin(7).unwrap(),
448        ]
449    );
450
451    let led_driver =
452        components::led::LedsComponent::new().finalize(components::led_component_static!(
453            kernel::hil::led::LedHigh<GPIOPin>,
454            LedHigh::new(&led_gpios[0]),
455            LedHigh::new(&led_gpios[1]),
456            LedHigh::new(&led_gpios[2]),
457            LedHigh::new(&led_gpios[3]),
458            LedHigh::new(&led_gpios[4]),
459            LedHigh::new(&led_gpios[5]),
460            LedHigh::new(&led_gpios[6]),
461            LedHigh::new(&led_gpios[7]),
462        ));
463
464    // ---------- BUTTON ----------
465
466    let button_driver = components::button::ButtonComponent::new(
467        board_kernel,
468        capsules_core::button::DRIVER_NUM,
469        components::button_component_helper_owned!(
470            GPIOPin,
471            (
472                gpio0.get_gpio_pin(8).unwrap(),
473                kernel::hil::gpio::ActivationMode::ActiveHigh,
474                kernel::hil::gpio::FloatingState::PullNone
475            ),
476            (
477                gpio0.get_gpio_pin(9).unwrap(),
478                kernel::hil::gpio::ActivationMode::ActiveHigh,
479                kernel::hil::gpio::FloatingState::PullNone
480            ),
481            (
482                gpio0.get_gpio_pin(10).unwrap(),
483                kernel::hil::gpio::ActivationMode::ActiveHigh,
484                kernel::hil::gpio::FloatingState::PullNone
485            ),
486            (
487                gpio0.get_gpio_pin(11).unwrap(),
488                kernel::hil::gpio::ActivationMode::ActiveHigh,
489                kernel::hil::gpio::FloatingState::PullNone
490            ),
491            (
492                gpio0.get_gpio_pin(12).unwrap(),
493                kernel::hil::gpio::ActivationMode::ActiveHigh,
494                kernel::hil::gpio::FloatingState::PullNone
495            ),
496            (
497                gpio0.get_gpio_pin(13).unwrap(),
498                kernel::hil::gpio::ActivationMode::ActiveHigh,
499                kernel::hil::gpio::FloatingState::PullNone
500            ),
501            (
502                gpio0.get_gpio_pin(14).unwrap(),
503                kernel::hil::gpio::ActivationMode::ActiveHigh,
504                kernel::hil::gpio::FloatingState::PullNone
505            ),
506            (
507                gpio0.get_gpio_pin(15).unwrap(),
508                kernel::hil::gpio::ActivationMode::ActiveHigh,
509                kernel::hil::gpio::FloatingState::PullNone
510            ),
511        ),
512    )
513    .finalize(components::button_component_static!(GPIOPin));
514
515    // ---------- INITIALIZE CHIP, ENABLE INTERRUPTS ----------
516
517    let interrupt_service = static_init!(
518        LiteXSimInterruptablePeripherals,
519        LiteXSimInterruptablePeripherals {
520            gpio0,
521            uart0,
522            timer0,
523            ethmac0,
524        }
525    );
526    interrupt_service.init();
527
528    let chip = static_init!(
529        litex_vexriscv::chip::LiteXVexRiscv<
530            LiteXSimInterruptablePeripherals,
531        >,
532        litex_vexriscv::chip::LiteXVexRiscv::new(
533            "Verilated LiteX on VexRiscv",
534            interrupt_service,
535            pmp,
536        )
537    );
538
539    PANIC_REFERENCES.chip = Some(chip);
540
541    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
542        .finalize(components::process_printer_text_component_static!());
543
544    PANIC_REFERENCES.process_printer = Some(process_printer);
545
546    // Enable RISC-V interrupts globally
547    csr::CSR
548        .mie
549        .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET);
550    csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
551
552    // Unmask all interrupt sources in the interrupt controller
553    chip.unmask_interrupts();
554
555    // Setup the console.
556    let console = components::console::ConsoleComponent::new(
557        board_kernel,
558        capsules_core::console::DRIVER_NUM,
559        uart_mux,
560    )
561    .finalize(components::console_component_static!());
562    // Create the debugger object that handles calls to `debug!()`.
563    components::debug_writer::DebugWriterComponent::new_unsafe(
564        uart_mux,
565        create_capability!(capabilities::SetDebugWriterCapability),
566        || unsafe {
567            kernel::debug::initialize_debug_writer_wrapper_unsafe::<
568                <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
569            >();
570        },
571    )
572    .finalize(components::debug_writer_component_static!());
573
574    let lldb = components::lldb::LowLevelDebugComponent::new(
575        board_kernel,
576        capsules_core::low_level_debug::DRIVER_NUM,
577        uart_mux,
578    )
579    .finalize(components::low_level_debug_component_static!());
580
581    let scheduler = components::sched::mlfq::MLFQComponent::new(mux_alarm, processes).finalize(
582        components::mlfq_component_static!(
583            litex_vexriscv::timer::LiteXAlarm<
584                'static,
585                'static,
586                socc::SoCRegisterFmt,
587                socc::ClockFrequency,
588            >,
589            NUM_PROCS
590        ),
591    );
592
593    let litex_sim = LiteXSim {
594        gpio_driver,
595        button_driver,
596        led_driver,
597        console,
598        alarm,
599        lldb,
600        ipc: kernel::ipc::IPC::new(
601            board_kernel,
602            kernel::ipc::DRIVER_NUM,
603            &memory_allocation_cap,
604        ),
605        scheduler,
606        scheduler_timer,
607    };
608
609    debug!("Verilated LiteX+VexRiscv: initialization complete, entering main loop.");
610
611    kernel::process::load_processes(
612        board_kernel,
613        chip,
614        core::slice::from_raw_parts(
615            core::ptr::addr_of!(_sapps),
616            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
617        ),
618        core::slice::from_raw_parts_mut(
619            core::ptr::addr_of_mut!(_sappmem),
620            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
621        ),
622        &FAULT_RESPONSE,
623        &process_mgmt_cap,
624    )
625    .unwrap_or_else(|err| {
626        debug!("Error loading processes!");
627        debug!("{:?}", err);
628    });
629
630    (board_kernel, litex_sim, chip)
631}
632
633/// Main function called after RAM initialized.
634#[no_mangle]
635pub unsafe fn main() {
636    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
637
638    let (board_kernel, board, chip) = start();
639    board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
640}