hifive_inventor/
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
5//! Board file for BBC HiFive Inventor RISC-V development platform.
6//!
7//! - <https://www.hifiveinventor.com/>
8
9#![no_std]
10#![no_main]
11
12use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
13use e310_g003::interrupt_service::E310G003DefaultPeripherals;
14use kernel::capabilities;
15use kernel::component::Component;
16use kernel::hil;
17use kernel::platform::{KernelResources, SyscallDriverLookup};
18use kernel::process::ProcessArray;
19use kernel::scheduler::cooperative::CooperativeSched;
20use kernel::utilities::registers::interfaces::ReadWriteable;
21use kernel::{create_capability, debug, static_init};
22use rv32i::csr;
23
24pub mod io;
25
26pub const NUM_PROCS: usize = 4;
27
28type ChipHw = e310_g003::chip::E310x<'static, E310G003DefaultPeripherals<'static>>;
29type AlarmHw = e310_g003::chip::E310xClint<'static>;
30type SchedulerTimerHw =
31    components::virtual_scheduler_timer::VirtualSchedulerTimerComponentType<AlarmHw>;
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 e310_g003::chip::E310x<E310G003DefaultPeripherals>> = None;
37// Reference to the 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
45kernel::stack_size! {0x1500}
46
47/// A structure representing this platform that holds references to all
48/// capsules for this platform. We've included an alarm and console.
49struct HiFiveInventor {
50    console: &'static capsules_core::console::Console<'static>,
51    lldb: &'static capsules_core::low_level_debug::LowLevelDebug<
52        'static,
53        capsules_core::virtualizers::virtual_uart::UartDevice<'static>,
54    >,
55    alarm: &'static capsules_core::alarm::AlarmDriver<
56        'static,
57        VirtualMuxAlarm<'static, e310_g003::chip::E310xClint<'static>>,
58    >,
59    scheduler: &'static CooperativeSched<'static>,
60    scheduler_timer: &'static SchedulerTimerHw,
61}
62
63/// Mapping of integer syscalls to objects that implement syscalls.
64impl SyscallDriverLookup for HiFiveInventor {
65    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
66    where
67        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
68    {
69        match driver_num {
70            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
71            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
72            capsules_core::low_level_debug::DRIVER_NUM => f(Some(self.lldb)),
73            _ => f(None),
74        }
75    }
76}
77
78impl KernelResources<e310_g003::chip::E310x<'static, E310G003DefaultPeripherals<'static>>>
79    for HiFiveInventor
80{
81    type SyscallDriverLookup = Self;
82    type SyscallFilter = ();
83    type ProcessFault = ();
84    type Scheduler = CooperativeSched<'static>;
85    type SchedulerTimer = SchedulerTimerHw;
86    type WatchDog = ();
87    type ContextSwitchCallback = ();
88
89    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
90        self
91    }
92    fn syscall_filter(&self) -> &Self::SyscallFilter {
93        &()
94    }
95    fn process_fault(&self) -> &Self::ProcessFault {
96        &()
97    }
98    fn scheduler(&self) -> &Self::Scheduler {
99        self.scheduler
100    }
101    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
102        self.scheduler_timer
103    }
104    fn watchdog(&self) -> &Self::WatchDog {
105        &()
106    }
107    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
108        &()
109    }
110}
111
112/// This is in a separate, inline(never) function so that its stack frame is
113/// removed when this function returns. Otherwise, the stack space used for
114/// these static_inits is wasted.
115#[inline(never)]
116unsafe fn start() -> (
117    &'static kernel::Kernel,
118    HiFiveInventor,
119    &'static e310_g003::chip::E310x<'static, E310G003DefaultPeripherals<'static>>,
120) {
121    // only machine mode
122    rv32i::configure_trap_handler();
123
124    // Initialize deferred calls very early.
125    kernel::deferred_call::initialize_deferred_call_state::<
126        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
127    >();
128
129    let peripherals = static_init!(
130        E310G003DefaultPeripherals,
131        E310G003DefaultPeripherals::new(16_000_000)
132    );
133
134    // Setup any recursive dependencies and register deferred calls:
135    peripherals.init();
136
137    peripherals
138        .e310x
139        .prci
140        .set_clock_frequency(sifive::prci::ClockFrequency::Freq16Mhz);
141
142    peripherals.e310x.uart0.initialize_gpio_pins(
143        &peripherals.e310x.gpio_port[17],
144        &peripherals.e310x.gpio_port[16],
145    );
146    peripherals.e310x.uart1.initialize_gpio_pins(
147        &peripherals.e310x.gpio_port[18],
148        &peripherals.e310x.gpio_port[23],
149    );
150
151    peripherals.e310x.watchdog.disable();
152    peripherals.e310x.rtc.disable();
153    peripherals.e310x.pwm0.disable();
154    peripherals.e310x.pwm1.disable();
155    peripherals.e310x.pwm2.disable();
156    peripherals.e310x.uart1.disable();
157
158    // initialize capabilities
159    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
160    let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
161
162    // Create an array to hold process references.
163    let processes = components::process_array::ProcessArrayComponent::new()
164        .finalize(components::process_array_component_static!(NUM_PROCS));
165    PROCESSES = Some(processes);
166
167    // Setup space to store the core kernel data structure.
168    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
169
170    // Create a shared UART channel for the console and for kernel debug.
171    let uart_mux = components::console::UartMuxComponent::new(&peripherals.e310x.uart0, 115200)
172        .finalize(components::uart_mux_component_static!());
173
174    let hardware_timer = static_init!(
175        e310_g003::chip::E310xClint,
176        e310_g003::chip::E310xClint::new(&e310_g003::clint::CLINT_BASE)
177    );
178
179    // Create a shared virtualization mux layer on top of a single hardware
180    // alarm.
181    let mux_alarm = static_init!(
182        MuxAlarm<'static, e310_g003::chip::E310xClint>,
183        MuxAlarm::new(hardware_timer)
184    );
185    hil::time::Alarm::set_alarm_client(hardware_timer, mux_alarm);
186
187    // Alarm
188    let virtual_alarm_user = static_init!(
189        VirtualMuxAlarm<'static, e310_g003::chip::E310xClint>,
190        VirtualMuxAlarm::new(mux_alarm)
191    );
192    virtual_alarm_user.setup();
193
194    let alarm = static_init!(
195        capsules_core::alarm::AlarmDriver<
196            'static,
197            VirtualMuxAlarm<'static, e310_g003::chip::E310xClint>,
198        >,
199        capsules_core::alarm::AlarmDriver::new(
200            virtual_alarm_user,
201            board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
202        )
203    );
204    hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
205
206    let chip = static_init!(
207        e310_g003::chip::E310x<E310G003DefaultPeripherals>,
208        e310_g003::chip::E310x::new(peripherals, hardware_timer)
209    );
210    CHIP = Some(chip);
211
212    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
213        .finalize(components::process_printer_text_component_static!());
214    PROCESS_PRINTER = Some(process_printer);
215
216    let process_console = components::process_console::ProcessConsoleComponent::new(
217        board_kernel,
218        uart_mux,
219        mux_alarm,
220        process_printer,
221        None,
222    )
223    .finalize(components::process_console_component_static!(
224        e310_g003::chip::E310xClint
225    ));
226    let _ = process_console.start();
227
228    // Need to enable all interrupts for Tock Kernel
229    chip.enable_plic_interrupts();
230
231    // enable interrupts globally
232    csr::CSR
233        .mie
234        .modify(csr::mie::mie::mext::SET + csr::mie::mie::msoft::SET + csr::mie::mie::mtimer::SET);
235    csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
236
237    // Setup the console.
238    let console = components::console::ConsoleComponent::new(
239        board_kernel,
240        capsules_core::console::DRIVER_NUM,
241        uart_mux,
242    )
243    .finalize(components::console_component_static!());
244    // Create the debugger object that handles calls to `debug!()`.
245    components::debug_writer::DebugWriterComponent::new::<
246        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
247    >(
248        uart_mux,
249        create_capability!(capabilities::SetDebugWriterCapability),
250    )
251    .finalize(components::debug_writer_component_static!());
252
253    let lldb = components::lldb::LowLevelDebugComponent::new(
254        board_kernel,
255        capsules_core::low_level_debug::DRIVER_NUM,
256        uart_mux,
257    )
258    .finalize(components::low_level_debug_component_static!());
259
260    debug!("HiFive1 initialization complete. Entering main loop.");
261
262    // These symbols are defined in the linker script.
263    extern "C" {
264        /// Beginning of the ROM region containing app images.
265        static _sapps: u8;
266        /// End of the ROM region containing app images.
267        static _eapps: u8;
268        /// Beginning of the RAM region for app memory.
269        static mut _sappmem: u8;
270        /// End of the RAM region for app memory.
271        static _eappmem: u8;
272    }
273
274    let scheduler = components::sched::cooperative::CooperativeComponent::new(processes)
275        .finalize(components::cooperative_component_static!(NUM_PROCS));
276
277    let scheduler_timer =
278        components::virtual_scheduler_timer::VirtualSchedulerTimerComponent::new(mux_alarm)
279            .finalize(components::virtual_scheduler_timer_component_static!(
280                AlarmHw
281            ));
282
283    let hifive1 = HiFiveInventor {
284        console,
285        lldb,
286        alarm,
287        scheduler,
288        scheduler_timer,
289    };
290    kernel::process::load_processes(
291        board_kernel,
292        chip,
293        core::slice::from_raw_parts(
294            core::ptr::addr_of!(_sapps),
295            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
296        ),
297        core::slice::from_raw_parts_mut(
298            core::ptr::addr_of_mut!(_sappmem),
299            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
300        ),
301        &FAULT_RESPONSE,
302        &process_mgmt_cap,
303    )
304    .unwrap_or_else(|err| {
305        debug!("Error loading processes!");
306        debug!("{:?}", err);
307    });
308
309    (board_kernel, hifive1, chip)
310}
311
312/// Main function called after RAM initialized.
313#[no_mangle]
314pub unsafe fn main() {
315    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
316
317    let (board_kernel, board, chip) = start();
318    board_kernel.kernel_loop(
319        &board,
320        chip,
321        None::<&kernel::ipc::IPC<0>>,
322        &main_loop_capability,
323    );
324}