Correctly set up TLS on Redox and other fixes for pthread_clone

This commit is contained in:
Jeremy Soller
2019-04-14 19:08:58 -06:00
parent 7fe0beb916
commit 30aef27c76
6 changed files with 99 additions and 51 deletions
+1
View File
@@ -1,5 +1,6 @@
//! dl-tls implementation for Redox
use ld_so::tcb::Tcb;
use platform::types::*;
#[repr(C)]
+2 -2
View File
@@ -199,7 +199,7 @@ impl Linker {
if let Some(name_res) = elf.dynstrtab.get(sym.st_name) {
let name = name_res?;
let value = mmap.as_ptr() as usize + sym.st_value as usize;
//println!(" global {}: {:x?} = {:#x}", name, sym, value);
// println!(" global {}: {:x?} = {:#x}", name, sym, value);
globals.insert(name, value);
}
}
@@ -356,7 +356,7 @@ impl Linker {
};
let set_u64 = |value| {
//println!(" set_u64 {:#x}", value);
// println!(" set_u64 {:#x}", value);
unsafe { *(ptr as *mut u64) = value; }
};
+14 -11
View File
@@ -3,7 +3,7 @@ use core::{mem, ptr, slice};
use core::ops::Range;
use goblin::error::{Error, Result};
use header::sys_mman;
use header::{sys_mman, unistd};
use super::PAGE_SIZE;
@@ -36,17 +36,17 @@ impl Master {
#[repr(C)]
pub struct Tcb {
/// Pointer to the end of static TLS. Must be the first member
tls_end: *mut u8,
pub tls_end: *mut u8,
/// Size of the memory allocated for the static TLS in bytes (multiple of PAGE_SIZE)
tls_len: usize,
pub tls_len: usize,
/// Pointer to this structure
tcb_ptr: *mut Tcb,
pub tcb_ptr: *mut Tcb,
/// Size of the memory allocated for this structure in bytes (should be PAGE_SIZE)
tcb_len: usize,
pub tcb_len: usize,
/// Pointer to a list of initial TLS data
masters_ptr: *mut Master,
pub masters_ptr: *mut Master,
/// Size of the masters list in bytes (multiple of mem::size_of::<Master>())
masters_len: usize,
pub masters_len: usize,
}
impl Tcb {
@@ -55,7 +55,7 @@ impl Tcb {
let (tls, tcb_page) = Self::os_new(size)?;
let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self;
ptr::write(tcb_ptr, Tcb {
ptr::write(tcb_ptr, Self {
tls_end: tls.as_mut_ptr().add(tls.len()),
tls_len: tls.len(),
tcb_ptr: tcb_ptr,
@@ -171,11 +171,14 @@ impl Tcb {
/// OS specific code to create a new TLS and TCB - Redox
#[cfg(target_os = "redox")]
unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8])> {
//TODO: better method of finding fs offset
let pid = unistd::getpid();
let tcb_addr = 0xB000_0000 + pid as usize * PAGE_SIZE;
let tls = Self::map(size)?;
Ok((
tls,
//TODO: Consider allocating TCB as part of TLS
slice::from_raw_parts_mut(0xB000_0000 as *mut u8, PAGE_SIZE)
slice::from_raw_parts_mut(tcb_addr as *mut u8, PAGE_SIZE)
))
}
@@ -185,10 +188,10 @@ impl Tcb {
unsafe fn arch_read(offset: usize) -> usize {
let value;
asm!("
mov rax, [fs:rdi]
mov rax, fs:[rdi]
"
: "={rax}"(value)
: "{rax}"(offset)
: "{rdi}"(offset)
:
: "intel"
);
+9 -2
View File
@@ -343,9 +343,16 @@ impl Pal for Sys {
test rax, rax
jnz .parent
# Call entry point
pop rdi
# Load registers
pop rax
pop rdi
pop rsi
pop rdx
pop rcx
pop r8
pop r9
# Call entry point
call rax
# Exit
+64 -34
View File
@@ -7,6 +7,7 @@ use core::{intrinsics, ptr};
use header::sys_mman;
use header::time::timespec;
use ld_so::tcb::{Tcb, Master};
use mutex::{FUTEX_WAIT, FUTEX_WAKE};
use platform::types::{c_int, c_uint, c_void, pid_t, size_t};
use platform::{Pal, Sys};
@@ -58,6 +59,27 @@ pub unsafe extern "C" fn pte_osInit() -> pte_osResult {
PTE_OS_OK
}
/// A shim to wrap thread entry points in logic to set up TLS, for example
unsafe extern "C" fn pte_osThreadShim(
entryPoint: pte_osThreadEntryPoint,
argv: *mut c_void,
mutex: pte_osMutexHandle,
tls_size: usize,
tls_masters_ptr: *mut Master,
tls_masters_len: usize
) {
let mut tcb = Tcb::new(tls_size).unwrap();
tcb.masters_ptr = tls_masters_ptr;
tcb.masters_len = tls_masters_len;
tcb.copy_masters().unwrap();
tcb.activate();
// Wait until pte_osThreadStart
pte_osMutexLock(mutex);
entryPoint(argv);
pte_osThreadExit();
}
#[no_mangle]
pub unsafe extern "C" fn pte_osThreadCreate(
entryPoint: pte_osThreadEntryPoint,
@@ -66,6 +88,9 @@ pub unsafe extern "C" fn pte_osThreadCreate(
argv: *mut c_void,
ppte_osThreadHandle: *mut pte_osThreadHandle,
) -> pte_osResult {
// Create a locked mutex, unlocked by pte_osThreadStart
let mutex: pte_osMutexHandle = Box::into_raw(Box::new(2));
let stack_size = if stackSize == 0 {
1024 * 1024
} else {
@@ -85,45 +110,50 @@ pub unsafe extern "C" fn pte_osThreadCreate(
let stack_end = stack_base.add(stack_size);
let mut stack = stack_end as *mut usize;
{
stack = stack.offset(-1);
*stack = entryPoint as usize;
let mut push = |value: usize| {
stack = stack.offset(-1);
*stack = value;
};
stack = stack.offset(-1);
*stack = argv as usize;
}
// Create a locked mutex, unlocked by pte_osThreadStart
let mutex = Box::into_raw(Box::new(2));
{
let id = Sys::pte_clone(stack);
if id < 0 {
return PTE_OS_GENERAL_FAILURE;
}
if id == 0 {
// Wait until pte_osThreadStart
pte_osMutexLock(mutex);
entryPoint(argv);
pte_osThreadExit();
if let Some(tcb) = Tcb::current() {
push(tcb.masters_len);
push(tcb.masters_ptr as usize);
push(tcb.tls_len);
} else {
pte_osMutexLock(&mut pid_mutexes_lock);
if pid_mutexes.is_none() {
pid_mutexes = Some(BTreeMap::new());
}
pid_mutexes.as_mut().unwrap().insert(id, mutex);
pte_osMutexUnlock(&mut pid_mutexes_lock);
pte_osMutexLock(&mut pid_stacks_lock);
if pid_stacks.is_none() {
pid_stacks = Some(BTreeMap::new());
}
pid_stacks.as_mut().unwrap().insert(id, (stack_base, stack_size));
pte_osMutexUnlock(&mut pid_stacks_lock);
*ppte_osThreadHandle = id;
push(0);
push(0);
push(0);
}
push(mutex as usize);
push(argv as usize);
push(entryPoint as usize);
push(pte_osThreadShim as usize);
}
let id = Sys::pte_clone(stack);
if id < 0 {
return PTE_OS_GENERAL_FAILURE;
}
pte_osMutexLock(&mut pid_mutexes_lock);
if pid_mutexes.is_none() {
pid_mutexes = Some(BTreeMap::new());
}
pid_mutexes.as_mut().unwrap().insert(id, mutex);
pte_osMutexUnlock(&mut pid_mutexes_lock);
pte_osMutexLock(&mut pid_stacks_lock);
if pid_stacks.is_none() {
pid_stacks = Some(BTreeMap::new());
}
pid_stacks.as_mut().unwrap().insert(id, (stack_base, stack_size));
pte_osMutexUnlock(&mut pid_stacks_lock);
*ppte_osThreadHandle = id;
PTE_OS_OK
}
+9 -2
View File
@@ -832,9 +832,16 @@ impl Pal for Sys {
test rax, rax
jnz .parent
# Call entry point
pop rdi
# Load registers
pop rax
pop rdi
pop rsi
pop rdx
pop rcx
pop r8
pop r9
# Call entry point
call rax
# Exit