Add 'bootstrap/' from commit '6898d8b14c078805b7b0b6c4b5d9359ca911bbc6'
git-subtree-dir: bootstrap git-subtree-mainline:16e0cb79b9git-subtree-split:6898d8b14c
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/target
|
||||
Generated
+240
@@ -0,0 +1,240 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"hashbrown",
|
||||
"linked_list_allocator",
|
||||
"log",
|
||||
"plain",
|
||||
"redox-initfs",
|
||||
"redox-path",
|
||||
"redox-rt",
|
||||
"redox-scheme",
|
||||
"redox_syscall",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "generic-rt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#696ae4eca1df5e3b76a57f62903ee1a94b9c6aa6"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked_list_allocator"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
|
||||
dependencies = [
|
||||
"spinning_top",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-initfs"
|
||||
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#696ae4eca1df5e3b76a57f62903ee1a94b9c6aa6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"generic-rt",
|
||||
"goblin",
|
||||
"plain",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-scheme"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a14f94bc95b388d8f40a61f25577863f1cf151aaf600a5b7778d1a2018ff7742"
|
||||
dependencies = [
|
||||
"libredox",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.11"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?branch=master#8f646a63ac9c3aa532a37ddfdc136ec19878f0d6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
@@ -0,0 +1,36 @@
|
||||
[package]
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
authors = ["4lDO2 <4lDO2@protonmail.com>"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "bootstrap"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
hashbrown = { version = "0.15", default-features = false, features = [
|
||||
"inline-more",
|
||||
"default-hasher",
|
||||
] }
|
||||
linked_list_allocator = "0.10"
|
||||
log = { version = "0.4", default-features = false }
|
||||
plain = "0.2"
|
||||
redox-initfs = { git = "https://gitlab.redox-os.org/redox-os/redox-initfs.git", default-features = false }
|
||||
redox_syscall = { version = "0.5.4", default-features = false }
|
||||
redox-scheme = { version = "0.6", default-features = false }
|
||||
redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", default-features = false }
|
||||
redox-path = "0.3.1"
|
||||
slab = { version = "0.4.9", default-features = false }
|
||||
arrayvec = { version = "0.7.6", default-features = false }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
lto = "fat"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[patch.crates-io]
|
||||
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", branch = "master" }
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 4lDO2
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,26 @@
|
||||
# bootstrap
|
||||
|
||||
First code that the kernel executes, responsible for spawning init.
|
||||
|
||||
## How To Contribute
|
||||
|
||||
To learn how to contribute to this system component you need to read the following document:
|
||||
|
||||
- [CONTRIBUTING.md](https://gitlab.redox-os.org/redox-os/redox/-/blob/master/CONTRIBUTING.md)
|
||||
|
||||
## Development
|
||||
|
||||
To learn how to do development with this system component inside the Redox build system you need to read the [Build System](https://doc.redox-os.org/book/build-system-reference.html) and [Coding and Building](https://doc.redox-os.org/book/coding-and-building.html) pages.
|
||||
|
||||
### How To Build
|
||||
|
||||
To build this system component you need to download the Redox build system, you can learn how to do it on the [Building Redox](https://doc.redox-os.org/book/podman-build.html) page.
|
||||
|
||||
This is necessary because they only work with cross-compilation to a Redox virtual machine, but you can do some testing from Linux.
|
||||
|
||||
## Funding - Process Manager (`src/procmgr.rs`)
|
||||
|
||||
The _Unix-style Signals and Process Management_ project is funded through [NGI Zero Core](https://nlnet.nl/core), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/RedoxOS-Signals).
|
||||
|
||||
[<img src="https://nlnet.nl/logo/banner.png" alt="NLnet foundation logo" width="20%" />](https://nlnet.nl)
|
||||
[<img src="https://nlnet.nl/image/logos/NGI0_tag.svg" alt="NGI Zero Logo" width="20%" />](https://nlnet.nl/core)
|
||||
@@ -0,0 +1,46 @@
|
||||
ENTRY(_start)
|
||||
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
|
||||
|
||||
SECTIONS {
|
||||
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
|
||||
__initfs_header = . - 4096;
|
||||
. += SIZEOF_HEADERS;
|
||||
. = ALIGN(4096);
|
||||
|
||||
.text : {
|
||||
__text_start = .;
|
||||
*(.text*)
|
||||
. = ALIGN(4096);
|
||||
__text_end = .;
|
||||
}
|
||||
.rodata : {
|
||||
__rodata_start = .;
|
||||
*(.rodata*)
|
||||
. = ALIGN(4096);
|
||||
__rodata_end = .;
|
||||
}
|
||||
.data : {
|
||||
__data_start = .;
|
||||
*(.data*)
|
||||
. = ALIGN(4096);
|
||||
__data_end = .;
|
||||
|
||||
*(.tbss*)
|
||||
. = ALIGN(4096);
|
||||
*(.tdata*)
|
||||
. = ALIGN(4096);
|
||||
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
. = ALIGN(4096);
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment*)
|
||||
*(.eh_frame*)
|
||||
*(.gcc_except_table*)
|
||||
*(.note*)
|
||||
*(.rel.eh_frame*)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use core::mem;
|
||||
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
static MAP: Map = Map {
|
||||
offset: 0,
|
||||
size: STACK_SIZE,
|
||||
flags: MapFlags::PROT_READ
|
||||
.union(MapFlags::PROT_WRITE)
|
||||
.union(MapFlags::MAP_PRIVATE)
|
||||
.union(MapFlags::MAP_FIXED_NOREPLACE),
|
||||
address: STACK_START, // highest possible user address
|
||||
};
|
||||
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.globl _start
|
||||
_start:
|
||||
// Setup a stack.
|
||||
ldr x8, ={number}
|
||||
ldr x0, ={fd}
|
||||
ldr x1, ={map} // pointer to Map struct
|
||||
ldr x2, ={map_size} // size of Map struct
|
||||
svc 0
|
||||
|
||||
// Failure if return value is zero
|
||||
cbz x0, 1f
|
||||
|
||||
// Failure if return value is negative
|
||||
tbnz x0, 63, 1f
|
||||
|
||||
// Set up stack frame
|
||||
mov sp, x0
|
||||
add sp, sp, #{stack_size}
|
||||
mov fp, sp
|
||||
|
||||
// Stack has the same alignment as `size`.
|
||||
bl start
|
||||
// `start` must never return.
|
||||
|
||||
// failure, emit undefined instruction
|
||||
1:
|
||||
udf #0
|
||||
",
|
||||
fd = const usize::MAX, // dummy fd indicates anonymous map
|
||||
map = sym MAP,
|
||||
map_size = const mem::size_of::<Map>(),
|
||||
number = const SYS_FMAP,
|
||||
stack_size = const STACK_SIZE,
|
||||
);
|
||||
@@ -0,0 +1,163 @@
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use syscall::flag::{O_CLOEXEC, O_RDONLY};
|
||||
use syscall::{Error, EINTR};
|
||||
|
||||
use redox_rt::proc::*;
|
||||
|
||||
struct Logger;
|
||||
|
||||
impl log::Log for Logger {
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
metadata.level() <= log::max_level()
|
||||
}
|
||||
fn log(&self, record: &log::Record) {
|
||||
let file = record.file().unwrap_or("");
|
||||
let line = record.line().unwrap_or(0);
|
||||
let level = record.level();
|
||||
let msg = record.args();
|
||||
let _ = syscall::write(
|
||||
1,
|
||||
alloc::format!("[{file}:{line} {level}] {msg}\n").as_bytes(),
|
||||
);
|
||||
}
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
pub fn main() -> ! {
|
||||
let auth = FdGuard::new(
|
||||
syscall::open("/scheme/kernel.proc/authority", O_CLOEXEC)
|
||||
.expect("failed to get proc authority"),
|
||||
);
|
||||
let this_thr_fd =
|
||||
FdGuard::new(syscall::dup(*auth, b"cur-context").expect("failed to open open_via_dup"));
|
||||
let this_thr_fd = unsafe { redox_rt::initialize_freestanding(this_thr_fd) };
|
||||
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
let _ = log::set_logger(&Logger);
|
||||
|
||||
let envs = {
|
||||
let mut env = [0_u8; 4096];
|
||||
|
||||
let fd = FdGuard::new(
|
||||
syscall::open("/scheme/sys/env", O_RDONLY).expect("bootstrap: failed to open env"),
|
||||
);
|
||||
let bytes_read = syscall::read(*fd, &mut env).expect("bootstrap: failed to read env");
|
||||
|
||||
if bytes_read >= env.len() {
|
||||
// TODO: Handle this, we can allocate as much as we want in theory.
|
||||
panic!("env is too large");
|
||||
}
|
||||
let env = &mut env[..bytes_read];
|
||||
|
||||
let raw_iter = || env.split(|c| *c == b'\n').filter(|var| !var.is_empty());
|
||||
|
||||
let iter = || raw_iter().filter(|var| !var.starts_with(b"INITFS_"));
|
||||
|
||||
iter().map(|var| var.to_owned()).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
spawn(
|
||||
"initfs daemon",
|
||||
&auth,
|
||||
&this_thr_fd,
|
||||
move |write_fd| 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.
|
||||
let initfs_start = core::ptr::addr_of!(__initfs_header);
|
||||
let initfs_length = initfs_length.get() as usize;
|
||||
|
||||
crate::initfs::run(
|
||||
core::slice::from_raw_parts(initfs_start, initfs_length),
|
||||
write_fd,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
spawn("process manager", &auth, &this_thr_fd, |write_fd| {
|
||||
crate::procmgr::run(write_fd, &auth)
|
||||
});
|
||||
let [init_proc_fd, init_thr_fd] = unsafe { redox_rt::proc::make_init() };
|
||||
// from this point, this_thr_fd is no longer valid
|
||||
|
||||
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,
|
||||
umask: redox_rt::sys::get_umask(),
|
||||
thr_fd: **init_thr_fd,
|
||||
proc_fd: **init_proc_fd,
|
||||
};
|
||||
|
||||
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
|
||||
+ DEFAULT_SCHEME.len()
|
||||
+ 1;
|
||||
|
||||
let image_file = FdGuard::new(syscall::open(path, O_RDONLY).expect("failed to open init"));
|
||||
let memory = FdGuard::new(syscall::open("/scheme/memory", 0).expect("failed to open memory"));
|
||||
|
||||
fexec_impl(
|
||||
image_file,
|
||||
init_thr_fd,
|
||||
init_proc_fd,
|
||||
&memory,
|
||||
path.as_bytes(),
|
||||
[path],
|
||||
envs.iter(),
|
||||
total_args_envs_auxvpointee_size,
|
||||
&extrainfo,
|
||||
None,
|
||||
)
|
||||
.expect("failed to execute init");
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn spawn(name: &str, auth: &FdGuard, this_thr_fd: &FdGuard, inner: impl FnOnce(usize)) {
|
||||
let read = syscall::open("/scheme/pipe", O_CLOEXEC).expect("failed to open sync read pipe");
|
||||
|
||||
// The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later.
|
||||
let write = syscall::dup(read, b"write").expect("failed to open sync write pipe");
|
||||
|
||||
match fork_impl(&ForkArgs::Init { this_thr_fd, auth }) {
|
||||
Err(err) => {
|
||||
panic!("Failed to fork in order to start {name}: {err}");
|
||||
}
|
||||
// Continue serving the scheme as the child.
|
||||
Ok(0) => {
|
||||
let _ = syscall::close(read);
|
||||
}
|
||||
// Return in order to execute init, as the parent.
|
||||
Ok(_) => {
|
||||
let _ = syscall::close(write);
|
||||
loop {
|
||||
match syscall::read(read, &mut [0]) {
|
||||
Err(Error { errno: EINTR }) => continue,
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
inner(write);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
ENTRY(_start)
|
||||
OUTPUT_FORMAT(elf32-i386)
|
||||
|
||||
SECTIONS {
|
||||
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
|
||||
__initfs_header = . - 4096;
|
||||
. += SIZEOF_HEADERS;
|
||||
. = ALIGN(4096);
|
||||
|
||||
.text : {
|
||||
__text_start = .;
|
||||
*(.text*)
|
||||
. = ALIGN(4096);
|
||||
__text_end = .;
|
||||
}
|
||||
.rodata : {
|
||||
__rodata_start = .;
|
||||
*(.rodata*)
|
||||
. = ALIGN(4096);
|
||||
__rodata_end = .;
|
||||
}
|
||||
.data : {
|
||||
__data_start = .;
|
||||
*(.data*)
|
||||
. = ALIGN(4096);
|
||||
__data_end = .;
|
||||
|
||||
*(.tbss*)
|
||||
. = ALIGN(4096);
|
||||
*(.tdata*)
|
||||
. = ALIGN(4096);
|
||||
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
. = ALIGN(4096);
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment*)
|
||||
*(.eh_frame*)
|
||||
*(.gcc_except_table*)
|
||||
*(.note*)
|
||||
*(.rel.eh_frame*)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
use core::mem;
|
||||
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
pub const USERMODE_END: usize = 0x8000_0000;
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
|
||||
static MAP: Map = Map {
|
||||
offset: 0,
|
||||
size: STACK_SIZE,
|
||||
flags: MapFlags::PROT_READ
|
||||
.union(MapFlags::PROT_WRITE)
|
||||
.union(MapFlags::MAP_PRIVATE)
|
||||
.union(MapFlags::MAP_FIXED_NOREPLACE),
|
||||
address: STACK_START, // highest possible user address
|
||||
};
|
||||
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.globl _start
|
||||
_start:
|
||||
# Setup a stack.
|
||||
mov eax, {number}
|
||||
mov ebx, {fd}
|
||||
mov ecx, offset {map} # pointer to Map struct
|
||||
mov edx, {map_size} # size of Map struct
|
||||
int 0x80
|
||||
|
||||
# Test for success (nonzero value).
|
||||
cmp eax, 0
|
||||
jg 1f
|
||||
# (failure)
|
||||
ud2
|
||||
1:
|
||||
# Subtract 16 since all instructions seem to hate non-canonical ESP values :)
|
||||
lea esp, [eax+{stack_size}-16]
|
||||
mov ebp, esp
|
||||
|
||||
# Stack has the same alignment as `size`.
|
||||
call start
|
||||
# `start` must never return.
|
||||
ud2
|
||||
",
|
||||
fd = const usize::MAX, // dummy fd indicates anonymous map
|
||||
map = sym MAP,
|
||||
map_size = const mem::size_of::<Map>(),
|
||||
number = const SYS_FMAP,
|
||||
stack_size = const STACK_SIZE,
|
||||
);
|
||||
@@ -0,0 +1,365 @@
|
||||
use core::convert::TryFrom;
|
||||
#[allow(deprecated)]
|
||||
use core::hash::{BuildHasherDefault, SipHasher};
|
||||
use core::str;
|
||||
|
||||
use alloc::string::String;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use redox_initfs::{types::Timespec, InitFs, Inode, InodeDir, InodeKind, InodeStruct};
|
||||
|
||||
use redox_path::canonicalize_to_standard;
|
||||
use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult, RequestKind};
|
||||
|
||||
use redox_scheme::{SignalBehavior, Socket};
|
||||
use syscall::data::Stat;
|
||||
use syscall::dirent::DirEntry;
|
||||
use syscall::dirent::DirentBuf;
|
||||
use syscall::dirent::DirentKind;
|
||||
use syscall::error::*;
|
||||
use syscall::flag::*;
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
|
||||
struct Handle {
|
||||
inode: Inode,
|
||||
// TODO: Any better way to implement fpath? Or maybe work around it, e.g. by giving paths such
|
||||
// as `initfs:__inodes__/<inode>`?
|
||||
filename: String,
|
||||
}
|
||||
pub struct InitFsScheme {
|
||||
#[allow(deprecated)]
|
||||
handles: HashMap<usize, Handle, BuildHasherDefault<SipHasher>>,
|
||||
next_id: usize,
|
||||
fs: InitFs<'static>,
|
||||
}
|
||||
impl InitFsScheme {
|
||||
pub fn new(bytes: &'static [u8]) -> Self {
|
||||
Self {
|
||||
handles: HashMap::default(),
|
||||
next_id: 0,
|
||||
fs: InitFs::new(bytes).expect("failed to parse initfs"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_inode(fs: &InitFs<'static>, inode: Inode) -> Result<InodeStruct<'static>> {
|
||||
fs.get_inode(inode).ok_or_else(|| Error::new(EIO))
|
||||
}
|
||||
fn next_id(&mut self) -> usize {
|
||||
assert_ne!(self.next_id, usize::MAX, "usize overflow in initfs scheme");
|
||||
self.next_id += 1;
|
||||
self.next_id
|
||||
}
|
||||
}
|
||||
|
||||
struct Iter {
|
||||
dir: InodeDir<'static>,
|
||||
idx: u32,
|
||||
}
|
||||
impl Iterator for Iter {
|
||||
type Item = Result<redox_initfs::Entry<'static>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let entry = self.dir.get_entry(self.idx).map_err(|_| Error::new(EIO));
|
||||
self.idx += 1;
|
||||
entry.transpose()
|
||||
}
|
||||
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");
|
||||
(size, Some(size))
|
||||
}
|
||||
None => (0, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::Link(link) => link.data().map_err(|_| Error::new(EIO))?.len(),
|
||||
InodeKind::Unknown => return Err(Error::new(EIO)),
|
||||
})
|
||||
}
|
||||
|
||||
impl SchemeSync for InitFsScheme {
|
||||
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
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 = Self::get_inode(&self.fs, current_inode)?;
|
||||
|
||||
let dir = match current_inode_struct.kind() {
|
||||
InodeKind::Dir(dir) => dir,
|
||||
|
||||
// TODO: Support symlinks in other position than xopen target
|
||||
InodeKind::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 };
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 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(),
|
||||
},
|
||||
);
|
||||
assert!(old.is_none());
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
flags: NewFdFlags::POSITIONED,
|
||||
})
|
||||
}
|
||||
|
||||
fn read(
|
||||
&mut self,
|
||||
id: usize,
|
||||
buffer: &mut [u8],
|
||||
offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let Ok(offset) = usize::try_from(offset) else {
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
match Self::get_inode(&self.fs, handle.inode)?.kind() {
|
||||
InodeKind::File(file) => {
|
||||
let data = file.data().map_err(|_| Error::new(EIO))?;
|
||||
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::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]>> {
|
||||
let Ok(offset) = u32::try_from(opaque_offset) else {
|
||||
return Ok(buf);
|
||||
};
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let InodeKind::Dir(dir) = Self::get_inode(&self.fs, handle.inode)?.kind() else {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
};
|
||||
let iter = Iter { dir, idx: offset };
|
||||
for (index, entry) in iter.enumerate() {
|
||||
let entry = entry?;
|
||||
buf.entry(DirEntry {
|
||||
// TODO: Add getter
|
||||
//inode: entry.inode(),
|
||||
inode: 0,
|
||||
|
||||
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,
|
||||
})?;
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn fsize(&mut self, id: usize, _ctx: &CallerCtx) -> Result<u64> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
Ok(inode_len(Self::get_inode(&self.fs, handle.inode)?)? as u64)
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
// TODO: Copy scheme part in kernel
|
||||
let scheme_path = b"/scheme/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(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
let Timespec { sec, nsec } = self.fs.image_creation_time();
|
||||
|
||||
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_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(())
|
||||
}
|
||||
|
||||
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
if !self.handles.contains_key(&id) {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! {
|
||||
let mut scheme = InitFsScheme::new(bytes);
|
||||
|
||||
let socket = Socket::create("initfs").expect("failed to open initfs scheme socket");
|
||||
|
||||
let _ = syscall::write(sync_pipe, &[0]);
|
||||
let _ = syscall::close(sync_pipe);
|
||||
|
||||
loop {
|
||||
let Some(req) = socket
|
||||
.next_request(SignalBehavior::Restart)
|
||||
.expect("bootstrap: failed to read scheme request from kernel")
|
||||
else {
|
||||
break;
|
||||
};
|
||||
match req.kind() {
|
||||
RequestKind::Call(req) => {
|
||||
let resp = req.handle_sync(&mut scheme);
|
||||
|
||||
if !socket
|
||||
.write_response(resp, SignalBehavior::Restart)
|
||||
.expect("bootstrap: failed to write scheme response to kernel")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
RequestKind::OnClose { id } => {
|
||||
scheme.handles.remove(&id);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
// TODO: Restructure bootstrap so it calls into relibc, or a split-off derivative without the C
|
||||
// parts, such as "redox-rt".
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_read_v1(fd: usize, ptr: *mut u8, len: usize) -> isize {
|
||||
Error::mux(syscall::read(fd, core::slice::from_raw_parts_mut(ptr, len))) as isize
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_write_v1(fd: usize, ptr: *const u8, len: usize) -> isize {
|
||||
Error::mux(syscall::write(fd, core::slice::from_raw_parts(ptr, len))) as isize
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_open_v1(ptr: *const u8, len: usize, flags: usize) -> isize {
|
||||
Error::mux(syscall::open(core::str::from_raw_parts(ptr, len), flags)) as isize
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn redox_close_v1(fd: usize) -> isize {
|
||||
Error::mux(syscall::close(fd)) as isize
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#![no_std]
|
||||
#![allow(internal_features)]
|
||||
#![feature(core_intrinsics, let_chains, iter_intersperse, str_from_raw_parts)]
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[path = "aarch64.rs"]
|
||||
pub mod arch;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[path = "i686.rs"]
|
||||
pub mod arch;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[path = "x86_64.rs"]
|
||||
pub mod arch;
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
#[path = "riscv64.rs"]
|
||||
pub mod arch;
|
||||
|
||||
pub mod exec;
|
||||
pub mod initfs;
|
||||
pub mod procmgr;
|
||||
pub mod start;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
use syscall::data::Map;
|
||||
use syscall::flag::MapFlags;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
use core::fmt::Write;
|
||||
|
||||
struct Writer;
|
||||
|
||||
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(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
let _ = writeln!(&mut Writer, "{}", info);
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
const HEAP_OFF: usize = arch::USERMODE_END / 2;
|
||||
|
||||
struct Allocator;
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Allocator = Allocator;
|
||||
|
||||
struct AllocStateInner {
|
||||
heap: Option<linked_list_allocator::Heap>,
|
||||
heap_top: usize,
|
||||
}
|
||||
struct AllocState(UnsafeCell<AllocStateInner>);
|
||||
unsafe impl Send for AllocState {}
|
||||
unsafe impl Sync for AllocState {}
|
||||
static ALLOC_STATE: AllocState = AllocState(UnsafeCell::new(AllocStateInner {
|
||||
heap: None,
|
||||
heap_top: HEAP_OFF + SIZE,
|
||||
}));
|
||||
|
||||
const SIZE: usize = 1024 * 1024;
|
||||
const HEAP_INCREASE_BY: usize = SIZE;
|
||||
|
||||
unsafe impl alloc::alloc::GlobalAlloc for Allocator {
|
||||
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
|
||||
let state = &mut (*ALLOC_STATE.0.get());
|
||||
let heap = state.heap.get_or_insert_with(|| {
|
||||
state.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");
|
||||
linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE)
|
||||
});
|
||||
|
||||
match heap.allocate_first_fit(layout) {
|
||||
Ok(p) => p.as_ptr(),
|
||||
Err(_) => {
|
||||
if layout.size() > HEAP_INCREASE_BY || layout.align() > 4096 {
|
||||
return core::ptr::null_mut();
|
||||
}
|
||||
|
||||
let _ = syscall::fmap(
|
||||
!0,
|
||||
&Map {
|
||||
offset: 0,
|
||||
size: HEAP_INCREASE_BY,
|
||||
address: state.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);
|
||||
state.heap_top += HEAP_INCREASE_BY;
|
||||
|
||||
return self.alloc(layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
|
||||
(&mut *ALLOC_STATE.0.get())
|
||||
.heap
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
ENTRY(_start)
|
||||
OUTPUT_FORMAT(elf64-littleriscv)
|
||||
|
||||
SECTIONS {
|
||||
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
|
||||
__initfs_header = . - 4096;
|
||||
. += SIZEOF_HEADERS;
|
||||
. = ALIGN(4096);
|
||||
|
||||
.text : {
|
||||
__text_start = .;
|
||||
*(.text*)
|
||||
. = ALIGN(4096);
|
||||
__text_end = .;
|
||||
}
|
||||
.rodata : {
|
||||
__rodata_start = .;
|
||||
*(.rodata*)
|
||||
. = ALIGN(4096);
|
||||
__rodata_end = .;
|
||||
}
|
||||
.data : {
|
||||
__data_start = .;
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
*(.got*)
|
||||
. = ALIGN(4096);
|
||||
__data_end = .;
|
||||
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
*(.sbss*)
|
||||
. = ALIGN(4096);
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment*)
|
||||
*(.eh_frame*)
|
||||
*(.gcc_except_table*)
|
||||
*(.note*)
|
||||
*(.rel.eh_frame*)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use core::mem;
|
||||
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
pub const USERMODE_END: usize = 1 << 47; // Assuming Sv48; it should work with Sv57 also
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
|
||||
static MAP: Map = Map {
|
||||
offset: 0,
|
||||
size: STACK_SIZE,
|
||||
flags: MapFlags::PROT_READ
|
||||
.union(MapFlags::PROT_WRITE)
|
||||
.union(MapFlags::MAP_PRIVATE)
|
||||
.union(MapFlags::MAP_FIXED_NOREPLACE),
|
||||
address: STACK_START, // highest possible user address
|
||||
};
|
||||
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.globl _start
|
||||
_start:
|
||||
# Setup a stack.
|
||||
li a7, {number}
|
||||
li a0, {fd}
|
||||
la a1, {map} # pointer to Map struct
|
||||
li a2, {map_size} # size of Map struct
|
||||
ecall
|
||||
|
||||
# Test for success (nonzero value).
|
||||
bne a0, x0, 2f
|
||||
# (failure)
|
||||
unimp
|
||||
2:
|
||||
li sp, {stack_size}
|
||||
add sp, sp, a0
|
||||
mv fp, x0
|
||||
|
||||
jal start
|
||||
# `start` must never return.
|
||||
unimp
|
||||
",
|
||||
fd = const usize::MAX, // dummy fd indicates anonymous map
|
||||
map = sym MAP,
|
||||
map_size = const mem::size_of::<Map>(),
|
||||
number = const SYS_FMAP,
|
||||
stack_size = const STACK_SIZE,
|
||||
);
|
||||
@@ -0,0 +1,84 @@
|
||||
use syscall::flag::MapFlags;
|
||||
|
||||
mod offsets {
|
||||
extern "C" {
|
||||
// text (R-X)
|
||||
static __text_start: u8;
|
||||
static __text_end: u8;
|
||||
// rodata (R--)
|
||||
static __rodata_start: u8;
|
||||
static __rodata_end: u8;
|
||||
// data+bss (RW-)
|
||||
static __data_start: u8;
|
||||
static __bss_end: u8;
|
||||
}
|
||||
pub fn text() -> (usize, 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
pub fn data_and_bss() -> (usize, usize) {
|
||||
unsafe {
|
||||
(
|
||||
&__data_start as *const u8 as usize,
|
||||
&__bss_end as *const u8 as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn start() -> ! {
|
||||
// Remap self, from the previous RWX
|
||||
|
||||
let (text_start, text_end) = offsets::text();
|
||||
let (rodata_start, rodata_end) = offsets::rodata();
|
||||
let (data_start, data_end) = offsets::data_and_bss();
|
||||
|
||||
let _ = syscall::open("/scheme/debug", syscall::O_RDONLY); // stdin
|
||||
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(
|
||||
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");
|
||||
|
||||
// FIXME make the initfs read-only
|
||||
|
||||
crate::exec::main();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
ENTRY(_start)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
SECTIONS {
|
||||
. = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */
|
||||
__initfs_header = . - 4096;
|
||||
. += SIZEOF_HEADERS;
|
||||
. = ALIGN(4096);
|
||||
|
||||
.text : {
|
||||
__text_start = .;
|
||||
*(.text*)
|
||||
. = ALIGN(4096);
|
||||
__text_end = .;
|
||||
}
|
||||
.rodata : {
|
||||
__rodata_start = .;
|
||||
*(.rodata*)
|
||||
. = ALIGN(4096);
|
||||
__rodata_end = .;
|
||||
}
|
||||
.data : {
|
||||
__data_start = .;
|
||||
*(.data*)
|
||||
. = ALIGN(4096);
|
||||
__data_end = .;
|
||||
|
||||
*(.tbss*)
|
||||
. = ALIGN(4096);
|
||||
*(.tdata*)
|
||||
. = ALIGN(4096);
|
||||
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
. = ALIGN(4096);
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment*)
|
||||
*(.eh_frame*)
|
||||
*(.gcc_except_table*)
|
||||
*(.note*)
|
||||
*(.rel.eh_frame*)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
use core::mem;
|
||||
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
|
||||
static MAP: Map = Map {
|
||||
offset: 0,
|
||||
size: STACK_SIZE,
|
||||
flags: MapFlags::PROT_READ
|
||||
.union(MapFlags::PROT_WRITE)
|
||||
.union(MapFlags::MAP_PRIVATE)
|
||||
.union(MapFlags::MAP_FIXED_NOREPLACE),
|
||||
address: STACK_START, // highest possible user address
|
||||
};
|
||||
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.globl _start
|
||||
_start:
|
||||
# Setup a stack.
|
||||
mov rax, {number}
|
||||
mov rdi, {fd}
|
||||
mov rsi, offset {map} # pointer to Map struct
|
||||
mov rdx, {map_size} # size of Map struct
|
||||
syscall
|
||||
|
||||
# Test for success (nonzero value).
|
||||
cmp rax, 0
|
||||
jg 1f
|
||||
# (failure)
|
||||
ud2
|
||||
1:
|
||||
# Subtract 16 since all instructions seem to hate non-canonical RSP values :)
|
||||
lea rsp, [rax+{stack_size}-16]
|
||||
mov rbp, rsp
|
||||
|
||||
# Stack has the same alignment as `size`.
|
||||
call start
|
||||
# `start` must never return.
|
||||
ud2
|
||||
",
|
||||
fd = const usize::MAX, // dummy fd indicates anonymous map
|
||||
map = sym MAP,
|
||||
map_size = const mem::size_of::<Map>(),
|
||||
number = const SYS_FMAP,
|
||||
stack_size = const STACK_SIZE,
|
||||
);
|
||||
Reference in New Issue
Block a user