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