diff --git a/kernel/src/config/mod.rs b/kernel/src/config/mod.rs index d6c0bdd3..34903af9 100644 --- a/kernel/src/config/mod.rs +++ b/kernel/src/config/mod.rs @@ -1,5 +1,6 @@ pub use self::arch::*; +use alloc::sync::Arc; use core::num::NonZero; use macros::elf_note; @@ -10,5 +11,26 @@ mod arch; pub const PAGE_SIZE: NonZero = NonZero::new(1 << PAGE_SHIFT).unwrap(); pub const PAGE_MASK: NonZero = NonZero::new(PAGE_SIZE.get() - 1).unwrap(); +/// Runtime configurations for the kernel populated from [`config::Config`]. +pub struct Config { + max_cpu: NonZero, +} + +impl Config { + pub fn new(src: &'static ::config::Config) -> Arc { + Arc::new(Self { + max_cpu: src.max_cpu, + }) + } + + pub fn max_cpu(&self) -> NonZero { + self.max_cpu + } + + pub fn env(&self, _: &str) -> Option<&'static str> { + todo!() + } +} + #[elf_note(section = ".note.obkrnl.page-size", name = "obkrnl", ty = 0)] static NOTE_PAGE_SIZE: [u8; size_of::()] = PAGE_SIZE.get().to_ne_bytes(); diff --git a/kernel/src/context/local.rs b/kernel/src/context/local.rs index 52b1a699..30b8e72d 100644 --- a/kernel/src/context/local.rs +++ b/kernel/src/context/local.rs @@ -1,7 +1,6 @@ -use super::{PinnedContext, pin_cpu}; +use super::{PinnedContext, current_config, pin_cpu}; use alloc::vec::Vec; use core::ops::Deref; -use krt::config; /// Encapsulates per-CPU value. /// @@ -15,7 +14,7 @@ pub struct CpuLocal(Vec); impl CpuLocal { pub fn new(mut f: impl FnMut(usize) -> T) -> Self { - let len = config().max_cpu.get(); + let len = current_config().max_cpu().get(); let mut vec = Vec::with_capacity(len); for i in 0..len { diff --git a/kernel/src/context/mod.rs b/kernel/src/context/mod.rs index 272e5878..4be91224 100644 --- a/kernel/src/context/mod.rs +++ b/kernel/src/context/mod.rs @@ -3,6 +3,7 @@ pub use self::arch::*; pub use self::local::*; use crate::arch::ArchConfig; +use crate::config::Config; use crate::proc::{ProcMgr, Thread}; use crate::uma::Uma; use alloc::rc::Rc; @@ -23,6 +24,7 @@ mod local; /// /// # Safety /// - This function can be called only once per CPU. +/// - `config` must be the same object for all context. /// - `arch` must be the same object for all context. /// - `cpu` must be unique and valid. /// - `setup` must return the same objects for all context. @@ -32,6 +34,7 @@ mod local; /// |---------|--------| /// |PS4 11.00|0x08DA70| pub unsafe fn run_with_context( + config: Arc, arch: Arc, cpu: usize, td: Arc, @@ -42,6 +45,7 @@ pub unsafe fn run_with_context( // on each CPU stack instead. let mut cx = pin!(Context::new( Base { + config: Arc::into_raw(config), arch: Arc::into_raw(arch.clone()), cpu, thread: Arc::into_raw(td), @@ -66,6 +70,16 @@ pub unsafe fn run_with_context( main(); } +/// # Interrupt safety +/// This function can be called from interrupt handler. +pub fn current_config() -> BorrowedArc { + // It does not matter if we are on a different CPU after we load the Context::arch because it is + // always the same for all CPU. + unsafe { + BorrowedArc::from_non_null(Context::load_static_ptr::<{ offset_of!(Base, config) }, _>()) + } +} + /// # Interrupt safety /// This function can be called from interrupt handler. pub fn current_arch() -> BorrowedArc { @@ -156,6 +170,7 @@ pub struct ContextSetup { /// panic handler, both of them does not require a CPU context. #[repr(C)] struct Base { + config: *const Config, arch: *const ArchConfig, cpu: usize, // pc_cpuid thread: *const Thread, // pc_curthread diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 2545b860..d17736d0 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -1,6 +1,7 @@ #![no_std] #![cfg_attr(not(test), no_main)] +use self::config::Config; use self::context::{ContextSetup, current_procmgr}; use self::imgact::Ps4Abi; use self::malloc::KernelHeap; @@ -36,12 +37,13 @@ extern crate alloc; /// /// See Orbis kernel entry point for a reference. #[cfg_attr(target_os = "none", unsafe(no_mangle))] -fn main() -> ! { +fn main(config: &'static ::config::Config) -> ! { // SAFETY: This function has a lot of restrictions. See Context documentation for more details. info!("Starting Obliteration Kernel."); // Setup the CPU after the first print to let the bootloader developer know (some of) their code // are working. + let config = Config::new(config); let arch = unsafe { self::arch::setup_main_cpu() }; // Setup proc0 to represent the kernel. @@ -54,7 +56,7 @@ fn main() -> ! { // Activate CPU context. let thread0 = Arc::new(thread0); - unsafe { self::context::run_with_context(arch, 0, thread0, setup, run) }; + unsafe { self::context::run_with_context(config, arch, 0, thread0, setup, run) }; } fn setup() -> ContextSetup { diff --git a/kernel/src/vm/mod.rs b/kernel/src/vm/mod.rs index 16a6f9db..41f10e21 100644 --- a/kernel/src/vm/mod.rs +++ b/kernel/src/vm/mod.rs @@ -1,8 +1,8 @@ pub use self::object::*; use self::stats::VmStats; -use crate::config::{PAGE_MASK, PAGE_SIZE}; -use crate::context::{current_arch, current_thread}; +use crate::config::{PAGE_MASK, PAGE_SHIFT, PAGE_SIZE}; +use crate::context::{current_arch, current_config, current_thread}; use crate::lock::GutexGroup; use crate::proc::Proc; use alloc::sync::{Arc, Weak}; @@ -16,10 +16,11 @@ mod stats; /// Implementation of Virtual Memory system. pub struct Vm { - boot_area: u64, // basemem - boot_addr: u64, // boot_address - boot_tables: u64, // mptramp_pagetables - initial_memory_size: u64, + boot_area: u64, // basemem + boot_addr: u64, // boot_address + boot_tables: u64, // mptramp_pagetables + initial_memory_size: u64, // initial_memory_size + end_page: u64, // Maxmem stats: [VmStats; 3], pagers: [Weak; 2], // pageproc } @@ -62,6 +63,7 @@ impl Vm { boot_addr: 0, boot_tables: 0, initial_memory_size: 0, + end_page: 0, stats, pagers: Default::default(), }; @@ -122,9 +124,9 @@ impl Vm { /// |---------|--------| /// |PS4 11.00|0x25CF00| fn load_memory_map(&mut self) -> Result<(), VmError> { - // TODO: Some of the logic around physmap does not make sense. + // TODO: Some of the logic around here are very hard to understand. let mut physmap = [0u64; 60]; - let mut i = 0usize; + let mut last = 0usize; let map = match boot_env() { BootEnv::Vm(v) => v.memory_map.as_slice(), }; @@ -142,12 +144,14 @@ impl Vm { break; } - let mut insert_idx = i + 2; + // Check if we need to insert before the previous entries. + let mut insert_idx = last + 2; let mut j = 0usize; - while j <= i { + while j <= last { if m.base < physmap[j + 1] { - if physmap[j] < m.base + m.len { + // Check if end address overlapped. + if m.base + m.len > physmap[j] { warn!("Overlapping memory regions, ignoring second region."); continue 'top; } @@ -159,19 +163,23 @@ impl Vm { j += 2; } - if insert_idx <= i && m.base + m.len == physmap[insert_idx] { + // Check if end address is the start address of the next entry. If yes we just change + // base address of it to increase its size. + if insert_idx <= last && m.base + m.len == physmap[insert_idx] { physmap[insert_idx] = m.base; continue; } + // Check if start address is the end address of the previous entry. If yes we just + // increase the size of previous entry. if insert_idx > 0 && m.base == physmap[insert_idx - 1] { physmap[insert_idx - 1] = m.base + m.len; continue; } - i += 2; + last += 2; - if i == physmap.len() { + if last == physmap.len() { warn!("Too many segments in the physical address map, giving up."); break; } @@ -179,7 +187,7 @@ impl Vm { // This loop does not make sense on the Orbis. It seems like if this loop once // entered it will never exit. #[allow(clippy::while_immutable_condition)] - while insert_idx < i { + while insert_idx < last { todo!() } @@ -187,10 +195,10 @@ impl Vm { physmap[insert_idx + 1] = m.base + m.len; } - // Check if bootloader provide us a memory map. - let physmap = &mut physmap[..i]; - - if physmap.is_empty() { + // Check if bootloader provide us a memory map. The Orbis will check if + // preload_search_info() return null but we can't do that since we use a static size array + // to pass this information. + if physmap[1] == 0 { return Err(VmError::NoMemoryMap); } @@ -198,16 +206,16 @@ impl Vm { let page_size = PAGE_SIZE.get().try_into().unwrap(); let page_mask = !u64::try_from(PAGE_MASK.get()).unwrap(); - for e in physmap.chunks(2) { + for i in (0..=last).step_by(2) { // Check if BIOS boot area. - if e[0] == 0 { + if physmap[i] == 0 { // TODO: Why 1024? - self.boot_area = e[1] / 1024; + self.boot_area = physmap[i + 1] / 1024; } // Add to initial memory size. - let start = e[0].next_multiple_of(page_size); - let end = e[1] & page_mask; + let start = physmap[i].next_multiple_of(page_size); + let end = physmap[i + 1] & page_mask; self.initial_memory_size += end.saturating_sub(start); } @@ -220,6 +228,13 @@ impl Vm { // what is the point of the logic on the above to find boot_area? physmap[1] = self.adjust_boot_area(physmap[1] / 1024); + // Get end page. + self.end_page = physmap[last + 1] >> PAGE_SHIFT; + + if let Some(v) = current_config().env("hw.physmem") { + self.end_page = v.parse::().unwrap() >> PAGE_SHIFT; + } + Ok(()) } diff --git a/lib/krt/src/config/mod.rs b/lib/krt/src/config/mod.rs index f4c01e51..87298dfe 100644 --- a/lib/krt/src/config/mod.rs +++ b/lib/krt/src/config/mod.rs @@ -1,4 +1,4 @@ -use config::{BootEnv, Config}; +use config::BootEnv; use core::ptr::null; pub fn boot_env() -> &'static BootEnv { @@ -6,19 +6,12 @@ pub fn boot_env() -> &'static BootEnv { unsafe { &*BOOT_ENV } } -pub fn config() -> &'static Config { - // SAFETY: This is safe because the setup() requirements. - unsafe { &*CONFIG } -} - /// # Safety /// This function must be called immediately in the [_start](super::_start) function. After that it /// must never be called again. #[allow(dead_code)] -pub(super) unsafe fn setup(env: &'static BootEnv, conf: &'static Config) { +pub(super) unsafe fn setup(env: &'static BootEnv) { unsafe { BOOT_ENV = env }; - unsafe { CONFIG = conf }; } static mut BOOT_ENV: *const BootEnv = null(); -static mut CONFIG: *const Config = null(); diff --git a/lib/krt/src/lib.rs b/lib/krt/src/lib.rs index 885dfd01..80dde142 100644 --- a/lib/krt/src/lib.rs +++ b/lib/krt/src/lib.rs @@ -1,4 +1,4 @@ -//! Minical Rust runtime for the kernel. +//! Minimal Rust runtime for the kernel. //! //! This crate provides foundations for the kernel to run. Its contains panic handler, console I/O //! and other stuff. All of the provided functionalities here can be used immediately when @@ -26,10 +26,10 @@ mod panic; /// 3. Only main CPU can execute this function. #[cfg(target_os = "none")] #[unsafe(no_mangle)] -extern "C" fn _start(env: &'static ::config::BootEnv, conf: &'static ::config::Config) -> ! { +extern "C" fn _start(env: &'static ::config::BootEnv, config: &'static ::config::Config) -> ! { // SAFETY: We call it as the first thing here. - unsafe { self::config::setup(env, conf) }; - main(); + unsafe { self::config::setup(env) }; + main(config); } #[allow(dead_code)] @@ -47,5 +47,5 @@ fn panic(i: &PanicInfo) -> ! { #[cfg(target_os = "none")] unsafe extern "Rust" { - safe fn main() -> !; + safe fn main(config: &'static ::config::Config) -> !; }