xous-core/kernel/src/main.rs
Jean-Pierre De Jesus DIAZ d8807e6cea
kernel: Move rand driver to platform module.
Signed-off-by: Jean-Pierre De Jesus DIAZ <me@jeandudey.tech>
2022-11-02 14:36:41 +01:00

168 lines
5.3 KiB
Rust

// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
// SPDX-License-Identifier: Apache-2.0
#![cfg_attr(baremetal, no_main)]
#![cfg_attr(baremetal, no_std)]
#[cfg(baremetal)]
#[macro_use]
extern crate bitflags;
#[macro_use]
mod debug;
#[cfg(all(test, not(baremetal)))]
mod test;
mod arch;
#[macro_use]
mod args;
mod io;
mod irq;
mod macros;
mod mem;
mod platform;
mod server;
mod services;
mod syscall;
use services::SystemServices;
use xous_kernel::*;
#[cfg(baremetal)]
use core::panic::PanicInfo;
#[cfg(baremetal)]
#[panic_handler]
fn handle_panic(_arg: &PanicInfo) -> ! {
println!("PANIC in PID {}: {}", crate::arch::current_pid(), _arg);
loop {
arch::idle();
}
}
#[cfg(baremetal)]
#[no_mangle]
/// This function is called from baremetal startup code to initialize various kernel structures
/// based on arguments passed by the bootloader. It is unused when running under an operating system.
///
/// # Safety
///
/// This is safe to call only to initialize the kernel.
pub unsafe extern "C" fn init(arg_offset: *const u32, init_offset: *const u32, rpt_offset: *mut u32) {
args::KernelArguments::init(arg_offset);
let args = args::KernelArguments::get();
// Everything needs memory, so the first thing we should do is initialize the memory manager.
crate::mem::MemoryManager::with_mut(|mm| {
mm.init_from_memory(rpt_offset, &args)
.expect("couldn't initialize memory manager")
});
SystemServices::with_mut(|system_services| {
system_services.init_from_memory(init_offset, &args)
});
// Now that the memory manager is set up, perform any architecture and
// platform specific initializations.
arch::init();
platform::init();
println!("KMAIN (clean boot): Supervisor mode started...");
// rand::init() already clears the initial pipe, but pump the TRNG a little more out of no other reason than sheer paranoia
platform::rand::get_u32();
platform::rand::get_u32();
}
/// Loop through the SystemServices list to determine the next PID to be run.
/// If no process is ready, return `None`.
fn next_pid_to_run(last_pid: Option<PID>) -> Option<PID> {
// PIDs are 1-indexed but arrays are 0-indexed. By not subtracting
// 1 from the PID when we use it as an array index, we automatically
// pick the next process in the list.
let current_pid = last_pid.unwrap_or(unsafe { PID::new_unchecked(1) }).get() as usize;
SystemServices::with(|system_services| {
for test_idx in current_pid..system_services.processes.len() {
if system_services.processes[test_idx].ppid.get() == 1 {
// print!("PID {} is owned by PID1... ", test_idx + 1);
if system_services.processes[test_idx].runnable() {
// println!(" and is runnable");
return match pid_from_usize(test_idx + 1) {
Ok(x) => Some(x),
Err(_) => None,
};
}
// println!(" and is NOT RUNNABLE");
}
}
for test_idx in 0..current_pid {
if system_services.processes[test_idx].ppid.get() == 1 {
// print!("PID {} is owned by PID1... ", test_idx + 1);
if system_services.processes[test_idx].runnable() {
// println!(" and is runnable");
return match pid_from_usize(test_idx + 1) {
Ok(x) => Some(x),
Err(_) => None,
};
}
// println!(" and is NOT RUNNABLE");
}
}
None
})
}
/// Common main function for baremetal and hosted environments.
#[no_mangle]
pub extern "C" fn kmain() {
// Start performing round-robin on all child processes.
// Note that at this point, no new direct children of INIT may be created.
let mut pid = None;
#[cfg(not(any(target_os = "none", target_os = "xous", all(ci, test))))]
{
use std::panic;
panic::set_hook(Box::new(|arg| {
println!("Panic Details: {:?}", arg);
// debug_here::debug_here!();
}));
}
loop {
pid = next_pid_to_run(pid);
match pid {
Some(pid) => {
// #[cfg(feature = "debug-print")]
// println!("switching to pid {}", pid);
xous_kernel::rsyscall(xous_kernel::SysCall::SwitchTo(pid, 0))
.expect("couldn't switch to pid");
}
None => {
#[cfg(feature = "debug-print")]
println!("NO RUNNABLE TASKS FOUND, entering idle state");
#[cfg(feature = "debug-print")]
SystemServices::with(|system_services| {
for (test_idx, process) in system_services.processes.iter().enumerate() {
if !process.free() {
println!("PID {}: {:?}", test_idx + 1, process);
}
}
});
// Special case for testing: idle can return `false` to indicate exit
if !arch::idle() {
return;
}
}
}
}
}
/// The main entrypoint when run in hosted mode. When running in embedded mode,
/// this function does not exist.
#[cfg(all(not(baremetal)))]
fn main() {
kmain();
}