Clean up the `init_stack` module

This commit is contained in:
Ruihan Li 2026-01-13 23:49:07 +08:00
parent 4fa2b55e47
commit 27cb81b295
3 changed files with 52 additions and 95 deletions

View File

@ -6,7 +6,7 @@ use core::cell::Ref;
use inherit_methods_macro::inherit_methods; use inherit_methods_macro::inherit_methods;
use ostd::{ use ostd::{
mm::{Fallible, MAX_USERSPACE_VADDR, PodAtomic, VmIo, VmReader, VmWriter}, mm::{Fallible, PodAtomic, VmIo, VmReader, VmWriter},
task::Task, task::Task,
}; };
@ -17,7 +17,7 @@ use crate::{
posix_thread::{PosixThread, ThreadLocal}, posix_thread::{PosixThread, ThreadLocal},
}, },
thread::Thread, 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. /// The context that can be accessed from the current POSIX thread.
@ -205,10 +205,10 @@ impl<'a> CurrentUserSpace<'a> {
check_vaddr_lowerbound(vaddr)?; 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 // If `vaddr` is outside user address space, `userspace_max_len` will be set to zero and
// further call to `self.reader` will return `EFAULT`. // 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)?; let mut user_reader = self.reader(vaddr, userspace_max_len)?;
user_reader.read_cstring_until_nul(userspace_max_len)? user_reader.read_cstring_until_nul(userspace_max_len)?

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
#![expect(dead_code)]
use crate::prelude::*; use crate::prelude::*;
/// Auxiliary Vector. /// 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_ /// > is a table of key-value pairs, where the keys are from the set of AT_
/// > values in elf.h. /// > values in elf.h.
#[expect(non_camel_case_types)] #[expect(non_camel_case_types)]
#[expect(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)] #[repr(u8)]
pub enum AuxKey { pub enum AuxKey {
@ -50,12 +49,6 @@ pub enum AuxKey {
AT_SYSINFO_EHDR = 33, /* the start address of the page containing the VDSO */ 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)] #[derive(Clone, Default, Debug)]
pub struct AuxVec { pub struct AuxVec {
table: BTreeMap<AuxKey, u64>, table: BTreeMap<AuxKey, u64>,
@ -67,9 +60,7 @@ impl AuxVec {
table: BTreeMap::new(), table: BTreeMap::new(),
} }
} }
}
impl AuxVec {
pub fn set(&mut self, key: AuxKey, val: u64) -> Result<()> { pub fn set(&mut self, key: AuxKey, val: u64) -> Result<()> {
if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE { if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE {
return_errno_with_message!(Errno::EINVAL, "Illegal key"); return_errno_with_message!(Errno::EINVAL, "Illegal key");
@ -81,14 +72,6 @@ impl AuxVec {
Ok(()) 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> { pub fn table(&self) -> &BTreeMap<AuxKey, u64> {
&self.table &self.table
} }

View File

@ -1,16 +1,15 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
#![expect(dead_code)]
//! The init stack for the process. //! 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. //! We can read `argv` and `envp` of a process from the init stack.
//! Usually, the lowest address of init stack is //! Usually, the lowest address of the init stack is
//! the highest address of the user stack of the first thread. //! the highest address of the user stack of the main thread.
//! //!
//! However, the init stack will be mapped to user space //! However, the init stack will be mapped to user space
//! and the user process can write the content of init stack, //! and the user process can write the content of the init stack,
//! so the content reading from init stack may not be the same as the process init status. //! so the content reading from the init stack may not be the same as the initial one.
//! //!
use core::{ use core::{
@ -18,7 +17,7 @@ use core::{
sync::atomic::{AtomicUsize, Ordering}, sync::atomic::{AtomicUsize, Ordering},
}; };
use ostd::mm::{MAX_USERSPACE_VADDR, VmIo}; use ostd::mm::VmIo;
use self::aux_vec::{AuxKey, AuxVec}; use self::aux_vec::{AuxKey, AuxVec};
use crate::{ use crate::{
@ -26,7 +25,7 @@ use crate::{
util::random::getrandom, util::random::getrandom,
vm::{ vm::{
perms::VmPerms, perms::VmPerms,
vmar::Vmar, vmar::{VMAR_CAP_ADDR, Vmar},
vmo::{Vmo, VmoOptions}, 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. /// The initial portion of the main stack of a process.
pub struct InitStack { pub struct InitStack {
/// The initial highest address. /// The top address of the init stack.
/// The stack grows down from this address ///
/// The stack grows down from this address.
initial_top: Vaddr, initial_top: Vaddr,
/// The max allowed stack size /// The maximum size of the stack.
max_size: usize, max_size: usize,
/// The current stack pointer. /// The current stack pointer.
/// Before initialized, `pos` points to the `initial_top`, ///
/// After initialized, `pos` points to the user stack pointer(rsp) /// Before initialization, `pos` points to `initial_top`.
/// of the process. /// After initialization, `pos` points to the top of the process stack.
pos: AtomicUsize, pos: AtomicUsize,
argv_range: SpinLock<Range<Vaddr>>, argv_range: SpinLock<Range<Vaddr>>,
envp_range: SpinLock<Range<Vaddr>>, envp_range: SpinLock<Range<Vaddr>>,
@ -126,7 +126,7 @@ impl Clone for InitStack {
impl InitStack { impl InitStack {
pub fn new() -> Self { pub fn new() -> Self {
let nr_pages_padding = { 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. // So we add this fixed padding. Any small value greater than zero will do.
const NR_FIXED_PADDING_PAGES: usize = 7; const NR_FIXED_PADDING_PAGES: usize = 7;
@ -138,7 +138,7 @@ impl InitStack {
nr_random_padding_pages as usize + NR_FIXED_PADDING_PAGES 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; let max_size = INIT_STACK_SIZE;
Self { 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. /// This method should only be called after the stack is initialized.
pub fn user_stack_top(&self) -> Vaddr { pub fn user_stack_top(&self) -> Vaddr {
let stack_top = self.pos();
debug_assert!(self.is_initialized()); debug_assert!(self.is_initialized());
stack_top self.pos()
} }
/// Maps the VMO of the init stack and constructs a writer to initialize its content. /// 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`. /// 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> { pub(super) fn reader<'a>(&self, vmar: &'a Vmar) -> InitStackReader<'a> {
debug_assert!(self.is_initialized()); debug_assert!(self.is_initialized());
InitStackReader { InitStackReader {
base: self.pos(),
vmar, vmar,
map_addr: self.initial_top - self.max_size,
argv_range: self.argv_range.lock().clone(), argv_range: self.argv_range.lock().clone(),
envp_range: self.envp_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. /// Returns the range of argv and envp in the init stack.
fn write(mut self) -> Result<(Range<Vaddr>, Range<Vaddr>)> { fn write(mut self) -> Result<(Range<Vaddr>, Range<Vaddr>)> {
// FIXME: Some OSes may put the first page of executable file here // FIXME: Some OSes may put the first page of the executable file here
// for interpreting elf headers. // for interpreting ELF headers.
let argc = self.argv.len() as u64; // Write envp strings.
// Write envp string
let envp_end = self.pos(); let envp_end = self.pos();
let envp_pointers = self.write_envp_strings()?; let envp_pointers = self.write_envp_strings()?;
let envp_start = self.pos(); let envp_start = self.pos();
// Write argv string // Write argv strings.
let argv_end = self.pos(); let argv_end = self.pos();
let argv_pointers = self.write_argv_strings()?; let argv_pointers = self.write_argv_strings()?;
let argv_start = self.pos(); let argv_start = self.pos();
// Generate random values for auxvec // Generate random values for the auxiliary vector.
let random_value_pointer = { let random_value_pointer = {
let random_value = generate_random_for_aux_vec(); let random_value = generate_random_for_aux_vec();
self.write_bytes(&random_value)? self.write_bytes(&random_value)?
@ -269,10 +266,11 @@ impl InitStackWriter<'_> {
self.write_envp_pointers(envp_pointers)?; self.write_envp_pointers(envp_pointers)?;
self.write_argv_pointers(argv_pointers)?; self.write_argv_pointers(argv_pointers)?;
// write argc // Write argc.
self.write_u64(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()); debug_assert_eq!(self.pos() & !0xf, self.pos());
Ok((argv_start..argv_end, envp_start..envp_end)) Ok((argv_start..argv_end, envp_start..envp_end))
@ -298,11 +296,12 @@ impl InitStackWriter<'_> {
Ok(argv_pointers) Ok(argv_pointers)
} }
/// Libc ABI requires 16-byte alignment of the stack entrypoint. /// Ensures that the top address of the user stack is 16-byte aligned.
/// Current position of the stack is 8-byte aligned already, insert 8 byte ///
/// to meet the requirement if necessary. /// 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<()> { fn adjust_stack_alignment(&self, envp_pointers: &[u64], argv_pointers: &[u64]) -> Result<()> {
// Ensure 8-byte alignment // Ensure 8-byte alignment.
self.write_u64(0)?; self.write_u64(0)?;
let auxvec_size = (self.auxvec.table().len() + 1) * (size_of::<u64>() * 2); let auxvec_size = (self.auxvec.table().len() + 1) * (size_of::<u64>() * 2);
let envp_pointers_size = (envp_pointers.len() + 1) * size_of::<u64>(); let envp_pointers_size = (envp_pointers.len() + 1) * size_of::<u64>();
@ -316,10 +315,10 @@ impl InitStackWriter<'_> {
} }
fn write_aux_vec(&self) -> Result<()> { fn write_aux_vec(&self) -> Result<()> {
// Write NULL auxiliary // Write a NULL auxiliary entry.
self.write_u64(0)?; self.write_u64(0)?;
self.write_u64(AuxKey::AT_NULL as u64)?; self.write_u64(AuxKey::AT_NULL as u64)?;
// Write Auxiliary vectors // Write the auxiliary vector.
let aux_vec: Vec<_> = self let aux_vec: Vec<_> = self
.auxvec .auxvec
.table() .table()
@ -334,9 +333,9 @@ impl InitStackWriter<'_> {
} }
fn write_envp_pointers(&self, mut envp_pointers: Vec<u64>) -> Result<()> { fn write_envp_pointers(&self, mut envp_pointers: Vec<u64>) -> Result<()> {
// write NULL pointer // Write a NULL pointer.
self.write_u64(0)?; self.write_u64(0)?;
// write envp pointers // Write envp pointers.
envp_pointers.reverse(); envp_pointers.reverse();
for envp_pointer in envp_pointers { for envp_pointer in envp_pointers {
self.write_u64(envp_pointer)?; self.write_u64(envp_pointer)?;
@ -345,9 +344,9 @@ impl InitStackWriter<'_> {
} }
fn write_argv_pointers(&self, mut argv_pointers: Vec<u64>) -> Result<()> { fn write_argv_pointers(&self, mut argv_pointers: Vec<u64>) -> Result<()> {
// write 0 // Write a NULL pointer.
self.write_u64(0)?; self.write_u64(0)?;
// write argv pointers // Write argv pointers.
argv_pointers.reverse(); argv_pointers.reverse();
for argv_pointer in argv_pointers { for argv_pointer in argv_pointers {
self.write_u64(argv_pointer)?; self.write_u64(argv_pointer)?;
@ -355,16 +354,16 @@ impl InitStackWriter<'_> {
Ok(()) Ok(())
} }
/// Writes u64 to the stack. /// Writes a `u64` to the stack.
/// Returns the writing address /// Returns the writing address.
fn write_u64(&self, val: u64) -> Result<u64> { fn write_u64(&self, val: u64) -> Result<u64> {
let new_pos = self.reserve_pos(size_of::<u64>(), align_of::<u64>())?; let new_pos = self.reserve_pos(size_of::<u64>(), align_of::<u64>())?;
self.vmo.write_val(new_pos - self.map_addr, &val)?; self.vmo.write_val(new_pos - self.map_addr, &val)?;
Ok(new_pos as u64) Ok(new_pos as u64)
} }
/// Writes a CString including the ending null byte to the stack. /// Writes a `CString` including the nul byte to the stack.
/// Returns the writing address /// Returns the writing address.
fn write_cstring(&self, val: &CString) -> Result<u64> { fn write_cstring(&self, val: &CString) -> Result<u64> {
let bytes = val.as_bytes_with_nul(); let bytes = val.as_bytes_with_nul();
self.write_bytes(bytes) self.write_bytes(bytes)
@ -386,7 +385,7 @@ impl InitStackWriter<'_> {
self.pos.store(new_pos, Ordering::Relaxed); self.pos.store(new_pos, Ordering::Relaxed);
return Ok(new_pos); 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 { 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`. /// A reader to parse the content of an `InitStack`.
pub struct InitStackReader<'a> { pub struct InitStackReader<'a> {
base: Vaddr,
vmar: &'a Vmar, vmar: &'a Vmar,
/// The mapping address of the `InitStack`.
map_addr: usize,
argv_range: Range<Vaddr>, argv_range: Range<Vaddr>,
envp_range: Range<Vaddr>, envp_range: Range<Vaddr>,
} }
impl InitStackReader<'_> { 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. /// Reads argv at the `offset` from the process init stack.
pub fn argv(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> { pub fn argv(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
if offset >= self.argv_range.end - self.argv_range.start { if offset >= self.argv_range.end - self.argv_range.start {
@ -453,9 +432,4 @@ impl InitStackReader<'_> {
Ok(bytes_read) Ok(bytes_read)
} }
/// Returns the bottom address of the init stack (lowest address).
pub const fn init_stack_bottom(&self) -> Vaddr {
self.base
}
} }