mirror of
https://github.com/obhq/obliteration.git
synced 2025-04-02 11:02:08 -04:00
Populates Maxmem (#1319)
This commit is contained in:
parent
9401c58c4d
commit
3703853c03
7 changed files with 89 additions and 43 deletions
|
@ -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<usize> = NonZero::new(1 << PAGE_SHIFT).unwrap();
|
||||
pub const PAGE_MASK: NonZero<usize> = NonZero::new(PAGE_SIZE.get() - 1).unwrap();
|
||||
|
||||
/// Runtime configurations for the kernel populated from [`config::Config`].
|
||||
pub struct Config {
|
||||
max_cpu: NonZero<usize>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(src: &'static ::config::Config) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
max_cpu: src.max_cpu,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn max_cpu(&self) -> NonZero<usize> {
|
||||
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::<usize>()] = PAGE_SIZE.get().to_ne_bytes();
|
||||
|
|
|
@ -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<T>(Vec<T>);
|
|||
|
||||
impl<T> CpuLocal<T> {
|
||||
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 {
|
||||
|
|
|
@ -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<Config>,
|
||||
arch: Arc<ArchConfig>,
|
||||
cpu: usize,
|
||||
td: Arc<Thread>,
|
||||
|
@ -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<Config> {
|
||||
// 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<ArchConfig> {
|
||||
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<Proc>; 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::<u64>().unwrap() >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) -> !;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue