Skip to content
Snippets Groups Projects
mod.rs 2.78 KiB
use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader};

use self::tcb::{Master, Tcb};
use crate::start::Stack;

pub const PAGE_SIZE: usize = 4096;

pub mod debug;
pub mod linker;
pub mod start;
pub mod tcb;
pub fn static_init(sp: &'static Stack) {
    let mut phdr_opt = None;
    let mut phent_opt = None;
    let mut phnum_opt = None;

    let mut auxv = sp.auxv();
    loop {
        let (kind, value) = unsafe { *auxv };
        if kind == 0 {
            break;
        }

        match kind {
            3 => phdr_opt = Some(value),
            4 => phent_opt = Some(value),
            5 => phnum_opt = Some(value),
            _ => (),
        }

        auxv = unsafe { auxv.add(1) };
    }

    let phdr = phdr_opt.expect("failed to find AT_PHDR");
    let phent = phent_opt.expect("failed to find AT_PHENT");
    let phnum = phnum_opt.expect("failed to find AT_PHNUM");

    for i in 0..phnum {
        let ph_addr = phdr + phent * i;
        let ph: ProgramHeader = match phent {
            program_header32::SIZEOF_PHDR => {
                unsafe { *(ph_addr as *const program_header32::ProgramHeader) }.into()
            }
            program_header64::SIZEOF_PHDR => {
                unsafe { *(ph_addr as *const program_header64::ProgramHeader) }.into()
            }
            _ => panic!("unknown AT_PHENT size {}", phent),
        };

        let voff = ph.p_vaddr as usize % PAGE_SIZE;
        let vaddr = ph.p_vaddr as usize - voff;
        let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;

        match ph.p_type {
            program_header::PT_TLS => {
                let valign = if ph.p_align > 0 {
                    ((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align
                } else {
                    ph.p_memsz
                } as usize;

                let tcb_master = Master {
                    ptr: ph.p_vaddr as usize as *const u8,
                    len: ph.p_filesz as usize,
                    offset: vsize - valign,
                };

                unsafe {
                    let tcb = Tcb::new(vsize).expect("failed to allocate TCB");
                    tcb.set_masters(vec![tcb_master].into_boxed_slice());
                    tcb.copy_masters().expect("failed to copy TLS master data");
                    tcb.activate();
                }

                //TODO: Warning on multiple TLS sections?
                return;
            }
            _ => (),
        }
    }
}

#[cfg(target_os = "linux")]
pub unsafe fn init(sp: &'static Stack) {
    let mut tp = 0usize;
    const ARCH_GET_FS: usize = 0x1003;
    syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize);
    if tp == 0 {
        static_init(sp);
    }
}

#[cfg(target_os = "redox")]
pub unsafe fn init(_sp: &'static Stack) {}