Initial Commit.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/target
|
||||
Generated
+113
@@ -0,0 +1,113 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"goblin",
|
||||
"libc",
|
||||
"linked_list_allocator",
|
||||
"memoffset",
|
||||
"redox_syscall",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32401e89c6446dcd28185931a01b1093726d0356820ac744023e6850689bf926"
|
||||
dependencies = [
|
||||
"plain",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "linked_list_allocator"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a"
|
||||
dependencies = [
|
||||
"spinning_top",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.13"
|
||||
source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=userspace_fexec#933adb23683e9d6529ff2f6ffe7f1211c952897c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec"
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
authors = ["4lDO2 <4lDO2@protonmail.com>"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "bootstrap"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
arrayvec = { version = "0.7", default-features = false }
|
||||
goblin = { version = "0.4", default-features = false, features = ["elf32", "elf64"] }
|
||||
libc = "0.2"
|
||||
memoffset = "0.6"
|
||||
scroll = { version = "0.10", default-features = false }
|
||||
linked_list_allocator = "0.9"
|
||||
redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "userspace_fexec" }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn main(_: libc::c_int, _: *const *const libc::c_char) -> libc::c_int {
|
||||
let envp = {
|
||||
let len = 4096;
|
||||
let buf = libc::calloc(len, 1);
|
||||
if buf.is_null() { panic!("failed to allocate env buf"); }
|
||||
let env = core::slice::from_raw_parts_mut(buf as *mut u8, len);
|
||||
|
||||
let fd = syscall::open("sys:env", syscall::O_RDONLY | syscall::O_CLOEXEC).expect("bootstrap: failed to open env");
|
||||
let bytes_read = syscall::read(fd, env).expect("bootstrap: failed to read env");
|
||||
|
||||
if bytes_read >= len {
|
||||
// TODO: Handle this, we can allocate as much as we want in theory.
|
||||
panic!("env is too large");
|
||||
}
|
||||
|
||||
for c in &mut *env {
|
||||
if *c == b'\n' {
|
||||
*c = b'\0';
|
||||
}
|
||||
}
|
||||
let env_count = env.split(|c| *c == b'\0').count();
|
||||
|
||||
let envp = libc::calloc(env_count, core::mem::size_of::<*const u8>()) as *mut *const libc::c_char;
|
||||
if envp.is_null() { panic!("failed to allocate envp buf"); }
|
||||
|
||||
for (idx, var) in env.split(|c| *c == b'\0').enumerate() {
|
||||
envp.add(idx).write(var.as_ptr() as *const libc::c_char);
|
||||
}
|
||||
|
||||
envp
|
||||
};
|
||||
|
||||
let name_ptr = b"initfs:bin/init\0".as_ptr() as *const libc::c_char;
|
||||
let argv = [name_ptr, core::ptr::null()];
|
||||
|
||||
if libc::execve(name_ptr, argv.as_ptr(), envp) == -1 {
|
||||
libc::perror(b"Failed to execute init\0".as_ptr() as *const libc::c_char);
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#![no_std]
|
||||
#![feature(alloc_error_handler, core_intrinsics, lang_items)]
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod x86_64;
|
||||
|
||||
pub mod exec;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(_: core::alloc::Layout) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
#[lang = "eh_personality"]
|
||||
extern "C" fn rust_eh_personality() {}
|
||||
@@ -0,0 +1,42 @@
|
||||
BITS 64
|
||||
|
||||
section .text
|
||||
|
||||
global ustart
|
||||
extern start
|
||||
|
||||
ustart:
|
||||
; Setup a stack.
|
||||
mov rax, 0x21000384 ; SYS_CLASS_FILE+SYS_ARG_SLICE+SYS_MMAP
|
||||
mov rdi, 0xFFFFFFFFFFFFFFFF ; dummy `fd`, indicates anonymous map
|
||||
mov rsi, map ; pointer to Map struct
|
||||
mov rdx, map_size ; size of Map struct
|
||||
syscall
|
||||
|
||||
; Test for success (nonzero value).
|
||||
cmp rax, 0
|
||||
jg .continue
|
||||
; (failure)
|
||||
ud2
|
||||
.continue:
|
||||
; Subtract 16 since all instructions seem to hate non-canonical RSP values :)
|
||||
lea rsp, [rax+size-16]
|
||||
mov rbp, rsp
|
||||
|
||||
; Stack has the same alignment as `size`.
|
||||
call start
|
||||
; `start` must never return.
|
||||
ud2
|
||||
|
||||
section .rodata
|
||||
map:
|
||||
dq 0 ; offset (unused)
|
||||
dq size
|
||||
dq flags
|
||||
dq address - size
|
||||
|
||||
map_size equ $ - map
|
||||
|
||||
size equ 65536 ; 64 KiB
|
||||
address equ 0x0000800000000000 ; highest possible (normal) user address, why not
|
||||
flags equ 0x0006000E ; PROT_READ+PROT_WRITE, MAP_PRIVATE+MAP_FIXED_NOREPLACE
|
||||
@@ -0,0 +1,46 @@
|
||||
ENTRY(ustart)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
SECTIONS {
|
||||
. = 0;
|
||||
. += 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 = .;
|
||||
}
|
||||
__end = .;
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment*)
|
||||
*(.eh_frame*)
|
||||
*(.gcc_except_table*)
|
||||
*(.note*)
|
||||
*(.rel.eh_frame*)
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
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;
|
||||
|
||||
static __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) }
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub fn end() -> usize {
|
||||
unsafe { &__end as *const u8 as usize }
|
||||
}
|
||||
}
|
||||
|
||||
// relibc linkage stuff
|
||||
#[no_mangle]
|
||||
extern "C" fn _init() {}
|
||||
#[no_mangle]
|
||||
extern "C" fn _fini() {}
|
||||
|
||||
extern "C" fn nop() {}
|
||||
|
||||
#[no_mangle]
|
||||
static __preinit_array_start: extern "C" fn() = nop;
|
||||
#[no_mangle]
|
||||
static __preinit_array_end: extern "C" fn() = nop;
|
||||
#[no_mangle]
|
||||
static __init_array_start: extern "C" fn() = nop;
|
||||
#[no_mangle]
|
||||
static __init_array_end: extern "C" fn() = nop;
|
||||
|
||||
#[no_mangle]
|
||||
static __fini_array_start: extern "C" fn() = nop;
|
||||
#[no_mangle]
|
||||
static __fini_array_end: extern "C" fn() = nop;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "sysv64" 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("debug:", syscall::O_RDONLY); // stdin
|
||||
let _ = syscall::open("debug:", syscall::O_WRONLY); // stdout
|
||||
let _ = syscall::open("debug:", syscall::O_WRONLY); // stderr
|
||||
|
||||
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");
|
||||
|
||||
/*const FD_ANONYMOUS: usize = !0;
|
||||
|
||||
{
|
||||
let heap_size = 1024 * 1024;
|
||||
let heap_start = syscall::fmap(FD_ANONYMOUS, &syscall::Map { offset: 0, address: 0, size: heap_size, flags: MapFlags::MAP_PRIVATE | MapFlags::PROT_READ | MapFlags::PROT_WRITE }).expect("failed to map heap");
|
||||
crate::ALLOCATOR.0.get().write(linked_list_allocator::Heap::new(heap_start, heap_size));
|
||||
}
|
||||
|
||||
let init_fd = syscall::open("initfs:/bin/init", syscall::O_CLOEXEC | syscall::O_RDONLY).expect("failed to open init");
|
||||
|
||||
const STACK_SIZE: usize = 1024 * 1024;
|
||||
let stack = syscall::fmap(FD_ANONYMOUS, &syscall::Map { offset: 0, address: 0, flags: MapFlags::MAP_PRIVATE | MapFlags::PROT_READ | MapFlags::PROT_WRITE, size: STACK_SIZE }).unwrap();
|
||||
|
||||
let stack_top = 1_usize << 48;
|
||||
memranges.push(syscall::ExecMemRange { address: stack_top - STACK_SIZE, size: STACK_SIZE, flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE, old_address: stack });
|
||||
|
||||
// Now, push things such as argv, env (i.e. kernel cmdline when executing init) and auxv.
|
||||
// TODO: Figure out reason behind subtraction by 256 (inherited from kernel behavior).
|
||||
let mut target_sp = stack_top - 256;
|
||||
let actual_sp = (stack + STACK_SIZE) as *mut usize;
|
||||
|
||||
let mut push = |value: usize| {
|
||||
target_sp -= core::mem::size_of::<usize>();
|
||||
actual_sp = actual_sp.sub(core::mem::size_of::<usize>());
|
||||
actual_sp.write(value);
|
||||
};*/
|
||||
extern "C" {
|
||||
fn relibc_start(stack: usize);
|
||||
}
|
||||
use goblin::elf::header::header64::Header;
|
||||
use memoffset::offset_of;
|
||||
|
||||
let stack = [
|
||||
// argc
|
||||
0,
|
||||
// argv null terminator
|
||||
0_usize,
|
||||
// envp null terminator
|
||||
0_usize,
|
||||
|
||||
// Make the TLS part of ld.so happy, even though we do not use TLS.
|
||||
syscall::AT_PHDR,
|
||||
// The kernel loads the entire ELF, so the program header offset can be trivially received.
|
||||
// TODO: Use goblin for the ELF header (except rust accepts no null pointers...).
|
||||
(offset_of!(Header, e_phoff) as *mut u64).read() as usize,
|
||||
syscall::AT_PHENT,
|
||||
(offset_of!(Header, e_phentsize) as *mut u16).read() as usize,
|
||||
syscall::AT_PHNUM,
|
||||
(offset_of!(Header, e_phnum) as *mut u16).read() as usize,
|
||||
// auxv null terminator
|
||||
syscall::AT_NULL,
|
||||
0,
|
||||
];
|
||||
relibc_start(stack.as_ptr() as usize);
|
||||
panic!();
|
||||
}
|
||||
Reference in New Issue
Block a user