Merge branch 'better_proc_apis' into 'master'

Use improved `proc:` APIs from demand paging

See merge request redox-os/relibc!415
This commit is contained in:
Jeremy Soller
2023-08-07 15:34:47 +00:00
4 changed files with 317 additions and 150 deletions
Generated
+60 -61
View File
@@ -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",
+1
View File
@@ -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" }
+2 -3
View File
@@ -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};
+254 -86
View File
@@ -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::<MmapGuard>::None;
let mut push = |word: usize| {
let old_page_no = sp / PAGE_SIZE;
sp -= size_of::<usize>();
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::<usize>().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<u64>, buf: &mut [u8]) -> Result<()> {
}
Ok(())
}
fn write_all(fd: usize, offset: Option<u64>, 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<usize, usize>, size: usize) -> Option<u
None
}
pub struct MmapGuard {
fd: usize,
base: usize,
size: usize,
}
impl MmapGuard {
pub fn map(fd: usize, map: &Map) -> Result<Self> {
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<usize> {
{
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<usize> {
// 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::<GrantDesc>()) };
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::<GrantDesc>()];
for struct_bytes in bytes.array_chunks::<{ size_of::<usize>() * 4 }>() {
let mut words = struct_bytes
.array_chunks::<{ size_of::<usize>() }>()
.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.