veer_el2_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// Copyright (c) 2024 Antmicro <www.antmicro.com>
5
6//! Board file for VeeR EL2 simulation platform.
7
8#![no_std]
9// Disable this attribute when documenting, as a workaround for
10// https://github.com/rust-lang/rust/issues/62184.
11#![cfg_attr(not(doc), no_main)]
12
13use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
14use core::ptr::{addr_of, addr_of_mut};
15use kernel::capabilities;
16use kernel::component::Component;
17use kernel::hil;
18use kernel::platform::scheduler_timer::VirtualSchedulerTimer;
19use kernel::platform::{KernelResources, SyscallDriverLookup};
20use kernel::scheduler::cooperative::CooperativeSched;
21use kernel::utilities::registers::interfaces::ReadWriteable;
22use kernel::{create_capability, debug, static_init};
23use rv32i::csr;
24use veer_el2::chip::VeeRDefaultPeripherals;
25
26use veer_el2::machine_timer::Clint;
27use veer_el2::machine_timer::CLINT_BASE;
28
29pub mod io;
30
31pub const NUM_PROCS: usize = 4;
32
33// Actual memory for holding the active process structures. Need an empty list
34// at least.
35static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
36    [None; NUM_PROCS];
37
38pub type VeeRChip = veer_el2::chip::VeeR<'static, VeeRDefaultPeripherals>;
39
40// Reference to the chip for panic dumps.
41static mut CHIP: Option<&'static VeeRChip> = None;
42// Static reference to process printer for panic dumps.
43static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
44    None;
45
46// How should the kernel respond when a process faults.
47const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
48    capsules_system::process_policies::PanicFaultPolicy {};
49
50/// Dummy buffer that causes the linker to reserve enough space for the stack.
51#[no_mangle]
52#[link_section = ".stack_buffer"]
53pub static mut STACK_MEMORY: [u8; 0x900] = [0; 0x900];
54
55/// A structure representing this platform that holds references to all
56/// capsules for this platform.
57struct VeeR {
58    console: &'static capsules_core::console::Console<'static>,
59    alarm: &'static capsules_core::alarm::AlarmDriver<
60        'static,
61        VirtualMuxAlarm<'static, Clint<'static>>,
62    >,
63    scheduler: &'static CooperativeSched<'static>,
64    scheduler_timer: &'static VirtualSchedulerTimer<VirtualMuxAlarm<'static, Clint<'static>>>,
65}
66
67/// Mapping of integer syscalls to objects that implement syscalls.
68impl SyscallDriverLookup for VeeR {
69    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
70    where
71        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
72    {
73        match driver_num {
74            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
75            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
76            _ => f(None),
77        }
78    }
79}
80
81impl KernelResources<VeeRChip> for VeeR {
82    type SyscallDriverLookup = Self;
83    type SyscallFilter = ();
84    type ProcessFault = ();
85    type Scheduler = CooperativeSched<'static>;
86    type SchedulerTimer = VirtualSchedulerTimer<VirtualMuxAlarm<'static, Clint<'static>>>;
87    type WatchDog = ();
88    type ContextSwitchCallback = ();
89
90    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
91        self
92    }
93    fn syscall_filter(&self) -> &Self::SyscallFilter {
94        &()
95    }
96    fn process_fault(&self) -> &Self::ProcessFault {
97        &()
98    }
99    fn scheduler(&self) -> &Self::Scheduler {
100        self.scheduler
101    }
102    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
103        self.scheduler_timer
104    }
105    fn watchdog(&self) -> &Self::WatchDog {
106        &()
107    }
108    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
109        &()
110    }
111}
112
113/// This is in a separate, inline(never) function so that its stack frame is
114/// removed when this function returns. Otherwise, the stack space used for
115/// these static_inits is wasted.
116#[inline(never)]
117unsafe fn start() -> (&'static kernel::Kernel, VeeR, &'static VeeRChip) {
118    // only machine mode
119    rv32i::configure_trap_handler();
120
121    let peripherals = static_init!(VeeRDefaultPeripherals, VeeRDefaultPeripherals::new());
122    peripherals.init();
123
124    // initialize capabilities
125    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
126    let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
127
128    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
129
130    // Configure kernel debug gpios as early as possible
131    kernel::debug::assign_gpios(None, None, None);
132
133    // Create a shared UART channel for the console and for kernel debug.
134    let uart_mux = components::console::UartMuxComponent::new(&peripherals.sim_uart, 115200)
135        .finalize(components::uart_mux_component_static!());
136
137    let mtimer = static_init!(Clint, Clint::new(&CLINT_BASE));
138
139    // Create a shared virtualization mux layer on top of a single hardware
140    // alarm.
141    let mux_alarm = static_init!(MuxAlarm<'static, Clint>, MuxAlarm::new(mtimer));
142    hil::time::Alarm::set_alarm_client(mtimer, mux_alarm);
143
144    // Alarm
145    let virtual_alarm_user = static_init!(
146        VirtualMuxAlarm<'static, Clint>,
147        VirtualMuxAlarm::new(mux_alarm)
148    );
149    virtual_alarm_user.setup();
150
151    let systick_virtual_alarm = static_init!(
152        VirtualMuxAlarm<'static, Clint>,
153        VirtualMuxAlarm::new(mux_alarm)
154    );
155    systick_virtual_alarm.setup();
156
157    let alarm = static_init!(
158        capsules_core::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, Clint>>,
159        capsules_core::alarm::AlarmDriver::new(
160            virtual_alarm_user,
161            board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
162        )
163    );
164    hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
165
166    let chip = static_init!(VeeRChip, veer_el2::chip::VeeR::new(peripherals, mtimer));
167    CHIP = Some(chip);
168
169    // Create a process printer for panic.
170    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
171        .finalize(components::process_printer_text_component_static!());
172    PROCESS_PRINTER = Some(process_printer);
173
174    let process_console = components::process_console::ProcessConsoleComponent::new(
175        board_kernel,
176        uart_mux,
177        mux_alarm,
178        process_printer,
179        None,
180    )
181    .finalize(components::process_console_component_static!(Clint));
182    let _ = process_console.start();
183
184    // Need to enable all interrupts for Tock Kernel
185    chip.enable_pic_interrupts();
186
187    // enable interrupts globally
188    csr::CSR
189        .mie
190        .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET);
191    csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
192
193    // Setup the console.
194    let console = components::console::ConsoleComponent::new(
195        board_kernel,
196        capsules_core::console::DRIVER_NUM,
197        uart_mux,
198    )
199    .finalize(components::console_component_static!());
200    // Create the debugger object that handles calls to `debug!()`.
201    components::debug_writer::DebugWriterComponent::new(uart_mux)
202        .finalize(components::debug_writer_component_static!());
203
204    debug!("VeeR EL2 initialisation complete.");
205    debug!("Entering main loop.");
206
207    // These symbols are defined in the linker script.
208    extern "C" {
209        /// Beginning of the ROM region containing app images.
210        static _sapps: u8;
211        /// End of the ROM region containing app images.
212        static _eapps: u8;
213        /// Beginning of the RAM region for app memory.
214        static mut _sappmem: u8;
215        /// End of the RAM region for app memory.
216        static _eappmem: u8;
217    }
218
219    let scheduler =
220        components::sched::cooperative::CooperativeComponent::new(&*addr_of!(PROCESSES))
221            .finalize(components::cooperative_component_static!(NUM_PROCS));
222
223    let scheduler_timer = static_init!(
224        VirtualSchedulerTimer<VirtualMuxAlarm<'static, Clint<'static>>>,
225        VirtualSchedulerTimer::new(systick_virtual_alarm)
226    );
227
228    let veer = VeeR {
229        console,
230        alarm,
231        scheduler,
232        scheduler_timer,
233    };
234
235    kernel::process::load_processes(
236        board_kernel,
237        chip,
238        core::slice::from_raw_parts(
239            core::ptr::addr_of!(_sapps),
240            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
241        ),
242        core::slice::from_raw_parts_mut(
243            core::ptr::addr_of_mut!(_sappmem),
244            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
245        ),
246        &mut *addr_of_mut!(PROCESSES),
247        &FAULT_RESPONSE,
248        &process_mgmt_cap,
249    )
250    .unwrap_or_else(|err| {
251        debug!("Error loading processes!");
252        debug!("{:?}", err);
253    });
254
255    (board_kernel, veer, chip)
256}
257
258/// Main function called after RAM initialized.
259///
260/// # Safety
261/// Accesses memory, memory-mapped registers and CSRs.
262#[no_mangle]
263pub unsafe fn main() {
264    let main_loop_cap = create_capability!(capabilities::MainLoopCapability);
265    let (board_kernel, veer, chip) = start();
266    board_kernel.kernel_loop(&veer, chip, None::<&kernel::ipc::IPC<0>>, &main_loop_cap);
267}