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