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::debug::PanicResources;
15use kernel::hil;
16use kernel::platform::{KernelResources, SyscallDriverLookup};
17use kernel::scheduler::cooperative::CooperativeSched;
18use kernel::utilities::registers::interfaces::ReadWriteable;
19use kernel::utilities::single_thread_value::SingleThreadValue;
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;
33type AlarmHw = Clint<'static>;
34type SchedulerTimerHw =
35    components::virtual_scheduler_timer::VirtualSchedulerTimerComponentType<AlarmHw>;
36type ProcessPrinterInUse = capsules_system::process_printer::ProcessPrinterText;
37
38/// Resources for when a board panics used by io.rs.
39static PANIC_RESOURCES: SingleThreadValue<PanicResources<ChipHw, ProcessPrinterInUse>> =
40    SingleThreadValue::new(PanicResources::new());
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 SchedulerTimerHw,
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 = SchedulerTimerHw;
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    // Initialize deferred calls very early.
115    kernel::deferred_call::initialize_deferred_call_state_unsafe::<
116        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
117    >();
118
119    // Bind global variables to this thread.
120    PANIC_RESOURCES
121        .bind_to_thread_unsafe::<<ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider>();
122
123    let peripherals = static_init!(VeeRDefaultPeripherals, VeeRDefaultPeripherals::new());
124    peripherals.init();
125
126    // initialize capabilities
127    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
128    let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
129
130    // Create an array to hold process references.
131    let processes = components::process_array::ProcessArrayComponent::new()
132        .finalize(components::process_array_component_static!(NUM_PROCS));
133    PANIC_RESOURCES.get().map(|resources| {
134        resources.processes.put(processes.as_slice());
135    });
136
137    // Setup space to store the core kernel data structure.
138    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
139
140    // Create a shared UART channel for the console and for kernel debug.
141    let uart_mux = components::console::UartMuxComponent::new(&peripherals.sim_uart, 115200)
142        .finalize(components::uart_mux_component_static!());
143
144    let mtimer = static_init!(Clint, Clint::new(&CLINT_BASE));
145
146    // Create a shared virtualization mux layer on top of a single hardware
147    // alarm.
148    let mux_alarm = static_init!(MuxAlarm<'static, Clint>, MuxAlarm::new(mtimer));
149    hil::time::Alarm::set_alarm_client(mtimer, mux_alarm);
150
151    // Alarm
152    let virtual_alarm_user = static_init!(
153        VirtualMuxAlarm<'static, Clint>,
154        VirtualMuxAlarm::new(mux_alarm)
155    );
156    virtual_alarm_user.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    PANIC_RESOURCES.get().map(|resources| {
169        resources.chip.put(chip);
170    });
171
172    // Create a process printer for panic.
173    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
174        .finalize(components::process_printer_text_component_static!());
175    PANIC_RESOURCES.get().map(|resources| {
176        resources.printer.put(process_printer);
177    });
178
179    let process_console = components::process_console::ProcessConsoleComponent::new(
180        board_kernel,
181        uart_mux,
182        mux_alarm,
183        process_printer,
184        None,
185    )
186    .finalize(components::process_console_component_static!(Clint));
187    let _ = process_console.start();
188
189    // Need to enable all interrupts for Tock Kernel
190    chip.enable_pic_interrupts();
191
192    // enable interrupts globally
193    csr::CSR
194        .mie
195        .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET);
196    csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
197
198    // Setup the console.
199    let console = components::console::ConsoleComponent::new(
200        board_kernel,
201        capsules_core::console::DRIVER_NUM,
202        uart_mux,
203    )
204    .finalize(components::console_component_static!());
205    // Create the debugger object that handles calls to `debug!()`.
206    components::debug_writer::DebugWriterComponent::new_unsafe(
207        uart_mux,
208        create_capability!(capabilities::SetDebugWriterCapability),
209        || unsafe {
210            kernel::debug::initialize_debug_writer_wrapper_unsafe::<
211                <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
212            >();
213        },
214    )
215    .finalize(components::debug_writer_component_static!());
216
217    debug!("VeeR EL2 initialisation complete.");
218    debug!("Entering main loop.");
219
220    // These symbols are defined in the linker script.
221    extern "C" {
222        /// Beginning of the ROM region containing app images.
223        static _sapps: u8;
224        /// End of the ROM region containing app images.
225        static _eapps: u8;
226        /// Beginning of the RAM region for app memory.
227        static mut _sappmem: u8;
228        /// End of the RAM region for app memory.
229        static _eappmem: u8;
230    }
231
232    let scheduler = components::sched::cooperative::CooperativeComponent::new(processes)
233        .finalize(components::cooperative_component_static!(NUM_PROCS));
234
235    let scheduler_timer =
236        components::virtual_scheduler_timer::VirtualSchedulerTimerComponent::new(mux_alarm)
237            .finalize(components::virtual_scheduler_timer_component_static!(
238                AlarmHw
239            ));
240
241    let veer = VeeR {
242        console,
243        alarm,
244        scheduler,
245        scheduler_timer,
246    };
247
248    kernel::process::load_processes(
249        board_kernel,
250        chip,
251        core::slice::from_raw_parts(
252            core::ptr::addr_of!(_sapps),
253            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
254        ),
255        core::slice::from_raw_parts_mut(
256            core::ptr::addr_of_mut!(_sappmem),
257            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
258        ),
259        &FAULT_RESPONSE,
260        &process_mgmt_cap,
261    )
262    .unwrap_or_else(|err| {
263        debug!("Error loading processes!");
264        debug!("{:?}", err);
265    });
266
267    (board_kernel, veer, chip)
268}
269
270/// Main function called after RAM initialized.
271///
272/// # Safety
273/// Accesses memory, memory-mapped registers and CSRs.
274#[no_mangle]
275pub unsafe fn main() {
276    let main_loop_cap = create_capability!(capabilities::MainLoopCapability);
277    let (board_kernel, veer, chip) = start();
278    board_kernel.kernel_loop(&veer, chip, None::<&kernel::ipc::IPC<0>>, &main_loop_cap);
279}