Skip to content

Commit

Permalink
Prepares process memory for multi-processes supports (obhq#760)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Mar 24, 2024
1 parent 024f5a8 commit b611c64
Show file tree
Hide file tree
Showing 15 changed files with 85 additions and 108 deletions.
2 changes: 2 additions & 0 deletions src/kernel/src/budget/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl Budget {
}
}

#[allow(dead_code)]
#[derive(Debug)]
pub enum BudgetType {
DirectMemory = 1,
Expand All @@ -81,6 +82,7 @@ pub enum BudgetType {
FdIpcSocket = 11,
}

#[allow(dead_code)]
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProcType {
Expand Down
10 changes: 3 additions & 7 deletions src/kernel/src/ee/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::arnd::rand_bytes;
use crate::memory::MemoryManager;
use crate::process::ResourceType;
use crate::process::VProc;
use crate::process::{ResourceType, VProc};
use crate::rtld::Module;
use std::ffi::CString;
use std::marker::PhantomPinned;
Expand All @@ -15,7 +13,6 @@ pub mod native;
/// Encapsulate an argument of the PS4 entry point.
pub struct EntryArg {
vp: Arc<VProc>,
mm: Arc<MemoryManager>,
app: Arc<Module>,
name: CString,
path: CString,
Expand All @@ -26,7 +23,7 @@ pub struct EntryArg {
}

impl EntryArg {
pub fn new(vp: &Arc<VProc>, mm: &Arc<MemoryManager>, app: Arc<Module>) -> Self {
pub fn new(vp: &Arc<VProc>, app: Arc<Module>) -> Self {
let path = app.path();
let name = CString::new(path.file_name().unwrap()).unwrap();
let path = CString::new(path.as_str()).unwrap();
Expand All @@ -36,7 +33,6 @@ impl EntryArg {

Self {
vp: vp.clone(),
mm: mm.clone(),
app,
name,
path,
Expand Down Expand Up @@ -100,7 +96,7 @@ impl EntryArg {
pin.vec.push(21); // AT_PAGESIZESLEN
pin.vec.push(size_of_val(&pin.pagesizes));
pin.vec.push(23); // AT_STACKPROT
pin.vec.push(pin.mm.stack().prot().bits() as _);
pin.vec.push(pin.vp.vm().stack().prot().bits() as _);
pin.vec.push(0); // AT_NULL
pin.vec.push(0);

Expand Down
3 changes: 1 addition & 2 deletions src/kernel/src/ee/native/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::fs::{VPath, VPathBuf};
use crate::memory::Protections;
use crate::process::VThread;
use crate::process::{Protections, VThread};
use crate::rtld::{CodeWorkspaceError, Memory, Module, UnprotectSegmentError};
use crate::syscalls::{SysIn, SysOut, Syscalls};
use byteorder::{ByteOrder, LE};
Expand Down
43 changes: 11 additions & 32 deletions src/kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::errno::EEXIST;
use crate::fs::{Fs, FsInitError, MkdirError, MountError, MountFlags, MountOpts, VPath, VPathBuf};
use crate::kqueue::KernelQueueManager;
use crate::log::{print, LOGGER};
use crate::memory::{MemoryManager, MemoryManagerError};
use crate::namedobj::NamedObjManager;
use crate::net::NetManager;
use crate::osem::OsemManager;
Expand Down Expand Up @@ -48,7 +47,6 @@ mod fs;
mod idt;
mod kqueue;
mod log;
mod memory;
mod namedobj;
mod net;
mod osem;
Expand Down Expand Up @@ -337,28 +335,6 @@ fn run() -> Result<(), KernelError> {
return Err(KernelError::MountFailed(path, e));
}

// Initialize memory management.
let mm = MemoryManager::new(&mut syscalls)?;

let mut log = info!();

writeln!(log, "Page size : {:#x}", mm.page_size()).unwrap();
writeln!(
log,
"Allocation granularity: {:#x}",
mm.allocation_granularity()
)
.unwrap();
writeln!(
log,
"Main stack : {:p}:{:p}",
mm.stack().start(),
mm.stack().end()
)
.unwrap();

print(log);

// Initialize TTY system.
#[allow(unused_variables)] // TODO: Remove this when someone uses tty.
let tty = TtyManager::new()?;
Expand All @@ -371,8 +347,8 @@ fn run() -> Result<(), KernelError> {
let budget = BudgetManager::new(&mut syscalls);

DmemManager::new(&fs, &mut syscalls);
SharedMemoryManager::new(&mm, &mut syscalls);
Sysctl::new(&mm, &machdep, &mut syscalls);
SharedMemoryManager::new(&mut syscalls);
Sysctl::new(&machdep, &mut syscalls);
TimeManager::new(&mut syscalls);
KernelQueueManager::new(&mut syscalls);
NetManager::new(&mut syscalls);
Expand All @@ -390,6 +366,12 @@ fn run() -> Result<(), KernelError> {
&mut syscalls,
)?;

info!(
"Application stack: {:p}:{:p}",
proc.vm().stack().start(),
proc.vm().stack().end()
);

NamedObjManager::new(&mut syscalls, &proc);
OsemManager::new(&mut syscalls, &proc);
UmtxManager::new(&mut syscalls);
Expand All @@ -398,7 +380,7 @@ fn run() -> Result<(), KernelError> {
info!("Initializing runtime linker.");

let ee = NativeEngine::new();
let ld = RuntimeLinker::new(&fs, &mm, &ee, &mut syscalls);
let ld = RuntimeLinker::new(&fs, &ee, &mut syscalls);

ee.set_syscalls(syscalls);

Expand Down Expand Up @@ -473,15 +455,15 @@ fn run() -> Result<(), KernelError> {

// Get entry point.
let boot = ld.kernel().unwrap();
let mut arg = Box::pin(EntryArg::new(&proc, &mm, app.clone()));
let mut arg = Box::pin(EntryArg::new(&proc, app.clone()));
let entry = unsafe { boot.get_function(boot.entry().unwrap()) };
let entry = move || unsafe { entry.exec1(arg.as_mut().as_vec().as_ptr()) };

// Start main thread.
info!("Starting application.");

// TODO: Check how this constructed.
let stack = mm.stack();
let stack = proc.vm().stack();
let main: OsThread = unsafe { main.start(stack.start(), stack.len(), entry) }?;

// Begin Discord Rich Presence before blocking current thread.
Expand Down Expand Up @@ -622,9 +604,6 @@ enum KernelError {
#[error("couldn't mount {0}")]
MountFailed(VPathBuf, #[source] MountError),

#[error("memory manager initialization failed")]
MemoryManagerInitFailed(#[from] MemoryManagerError),

#[error("tty initialization failed")]
TtyInitFailed(#[from] TtyInitError),

Expand Down
19 changes: 14 additions & 5 deletions src/kernel/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub use self::rlimit::*;
pub use self::session::*;
pub use self::signal::*;
pub use self::thread::*;
pub use self::vm::*;

mod appinfo;
mod binary;
Expand All @@ -44,19 +45,19 @@ mod rlimit;
mod session;
mod signal;
mod thread;
mod vm;

/// An implementation of `proc` structure represent the main application process.
/// An implementation of `proc` structure.
///
/// Each process of the Obliteration Kernel encapsulates only one PS4 process. The reason we don't
/// encapsulate multiple PS4 processes is because there is no way to emulate `fork` with 100%
/// compatibility from the user-mode application. The PS4 also forbids the game process from creating
/// a child process, so there's no reason for us to support this.
/// Currently this struct represent the main application process. We will support multiple processes
/// once we have migrated the PS4 code to run inside a virtual machine.
#[derive(Debug)]
pub struct VProc {
id: NonZeroI32, // p_pid
threads: Gutex<Vec<Arc<VThread>>>, // p_threads
cred: Ucred, // p_ucred
group: Gutex<Option<VProcGroup>>, // p_pgrp
vm: Arc<MemoryManager>, // p_vmspace
sigacts: Gutex<SignalActs>, // p_sigacts
files: Arc<FileDesc>, // p_fd
system_path: String, // p_randomized_path
Expand Down Expand Up @@ -98,6 +99,7 @@ impl VProc {
threads: gg.spawn(Vec::new()),
cred,
group: gg.spawn(None),
vm: MemoryManager::new(sys)?,
sigacts: gg.spawn(SignalActs::new()),
files: FileDesc::new(root),
system_path: system_path.into(),
Expand Down Expand Up @@ -139,6 +141,10 @@ impl VProc {
&self.cred
}

pub fn vm(&self) -> &MemoryManager {
&self.vm
}

pub fn files(&self) -> &Arc<FileDesc> {
&self.files
}
Expand Down Expand Up @@ -769,6 +775,9 @@ struct RtPrio {
pub enum VProcInitError {
#[error("failed to load limits")]
FailedToLoadLimits(#[from] LoadLimitError),

#[error("virtual memory initialization failed")]
VmInitFailed(#[from] MemoryManagerError),
}

#[derive(Debug, Error, Errno)]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
34 changes: 19 additions & 15 deletions src/kernel/src/rtld/mem.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::MapError;
use crate::fs::VFile;
use crate::memory::{MappingFlags, MemoryManager, MemoryUpdateError, Protections};
use crate::process::{MappingFlags, MemoryUpdateError, Protections, VProc};
use elf::{Elf, ProgramFlags, ProgramType};
use gmtx::{Gutex, GutexGroup, GutexWriteGuard};
use std::alloc::Layout;
Expand All @@ -11,7 +11,8 @@ use thiserror::Error;

/// A memory of the loaded module.
pub struct Memory {
mm: Arc<MemoryManager>,
// This will be remove from here soon once we started working on multi-processes.
proc: Arc<VProc>,
ptr: *mut u8,
len: usize,
segments: Vec<MemorySegment>,
Expand All @@ -27,7 +28,7 @@ pub struct Memory {

impl Memory {
pub(super) fn new<N: Into<String>>(
mm: &Arc<MemoryManager>,
proc: &Arc<VProc>,
image: &Elf<VFile>,
base: usize,
name: N,
Expand Down Expand Up @@ -144,7 +145,7 @@ impl Memory {
segments.push(segment);

// TODO: Use separate name for our code and data.
let mut pages = match mm.mmap(
let mut pages = match proc.vm().mmap(
0,
len,
Protections::empty(),
Expand All @@ -163,15 +164,15 @@ impl Memory {
let len = seg.len;
let prot = seg.prot;

if let Err(e) = mm.mprotect(addr, len, prot) {
if let Err(e) = proc.vm().mprotect(addr, len, prot) {
return Err(MapError::ProtectMemoryFailed(addr, len, prot, e));
}
}

let gg = GutexGroup::new();

Ok(Self {
mm: mm.clone(),
proc: proc.clone(),
ptr: pages.into_raw(),
len,
segments,
Expand Down Expand Up @@ -286,12 +287,12 @@ impl Memory {
let len = seg.len;
let prot = Protections::CPU_READ | Protections::CPU_WRITE;

if let Err(e) = self.mm.mprotect(ptr, len, prot) {
if let Err(e) = self.proc.vm().mprotect(ptr, len, prot) {
return Err(UnprotectSegmentError::MprotectFailed(ptr, len, prot, e));
}

Ok(UnprotectedSegment {
mm: &self.mm,
proc: &self.proc,
ptr,
len,
prot: seg.prot,
Expand Down Expand Up @@ -319,12 +320,12 @@ impl Memory {
// Unprotect the memory.
let prot = Protections::CPU_READ | Protections::CPU_WRITE;

if let Err(e) = self.mm.mprotect(self.ptr, end, prot) {
if let Err(e) = self.proc.vm().mprotect(self.ptr, end, prot) {
return Err(UnprotectError::MprotectFailed(self.ptr, end, prot, e));
}

Ok(UnprotectedMemory {
mm: &self.mm,
proc: &self.proc,
ptr: self.ptr,
len: end,
segments: &self.segments,
Expand All @@ -342,7 +343,7 @@ impl Drop for Memory {
}

// Unmap the memory.
self.mm.munmap(self.ptr, self.len).unwrap();
self.proc.vm().munmap(self.ptr, self.len).unwrap();
}
}

Expand Down Expand Up @@ -404,7 +405,7 @@ impl MemorySegment {

/// A memory segment in an unprotected form.
pub struct UnprotectedSegment<'a> {
mm: &'a MemoryManager,
proc: &'a VProc,
ptr: *mut u8,
len: usize,
prot: Protections,
Expand All @@ -419,13 +420,16 @@ impl<'a> AsMut<[u8]> for UnprotectedSegment<'a> {

impl<'a> Drop for UnprotectedSegment<'a> {
fn drop(&mut self) {
self.mm.mprotect(self.ptr, self.len, self.prot).unwrap();
self.proc
.vm()
.mprotect(self.ptr, self.len, self.prot)
.unwrap();
}
}

/// The unprotected form of [`Memory`], not including our custom segments.
pub struct UnprotectedMemory<'a> {
mm: &'a MemoryManager,
proc: &'a VProc,
ptr: *mut u8,
len: usize,
segments: &'a [MemorySegment],
Expand All @@ -440,7 +444,7 @@ impl<'a> Drop for UnprotectedMemory<'a> {

let addr = unsafe { self.ptr.add(s.start()) };

self.mm.mprotect(addr, s.len(), s.prot()).unwrap();
self.proc.vm().mprotect(addr, s.len(), s.prot()).unwrap();
}
}
}
Expand Down
Loading

0 comments on commit b611c64

Please sign in to comment.