Clean up the `init_stack` module
This commit is contained in:
parent
738d14f3c0
commit
48ccafd7f9
|
|
@ -6,7 +6,7 @@ use core::cell::Ref;
|
|||
|
||||
use inherit_methods_macro::inherit_methods;
|
||||
use ostd::{
|
||||
mm::{Fallible, MAX_USERSPACE_VADDR, PodAtomic, VmIo, VmReader, VmWriter},
|
||||
mm::{Fallible, PodAtomic, VmIo, VmReader, VmWriter},
|
||||
task::Task,
|
||||
};
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
posix_thread::{PosixThread, ThreadLocal},
|
||||
},
|
||||
thread::Thread,
|
||||
vm::vmar::{VMAR_LOWEST_ADDR, Vmar},
|
||||
vm::vmar::{VMAR_CAP_ADDR, VMAR_LOWEST_ADDR, Vmar},
|
||||
};
|
||||
|
||||
/// The context that can be accessed from the current POSIX thread.
|
||||
|
|
@ -205,10 +205,10 @@ impl<'a> CurrentUserSpace<'a> {
|
|||
check_vaddr_lowerbound(vaddr)?;
|
||||
}
|
||||
|
||||
// Adjust `max_len` to ensure `vaddr + max_len` does not exceed `MAX_USERSPACE_VADDR`.
|
||||
// Adjust `max_len` to ensure `vaddr + max_len` does not exceed `VMAR_CAP_ADDR`.
|
||||
// If `vaddr` is outside user address space, `userspace_max_len` will be set to zero and
|
||||
// further call to `self.reader` will return `EFAULT`.
|
||||
let userspace_max_len = MAX_USERSPACE_VADDR.saturating_sub(vaddr).min(max_len);
|
||||
let userspace_max_len = VMAR_CAP_ADDR.saturating_sub(vaddr).min(max_len);
|
||||
|
||||
let mut user_reader = self.reader(vaddr, userspace_max_len)?;
|
||||
user_reader.read_cstring_until_nul(userspace_max_len)?
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![expect(dead_code)]
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Auxiliary Vector.
|
||||
|
|
@ -15,6 +13,7 @@ use crate::prelude::*;
|
|||
/// > is a table of key-value pairs, where the keys are from the set of ‘AT_’
|
||||
/// > values in elf.h.
|
||||
#[expect(non_camel_case_types)]
|
||||
#[expect(dead_code)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[repr(u8)]
|
||||
pub enum AuxKey {
|
||||
|
|
@ -50,12 +49,6 @@ pub enum AuxKey {
|
|||
AT_SYSINFO_EHDR = 33, /* the start address of the page containing the VDSO */
|
||||
}
|
||||
|
||||
impl AuxKey {
|
||||
pub fn as_u64(&self) -> u64 {
|
||||
*self as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct AuxVec {
|
||||
table: BTreeMap<AuxKey, u64>,
|
||||
|
|
@ -67,9 +60,7 @@ impl AuxVec {
|
|||
table: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AuxVec {
|
||||
pub fn set(&mut self, key: AuxKey, val: u64) -> Result<()> {
|
||||
if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE {
|
||||
return_errno_with_message!(Errno::EINVAL, "Illegal key");
|
||||
|
|
@ -81,14 +72,6 @@ impl AuxVec {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get(&self, key: AuxKey) -> Option<u64> {
|
||||
self.table.get(&key).copied()
|
||||
}
|
||||
|
||||
pub fn del(&mut self, key: AuxKey) -> Option<u64> {
|
||||
self.table.remove(&key)
|
||||
}
|
||||
|
||||
pub fn table(&self) -> &BTreeMap<AuxKey, u64> {
|
||||
&self.table
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![expect(dead_code)]
|
||||
|
||||
//! The init stack for the process.
|
||||
//! The init stack is used to store the `argv` and `envp` and auxiliary vectors.
|
||||
//!
|
||||
//! The init stack is used to store `argv`, `envp`, and auxiliary vectors.
|
||||
//! We can read `argv` and `envp` of a process from the init stack.
|
||||
//! Usually, the lowest address of init stack is
|
||||
//! the highest address of the user stack of the first thread.
|
||||
//! Usually, the lowest address of the init stack is
|
||||
//! the highest address of the user stack of the main thread.
|
||||
//!
|
||||
//! However, the init stack will be mapped to user space
|
||||
//! and the user process can write the content of init stack,
|
||||
//! so the content reading from init stack may not be the same as the process init status.
|
||||
//! and the user process can write the content of the init stack,
|
||||
//! so the content reading from the init stack may not be the same as the initial one.
|
||||
//!
|
||||
|
||||
use core::{
|
||||
|
|
@ -18,7 +17,7 @@ use core::{
|
|||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use ostd::mm::{MAX_USERSPACE_VADDR, VmIo};
|
||||
use ostd::mm::VmIo;
|
||||
|
||||
use self::aux_vec::{AuxKey, AuxVec};
|
||||
use crate::{
|
||||
|
|
@ -26,7 +25,7 @@ use crate::{
|
|||
util::random::getrandom,
|
||||
vm::{
|
||||
perms::VmPerms,
|
||||
vmar::Vmar,
|
||||
vmar::{VMAR_CAP_ADDR, Vmar},
|
||||
vmo::{Vmo, VmoOptions},
|
||||
},
|
||||
};
|
||||
|
|
@ -97,15 +96,16 @@ pub const MAX_LEN_STRING_ARG: usize = PAGE_SIZE * 32;
|
|||
|
||||
/// The initial portion of the main stack of a process.
|
||||
pub struct InitStack {
|
||||
/// The initial highest address.
|
||||
/// The stack grows down from this address
|
||||
/// The top address of the init stack.
|
||||
///
|
||||
/// The stack grows down from this address.
|
||||
initial_top: Vaddr,
|
||||
/// The max allowed stack size
|
||||
/// The maximum size of the stack.
|
||||
max_size: usize,
|
||||
/// The current stack pointer.
|
||||
/// Before initialized, `pos` points to the `initial_top`,
|
||||
/// After initialized, `pos` points to the user stack pointer(rsp)
|
||||
/// of the process.
|
||||
///
|
||||
/// Before initialization, `pos` points to `initial_top`.
|
||||
/// After initialization, `pos` points to the top of the process stack.
|
||||
pos: AtomicUsize,
|
||||
argv_range: SpinLock<Range<Vaddr>>,
|
||||
envp_range: SpinLock<Range<Vaddr>>,
|
||||
|
|
@ -126,7 +126,7 @@ impl Clone for InitStack {
|
|||
impl InitStack {
|
||||
pub fn new() -> Self {
|
||||
let nr_pages_padding = {
|
||||
// We do not want the stack top too close to MAX_USERSPACE_VADDR.
|
||||
// We do not want the stack top too close to `VMAR_CAP_ADDR`.
|
||||
// So we add this fixed padding. Any small value greater than zero will do.
|
||||
const NR_FIXED_PADDING_PAGES: usize = 7;
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ impl InitStack {
|
|||
|
||||
nr_random_padding_pages as usize + NR_FIXED_PADDING_PAGES
|
||||
};
|
||||
let initial_top = MAX_USERSPACE_VADDR - PAGE_SIZE * nr_pages_padding;
|
||||
let initial_top = VMAR_CAP_ADDR - PAGE_SIZE * nr_pages_padding;
|
||||
let max_size = INIT_STACK_SIZE;
|
||||
|
||||
Self {
|
||||
|
|
@ -150,14 +150,13 @@ impl InitStack {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the user stack top(highest address), used to setup rsp.
|
||||
/// Returns the top address of the user stack.
|
||||
///
|
||||
/// This method should only be called after the stack is initialized.
|
||||
pub fn user_stack_top(&self) -> Vaddr {
|
||||
let stack_top = self.pos();
|
||||
debug_assert!(self.is_initialized());
|
||||
|
||||
stack_top
|
||||
self.pos()
|
||||
}
|
||||
|
||||
/// Maps the VMO of the init stack and constructs a writer to initialize its content.
|
||||
|
|
@ -201,13 +200,13 @@ impl InitStack {
|
|||
}
|
||||
|
||||
/// Constructs a reader to parse the content of an `InitStack`.
|
||||
/// The `InitStack` should only be read after initialized
|
||||
///
|
||||
/// This method should only be called after the stack is initialized.
|
||||
pub(super) fn reader<'a>(&self, vmar: &'a Vmar) -> InitStackReader<'a> {
|
||||
debug_assert!(self.is_initialized());
|
||||
|
||||
InitStackReader {
|
||||
base: self.pos(),
|
||||
vmar,
|
||||
map_addr: self.initial_top - self.max_size,
|
||||
argv_range: self.argv_range.lock().clone(),
|
||||
envp_range: self.envp_range.lock().clone(),
|
||||
}
|
||||
|
|
@ -242,22 +241,20 @@ impl InitStackWriter<'_> {
|
|||
///
|
||||
/// Returns the range of argv and envp in the init stack.
|
||||
fn write(mut self) -> Result<(Range<Vaddr>, Range<Vaddr>)> {
|
||||
// FIXME: Some OSes may put the first page of executable file here
|
||||
// for interpreting elf headers.
|
||||
// FIXME: Some OSes may put the first page of the executable file here
|
||||
// for interpreting ELF headers.
|
||||
|
||||
let argc = self.argv.len() as u64;
|
||||
|
||||
// Write envp string
|
||||
// Write envp strings.
|
||||
let envp_end = self.pos();
|
||||
let envp_pointers = self.write_envp_strings()?;
|
||||
let envp_start = self.pos();
|
||||
|
||||
// Write argv string
|
||||
// Write argv strings.
|
||||
let argv_end = self.pos();
|
||||
let argv_pointers = self.write_argv_strings()?;
|
||||
let argv_start = self.pos();
|
||||
|
||||
// Generate random values for auxvec
|
||||
// Generate random values for the auxiliary vector.
|
||||
let random_value_pointer = {
|
||||
let random_value = generate_random_for_aux_vec();
|
||||
self.write_bytes(&random_value)?
|
||||
|
|
@ -269,10 +266,11 @@ impl InitStackWriter<'_> {
|
|||
self.write_envp_pointers(envp_pointers)?;
|
||||
self.write_argv_pointers(argv_pointers)?;
|
||||
|
||||
// write argc
|
||||
self.write_u64(argc)?;
|
||||
// Write argc.
|
||||
let argc = self.argv.len();
|
||||
self.write_u64(argc as u64)?;
|
||||
|
||||
// Ensure stack top is 16-bytes aligned
|
||||
// Ensure the stack top is 16-byte aligned.
|
||||
debug_assert_eq!(self.pos() & !0xf, self.pos());
|
||||
|
||||
Ok((argv_start..argv_end, envp_start..envp_end))
|
||||
|
|
@ -298,11 +296,12 @@ impl InitStackWriter<'_> {
|
|||
Ok(argv_pointers)
|
||||
}
|
||||
|
||||
/// Libc ABI requires 16-byte alignment of the stack entrypoint.
|
||||
/// Current position of the stack is 8-byte aligned already, insert 8 byte
|
||||
/// to meet the requirement if necessary.
|
||||
/// Ensures that the top address of the user stack is 16-byte aligned.
|
||||
///
|
||||
/// The 16-byte alignment is required by x86-64 System V ABI.
|
||||
/// To meet that requirement, this method may write some extra 8-byte `u64`s.
|
||||
fn adjust_stack_alignment(&self, envp_pointers: &[u64], argv_pointers: &[u64]) -> Result<()> {
|
||||
// Ensure 8-byte alignment
|
||||
// Ensure 8-byte alignment.
|
||||
self.write_u64(0)?;
|
||||
let auxvec_size = (self.auxvec.table().len() + 1) * (size_of::<u64>() * 2);
|
||||
let envp_pointers_size = (envp_pointers.len() + 1) * size_of::<u64>();
|
||||
|
|
@ -316,10 +315,10 @@ impl InitStackWriter<'_> {
|
|||
}
|
||||
|
||||
fn write_aux_vec(&self) -> Result<()> {
|
||||
// Write NULL auxiliary
|
||||
// Write a NULL auxiliary entry.
|
||||
self.write_u64(0)?;
|
||||
self.write_u64(AuxKey::AT_NULL as u64)?;
|
||||
// Write Auxiliary vectors
|
||||
// Write the auxiliary vector.
|
||||
let aux_vec: Vec<_> = self
|
||||
.auxvec
|
||||
.table()
|
||||
|
|
@ -334,9 +333,9 @@ impl InitStackWriter<'_> {
|
|||
}
|
||||
|
||||
fn write_envp_pointers(&self, mut envp_pointers: Vec<u64>) -> Result<()> {
|
||||
// write NULL pointer
|
||||
// Write a NULL pointer.
|
||||
self.write_u64(0)?;
|
||||
// write envp pointers
|
||||
// Write envp pointers.
|
||||
envp_pointers.reverse();
|
||||
for envp_pointer in envp_pointers {
|
||||
self.write_u64(envp_pointer)?;
|
||||
|
|
@ -345,9 +344,9 @@ impl InitStackWriter<'_> {
|
|||
}
|
||||
|
||||
fn write_argv_pointers(&self, mut argv_pointers: Vec<u64>) -> Result<()> {
|
||||
// write 0
|
||||
// Write a NULL pointer.
|
||||
self.write_u64(0)?;
|
||||
// write argv pointers
|
||||
// Write argv pointers.
|
||||
argv_pointers.reverse();
|
||||
for argv_pointer in argv_pointers {
|
||||
self.write_u64(argv_pointer)?;
|
||||
|
|
@ -355,16 +354,16 @@ impl InitStackWriter<'_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes u64 to the stack.
|
||||
/// Returns the writing address
|
||||
/// Writes a `u64` to the stack.
|
||||
/// Returns the writing address.
|
||||
fn write_u64(&self, val: u64) -> Result<u64> {
|
||||
let new_pos = self.reserve_pos(size_of::<u64>(), align_of::<u64>())?;
|
||||
self.vmo.write_val(new_pos - self.map_addr, &val)?;
|
||||
Ok(new_pos as u64)
|
||||
}
|
||||
|
||||
/// Writes a CString including the ending null byte to the stack.
|
||||
/// Returns the writing address
|
||||
/// Writes a `CString` including the nul byte to the stack.
|
||||
/// Returns the writing address.
|
||||
fn write_cstring(&self, val: &CString) -> Result<u64> {
|
||||
let bytes = val.as_bytes_with_nul();
|
||||
self.write_bytes(bytes)
|
||||
|
|
@ -386,7 +385,7 @@ impl InitStackWriter<'_> {
|
|||
self.pos.store(new_pos, Ordering::Relaxed);
|
||||
return Ok(new_pos);
|
||||
}
|
||||
return_errno_with_message!(Errno::E2BIG, "Init stack overflow");
|
||||
return_errno_with_message!(Errno::E2BIG, "the init stack overflows");
|
||||
}
|
||||
|
||||
fn pos(&self) -> Vaddr {
|
||||
|
|
@ -402,32 +401,12 @@ fn generate_random_for_aux_vec() -> [u8; 16] {
|
|||
|
||||
/// A reader to parse the content of an `InitStack`.
|
||||
pub struct InitStackReader<'a> {
|
||||
base: Vaddr,
|
||||
vmar: &'a Vmar,
|
||||
/// The mapping address of the `InitStack`.
|
||||
map_addr: usize,
|
||||
argv_range: Range<Vaddr>,
|
||||
envp_range: Range<Vaddr>,
|
||||
}
|
||||
|
||||
impl InitStackReader<'_> {
|
||||
/// Reads argc from the process init stack.
|
||||
pub fn argc(&self) -> Result<u64> {
|
||||
let mut buffer = [0u8; 8];
|
||||
|
||||
self.vmar.read_remote(
|
||||
self.init_stack_bottom(),
|
||||
&mut VmWriter::from(&mut buffer[..]).to_fallible(),
|
||||
)?;
|
||||
|
||||
let argc = u64::from_ne_bytes(buffer);
|
||||
if argc > MAX_NR_STRING_ARGS as u64 {
|
||||
return_errno_with_message!(Errno::EINVAL, "argc is corrupted");
|
||||
}
|
||||
|
||||
Ok(argc)
|
||||
}
|
||||
|
||||
/// Reads argv at the `offset` from the process init stack.
|
||||
pub fn argv(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
if offset >= self.argv_range.end - self.argv_range.start {
|
||||
|
|
@ -453,9 +432,4 @@ impl InitStackReader<'_> {
|
|||
|
||||
Ok(bytes_read)
|
||||
}
|
||||
|
||||
/// Returns the bottom address of the init stack (lowest address).
|
||||
pub const fn init_stack_bottom(&self) -> Vaddr {
|
||||
self.base
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue