diff --git a/Cargo.lock b/Cargo.lock index 6521070ac3..92eb0d3704 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,16 +27,16 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cbindgen" -version = "0.24.3" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6358dedf60f4d9b8db43ad187391afe959746101346fe51bb978126bec61dfb" +checksum = "4b922faaf31122819ec80c4047cc684c6979a087366c069611e33649bf98e18d" dependencies = [ "clap", "heck", "indexmap", "log", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "serde", "serde_json", "syn 1.0.109", @@ -55,9 +55,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "51f1226cd9da55587234753d1245dd5b132343ea240f26b6a9003d68706141ba" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -67,9 +70,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.23" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags", @@ -110,9 +113,9 @@ version = "0.1.0" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -172,9 +175,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "indexmap" @@ -197,20 +200,20 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", "windows-sys 0.48.0", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "lazy_static" @@ -232,15 +235,15 @@ source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox_0.2. [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -248,12 +251,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memchr" @@ -272,18 +272,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "os_str_bytes" -version = "6.5.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" [[package]] name = "plain" @@ -306,9 +306,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -324,11 +324,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.66", ] [[package]] @@ -389,8 +389,7 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +source = "git+https://gitlab.redox-os.org/redox-os/syscall#a525620c818a801bb7038e111b71033eff56a3ee" dependencies = [ "bitflags", ] @@ -454,9 +453,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "sc" @@ -466,9 +465,9 @@ checksum = "010e18bd3bfd1d45a7e666b236c78720df0d9a7698ebaa9c1c559961eb60a38b" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scroll" @@ -514,29 +513,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -581,19 +580,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.15" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "unicode-ident", ] @@ -642,9 +641,9 @@ checksum = "e92e959f029e4f8ee25d70d15ab58d2b46f98a17bc238b9265ff0c26f6f3d67f" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-width" @@ -704,7 +703,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -724,9 +723,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", diff --git a/Cargo.toml b/Cargo.toml index 982fb40c31..61f84fbbf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,4 @@ panic = "abort" [patch.crates-io] libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox_0.2.138" } +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall" } diff --git a/src/platform/redox/extra.rs b/src/platform/redox/extra.rs index f43330b408..0c151efdcd 100644 --- a/src/platform/redox/extra.rs +++ b/src/platform/redox/extra.rs @@ -1,9 +1,10 @@ use core::{ptr, slice}; use crate::platform::{sys::e, types::*}; - use syscall::{error::*, F_SETFD, F_SETFL}; +pub use redox_exec::*; + #[no_mangle] pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t { e(syscall::fpath( @@ -46,5 +47,3 @@ pub fn pipe2(fds: &mut [c_int], flags: usize) -> syscall::error::Result<()> { Ok(()) } - -pub use redox_exec::{create_set_addr_space_buf, FdGuard}; diff --git a/src/platform/redox/redox-exec/src/lib.rs b/src/platform/redox/redox-exec/src/lib.rs index f7527e4627..7420c22b5f 100644 --- a/src/platform/redox/redox-exec/src/lib.rs +++ b/src/platform/redox/redox-exec/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] -#![feature(array_chunks)] +#![feature(array_chunks, int_roundings, let_chains, slice_ptr_get)] +#![forbid(unreachable_patterns)] extern crate alloc; @@ -22,7 +23,8 @@ use goblin::elf64::{ use syscall::{ error::*, flag::{MapFlags, SEEK_SET}, - PAGE_SIZE, + PAGE_SIZE, Map, PROT_WRITE, O_CLOEXEC, + GrantDesc, GrantFlags, PROT_READ, PROT_EXEC, MAP_SHARED, MAP_FIXED_NOREPLACE, }; pub use self::arch::*; @@ -82,7 +84,6 @@ where let current_addrspace_fd = FdGuard::new(syscall::dup(*open_via_dup, b"addrspace")?); FdGuard::new(syscall::dup(*current_addrspace_fd, b"empty")?) }; - let memory_fd = FdGuard::new(syscall::dup(*grants_fd, b"mem")?); // Never allow more than 1 MiB of program headers. const MAX_PH_SIZE: usize = 1024 * 1024; @@ -105,9 +106,6 @@ where |o| core::mem::take(&mut o.tree), ); - const BUFSZ: usize = 1024 * 256; - let mut buf = vec![0_u8; BUFSZ]; - read_all(*image_file as usize, Some(header.e_phoff as u64), phs) .map_err(|_| Error::new(EIO))?; @@ -124,14 +122,6 @@ where flags |= syscall::PROT_WRITE; } - let voff = segment.p_vaddr as usize % PAGE_SIZE; - let vaddr = segment.p_vaddr as usize - voff; - let size = (segment.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; - - if segment.p_filesz > segment.p_memsz { - return Err(Error::new(ENOEXEC)); - } - #[forbid(unreachable_patterns)] match segment.p_type { // PT_INTERP must come before any PT_LOAD, so we don't have to iterate twice. PT_INTERP => { @@ -157,28 +147,100 @@ where }); } PT_LOAD => { + let voff = segment.p_vaddr as usize % PAGE_SIZE; + let vaddr = segment.p_vaddr as usize - voff; + let filesz = segment.p_filesz as usize; + + let total_page_count = (segment.p_memsz as usize + voff).div_ceil(PAGE_SIZE); + + // The case where segments overlap so that they share one page, is not handled. + // TODO: Should it be? + + if segment.p_filesz > segment.p_memsz { + return Err(Error::new(ENOEXEC)); + } + allocate_remote( &grants_fd, memory_scheme_fd, vaddr, - size, - syscall::PROT_READ | syscall::PROT_WRITE, + total_page_count * PAGE_SIZE, + flags, )?; - syscall::lseek(*image_file as usize, segment.p_offset as isize, SEEK_SET) - .map_err(|_| Error::new(EIO))?; - syscall::lseek(*memory_fd, segment.p_vaddr as isize, SEEK_SET) + syscall::lseek(*image_file, segment.p_offset as isize, SEEK_SET) .map_err(|_| Error::new(EIO))?; - for size in core::iter::repeat(buf.len()) - .take((segment.p_filesz as usize) / buf.len()) - .chain(Some((segment.p_filesz as usize) % buf.len())) - { - read_all(*image_file as usize, None, &mut buf[..size]) - .map_err(|_| Error::new(EIO))?; - let _ = - syscall::write(*memory_fd, &buf[..size]).map_err(|_| Error::new(EIO))?; + // If unaligned, read the head page separately. + let (first_aligned_page, remaining_filesz) = if voff > 0 { + let bytes_to_next_page = PAGE_SIZE - voff; + + let (_guard, dst_page) = unsafe { + MmapGuard::map_mut_anywhere( + *grants_fd, + vaddr, + PAGE_SIZE, + )? + }; + + let length = core::cmp::min(bytes_to_next_page, filesz); + + read_all(*image_file, None, &mut dst_page[voff..][..length])?; + + (vaddr + PAGE_SIZE, filesz - length) + } else { + (vaddr, filesz) + }; + + let remaining_page_count = remaining_filesz.div_floor(PAGE_SIZE); + let tail_bytes = remaining_filesz % PAGE_SIZE; + + // TODO: Unless the calling process if *very* memory-constrained, the max amount of + // pages per iteration has no limit other than the time it takes to setup page + // tables. + // + // TODO: Reserve PAGES_PER_ITER "scratch pages" of virtual memory for that type of + // situation? + const PAGES_PER_ITER: usize = 64; + + // TODO: Before this loop, attempt to mmap with MAP_PRIVATE directly from the image + // file. + + for page_idx in (0..remaining_page_count).step_by(PAGES_PER_ITER) { + // Use commented out lines to trigger kernel bug (FIXME). + + //let pages_in_this_group = core::cmp::min(PAGES_PER_ITER, file_page_count - page_idx * PAGES_PER_ITER); + let pages_in_this_group = core::cmp::min(PAGES_PER_ITER, remaining_page_count - page_idx); + + if pages_in_this_group == 0 { break } + + // TODO: MAP_FIXED to optimize away funmap? + let (_guard, dst_memory) = unsafe { + MmapGuard::map_mut_anywhere( + *grants_fd, + first_aligned_page + page_idx * PAGE_SIZE, // offset + pages_in_this_group * PAGE_SIZE, // size + )? + }; + + // TODO: Are &mut [u8] and &mut [[u8; PAGE_SIZE]] interchangeable (if the + // lengths are aligned, obviously)? + + read_all(*image_file, None, dst_memory)?; } - mprotect_remote(&grants_fd, vaddr, size, flags)?; + + if tail_bytes > 0 { + let (_guard, dst_page) = unsafe { + MmapGuard::map_mut_anywhere( + *grants_fd, + first_aligned_page + remaining_page_count * PAGE_SIZE, + PAGE_SIZE, + )? + }; + read_all(*image_file, None, &mut dst_page[..tail_bytes])?; + } + + // file_page_count..file_page_count + zero_page_count are already zero-initialized + // by the kernel. if !tree .range(..=vaddr) @@ -186,7 +248,7 @@ where .filter(|(start, size)| **start + **size > vaddr) .is_some() { - tree.insert(vaddr, size); + tree.insert(vaddr, total_page_count * PAGE_SIZE); } } _ => continue, @@ -202,11 +264,36 @@ where )?; tree.insert(STACK_TOP - STACK_SIZE, STACK_SIZE); - let mut sp = STACK_TOP - 256; + let mut sp = STACK_TOP; + let mut stack_page = Option::::None; let mut push = |word: usize| { + let old_page_no = sp / PAGE_SIZE; sp -= size_of::(); - write_all(*memory_fd, Some(sp as u64), &usize::to_ne_bytes(word)) + let new_page_no = sp / PAGE_SIZE; + let new_page_off = sp % PAGE_SIZE; + + let page = if let Some(ref mut page) = stack_page && old_page_no == new_page_no { + page + } else if let Some(ref mut stack_page) = stack_page { + stack_page.remap(new_page_no * PAGE_SIZE, PROT_WRITE)?; + stack_page + } else { + let new = MmapGuard::map(*grants_fd, &Map { + offset: new_page_no * PAGE_SIZE, + size: PAGE_SIZE, + flags: PROT_WRITE, + address: 0, // let kernel decide + })?; + + stack_page.insert(new) + }; + + unsafe { + page.as_mut_ptr_slice().as_mut_ptr().add(new_page_off).cast::().write(word); + } + + Ok(()) }; let pheaders_to_convey = if let Some(ref r#override) = interp_override { @@ -214,7 +301,7 @@ where } else { &*phs_raw }; - let pheaders_size_aligned = (pheaders_to_convey.len() + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; + let pheaders_size_aligned = pheaders_to_convey.len().next_multiple_of(PAGE_SIZE); let pheaders = find_free_target_addr(&tree, pheaders_size_aligned).ok_or(Error::new(ENOMEM))?; tree.insert(pheaders, pheaders_size_aligned); allocate_remote( @@ -224,7 +311,15 @@ where pheaders_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE, )?; - write_all(*memory_fd, Some(pheaders as u64), &pheaders_to_convey)?; + unsafe { + let (_guard, memory) = MmapGuard::map_mut_anywhere( + *grants_fd, + pheaders, + pheaders_size_aligned, + )?; + + memory[..pheaders_to_convey.len()].copy_from_slice(pheaders_to_convey); + } mprotect_remote( &grants_fd, pheaders, @@ -257,8 +352,7 @@ where let total_args_envs_auxvpointee_size = total_args_envs_size + extrainfo.cwd.map_or(0, |s| s.len() + 1); - let args_envs_size_aligned = - (total_args_envs_auxvpointee_size + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; + let args_envs_size_aligned = total_args_envs_auxvpointee_size.next_multiple_of(PAGE_SIZE); let target_args_env_address = find_free_target_addr(&tree, args_envs_size_aligned).ok_or(Error::new(ENOMEM))?; allocate_remote( @@ -276,8 +370,25 @@ where { let mut append = |source_slice: &[u8]| { + // TODO let address = target_args_env_address + offset; - write_all(*memory_fd, Some(address as u64), source_slice)?; + + if !source_slice.is_empty() { + let containing_page = address.div_floor(PAGE_SIZE) * PAGE_SIZE; + let displacement = address - containing_page; + let size = source_slice.len() + displacement; + let aligned_size = size.next_multiple_of(PAGE_SIZE); + + let (_guard, memory) = unsafe { + MmapGuard::map_mut_anywhere( + *grants_fd, + containing_page, + aligned_size, + )? + }; + memory[displacement..][..source_slice.len()].copy_from_slice(source_slice); + } + offset += source_slice.len() + 1; Ok(address) }; @@ -328,7 +439,7 @@ where if interp_override.is_some() { let mmap_min_fd = FdGuard::new(syscall::dup(*grants_fd, b"mmap-min-addr")?); let last_addr = tree.iter().rev().nth(1).map_or(0, |(off, len)| *off + *len); - let aligned_last_addr = (last_addr + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; + let aligned_last_addr = last_addr.next_multiple_of(PAGE_SIZE); let _ = syscall::write(*mmap_min_fd, &usize::to_ne_bytes(aligned_last_addr)); } @@ -456,21 +567,6 @@ fn read_all(fd: usize, offset: Option, buf: &mut [u8]) -> Result<()> { } Ok(()) } -fn write_all(fd: usize, offset: Option, buf: &[u8]) -> Result<()> { - if let Some(offset) = offset { - syscall::lseek(fd, offset as isize, SEEK_SET)?; - } - - let mut total_bytes_written = 0; - - while total_bytes_written < buf.len() { - total_bytes_written += match syscall::write(fd, &buf[total_bytes_written..])? { - 0 => return Err(Error::new(EIO)), - bytes_written => bytes_written, - } - } - Ok(()) -} // TODO: With the introduction of remote mmaps, remove this and let the kernel handle address // allocation. @@ -493,6 +589,64 @@ fn find_free_target_addr(tree: &BTreeMap, size: usize) -> Option Result { + Ok(Self { + fd, + size: map.size, + base: unsafe { syscall::fmap(fd, map)? }, + }) + } + pub fn remap(&mut self, offset: usize, mut flags: MapFlags) -> Result<()> { + flags.remove(MapFlags::MAP_FIXED_NOREPLACE); + flags.insert(MapFlags::MAP_FIXED); + + let _new_base = unsafe { syscall::fmap(self.fd, &Map { + offset, + size: self.size, + flags, + address: self.base, + })? }; + + Ok(()) + } + pub unsafe fn map_mut_anywhere<'a>(fd: usize, offset: usize, size: usize) -> Result<(Self, &'a mut [u8])> { + let mut this = Self::map(fd, &Map { + size, + offset, + address: 0, + flags: PROT_WRITE, + })?; + let slice = &mut *this.as_mut_ptr_slice(); + + Ok((this, slice)) + } + pub fn addr(&self) -> usize { + self.base + } + pub fn len(&self) -> usize { + self.size + } + pub fn as_mut_ptr_slice(&mut self) -> *mut [u8] { + core::ptr::slice_from_raw_parts_mut(self.base as *mut u8, self.size) + } + pub fn take(mut self) { + self.size = 0; + } +} +impl Drop for MmapGuard { + fn drop(&mut self) { + if self.size != 0 { + let _ = unsafe { syscall::funmap(self.base, self.size) }; + } + } +} + pub struct FdGuard { fd: usize, taken: bool, @@ -552,7 +706,7 @@ fn fork_inner(initial_rsp: *mut usize) -> Result { { let cur_pid_fd = FdGuard::new(syscall::open( "thisproc:current/open_via_dup", - syscall::O_CLOEXEC, + O_CLOEXEC, )?); (new_pid_fd, new_pid) = new_context()?; @@ -596,50 +750,64 @@ fn fork_inner(initial_rsp: *mut usize) -> Result { // CoW-duplicate address space. { + let new_addr_space_sel_fd = + FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?); + let cur_addr_space_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"addrspace")?); - - // FIXME: Find mappings which use external file descriptors - let new_addr_space_fd = FdGuard::new(syscall::dup(*cur_addr_space_fd, b"exclusive")?); - let mut buf = vec![0_u8; 4096]; - let mut bytes_read = 0; - + let mut grant_desc_buf = [GrantDesc::default(); 16]; loop { - let new_bytes_read = syscall::read(*cur_addr_space_fd, &mut buf[bytes_read..])?; - - if new_bytes_read == 0 { + let bytes_read = { + let buf = unsafe { core::slice::from_raw_parts_mut(grant_desc_buf.as_mut_ptr().cast(), grant_desc_buf.len() * size_of::()) }; + syscall::read(*cur_addr_space_fd, buf)? + }; + if bytes_read == 0 { break; } - bytes_read += new_bytes_read; - } - let bytes = &buf[..bytes_read]; + let grants = &grant_desc_buf[..bytes_read / size_of::()]; - for struct_bytes in bytes.array_chunks::<{ size_of::() * 4 }>() { - let mut words = struct_bytes - .array_chunks::<{ size_of::() }>() - .copied() - .map(usize::from_ne_bytes); + for grant in grants { + if !grant.flags.contains(GrantFlags::GRANT_SCHEME) || !grant.flags.contains(GrantFlags::GRANT_SHARED) { + continue; + } - let addr = words.next().unwrap(); - let size = words.next().unwrap(); - let flags = words.next().unwrap(); - let offset = words.next().unwrap(); + let mut buf; - if flags & 0x8000_0000 == 0 { - continue; + // TODO: write! using some #![no_std] Cursor type (tracking the length)? + #[cfg(target_pointer_width = "64")] + { + //buf = *b"grant-fd-AAAABBBBCCCCDDDD"; + //write!(&mut buf, "grant-fd-{:>016x}", grant.base).unwrap(); + buf = alloc::format!("grant-fd-{:>016x}", grant.base).into_bytes(); + } + + #[cfg(target_pointer_width = "32")] + { + //buf = *b"grant-fd-AAAABBBB"; + //write!(&mut buf[..], "grant-fd-{:>08x}", grant.base).unwrap(); + buf = alloc::format!("grant-fd-{:>08x}", grant.base).into_bytes(); + } + + let grant_fd = FdGuard::new(syscall::dup(*cur_addr_space_fd, &buf)?); + + let mut flags = MAP_SHARED | MAP_FIXED_NOREPLACE; + + flags.set(PROT_READ, grant.flags.contains(GrantFlags::GRANT_READ)); + flags.set(PROT_WRITE, grant.flags.contains(GrantFlags::GRANT_WRITE)); + flags.set(PROT_EXEC, grant.flags.contains(GrantFlags::GRANT_EXEC)); + + mmap_remote( + &new_addr_space_fd, + &grant_fd, + grant.offset as usize, + grant.base, + grant.size, + flags, + )?; } - let map_flags = MapFlags::from_bits_truncate(flags); - - let grant_fd = FdGuard::new(syscall::dup( - *cur_addr_space_fd, - alloc::format!("grant-{:x}", addr).as_bytes(), - )?); - mmap_remote(&new_addr_space_fd, &grant_fd, offset, addr, size, map_flags)?; } - let new_addr_space_sel_fd = - FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?); let buf = create_set_addr_space_buf( *new_addr_space_fd, @@ -680,7 +848,7 @@ pub fn new_context() -> Result<(FdGuard, usize)> { // Create a new context (fields such as uid/gid will be inherited from the current context). let fd = FdGuard::new(syscall::open( "thisproc:new/open_via_dup", - syscall::O_CLOEXEC, + O_CLOEXEC, )?); // Extract pid.