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