Remove Vmar usage from InitStack

This commit is contained in:
Chen Chengjun
2024-08-09 16:11:19 +08:00
committed by Tate, Hongliang Tian
parent 12c60852f1
commit 7ade2fcb57
3 changed files with 85 additions and 50 deletions

View File

@ -19,14 +19,18 @@ use core::{
}; };
use align_ext::AlignExt; use align_ext::AlignExt;
use aster_rights::{Full, Rights}; use aster_rights::Full;
use ostd::mm::{VmIo, MAX_USERSPACE_VADDR}; use ostd::mm::{VmIo, MAX_USERSPACE_VADDR};
use self::aux_vec::{AuxKey, AuxVec}; use self::aux_vec::{AuxKey, AuxVec};
use crate::{ use crate::{
prelude::*, prelude::*,
util::{random::getrandom, read_cstring_from_vmar}, util::random::getrandom,
vm::{perms::VmPerms, vmar::Vmar, vmo::VmoOptions}, vm::{
perms::VmPerms,
vmar::Vmar,
vmo::{Vmo, VmoOptions, VmoRightsOp},
},
}; };
pub mod aux_vec; pub mod aux_vec;
@ -91,7 +95,6 @@ pub const MAX_ENV_LEN: usize = 128;
*/ */
/// The initial portion of the main stack of a process. /// The initial portion of the main stack of a process.
#[derive(Debug, Clone)]
pub struct InitStack { pub struct InitStack {
/// The initial highest address. /// The initial highest address.
/// The stack grows down from this address /// The stack grows down from this address
@ -103,6 +106,18 @@ pub struct InitStack {
/// After initialized, `pos` points to the user stack pointer(rsp) /// After initialized, `pos` points to the user stack pointer(rsp)
/// of the process. /// of the process.
pos: Arc<AtomicUsize>, pos: Arc<AtomicUsize>,
vmo: Vmo<Full>,
}
impl Clone for InitStack {
fn clone(&self) -> Self {
Self {
initial_top: self.initial_top,
max_size: self.max_size,
pos: self.pos.clone(),
vmo: self.vmo.new_cow_child(0..self.max_size).alloc().unwrap(),
}
}
} }
impl InitStack { impl InitStack {
@ -114,25 +129,28 @@ impl InitStack {
}; };
let initial_top = MAX_USERSPACE_VADDR - PAGE_SIZE * nr_pages_padding; let initial_top = MAX_USERSPACE_VADDR - PAGE_SIZE * nr_pages_padding;
let max_size = INIT_STACK_SIZE; let max_size = INIT_STACK_SIZE;
let vmo = {
let vmo_options = VmoOptions::<Full>::new(max_size);
vmo_options.alloc().unwrap()
};
Self { Self {
initial_top, initial_top,
max_size, max_size,
pos: Arc::new(AtomicUsize::new(initial_top)), pos: Arc::new(AtomicUsize::new(initial_top)),
vmo,
} }
} }
/// Init and map the vmo for init stack /// Maps the vmo of the init stack.
pub(super) fn alloc_and_map_vmo(&self, root_vmar: &Vmar<Full>) -> Result<()> { pub(super) fn map_init_stack_vmo(&self, root_vmar: &Vmar<Full>) -> Result<()> {
let vmo = {
let vmo_options = VmoOptions::<Rights>::new(self.max_size);
vmo_options.alloc()?
};
let vmar_map_options = { let vmar_map_options = {
let perms = VmPerms::READ | VmPerms::WRITE; let perms = VmPerms::READ | VmPerms::WRITE;
let map_addr = self.initial_top - self.max_size; let map_addr = self.initial_top - self.max_size;
debug_assert!(map_addr % PAGE_SIZE == 0); debug_assert!(map_addr % PAGE_SIZE == 0);
root_vmar.new_map(vmo, perms)?.offset(map_addr) root_vmar
.new_map(self.vmo.dup().to_dyn(), perms)?
.offset(map_addr)
}; };
vmar_map_options.build()?; vmar_map_options.build()?;
@ -151,30 +169,33 @@ impl InitStack {
stack_top stack_top
} }
pub(super) fn writer<'a>( /// Constructs a writer to initialize the content of an `InitStack`.
pub(super) fn writer(
&self, &self,
vmar: &'a Vmar<Full>,
argv: Vec<CString>, argv: Vec<CString>,
envp: Vec<CString>, envp: Vec<CString>,
auxvec: AuxVec, auxvec: AuxVec,
) -> InitStackWriter<'a> { ) -> InitStackWriter<'_> {
// The stack should be written only once. // The stack should be written only once.
debug_assert!(!self.is_initialized()); debug_assert!(!self.is_initialized());
InitStackWriter { InitStackWriter {
pos: self.pos.clone(), pos: self.pos.clone(),
vmar, vmo: &self.vmo,
argv, argv,
envp, envp,
auxvec, auxvec,
map_addr: self.initial_top - self.max_size,
} }
} }
pub(super) fn reader<'a>(&self, vmar: &'a Vmar<Full>) -> InitStackReader<'a> { /// Constructs a reader to parse the content of an `InitStack`.
// The stack should only be read after initialized /// The `InitStack` should only be read after initialized
pub(super) fn reader(&self) -> InitStackReader<'_> {
debug_assert!(self.is_initialized()); debug_assert!(self.is_initialized());
InitStackReader { InitStackReader {
base: self.pos(), base: self.pos(),
vmar, vmo: &self.vmo,
map_addr: self.initial_top - self.max_size,
} }
} }
@ -194,10 +215,12 @@ impl InitStack {
/// A writer to initialize the content of an `InitStack`. /// A writer to initialize the content of an `InitStack`.
pub struct InitStackWriter<'a> { pub struct InitStackWriter<'a> {
pos: Arc<AtomicUsize>, pos: Arc<AtomicUsize>,
vmar: &'a Vmar<Full>, vmo: &'a Vmo<Full>,
argv: Vec<CString>, argv: Vec<CString>,
envp: Vec<CString>, envp: Vec<CString>,
auxvec: AuxVec, auxvec: AuxVec,
/// The mapping address of the `InitStack`.
map_addr: usize,
} }
impl<'a> InitStackWriter<'a> { impl<'a> InitStackWriter<'a> {
@ -314,7 +337,7 @@ impl<'a> InitStackWriter<'a> {
fn write_u64(&self, val: u64) -> Result<u64> { fn write_u64(&self, val: u64) -> Result<u64> {
let start_address = (self.pos() - 8).align_down(8); let start_address = (self.pos() - 8).align_down(8);
self.pos.store(start_address, Ordering::Relaxed); self.pos.store(start_address, Ordering::Relaxed);
self.vmar.write_val(start_address, &val)?; self.vmo.write_val(start_address - self.map_addr, &val)?;
Ok(self.pos() as u64) Ok(self.pos() as u64)
} }
@ -331,7 +354,7 @@ impl<'a> InitStackWriter<'a> {
let len = bytes.len(); let len = bytes.len();
self.pos.fetch_sub(len, Ordering::Relaxed); self.pos.fetch_sub(len, Ordering::Relaxed);
let pos = self.pos(); let pos = self.pos();
self.vmar.write_bytes(pos, bytes)?; self.vmo.write_bytes(pos - self.map_addr, bytes)?;
Ok(pos as u64) Ok(pos as u64)
} }
@ -349,64 +372,71 @@ 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, base: Vaddr,
vmar: &'a Vmar<Full>, vmo: &'a Vmo<Full>,
/// The mapping address of the `InitStack`.
map_addr: usize,
} }
impl<'a> InitStackReader<'a> { impl<'a> InitStackReader<'a> {
/// Read argc from the process init stack /// Reads argc from the process init stack
pub fn argc(&self) -> Result<u64> { pub fn argc(&self) -> Result<u64> {
let stack_base = self.user_stack_top(); let stack_base = self.init_stack_bottom();
Ok(self.vmar.read_val(stack_base)?) Ok(self.vmo.read_val(stack_base - self.map_addr)?)
} }
/// Read argv from the process init stack /// Reads argv from the process init stack
pub fn argv(&self) -> Result<Vec<CString>> { pub fn argv(&self) -> Result<Vec<CString>> {
let argc = self.argc()? as usize; let argc = self.argc()? as usize;
// base = stack bottom + the size of argc // The reading offset in the initial stack is:
let base = self.user_stack_top() + 8; // the initial stack bottom address + the size of `argc` in memory
let read_offset = self.init_stack_bottom() + size_of::<usize>();
let mut argv = Vec::with_capacity(argc); let mut argv = Vec::with_capacity(argc);
for i in 0..argc { let user_space = CurrentUserSpace::get();
let arg_ptr = { let mut argv_reader = user_space.reader(read_offset, argc * size_of::<usize>())?;
let offset = base + i * 8; for _ in 0..argc {
self.vmar.read_val::<Vaddr>(offset)? let arg = {
let arg_ptr = argv_reader.read_val::<Vaddr>()?;
user_space.read_cstring(arg_ptr, MAX_ARG_LEN)?
}; };
let arg = read_cstring_from_vmar(self.vmar, arg_ptr, MAX_ARG_LEN)?;
argv.push(arg); argv.push(arg);
} }
Ok(argv) Ok(argv)
} }
/// Read envp from the process /// Reads envp from the process
pub fn envp(&self) -> Result<Vec<CString>> { pub fn envp(&self) -> Result<Vec<CString>> {
let argc = self.argc()? as usize; let argc = self.argc()? as usize;
// base = stack bottom // The reading offset in the initial stack is:
// the initial stack bottom address
// + the size of argc(8) // + the size of argc(8)
// + the size of arg pointer(8) * the number of arg(argc) // + the size of arg pointer(8) * the number of arg(argc)
// + the size of null pointer(8) // + the size of null pointer(8)
let base = self.user_stack_top() + 8 + 8 * argc + 8; let read_offset = self.init_stack_bottom()
+ size_of::<usize>()
+ size_of::<usize>() * argc
+ size_of::<usize>();
let mut envp = Vec::new(); let mut envp = Vec::new();
for i in 0..MAX_ENVP_NUMBER { let user_space = CurrentUserSpace::get();
let envp_ptr = { let mut envp_reader = user_space.reader(read_offset, MAX_ENVP_NUMBER)?;
let offset = base + i * 8; for _ in 0..MAX_ENVP_NUMBER {
self.vmar.read_val::<Vaddr>(offset)? let envp_ptr = envp_reader.read_val::<Vaddr>()?;
};
if envp_ptr == 0 { if envp_ptr == 0 {
break; break;
} }
let env = read_cstring_from_vmar(self.vmar, envp_ptr, MAX_ENV_LEN)?; let env = user_space.read_cstring(envp_ptr, MAX_ENV_LEN)?;
envp.push(env); envp.push(env);
} }
Ok(envp) Ok(envp)
} }
pub const fn user_stack_top(&self) -> Vaddr { /// Returns the bottom address of the init stack (lowest address).
pub const fn init_stack_bottom(&self) -> Vaddr {
self.base self.base
} }
} }

View File

@ -83,7 +83,7 @@ impl ProcessVm {
pub fn alloc() -> Self { pub fn alloc() -> Self {
let root_vmar = Vmar::<Full>::new_root(); let root_vmar = Vmar::<Full>::new_root();
let init_stack = InitStack::new(); let init_stack = InitStack::new();
init_stack.alloc_and_map_vmo(&root_vmar).unwrap(); init_stack.map_init_stack_vmo(&root_vmar).unwrap();
let heap = Heap::new(); let heap = Heap::new();
heap.alloc_and_map_vmo(&root_vmar).unwrap(); heap.alloc_and_map_vmo(&root_vmar).unwrap();
Self { Self {
@ -112,7 +112,12 @@ impl ProcessVm {
/// Returns a reader for reading contents from /// Returns a reader for reading contents from
/// the `InitStack`. /// the `InitStack`.
pub fn init_stack_reader(&self) -> InitStackReader { pub fn init_stack_reader(&self) -> InitStackReader {
self.init_stack.reader(&self.root_vmar) self.init_stack.reader()
}
/// Returns the top address of the user stack.
pub fn user_stack_top(&self) -> Vaddr {
self.init_stack.user_stack_top()
} }
pub(super) fn init_stack_writer( pub(super) fn init_stack_writer(
@ -121,7 +126,7 @@ impl ProcessVm {
envp: Vec<CString>, envp: Vec<CString>,
aux_vec: AuxVec, aux_vec: AuxVec,
) -> InitStackWriter { ) -> InitStackWriter {
self.init_stack.writer(&self.root_vmar, argv, envp, aux_vec) self.init_stack.writer(argv, envp, aux_vec)
} }
pub(super) fn heap(&self) -> &Heap { pub(super) fn heap(&self) -> &Heap {
@ -131,7 +136,7 @@ impl ProcessVm {
/// Clears existing mappings and then maps stack and heap vmo. /// Clears existing mappings and then maps stack and heap vmo.
pub(super) fn clear_and_map(&self) { pub(super) fn clear_and_map(&self) {
self.root_vmar.clear().unwrap(); self.root_vmar.clear().unwrap();
self.init_stack.alloc_and_map_vmo(&self.root_vmar).unwrap(); self.init_stack.map_init_stack_vmo(&self.root_vmar).unwrap();
self.heap.alloc_and_map_vmo(&self.root_vmar).unwrap(); self.heap.alloc_and_map_vmo(&self.root_vmar).unwrap();
} }
} }

View File

@ -61,7 +61,7 @@ pub fn load_elf_to_vm(
let init_stack_writer = process_vm.init_stack_writer(argv, envp, aux_vec); let init_stack_writer = process_vm.init_stack_writer(argv, envp, aux_vec);
init_stack_writer.write().unwrap(); init_stack_writer.write().unwrap();
let user_stack_top = process_vm.init_stack_reader().user_stack_top(); let user_stack_top = process_vm.user_stack_top();
Ok(ElfLoadInfo { Ok(ElfLoadInfo {
entry_point, entry_point,
user_stack_top, user_stack_top,