diff --git a/kernel/src/vm/mod.rs b/kernel/src/vm/mod.rs index adb24c6bc..80c534c68 100644 --- a/kernel/src/vm/mod.rs +++ b/kernel/src/vm/mod.rs @@ -5,6 +5,8 @@ use crate::context::current_thread; use crate::lock::GutexGroup; use crate::proc::Proc; use alloc::sync::{Arc, Weak}; +use config::{BootEnv, MapType}; +use krt::{boot_env, warn}; use macros::bitflag; mod object; @@ -24,6 +26,10 @@ impl Vm { /// |---------|--------| /// |PS4 11.00|0x029200| pub fn new() -> Arc { + // The Orbis invoke this in hammer_time but we do it here instead to keep it in the VM + // subsystem. + Self::load_memory_map(); + // Initializes stats. The Orbis initialize these data in vm_pageout function but it is // possible for data race so we do it here instead. let pageout_page_count = 0x10; // TODO: Figure out where this value come from. @@ -86,6 +92,77 @@ impl Vm { todo!() } + /// See `getmemsize` on the Orbis for a reference. + /// + /// # Reference offsets + /// | Version | Offset | + /// |---------|--------| + /// |PS4 11.00|0x25CF00| + fn load_memory_map() { + let mut physmap = [0u64; 60]; + let mut i = 0usize; + let map = match boot_env() { + BootEnv::Vm(v) => v.memory_map.as_slice(), + }; + + 'top: for m in map { + match m.ty { + MapType::None => break, + MapType::Ram => { + // TODO: This should be possible only when booting from BIOS. + if m.len == 0 { + break; + } + + let mut insert_idx = i + 2; + let mut j = 0usize; + + while j <= i { + if m.base < physmap[j + 1] { + insert_idx = j; + + if physmap[j] < m.base + m.len { + warn!("Overlapping memory regions, ignoring second region."); + continue 'top; + } + + break; + } + + j += 2; + } + + if insert_idx <= i && m.base + m.len == physmap[insert_idx] { + physmap[insert_idx] = m.base; + continue; + } + + if insert_idx > 0 && m.base == physmap[insert_idx - 1] { + physmap[insert_idx - 1] = m.base + m.len; + continue; + } + + i += 2; + + if i == physmap.len() { + warn!("Too many segments in the physical address map, giving up."); + break; + } + + // 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 { + todo!() + } + + physmap[insert_idx] = m.base; + physmap[insert_idx + 1] = m.base + m.len; + } + } + } + } + /// See `kick_pagedaemons` on the Orbis for a reference. /// /// # Reference offsets diff --git a/lib/krt/src/console/mod.rs b/lib/krt/src/console/mod.rs index 2f60213dc..041f1afb7 100644 --- a/lib/krt/src/console/mod.rs +++ b/lib/krt/src/console/mod.rs @@ -18,6 +18,19 @@ macro_rules! info { }; } +/// Write warning log. +/// +/// When running inside a VM each call will cause a VM to exit multiple times so don't do this in a +/// performance critical path. +/// +/// The LF character will be automatically appended. +#[macro_export] +macro_rules! warn { + ($($args:tt)*) => { + $crate::warn(file!(), line!(), format_args!($($args)*)) + }; +} + pub fn info(file: &str, line: u32, msg: impl Display) { let msg = Log { style: Style::new().effects(Effects::DIMMED), @@ -30,6 +43,18 @@ pub fn info(file: &str, line: u32, msg: impl Display) { print(ConsoleType::Info, msg); } +pub fn warn(file: &str, line: u32, msg: impl Display) { + let msg = Log { + style: Style::new().fg_color(Some(Color::Ansi(AnsiColor::BrightYellow))), + cat: 'W', + file, + line, + msg, + }; + + print(ConsoleType::Warn, msg); +} + pub fn error(file: &str, line: u32, msg: impl Display) { let msg = Log { style: Style::new().fg_color(Some(Color::Ansi(AnsiColor::BrightRed))),