Initial Commit.

This commit is contained in:
4lDO2
2022-07-05 14:06:59 +02:00
commit f174685820
8 changed files with 412 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/target
Generated
+113
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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() {}
+42
View File
@@ -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
+46
View File
@@ -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
View File
@@ -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!();
}