From 1cdd462244a1bfe49d8d2bee7440b59e9d696da5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 12 Jul 2022 14:09:55 +0200 Subject: [PATCH] Move the initfs scheme to userspace. --- Cargo.lock | 9 -- Cargo.toml | 1 - src/arch/x86_64/start.rs | 95 +++++++------- src/lib.rs | 51 +++----- src/scheme/initfs.rs | 276 --------------------------------------- src/scheme/live.rs | 2 +- src/scheme/mod.rs | 5 - src/scheme/sys/mod.rs | 2 +- src/syscall/process.rs | 37 ++---- 9 files changed, 76 insertions(+), 402 deletions(-) delete mode 100644 src/scheme/initfs.rs diff --git a/Cargo.lock b/Cargo.lock index 7c81df0..8c23a1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,7 +76,6 @@ dependencies = [ "log", "memoffset", "raw-cpuid", - "redox-initfs", "redox_syscall", "rmm", "rustc-cfg", @@ -147,14 +146,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox-initfs" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-initfs.git#89b8fb8984cf96c418880b7dcd9ce3d6afc3f71c" -dependencies = [ - "plain", -] - [[package]] name = "redox_syscall" version = "0.2.16" diff --git a/Cargo.toml b/Cargo.toml index 2bd3aa7..182aac5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ slab_allocator = { path = "slab_allocator", optional = true } # FIXME: There is some undefined behavior probably in the kernel, which forces us to use spin 0.9.0 and not 0.9.2. spin = "=0.9.0" rmm = { path = "rmm", default-features = false } -redox-initfs = { git = "https://gitlab.redox-os.org/redox-os/redox-initfs.git", features = ["kernel"], default-features = false } [dependencies.goblin] version = "0.2.1" diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index f7e5225..fb4c8a3 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -39,12 +39,12 @@ static BSP_READY: AtomicBool = AtomicBool::new(false); #[repr(packed)] pub struct KernelArgs { - kernel_base: u64, - kernel_size: u64, - stack_base: u64, - stack_size: u64, - env_base: u64, - env_size: u64, + kernel_base: usize, + kernel_size: usize, + stack_base: usize, + stack_size: usize, + env_base: usize, + env_size: usize, /// The base 64-bit pointer to an array of saved RSDPs. It's up to the kernel (and possibly /// userspace), to decide which RSDP to use. The buffer will be a linked list containing a @@ -53,36 +53,26 @@ pub struct KernelArgs { /// This field can be NULL, and if so, the system has not booted with UEFI or in some other way /// retrieved the RSDPs. The kernel or a userspace driver will thus try searching the BIOS /// memory instead. On UEFI systems, BIOS-like searching is not guaranteed to actually work though. - acpi_rsdps_base: u64, + acpi_rsdps_base: usize, /// The size of the RSDPs region. - acpi_rsdps_size: u64, + acpi_rsdps_size: usize, - areas_base: u64, - areas_size: u64, + areas_base: usize, + areas_size: usize, - /// The physical base 64-bit pointer to the contiguous initfs. - initfs_base: u64, - initfs_size: u64, + /// The physical base 64-bit pointer to the contiguous bootstrap/initfs. + bootstrap_base: usize, + /// Size of contiguous bootstrap/initfs physical region, not necessarily page aligned. + bootstrap_size: usize, + /// Entry point the kernel will jump to. + bootstrap_entry: usize, } /// The entry to Rust, all things must be initialized #[no_mangle] pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { - let env = { - let args = &*args_ptr; - - let kernel_base = args.kernel_base as usize; - let kernel_size = args.kernel_size as usize; - let stack_base = args.stack_base as usize; - let stack_size = args.stack_size as usize; - let env_base = args.env_base as usize; - let env_size = args.env_size as usize; - let acpi_rsdps_base = args.acpi_rsdps_base; - let acpi_rsdps_size = args.acpi_rsdps_size; - let areas_base = args.areas_base as usize; - let areas_size = args.areas_size as usize; - let initfs_base = args.initfs_base as usize; - let initfs_size = args.initfs_size as usize; + let bootstrap = { + let args = args_ptr.read(); // BSS should already be zero { @@ -90,12 +80,11 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF); } - KERNEL_BASE.store(kernel_base, Ordering::SeqCst); - KERNEL_SIZE.store(kernel_size, Ordering::SeqCst); + KERNEL_BASE.store(args.kernel_base, Ordering::SeqCst); + KERNEL_SIZE.store(args.kernel_size, Ordering::SeqCst); // Convert env to slice - let env = slice::from_raw_parts((env_base + crate::PHYS_OFFSET) as *const u8, env_size); - let initfs = slice::from_raw_parts((initfs_base + crate::PHYS_OFFSET) as *const u8, initfs_size); + let env = slice::from_raw_parts((args.env_base + crate::PHYS_OFFSET) as *const u8, args.env_size); // Set up graphical debug #[cfg(feature = "graphical_debug")] @@ -117,12 +106,13 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { }); info!("Redox OS starting..."); - info!("Kernel: {:X}:{:X}", kernel_base, kernel_base + kernel_size); - info!("Stack: {:X}:{:X}", stack_base, stack_base + stack_size); - info!("Env: {:X}:{:X}", env_base, env_base + env_size); - info!("RSDPs: {:X}:{:X}", acpi_rsdps_base, acpi_rsdps_base + acpi_rsdps_size); - info!("Areas: {:X}:{:X}", areas_base, areas_base + areas_size); - info!("Initfs: {:X}:{:X}", initfs_base, initfs_base + initfs_size); + info!("Kernel: {:X}:{:X}", args.kernel_base, args.kernel_base + args.kernel_size); + info!("Stack: {:X}:{:X}", args.stack_base, args.stack_base + args.stack_size); + info!("Env: {:X}:{:X}", args.env_base, args.env_base + args.env_size); + info!("RSDPs: {:X}:{:X}", args.acpi_rsdps_base, args.acpi_rsdps_base + args.acpi_rsdps_size); + info!("Areas: {:X}:{:X}", args.areas_base, args.areas_base + args.areas_size); + info!("Bootstrap: {:X}:{:X}", args.bootstrap_base, args.bootstrap_base + args.bootstrap_size); + info!("Bootstrap entry point: {:X}", args.bootstrap_entry); // Set up GDT before paging gdt::init(); @@ -132,19 +122,19 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Initialize RMM crate::arch::rmm::init( - kernel_base, kernel_size, - stack_base, stack_size, - env_base, env_size, - acpi_rsdps_base as usize, acpi_rsdps_size as usize, - areas_base, areas_size, - initfs_base, initfs_size, + args.kernel_base, args.kernel_size, + args.stack_base, args.stack_size, + args.env_base, args.env_size, + args.acpi_rsdps_base, args.acpi_rsdps_size, + args.areas_base, args.areas_size, + args.bootstrap_base, args.bootstrap_size, ); // Initialize paging let (mut active_table, tcb_offset) = paging::init(0); // Set up GDT after paging with TLS - gdt::init_paging(0, tcb_offset, stack_base + stack_size); + gdt::init_paging(0, tcb_offset, args.stack_base + args.stack_size); // Set up IDT idt::init_paging_bsp(); @@ -185,8 +175,8 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Read ACPI tables, starts APs #[cfg(feature = "acpi")] { - acpi::init(&mut active_table, if acpi_rsdps_base != 0 && acpi_rsdps_size > 0 { - Some((acpi_rsdps_base + crate::PHYS_OFFSET as u64, acpi_rsdps_size)) + acpi::init(&mut active_table, if args.acpi_rsdps_base != 0 && args.acpi_rsdps_size > 0 { + Some(((args.acpi_rsdps_base + crate::PHYS_OFFSET) as u64, args.acpi_rsdps_size as u64)) } else { None }); @@ -196,18 +186,21 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Initialize all of the non-core devices not otherwise needed to complete initialization device::init_noncore(); - crate::scheme::initfs::init(initfs); - // Stop graphical debug #[cfg(feature = "graphical_debug")] graphical_debug::fini(); BSP_READY.store(true, Ordering::SeqCst); - env + crate::Bootstrap { + base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(args.bootstrap_base)), + page_count: args.bootstrap_size / crate::memory::PAGE_SIZE, + entry: args.bootstrap_entry, + env, + } }; - crate::kmain(CPU_COUNT.load(Ordering::SeqCst), env); + crate::kmain(CPU_COUNT.load(Ordering::SeqCst), bootstrap); } #[repr(packed)] diff --git a/src/lib.rs b/src/lib.rs index 80ba746..f4f4c47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,6 @@ extern crate spin; #[cfg(feature = "slab")] extern crate slab_allocator; -use alloc::vec::Vec; use core::sync::atomic::{AtomicUsize, Ordering}; use crate::scheme::{FileHandle, SchemeNamespace}; @@ -169,48 +168,36 @@ pub fn cpu_count() -> usize { CPU_COUNT.load(Ordering::Relaxed) } -static mut INIT_ENV: &[u8] = &[]; - -/// Initialize userspace by running the initfs:bin/init process -/// This function will also set the CWD to initfs:bin and open debug: as stdio -pub extern fn userspace_init() { - let path = "initfs:/bin/bootstrap"; - - if let Err(err) = syscall::chdir("initfs:") { - info!("Failed to enter initfs ({}).", err); - panic!("Unexpected error while trying to enter initfs:."); - } - - let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init"); - - let mut total_bytes_read = 0; - let mut data = Vec::new(); - - loop { - data.resize(total_bytes_read + 4096, 0); - let bytes_read = syscall::file_op_mut_slice(syscall::number::SYS_READ, fd, &mut data[total_bytes_read..]).expect("failed to read init"); - if bytes_read == 0 { break } - total_bytes_read += bytes_read; - } - data.truncate(total_bytes_read); - - let _ = syscall::close(fd); - - crate::syscall::process::usermode_bootstrap(data.into_boxed_slice()); +pub fn init_env() -> &'static [u8] { + crate::BOOTSTRAP.get().expect("BOOTSTRAP was not set").env } +pub extern "C" fn userspace_init() { + let bootstrap = crate::BOOTSTRAP.get().expect("BOOTSTRAP was not set"); + unsafe { crate::syscall::process::usermode_bootstrap(bootstrap) } +} + +pub struct Bootstrap { + pub base: crate::memory::Frame, + pub page_count: usize, + pub entry: usize, + pub env: &'static [u8], +} +static BOOTSTRAP: spin::Once = spin::Once::new(); + /// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this -pub fn kmain(cpus: usize, env: &'static [u8]) -> ! { +pub fn kmain(cpus: usize, bootstrap: Bootstrap) -> ! { CPU_ID.store(0, Ordering::SeqCst); CPU_COUNT.store(cpus, Ordering::SeqCst); - unsafe { INIT_ENV = env }; //Initialize the first context, stored in kernel/src/context/mod.rs context::init(); let pid = syscall::getpid(); info!("BSP: {:?} {}", pid, cpus); - info!("Env: {:?}", ::core::str::from_utf8(unsafe { INIT_ENV })); + info!("Env: {:?}", ::core::str::from_utf8(bootstrap.env)); + + BOOTSTRAP.call_once(|| bootstrap); match context::contexts_mut().spawn(userspace_init) { Ok(context_lock) => { diff --git a/src/scheme/initfs.rs b/src/scheme/initfs.rs deleted file mode 100644 index c881cbd..0000000 --- a/src/scheme/initfs.rs +++ /dev/null @@ -1,276 +0,0 @@ -use core::convert::TryFrom; -use core::str; -use core::sync::atomic::{AtomicUsize, Ordering}; - -use alloc::collections::BTreeMap; -use alloc::string::String; -use alloc::vec::Vec; - -use spin::{Once, RwLock}; - -use redox_initfs::{InitFs, InodeStruct, Inode, InodeDir, InodeKind, types::Timespec}; - -use crate::syscall::data::Stat; -use crate::syscall::error::*; -use crate::syscall::flag::{MODE_DIR, MODE_FILE}; -use crate::syscall::scheme::{calc_seek_offset_usize, Scheme}; - -struct Handle { - inode: Inode, - seek: usize, - // TODO: Any better way to implement fpath? Or maybe work around it, e.g. by giving paths such - // as `initfs:__inodes__/`? - filename: String, -} - -static NEXT_ID: AtomicUsize = AtomicUsize::new(0); -static HANDLES: RwLock> = RwLock::new(BTreeMap::new()); - -static FS: Once> = Once::new(); - -fn fs() -> Result> { - FS.get().copied().ok_or(Error::new(ENODEV)) -} -fn get_inode(inode: Inode) -> Result> { - fs()?.get_inode(inode).ok_or_else(|| Error::new(EIO)) -} - -pub fn init(bytes: &'static [u8]) { - let mut called = false; - - FS.call_once(|| { - called = true; - - InitFs::new(bytes) - .expect("failed to parse initfs header") - }); - - assert!(called, "called initfs::init more than once"); -} - -fn next_id() -> usize { - let old = NEXT_ID.fetch_add(1, Ordering::Relaxed); - assert_ne!(old, usize::MAX, "usize overflow in initfs scheme"); - old -} - -pub struct InitFsScheme; - -struct Iter { - dir: InodeDir<'static>, - idx: u32, -} -impl Iterator for Iter { - type Item = Result>; - - fn next(&mut self) -> Option { - let entry = self.dir.get_entry(self.idx).map_err(|_| Error::new(EIO)); - self.idx += 1; - entry.transpose() - } - fn size_hint(&self) -> (usize, Option) { - match self.dir.entry_count().ok() { - Some(size) => { - let size = usize::try_from(size).expect("expected u32 to be convertible into usize"); - (size, Some(size)) - } - None => (0, None), - } - } -} - -fn entries_iter(dir: InodeDir<'static>) -> impl IntoIterator>> + 'static { - let mut index = 0_u32; - - core::iter::from_fn(move || { - let idx = index; - index += 1; - - dir.get_entry(idx).map_err(|_| Error::new(EIO)).transpose() - }) -} -fn inode_len(inode: InodeStruct<'static>) -> Result { - Ok(match inode.kind() { - InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?.len(), - InodeKind::Dir(dir) => (Iter { dir, idx: 0 }) - .fold(0, |len, entry| len + entry.and_then(|entry| entry.name().map_err(|_| Error::new(EIO))).map_or(0, |name| name.len() + 1)), - InodeKind::Unknown => return Err(Error::new(EIO)), - }) -} - -impl Scheme for InitFsScheme { - fn open(&self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { - let mut components = path - // trim leading and trailing slash - .trim_matches('/') - // divide into components - .split('/') - // filter out double slashes (e.g. /usr//bin/...) - .filter(|c| !c.is_empty()); - - let mut current_inode = InitFs::ROOT_INODE; - - while let Some(component) = components.next() { - match component { - "." => continue, - ".." => { - let _ = components.next_back(); - continue - } - - _ => (), - } - - let current_inode_struct = get_inode(current_inode)?; - - let dir = match current_inode_struct.kind() { - InodeKind::Dir(dir) => dir, - - // If we still have more components in the path, and the file tree for that - // particular branch is not all directories except the last, then that file cannot - // exist. - InodeKind::File(_) | InodeKind::Unknown => return Err(Error::new(ENOENT)), - }; - - let mut entries = Iter { - dir, - idx: 0, - }; - - current_inode = loop { - let entry_res = match entries.next() { - Some(e) => e, - None => return Err(Error::new(ENOENT)), - }; - let entry = entry_res?; - let name = entry.name().map_err(|_| Error::new(EIO))?; - if name == component.as_bytes() { - break entry.inode(); - } - }; - } - - let id = next_id(); - let old = HANDLES.write().insert(id, Handle { - inode: current_inode, - seek: 0_usize, - filename: path.into(), - }); - assert!(old.is_none()); - - Ok(id) - } - - fn read(&self, id: usize, buffer: &mut [u8]) -> Result { - let mut handles = HANDLES.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - match get_inode(handle.inode)?.kind() { - InodeKind::Dir(dir) => { - let mut bytes_read = 0; - let mut bytes_skipped = 0; - - for entry_res in (Iter { dir, idx: 0 }) { - let entry = entry_res?; - let name = entry.name().map_err(|_| Error::new(EIO))?; - let entry_len = name.len() + 1; - - let to_skip = core::cmp::min(handle.seek - bytes_skipped, entry_len); - let max_to_read = core::cmp::min(entry_len - to_skip, buffer.len()); - - let to_copy = entry_len.saturating_sub(to_skip).saturating_sub(1); - buffer[bytes_read..bytes_read + to_copy].copy_from_slice(&name[..to_copy]); - - if to_copy.saturating_sub(to_skip) == 1 { - buffer[bytes_read + to_copy] = b'\n'; - bytes_read += 1; - } - - bytes_read += to_copy; - bytes_skipped += to_skip; - } - - handle.seek = handle.seek.checked_add(bytes_read).ok_or(Error::new(EOVERFLOW))?; - - Ok(bytes_read) - } - InodeKind::File(file) => { - let data = file.data().map_err(|_| Error::new(EIO))?; - let src_buf = &data[core::cmp::min(handle.seek, data.len())..]; - - let to_copy = core::cmp::min(src_buf.len(), buffer.len()); - buffer[..to_copy].copy_from_slice(&src_buf[..to_copy]); - - handle.seek = handle.seek.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; - - Ok(to_copy) - } - InodeKind::Unknown => return Err(Error::new(EIO)), - } - } - - fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { - let mut handles = HANDLES.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let new_offset = calc_seek_offset_usize(handle.seek, pos, whence, inode_len(get_inode(handle.inode)?)?)?; - handle.seek = new_offset as usize; - Ok(new_offset) - } - - fn fcntl(&self, id: usize, _cmd: usize, _arg: usize) -> Result { - let handles = HANDLES.read(); - let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - Ok(0) - } - - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles = HANDLES.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - // TODO: Copy scheme part in kernel - let scheme_path = b"initfs:"; - let scheme_bytes = core::cmp::min(scheme_path.len(), buf.len()); - buf[..scheme_bytes].copy_from_slice(&scheme_path[..scheme_bytes]); - - let source = handle.filename.as_bytes(); - let path_bytes = core::cmp::min(buf.len() - scheme_bytes, source.len()); - buf[scheme_bytes..scheme_bytes + path_bytes].copy_from_slice(&source[..path_bytes]); - - Ok(scheme_bytes + path_bytes) - } - - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = HANDLES.read(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - let Timespec { sec, nsec } = fs()?.image_creation_time(); - - let inode = get_inode(handle.inode)?; - - stat.st_mode = inode.mode() | match inode.kind() { InodeKind::Dir(_) => MODE_DIR, InodeKind::File(_) => MODE_FILE, _ => 0 }; - stat.st_uid = inode.uid(); - stat.st_gid = inode.gid(); - stat.st_size = u64::try_from(inode_len(inode)?).unwrap_or(u64::MAX); - - stat.st_ctime = sec.get(); - stat.st_ctime_nsec = nsec.get(); - stat.st_mtime = sec.get(); - stat.st_mtime_nsec = nsec.get(); - - Ok(0) - } - - fn fsync(&self, id: usize) -> Result { - let handles = HANDLES.read(); - let _handle = handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(0) - } - - fn close(&self, id: usize) -> Result { - let _ = HANDLES.write().remove(&id).ok_or(Error::new(EBADF))?; - Ok(0) - } -} -impl crate::scheme::KernelScheme for InitFsScheme {} diff --git a/src/scheme/live.rs b/src/scheme/live.rs index b5d1e17..63877c8 100644 --- a/src/scheme/live.rs +++ b/src/scheme/live.rs @@ -37,7 +37,7 @@ impl DiskScheme { let mut phys = 0; let mut size = 0; - for line in str::from_utf8(unsafe { crate::INIT_ENV }).unwrap_or("").lines() { + for line in str::from_utf8(crate::init_env()).unwrap_or("").lines() { let mut parts = line.splitn(2, '='); let name = parts.next().unwrap_or(""); let value = parts.next().unwrap_or(""); diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index 6f66a44..ac81fbb 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -25,7 +25,6 @@ use self::acpi::AcpiScheme; use self::debug::DebugScheme; use self::event::EventScheme; -use self::initfs::InitFsScheme; use self::irq::IrqScheme; use self::itimer::ITimerScheme; use self::memory::MemoryScheme; @@ -46,9 +45,6 @@ pub mod debug; /// `event:` - allows reading of `Event`s which are registered using `fevent` pub mod event; -/// `initfs:` - a readonly filesystem used for initializing the system -pub mod initfs; - /// `irq:` - allows userspace handling of IRQs pub mod irq; @@ -166,7 +162,6 @@ impl SchemeList { self.insert(ns, "kernel/acpi", |scheme_id| Arc::new(AcpiScheme::new(scheme_id))).unwrap(); } self.insert(ns, "debug", |scheme_id| Arc::new(DebugScheme::new(scheme_id))).unwrap(); - self.insert(ns, "initfs", |_| Arc::new(InitFsScheme)).unwrap(); self.insert(ns, "irq", |scheme_id| Arc::new(IrqScheme::new(scheme_id))).unwrap(); self.insert(ns, "proc", |scheme_id| Arc::new(ProcScheme::new(scheme_id))).unwrap(); self.insert(ns, "thisproc", |_| Arc::new(ProcScheme::restricted())).unwrap(); diff --git a/src/scheme/sys/mod.rs b/src/scheme/sys/mod.rs index 82cea67..d8f1989 100644 --- a/src/scheme/sys/mod.rs +++ b/src/scheme/sys/mod.rs @@ -52,7 +52,7 @@ impl SysScheme { files.insert("scheme_num", Box::new(scheme_num::resource)); files.insert("syscall", Box::new(syscall::resource)); files.insert("uname", Box::new(uname::resource)); - files.insert("env", Box::new(|| Ok(Vec::from(unsafe { crate::INIT_ENV })))); + files.insert("env", Box::new(|| Ok(Vec::from(crate::init_env())))); #[cfg(target_arch = "x86_64")] files.insert("spurious_irq", Box::new(irq::spurious_irq_resource)); diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 1a1e725..7ad39bb 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -9,6 +9,7 @@ use spin::{RwLock, RwLockWriteGuard}; use crate::context::{Context, ContextId, memory, WaitpidKey}; +use crate::Bootstrap; use crate::context; use crate::interrupt; use crate::paging::mapper::{Flusher, InactiveFlusher, PageFlushAll}; @@ -624,28 +625,17 @@ pub fn waitpid(pid: ContextId, status_ptr: usize, flags: WaitFlags) -> Result) -> ! { - assert!(!data.is_empty()); - - const LOAD_BASE: usize = 0; +pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) -> ! { + assert_ne!(bootstrap.page_count, 0); { - let mut active_table = unsafe { ActivePageTable::new(TableKind::User) }; + let grant = context::memory::Grant::physmap( + bootstrap.base.start_address(), + VirtualAddress::new(0), + bootstrap.page_count * PAGE_SIZE, + PageFlags::new().user(true).write(true).execute(true), + ); - let grant = context::memory::Grant::zeroed(Page::containing_address(VirtualAddress::new(LOAD_BASE)), (data.len()+PAGE_SIZE-1)/PAGE_SIZE, PageFlags::new().user(true).write(true).execute(true), &mut active_table, PageFlushAll::new()).expect("failed to allocate memory for bootstrap"); - - - for (index, page) in grant.pages().enumerate() { - let len = if data.len() - index * PAGE_SIZE < PAGE_SIZE { data.len() % PAGE_SIZE } else { PAGE_SIZE }; - - let physaddr = active_table.translate_page(page) - .expect("expected mapped init memory to have a corresponding frame") - .start_address(); - - unsafe { - (RmmA::phys_to_virt(physaddr).data() as *mut u8).copy_from_nonoverlapping(data.as_ptr().add(index * PAGE_SIZE), len); - } - } context::contexts().current() .expect("expected a context to exist when executing init") .read().addr_space() @@ -653,12 +643,7 @@ pub fn usermode_bootstrap(mut data: Box<[u8]>) -> ! { .write().grants.insert(grant); } - drop(data); - #[cfg(target_arch = "x86_64")] - unsafe { - let start = ((LOAD_BASE + 0x18) as *mut usize).read(); - // Start with the (probably) ELF executable loaded, without any stack. - usermode(start, 0, 0, 0); - } + // Start in a minimal environment without any stack. + usermode(bootstrap.entry, 0, 0, 0); }