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