Merge branch 'kek/bump-redox-rt' into 'master'

Implement initfs symlinks; bump redox-rt

See merge request redox-os/bootstrap!14
This commit is contained in:
Jeremy Soller
2024-09-23 17:12:31 +00:00
6 changed files with 225 additions and 66 deletions
Generated
+21 -14
View File
@@ -21,6 +21,7 @@ dependencies = [
"hashbrown",
"linked_list_allocator",
"redox-initfs",
"redox-path",
"redox-rt",
"redox-scheme",
"redox_syscall",
@@ -29,7 +30,7 @@ dependencies = [
[[package]]
name = "generic-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git?rev=e97f26c7#e97f26c7632b1033ca062199db5633f3236821ed"
source = "git+https://gitlab.redox-os.org/redox-os/relibc#1e97bae11b1a51a1589bb6ea44cf8e507d2d1275"
[[package]]
name = "goblin"
@@ -50,9 +51,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "libc"
version = "0.2.158"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libredox"
@@ -107,25 +108,31 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.37"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox-initfs"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/redox-initfs.git#65cf406b7d4c5befc38b79696cdeb317bf06ed62"
version = "0.2.0"
source = "git+https://gitlab.redox-os.org/redox-os/redox-initfs.git#d0802237d7894881df7ddd338dfc64220d0646ff"
dependencies = [
"plain",
]
[[package]]
name = "redox-path"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
[[package]]
name = "redox-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git?rev=e97f26c7#e97f26c7632b1033ca062199db5633f3236821ed"
source = "git+https://gitlab.redox-os.org/redox-os/relibc#1e97bae11b1a51a1589bb6ea44cf8e507d2d1275"
dependencies = [
"bitflags",
"generic-rt",
@@ -136,8 +143,8 @@ dependencies = [
[[package]]
name = "redox-scheme"
version = "0.2.1"
source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#67c75441660e11280a97396714c0df3e677119bc"
version = "0.2.2"
source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#9a2e8a31894e397594ea4e3f033c4a91709bbbdc"
dependencies = [
"libredox",
"redox_syscall",
@@ -189,9 +196,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.77"
version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [
"proc-macro2",
"quote",
@@ -200,6 +207,6 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.13"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+5 -2
View File
@@ -10,12 +10,15 @@ name = "bootstrap"
crate-type = ["staticlib"]
[dependencies]
hashbrown = { version = "0.14", default-features = false, features = ["inline-more"] }
hashbrown = { version = "0.14", default-features = false, features = [
"inline-more",
] }
linked_list_allocator = "0.10"
redox-initfs = { git = "https://gitlab.redox-os.org/redox-os/redox-initfs.git", default-features = false }
redox_syscall = "0.5.4"
redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" }
redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", rev = "e97f26c7" }
redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc", default-features = false }
redox-path = "0.3.1"
[profile.release]
panic = "abort"
+35 -7
View File
@@ -1,8 +1,8 @@
use alloc::borrow::ToOwned;
use alloc::vec::Vec;
use syscall::{Error, EINTR};
use syscall::flag::{O_CLOEXEC, O_RDONLY};
use syscall::{Error, EINTR};
use redox_rt::proc::*;
@@ -28,27 +28,41 @@ pub fn main() -> ! {
iter().map(|var| var.to_owned()).collect::<Vec<_>>()
};
extern {
extern "C" {
// The linker script will define this as the location of the initfs header.
static __initfs_header: u8;
}
let initfs_length = unsafe { (*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header)).initfs_size };
let initfs_length = unsafe {
(*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header)).initfs_size
};
unsafe {
// Creating a reference to NULL is UB. Mask the UB for now using black_box.
// FIXME use a raw pointer and inline asm for reading instead for the initfs header.
spawn_initfs(core::ptr::addr_of!(__initfs_header), initfs_length.get() as usize);
spawn_initfs(
core::ptr::addr_of!(__initfs_header),
initfs_length.get() as usize,
);
}
const CWD: &[u8] = b"/scheme/initfs";
const DEFAULT_SCHEME: &[u8] = b"initfs";
let extrainfo = ExtraInfo {
cwd: Some(CWD),
default_scheme: Some(DEFAULT_SCHEME),
sigprocmask: 0,
sigignmask: 0,
};
let path = "/scheme/initfs/bin/init";
let total_args_envs_auxvpointee_size = path.len() + 1 + envs.len() + envs.iter().map(|v| v.len()).sum::<usize>() + CWD.len() + 1;
let total_args_envs_auxvpointee_size = path.len()
+ 1
+ envs.len()
+ envs.iter().map(|v| v.len()).sum::<usize>()
+ CWD.len()
+ 1
+ DEFAULT_SCHEME.len()
+ 1;
let image_file = FdGuard::new(syscall::open(path, O_RDONLY).expect("failed to open init"));
let open_via_dup = FdGuard::new(
@@ -57,7 +71,18 @@ pub fn main() -> ! {
);
let memory = FdGuard::new(syscall::open("/scheme/memory", 0).expect("failed to open memory"));
fexec_impl(image_file, open_via_dup, &memory, path.as_bytes(), [path], envs.iter(), total_args_envs_auxvpointee_size, &extrainfo, None).expect("failed to execute init");
fexec_impl(
image_file,
open_via_dup,
&memory,
path.as_bytes(),
[path],
envs.iter(),
total_args_envs_auxvpointee_size,
&extrainfo,
None,
)
.expect("failed to execute init");
unreachable!()
}
@@ -89,5 +114,8 @@ unsafe fn spawn_initfs(initfs_start: *const u8, initfs_length: usize) {
return;
}
}
crate::initfs::run(core::slice::from_raw_parts(initfs_start, initfs_length), write);
crate::initfs::run(
core::slice::from_raw_parts(initfs_start, initfs_length),
write,
);
}
+87 -24
View File
@@ -6,8 +6,9 @@ use core::str;
use alloc::string::String;
use hashbrown::HashMap;
use redox_initfs::{InitFs, InodeStruct, Inode, InodeDir, InodeKind, types::Timespec};
use redox_initfs::{types::Timespec, InitFs, Inode, InodeDir, InodeKind, InodeStruct};
use redox_path::canonicalize_to_standard;
use redox_scheme::CallerCtx;
use redox_scheme::OpenResult;
use redox_scheme::RequestKind;
@@ -55,7 +56,6 @@ impl InitFsScheme {
}
}
struct Iter {
dir: InodeDir<'static>,
idx: u32,
@@ -71,7 +71,8 @@ impl Iterator for Iter {
fn size_hint(&self) -> (usize, Option<usize>) {
match self.dir.entry_count().ok() {
Some(size) => {
let size = usize::try_from(size).expect("expected u32 to be convertible into usize");
let size =
usize::try_from(size).expect("expected u32 to be convertible into usize");
(size, Some(size))
}
None => (0, None),
@@ -82,14 +83,18 @@ impl Iterator for Iter {
fn inode_len(inode: InodeStruct<'static>) -> Result<usize> {
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::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::Link(link) => link.data().map_err(|_| Error::new(EIO))?.len(),
InodeKind::Unknown => return Err(Error::new(EIO)),
})
}
impl SchemeMut for InitFsScheme {
fn xopen(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
let mut components = path
// trim leading and trailing slash
.trim_matches('/')
@@ -105,7 +110,7 @@ impl SchemeMut for InitFsScheme {
"." => continue,
".." => {
let _ = components.next_back();
continue
continue;
}
_ => (),
@@ -116,16 +121,18 @@ impl SchemeMut for InitFsScheme {
let dir = match current_inode_struct.kind() {
InodeKind::Dir(dir) => dir,
// TODO: Support symlinks in other position than xopen target
InodeKind::Link(link) => {
return Err(Error::new(EOPNOTSUPP));
}
// 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,
};
let mut entries = Iter { dir, idx: 0 };
current_inode = loop {
let entry_res = match entries.next() {
@@ -140,17 +147,40 @@ impl SchemeMut for InitFsScheme {
};
}
// xopen target is link -- return EXDEV so that the file is opened as a link.
// TODO: Maybe follow initfs-local symlinks here? Would be faster
let is_link = matches!(
Self::get_inode(&self.fs, current_inode)?.kind(),
InodeKind::Link(_)
);
let o_symlink = flags & O_SYMLINK != 0;
if is_link && !o_symlink {
return Err(Error::new(EXDEV));
}
let id = self.next_id();
let old = self.handles.insert(id, Handle {
inode: current_inode,
filename: path.into(),
});
let old = self.handles.insert(
id,
Handle {
inode: current_inode,
filename: path.into(),
},
);
assert!(old.is_none());
Ok(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::POSITIONED,
})
}
fn read(&mut self, id: usize, buffer: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result<usize> {
fn read(
&mut self,
id: usize,
buffer: &mut [u8],
offset: u64,
_fcntl_flags: u32,
) -> Result<usize> {
let Ok(offset) = usize::try_from(offset) else {
return Ok(0);
};
@@ -168,10 +198,29 @@ impl SchemeMut for InitFsScheme {
Ok(to_copy)
}
InodeKind::Dir(_) => Err(Error::new(EISDIR)),
InodeKind::Link(link) => {
let link_data = link.data().map_err(|_| Error::new(EIO))?;
let path = core::str::from_utf8(link_data).map_err(|_| Error::new(ENOENT))?;
let cannonical =
canonicalize_to_standard(Some("/"), path).ok_or_else(|| Error::new(ENOENT))?;
let data = cannonical.as_bytes();
let src_buf = &data[core::cmp::min(offset, data.len())..];
let to_copy = core::cmp::min(src_buf.len(), buffer.len());
buffer[..to_copy].copy_from_slice(&src_buf[..to_copy]);
Ok(to_copy)
}
InodeKind::Unknown => Err(Error::new(EIO)),
}
}
fn getdents<'buf>(&mut self, id: usize, mut buf: DirentBuf<&'buf mut [u8]>, opaque_offset: u64) -> Result<DirentBuf<&'buf mut [u8]>> {
fn getdents<'buf>(
&mut self,
id: usize,
mut buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
let Ok(offset) = u32::try_from(opaque_offset) else {
return Ok(buf);
};
@@ -187,7 +236,11 @@ impl SchemeMut for InitFsScheme {
//inode: entry.inode(),
inode: 0,
name: entry.name().ok().and_then(|utf8| core::str::from_utf8(utf8).ok()).ok_or(Error::new(EIO))?,
name: entry
.name()
.ok()
.and_then(|utf8| core::str::from_utf8(utf8).ok())
.ok_or(Error::new(EIO))?,
next_opaque_id: index as u64 + 1,
kind: DirentKind::Unspecified,
})?;
@@ -229,7 +282,12 @@ impl SchemeMut for InitFsScheme {
let inode = Self::get_inode(&self.fs, handle.inode)?;
stat.st_mode = inode.mode() | match inode.kind() { InodeKind::Dir(_) => MODE_DIR, InodeKind::File(_) => MODE_FILE, _ => 0 };
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);
@@ -259,14 +317,16 @@ impl SchemeMut for InitFsScheme {
pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! {
let mut scheme = InitFsScheme::new(bytes);
let socket = Socket::<V2>::create("initfs")
.expect("failed to open initfs scheme socket");
let socket = Socket::<V2>::create("initfs").expect("failed to open initfs scheme socket");
let _ = syscall::write(sync_pipe, &[0]);
let _ = syscall::close(sync_pipe);
loop {
let RequestKind::Call(req) = (match socket.next_request(SignalBehavior::Restart).expect("bootstrap: failed to read scheme request from kernel") {
let RequestKind::Call(req) = (match socket
.next_request(SignalBehavior::Restart)
.expect("bootstrap: failed to read scheme request from kernel")
{
Some(req) => req.kind(),
None => break,
}) else {
@@ -274,7 +334,10 @@ pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! {
};
let resp = req.handle_scheme_mut(&mut scheme);
if !socket.write_response(resp, SignalBehavior::Restart).expect("bootstrap: failed to write scheme response to kernel") {
if !socket
.write_response(resp, SignalBehavior::Restart)
.expect("bootstrap: failed to write scheme response to kernel")
{
break;
}
}
+33 -11
View File
@@ -1,10 +1,6 @@
#![no_std]
#![allow(internal_features)]
#![feature(
asm_const,
core_intrinsics,
str_from_raw_parts,
)]
#![feature(asm_const, core_intrinsics, str_from_raw_parts, iter_intersperse)]
#[cfg(target_arch = "aarch64")]
#[path = "aarch64.rs"]
@@ -35,7 +31,9 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
impl Write for Writer {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
syscall::write(1, s.as_bytes()).map_err(|_| core::fmt::Error).map(|_| ())
syscall::write(1, s.as_bytes())
.map_err(|_| core::fmt::Error)
.map(|_| ())
}
}
@@ -62,8 +60,19 @@ unsafe impl alloc::alloc::GlobalAlloc for Allocator {
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
let heap = HEAP.get_or_insert_with(|| {
HEAP_TOP = HEAP_OFF + SIZE;
let _ = syscall::fmap(!0, &Map { offset: 0, size: SIZE, address: HEAP_OFF, flags: MapFlags::PROT_WRITE | MapFlags::PROT_READ | MapFlags::MAP_PRIVATE | MapFlags::MAP_FIXED_NOREPLACE })
.expect("failed to map initial heap");
let _ = syscall::fmap(
!0,
&Map {
offset: 0,
size: SIZE,
address: HEAP_OFF,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
.expect("failed to map initial heap");
linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE)
});
@@ -74,8 +83,19 @@ unsafe impl alloc::alloc::GlobalAlloc for Allocator {
return core::ptr::null_mut();
}
let _ = syscall::fmap(!0, &Map { offset: 0, size: HEAP_INCREASE_BY, address: HEAP_TOP, flags: MapFlags::PROT_WRITE | MapFlags::PROT_READ | MapFlags::MAP_PRIVATE | MapFlags::MAP_FIXED_NOREPLACE })
.expect("failed to extend heap");
let _ = syscall::fmap(
!0,
&Map {
offset: 0,
size: HEAP_INCREASE_BY,
address: HEAP_TOP,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
.expect("failed to extend heap");
heap.extend(HEAP_INCREASE_BY);
HEAP_TOP += HEAP_INCREASE_BY;
@@ -84,6 +104,8 @@ unsafe impl alloc::alloc::GlobalAlloc for Allocator {
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
HEAP.as_mut().unwrap().deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
HEAP.as_mut()
.unwrap()
.deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
}
}
+44 -8
View File
@@ -13,13 +13,28 @@ mod offsets {
static __bss_end: u8;
}
pub fn text() -> (usize, usize) {
unsafe { (&__text_start as *const u8 as usize, &__text_end as *const u8 as usize) }
unsafe {
(
&__text_start as *const u8 as usize,
&__text_end as *const u8 as usize,
)
}
}
pub fn rodata() -> (usize, usize) {
unsafe { (&__rodata_start as *const u8 as usize, &__rodata_end as *const u8 as usize) }
unsafe {
(
&__rodata_start as *const u8 as usize,
&__rodata_end as *const u8 as usize,
)
}
}
pub fn data_and_bss() -> (usize, usize) {
unsafe { (&__data_start as *const u8 as usize, &__bss_end as *const u8 as usize) }
unsafe {
(
&__data_start as *const u8 as usize,
&__bss_end as *const u8 as usize,
)
}
}
}
@@ -35,12 +50,33 @@ pub unsafe extern "C" fn start() -> ! {
let _ = syscall::open("/scheme/debug", syscall::O_WRONLY); // stdout
let _ = syscall::open("/scheme/debug", syscall::O_WRONLY); // stderr
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE).expect("mprotect failed for initfs header page");
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE)
.expect("mprotect failed for initfs header page");
let _ = syscall::mprotect(text_start, text_end - text_start, MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE).expect("mprotect failed for .text");
let _ = syscall::mprotect(rodata_start, rodata_end - rodata_start, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE).expect("mprotect failed for .rodata");
let _ = syscall::mprotect(data_start, data_end - data_start, MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE).expect("mprotect failed for .data/.bss");
let _ = syscall::mprotect(data_end, crate::arch::STACK_START - data_end, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE).expect("mprotect failed for rest of memory");
let _ = syscall::mprotect(
text_start,
text_end - text_start,
MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .text");
let _ = syscall::mprotect(
rodata_start,
rodata_end - rodata_start,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .rodata");
let _ = syscall::mprotect(
data_start,
data_end - data_start,
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .data/.bss");
let _ = syscall::mprotect(
data_end,
crate::arch::STACK_START - data_end,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for rest of memory");
redox_rt::initialize_freestanding();