Merge branch 'usignal' of gitlab.redox-os.org:4lDO2/relibc
This commit is contained in:
Generated
+31
-34
@@ -27,9 +27,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@@ -67,9 +67,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.99"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
||||
checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -143,6 +143,10 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-rt"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.7.1"
|
||||
@@ -194,9 +198,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
@@ -214,15 +218,6 @@ version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -272,9 +267,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -360,21 +355,23 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-exec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"goblin",
|
||||
"plain",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-path"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7"
|
||||
|
||||
[[package]]
|
||||
name = "redox-rt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"generic-rt",
|
||||
"goblin",
|
||||
"plain",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_event"
|
||||
version = "0.4.0"
|
||||
@@ -387,9 +384,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
|
||||
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -404,19 +401,19 @@ dependencies = [
|
||||
"cbitset",
|
||||
"cc",
|
||||
"dlmalloc",
|
||||
"generic-rt",
|
||||
"goblin",
|
||||
"libc",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"memoffset",
|
||||
"pbkdf2",
|
||||
"plain",
|
||||
"posix-regex",
|
||||
"rand",
|
||||
"rand_jitter",
|
||||
"rand_xorshift",
|
||||
"redox-exec",
|
||||
"redox-path",
|
||||
"redox-rt",
|
||||
"redox_event",
|
||||
"redox_syscall",
|
||||
"sc",
|
||||
@@ -496,15 +493,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
version = "2.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
+5
-4
@@ -13,8 +13,9 @@ members = [
|
||||
"src/crt0",
|
||||
"src/crti",
|
||||
"src/crtn",
|
||||
"src/platform/redox/redox-exec",
|
||||
"redox-rt",
|
||||
"ld_so",
|
||||
"generic-rt",
|
||||
]
|
||||
exclude = ["tests", "dlmalloc-rs"]
|
||||
|
||||
@@ -24,7 +25,6 @@ cc = "1"
|
||||
[dependencies]
|
||||
bitflags = "2"
|
||||
cbitset = "0.2"
|
||||
memoffset = "0.9"
|
||||
posix-regex = { path = "posix-regex", features = ["no_std"] }
|
||||
|
||||
# TODO: For some reason, rand_jitter hasn't been updated to use the latest rand_core
|
||||
@@ -43,6 +43,7 @@ bcrypt-pbkdf = { version = "0.10", default-features = false, features = ["alloc"
|
||||
scrypt = { version = "0.11", default-features = false, features = ["simple"]}
|
||||
pbkdf2 = { version = "0.12", features = ["sha2"]}
|
||||
sha2 = { version = "0.10", default-features = false }
|
||||
generic-rt = { path = "generic-rt" }
|
||||
|
||||
[dependencies.goblin]
|
||||
version = "0.7"
|
||||
@@ -58,8 +59,8 @@ features = ["c_api"]
|
||||
sc = "0.2.3"
|
||||
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
redox_syscall = "0.5.1"
|
||||
redox-exec = { path = "src/platform/redox/redox-exec" }
|
||||
redox_syscall = "0.5.3"
|
||||
redox-rt = { path = "redox-rt" }
|
||||
redox-path = "0.2"
|
||||
redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = ["redox_syscall"] }
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "generic-rt"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,112 @@
|
||||
#![no_std]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use core::arch::asm;
|
||||
use core::mem::{self, offset_of};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct GenericTcb<Os> {
|
||||
/// Pointer to the end of static TLS. Must be the first member
|
||||
pub tls_end: *mut u8,
|
||||
/// Size of the memory allocated for the static TLS in bytes (multiple of page size)
|
||||
pub tls_len: usize,
|
||||
/// Pointer to this structure
|
||||
pub tcb_ptr: *mut Self,
|
||||
/// Size of the memory allocated for this structure in bytes (should be same as page size)
|
||||
pub tcb_len: usize,
|
||||
pub os_specific: Os,
|
||||
}
|
||||
impl<Os> GenericTcb<Os> {
|
||||
/// Architecture specific code to read a usize from the TCB - aarch64
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub unsafe fn arch_read(offset: usize) -> usize {
|
||||
let abi_ptr: usize;
|
||||
asm!(
|
||||
"mrs {}, tpidr_el0",
|
||||
out(reg) abi_ptr,
|
||||
);
|
||||
|
||||
let tcb_ptr = *(abi_ptr as *const usize);
|
||||
*((tcb_ptr + offset) as *const usize)
|
||||
}
|
||||
|
||||
/// Architecture specific code to read a usize from the TCB - x86
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub unsafe fn arch_read(offset: usize) -> usize {
|
||||
let value;
|
||||
asm!(
|
||||
"
|
||||
mov {}, gs:[{}]
|
||||
",
|
||||
out(reg) value,
|
||||
in(reg) offset,
|
||||
);
|
||||
value
|
||||
}
|
||||
|
||||
/// Architecture specific code to read a usize from the TCB - x86_64
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub unsafe fn arch_read(offset: usize) -> usize {
|
||||
let value;
|
||||
asm!(
|
||||
"
|
||||
mov {}, fs:[{}]
|
||||
",
|
||||
out(reg) value,
|
||||
in(reg) offset,
|
||||
);
|
||||
value
|
||||
}
|
||||
|
||||
pub unsafe fn current_ptr() -> Option<*mut Self> {
|
||||
let tcb_ptr = Self::arch_read(offset_of!(Self, tcb_ptr)) as *mut Self;
|
||||
let tcb_len = Self::arch_read(offset_of!(Self, tcb_len));
|
||||
if tcb_ptr.is_null() || tcb_len < mem::size_of::<Self>() {
|
||||
None
|
||||
} else {
|
||||
Some(tcb_ptr)
|
||||
}
|
||||
}
|
||||
pub unsafe fn current() -> Option<&'static mut Self> {
|
||||
Some(&mut *Self::current_ptr()?)
|
||||
}
|
||||
}
|
||||
pub fn panic_notls(msg: impl core::fmt::Display) -> ! {
|
||||
//eprintln!("panicked in ld.so: {}", msg);
|
||||
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
pub trait ExpectTlsFree {
|
||||
type Unwrapped;
|
||||
|
||||
fn expect_notls(self, msg: &str) -> Self::Unwrapped;
|
||||
}
|
||||
impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> {
|
||||
type Unwrapped = T;
|
||||
|
||||
fn expect_notls(self, msg: &str) -> T {
|
||||
match self {
|
||||
Ok(t) => t,
|
||||
Err(err) => panic_notls(format_args!(
|
||||
"{}: expect failed for Result with err: {:?}",
|
||||
msg, err
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> ExpectTlsFree for Option<T> {
|
||||
type Unwrapped = T;
|
||||
|
||||
fn expect_notls(self, msg: &str) -> T {
|
||||
match self {
|
||||
Some(t) => t,
|
||||
None => panic_notls(format_args!("{}: expect failed for Option", msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,18 @@
|
||||
#define SIG_IGN ((void (*)(int))1)
|
||||
#define SIG_ERR ((void (*)(int))-1)
|
||||
|
||||
struct siginfo;
|
||||
typedef struct siginfo siginfo_t;
|
||||
typedef unsigned long long sigset_t;
|
||||
|
||||
struct sigaction {
|
||||
union {
|
||||
void (*sa_handler)(int);
|
||||
void (*sa_sigaction)(int, siginfo_t *, void *);
|
||||
};
|
||||
unsigned long sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
sigset_t sa_mask;
|
||||
};
|
||||
|
||||
#endif // _BITS_SIGNAL_H
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
[package]
|
||||
name = "redox-exec"
|
||||
name = "redox-rt"
|
||||
authors = ["4lDO2 <4lDO2@protonmail.com>"]
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "Libc-independent runtime for Redox"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
redox_syscall = "0.5.1"
|
||||
bitflags = "2"
|
||||
goblin = { version = "0.7", default-features = false, features = ["elf32", "elf64", "endian_fd"] }
|
||||
plain = "0.2"
|
||||
redox_syscall = "0.5.3"
|
||||
|
||||
generic-rt = { path = "../generic-rt" }
|
||||
@@ -0,0 +1,292 @@
|
||||
use core::mem::offset_of;
|
||||
|
||||
use syscall::data::*;
|
||||
use syscall::error::*;
|
||||
|
||||
use crate::proc::{fork_inner, FdGuard};
|
||||
use crate::signal::SigStack;
|
||||
use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT};
|
||||
use crate::Tcb;
|
||||
|
||||
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||
pub(crate) const STACK_TOP: usize = 1 << 47;
|
||||
pub(crate) const STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct SigArea {
|
||||
pub altstack_top: usize,
|
||||
pub altstack_bottom: usize,
|
||||
pub tmp_x1_x2: [usize; 2],
|
||||
pub tmp_x3_x4: [usize; 2],
|
||||
pub tmp_sp: usize,
|
||||
pub onstack: u64,
|
||||
pub disable_signals_depth: u64,
|
||||
pub pctl: usize, // TODO: remove
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ArchIntRegs {
|
||||
pub x30: usize,
|
||||
pub x29: usize,
|
||||
pub x28: usize,
|
||||
pub x27: usize,
|
||||
pub x26: usize,
|
||||
pub x25: usize,
|
||||
pub x24: usize,
|
||||
pub x23: usize,
|
||||
pub x22: usize,
|
||||
pub x21: usize,
|
||||
pub x20: usize,
|
||||
pub x19: usize,
|
||||
pub x18: usize,
|
||||
pub x17: usize,
|
||||
pub x16: usize,
|
||||
pub x15: usize,
|
||||
pub x14: usize,
|
||||
pub x13: usize,
|
||||
pub x12: usize,
|
||||
pub x11: usize,
|
||||
pub x10: usize,
|
||||
pub x9: usize,
|
||||
pub x8: usize,
|
||||
pub x7: usize,
|
||||
pub x6: usize,
|
||||
pub x5: usize,
|
||||
pub x4: usize,
|
||||
pub x3: usize,
|
||||
pub x2: usize,
|
||||
pub x1: usize,
|
||||
|
||||
pub sp: usize,
|
||||
pub nzcv: usize, // user-accessible PSTATE bits
|
||||
|
||||
pub pc: usize,
|
||||
pub x0: usize,
|
||||
}
|
||||
|
||||
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||
/// is already initialized as if it was a thread.
|
||||
pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = FdGuard::new(syscall::dup(open_via_dup, b"regs/env")?);
|
||||
|
||||
env.tpidr_el0 = 0;
|
||||
|
||||
let _ = syscall::write(*file, &mut env)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
// Copy environment registers.
|
||||
{
|
||||
let cur_env_regs_fd = FdGuard::new(syscall::dup(cur_pid_fd, b"regs/env")?);
|
||||
let new_env_regs_fd = FdGuard::new(syscall::dup(new_pid_fd, b"regs/env")?);
|
||||
|
||||
let mut env_regs = syscall::EnvRegisters::default();
|
||||
let _ = syscall::read(*cur_env_regs_fd, &mut env_regs)?;
|
||||
let _ = syscall::write(*new_env_regs_fd, &env_regs)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe extern "C" fn fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
}
|
||||
|
||||
unsafe extern "C" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
let _ = syscall::close(new_pid_fd);
|
||||
}
|
||||
|
||||
asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
stp x29, x30, [sp, #-16]!
|
||||
stp x27, x28, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x19, x20, [sp, #-16]!
|
||||
|
||||
sub sp, sp, #32
|
||||
|
||||
//TODO: store floating point regs
|
||||
|
||||
mov x0, sp
|
||||
bl {fork_impl}
|
||||
|
||||
add sp, sp, #32
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
ldp x29, x30, [sp], #16
|
||||
ret
|
||||
"] <= [fork_impl = sym fork_impl]);
|
||||
|
||||
asmfunction!(__relibc_internal_fork_ret: ["
|
||||
ldp x0, x1, [sp]
|
||||
bl {child_hook}
|
||||
|
||||
//TODO: load floating point regs
|
||||
|
||||
mov x0, xzr
|
||||
|
||||
add sp, sp, #32
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
ldp x29, x30, [sp], #16
|
||||
|
||||
ret
|
||||
"] <= [child_hook = sym child_hook]);
|
||||
|
||||
asmfunction!(__relibc_internal_sigentry: ["
|
||||
// old pc and x0 are saved in the sigcontrol struct
|
||||
mrs x0, tpidr_el0 // ABI ptr
|
||||
ldr x0, [x0] // TCB ptr
|
||||
|
||||
// save x1-x3 and sp
|
||||
stp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
|
||||
stp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
|
||||
mov x1, sp
|
||||
str x1, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
|
||||
|
||||
sub x1, x1, 128
|
||||
and x1, x1, -16
|
||||
mov sp, x1
|
||||
|
||||
ldr x3, [x0, #{tcb_sa_off} + {sa_pctl}]
|
||||
|
||||
// load x1 and x2 with each word (tearing between x1 and x2 can occur)
|
||||
// acquire ordering
|
||||
add x2, x0, #{tcb_sc_off} + {sc_word}
|
||||
ldaxp x1, x2, [x2]
|
||||
|
||||
// reduce them by ANDing the upper and lower 32 bits
|
||||
and x1, x1, x1, lsr #32 // put result in lo half
|
||||
and x2, x2, x2, lsl #32 // put result in hi half
|
||||
orr x1, x1, x2 // combine them into the set of pending unblocked
|
||||
|
||||
// count trailing zeroes, to find signal bit
|
||||
rbit x1, x1
|
||||
clz x1, x1
|
||||
mov x2, #32
|
||||
sub x1, x2, x1
|
||||
|
||||
// TODO: NOT ATOMIC!
|
||||
add x2, x3, w1, uxtb #4 // actions_base + sig_idx * sizeof Action
|
||||
ldxp x2, x3, [x2]
|
||||
|
||||
// skip sigaltstack step if SA_ONSTACK is clear
|
||||
// tbz x2, #57, 2f
|
||||
2:
|
||||
ldr x2, [x0, #{tcb_sc_off} + {sc_saved_pc}]
|
||||
ldr x3, [x0, #{tcb_sc_off} + {sc_saved_x0}]
|
||||
stp x2, x3, [sp], #-16
|
||||
|
||||
ldr x2, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
|
||||
mrs x3, nzcv
|
||||
stp x2, x3, [sp], #-16
|
||||
|
||||
ldp x2, x3, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
|
||||
stp x2, x3, [sp], #-16
|
||||
ldp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
|
||||
stp x4, x3, [sp], #-16
|
||||
stp x6, x5, [sp], #-16
|
||||
stp x8, x7, [sp], #-16
|
||||
stp x10, x9, [sp], #-16
|
||||
stp x12, x11, [sp], #-16
|
||||
stp x14, x13, [sp], #-16
|
||||
stp x16, x15, [sp], #-16
|
||||
stp x18, x17, [sp], #-16
|
||||
stp x20, x19, [sp], #-16
|
||||
stp x22, x21, [sp], #-16
|
||||
stp x24, x23, [sp], #-16
|
||||
stp x26, x25, [sp], #-16
|
||||
stp x28, x27, [sp], #-16
|
||||
stp x30, x29, [sp], #-16
|
||||
|
||||
mov x0, sp
|
||||
bl {inner}
|
||||
|
||||
ldp x30, x29, [sp], #16
|
||||
ldp x28, x27, [sp], #16
|
||||
ldp x26, x25, [sp], #16
|
||||
ldp x24, x23, [sp], #16
|
||||
ldp x22, x21, [sp], #16
|
||||
ldp x20, x19, [sp], #16
|
||||
ldp x18, x17, [sp], #16
|
||||
ldp x16, x15, [sp], #16
|
||||
ldp x14, x13, [sp], #16
|
||||
ldp x12, x11, [sp], #16
|
||||
ldp x10, x9, [sp], #16
|
||||
ldp x8, x7, [sp], #16
|
||||
ldp x6, x5, [sp], #16
|
||||
ldp x4, x3, [sp], #16
|
||||
ldp x2, x1, [sp], #16
|
||||
ldr x0, [sp, #8]
|
||||
msr nzcv, x0
|
||||
|
||||
// x18 is reserved by ABI as 'platform register', so clobbering it should be safe.
|
||||
mov x18, sp
|
||||
ldr x0, [sp], #16
|
||||
mov sp, x0
|
||||
mov x0, x18
|
||||
|
||||
ldp x18, x0, [x0]
|
||||
br x18
|
||||
"] <= [
|
||||
tcb_sc_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control)),
|
||||
tcb_sa_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch)),
|
||||
sa_tmp_x1_x2 = const offset_of!(SigArea, tmp_x1_x2),
|
||||
sa_tmp_x3_x4 = const offset_of!(SigArea, tmp_x3_x4),
|
||||
sa_tmp_sp = const offset_of!(SigArea, tmp_sp),
|
||||
sa_pctl = const offset_of!(SigArea, pctl),
|
||||
sc_saved_pc = const offset_of!(Sigcontrol, saved_ip),
|
||||
sc_saved_x0 = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||
sc_word = const offset_of!(Sigcontrol, word),
|
||||
inner = sym inner_c,
|
||||
]);
|
||||
|
||||
asmfunction!(__relibc_internal_rlct_clone_ret: ["
|
||||
# Load registers
|
||||
ldp x8, x0, [sp], #16
|
||||
ldp x1, x2, [sp], #16
|
||||
ldp x3, x4, [sp], #16
|
||||
|
||||
# Call entry point
|
||||
blr x8
|
||||
|
||||
ret
|
||||
"] <= []);
|
||||
|
||||
pub fn current_sp() -> usize {
|
||||
let sp: usize;
|
||||
unsafe {
|
||||
core::arch::asm!("mov {}, sp", out(reg) sp);
|
||||
}
|
||||
sp
|
||||
}
|
||||
|
||||
pub unsafe fn manually_enter_trampoline() {
|
||||
let ctl = &Tcb::current().unwrap().os_specific.control;
|
||||
|
||||
ctl.saved_archdep_reg.set(0);
|
||||
let ip_location = &ctl.saved_ip as *const _ as usize;
|
||||
|
||||
core::arch::asm!("
|
||||
bl 2f
|
||||
b 3f
|
||||
2:
|
||||
str lr, [x0]
|
||||
b __relibc_internal_sigentry
|
||||
3:
|
||||
", inout("x0") ip_location => _, out("lr") _);
|
||||
}
|
||||
|
||||
pub unsafe fn arch_pre(stack: &mut SigStack, os: &mut SigArea) {}
|
||||
@@ -0,0 +1,281 @@
|
||||
use core::mem::offset_of;
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use syscall::*;
|
||||
|
||||
use crate::proc::{fork_inner, FdGuard};
|
||||
use crate::signal::{inner_fastcall, PROC_CONTROL_STRUCT, RtSigarea, SigStack};
|
||||
|
||||
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||
pub(crate) const STACK_TOP: usize = 1 << 31;
|
||||
pub(crate) const STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct SigArea {
|
||||
pub altstack_top: usize,
|
||||
pub altstack_bottom: usize,
|
||||
pub tmp_eip: usize,
|
||||
pub tmp_esp: usize,
|
||||
pub tmp_eax: usize,
|
||||
pub tmp_edx: usize,
|
||||
pub disable_signals_depth: u64,
|
||||
}
|
||||
#[derive(Debug, Default)]
|
||||
#[repr(C, align(16))]
|
||||
pub struct ArchIntRegs {
|
||||
pub fxsave: [u16; 29],
|
||||
|
||||
// ensure fxsave region is 16 byte aligned
|
||||
pub _pad: [usize; 2], // fxsave "available" +0
|
||||
|
||||
pub ebp: usize, // fxsave "available" +8
|
||||
pub esi: usize, // avail +12
|
||||
pub edi: usize, // avail +16
|
||||
pub ebx: usize, // avail +20
|
||||
pub eax: usize, // avail +24
|
||||
pub ecx: usize, // avail +28
|
||||
pub edx: usize, // avail +32
|
||||
|
||||
pub eflags: usize, // avail +36
|
||||
pub eip: usize, // avail +40
|
||||
pub esp: usize, // avail +44
|
||||
}
|
||||
|
||||
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||
/// is already initialized as if it was a thread.
|
||||
pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = FdGuard::new(syscall::dup(open_via_dup, b"regs/env")?);
|
||||
|
||||
env.fsbase = 0;
|
||||
env.gsbase = 0;
|
||||
|
||||
let _ = syscall::write(*file, &mut env)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
// Copy environment registers.
|
||||
{
|
||||
let cur_env_regs_fd = FdGuard::new(syscall::dup(cur_pid_fd, b"regs/env")?);
|
||||
let new_env_regs_fd = FdGuard::new(syscall::dup(new_pid_fd, b"regs/env")?);
|
||||
|
||||
let mut env_regs = syscall::EnvRegisters::default();
|
||||
let _ = syscall::read(*cur_env_regs_fd, &mut env_regs)?;
|
||||
let _ = syscall::write(*new_env_regs_fd, &env_regs)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe extern "cdecl" fn fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
}
|
||||
|
||||
unsafe extern "cdecl" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
let _ = syscall::close(new_pid_fd);
|
||||
}
|
||||
|
||||
asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// Push preserved registers
|
||||
push ebx
|
||||
push edi
|
||||
push esi
|
||||
push ebp
|
||||
|
||||
sub esp, 32
|
||||
|
||||
//TODO stmxcsr [esp+16]
|
||||
fnstcw [esp+24]
|
||||
|
||||
push esp
|
||||
call {fork_impl}
|
||||
pop esp
|
||||
jmp 2f
|
||||
"] <= [fork_impl = sym fork_impl]);
|
||||
|
||||
asmfunction!(__relibc_internal_fork_ret: ["
|
||||
// Arguments already on the stack
|
||||
call {child_hook}
|
||||
|
||||
//TODO ldmxcsr [esp+16]
|
||||
fldcw [esp+24]
|
||||
|
||||
xor eax, eax
|
||||
|
||||
.p2align 4
|
||||
2:
|
||||
add esp, 32
|
||||
|
||||
// Pop preserved registers
|
||||
pop ebp
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebx
|
||||
|
||||
pop ebp
|
||||
ret
|
||||
"] <= [child_hook = sym child_hook]);
|
||||
asmfunction!(__relibc_internal_sigentry: ["
|
||||
// Save some registers
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_esp}], esp
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_eax}], eax
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_edx}], edx
|
||||
|
||||
// Read pending half of first signal. This can be done nonatomically wrt the mask bits, since
|
||||
// only this thread is allowed to modify the latter.
|
||||
|
||||
// Read first signal word
|
||||
mov eax, gs:[{tcb_sc_off} + {sc_word}]
|
||||
and eax, gs:[{tcb_sc_off} + {sc_word} + 4]
|
||||
bsf eax, eax
|
||||
jnz 2f
|
||||
|
||||
// Read second signal word
|
||||
mov eax, gs:[{tcb_sc_off} + {sc_word} + 8]
|
||||
and eax, gs:[{tcb_sc_off} + {sc_word} + 12]
|
||||
bsf eax, eax
|
||||
jz 7f
|
||||
add eax, 32
|
||||
2:
|
||||
and esp, -{STACK_ALIGN}
|
||||
|
||||
mov edx, eax
|
||||
add edx, edx
|
||||
bt dword ptr [{pctl} + {pctl_off_actions} + edx * 8 + 4], 28
|
||||
jnc 4f
|
||||
|
||||
mov edx, gs:[{tcb_sa_off} + {sa_altstack_top}]
|
||||
cmp esp, edx
|
||||
ja 3f
|
||||
|
||||
cmp esp, gs:[{tcb_sa_off} + {sa_altstack_bottom}]
|
||||
jnbe 4f
|
||||
3:
|
||||
mov esp, edx
|
||||
4:
|
||||
// Now that we have a stack, we can finally start populating the signal stack.
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_esp}]
|
||||
push dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}]
|
||||
push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}]
|
||||
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edx}]
|
||||
push ecx
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_eax}]
|
||||
push ebx
|
||||
push edi
|
||||
push esi
|
||||
push ebp
|
||||
|
||||
sub esp, 2 * 4 + 29 * 16
|
||||
fxsave [esp]
|
||||
|
||||
push eax
|
||||
sub esp, 3 * 4
|
||||
|
||||
mov ecx, esp
|
||||
call {inner}
|
||||
|
||||
fxrstor [esp + 16]
|
||||
add esp, 16 + 29 * 16 + 2 * 4
|
||||
|
||||
pop ebp
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ecx
|
||||
pop edx
|
||||
|
||||
popfd
|
||||
pop dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
|
||||
|
||||
.globl __relibc_internal_sigentry_crit_first
|
||||
__relibc_internal_sigentry_crit_first:
|
||||
pop esp
|
||||
|
||||
.globl __relibc_internal_sigentry_crit_second
|
||||
__relibc_internal_sigentry_crit_second:
|
||||
jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
|
||||
7:
|
||||
ud2
|
||||
"] <= [
|
||||
inner = sym inner_fastcall,
|
||||
sa_tmp_eip = const offset_of!(SigArea, tmp_eip),
|
||||
sa_tmp_esp = const offset_of!(SigArea, tmp_esp),
|
||||
sa_tmp_eax = const offset_of!(SigArea, tmp_eax),
|
||||
sa_tmp_edx = const offset_of!(SigArea, tmp_edx),
|
||||
sa_altstack_top = const offset_of!(SigArea, altstack_top),
|
||||
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
|
||||
sc_saved_eflags = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||
sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
|
||||
sc_word = const offset_of!(Sigcontrol, word),
|
||||
tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
|
||||
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||
pctl_off_actions = const offset_of!(SigProcControl, actions),
|
||||
pctl = sym PROC_CONTROL_STRUCT,
|
||||
STACK_ALIGN = const 16,
|
||||
]);
|
||||
|
||||
asmfunction!(__relibc_internal_rlct_clone_ret -> usize: ["
|
||||
# Load registers
|
||||
pop eax
|
||||
|
||||
sub esp, 8
|
||||
|
||||
mov DWORD PTR [esp], 0x00001F80
|
||||
# TODO: ldmxcsr [esp]
|
||||
mov WORD PTR [esp], 0x037F
|
||||
fldcw [esp]
|
||||
|
||||
add esp, 8
|
||||
|
||||
# Call entry point
|
||||
call eax
|
||||
|
||||
ret
|
||||
"] <= []);
|
||||
extern "C" {
|
||||
fn __relibc_internal_sigentry_crit_first();
|
||||
fn __relibc_internal_sigentry_crit_second();
|
||||
}
|
||||
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) {
|
||||
if stack.regs.eip == __relibc_internal_sigentry_crit_first as usize {
|
||||
let stack_ptr = stack.regs.esp as *const usize;
|
||||
stack.regs.esp = stack_ptr.read();
|
||||
stack.regs.eip = stack_ptr.sub(1).read();
|
||||
} else if stack.regs.eip == __relibc_internal_sigentry_crit_second as usize {
|
||||
stack.regs.eip = area.tmp_eip;
|
||||
}
|
||||
}
|
||||
pub unsafe fn manually_enter_trampoline() {
|
||||
let c = &crate::Tcb::current().unwrap().os_specific.control;
|
||||
c.control_flags.store(c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release);
|
||||
c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86?
|
||||
|
||||
core::arch::asm!("
|
||||
call 2f
|
||||
jmp 3f
|
||||
2:
|
||||
pop dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}]
|
||||
jmp __relibc_internal_sigentry
|
||||
3:
|
||||
",
|
||||
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||
sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
|
||||
);
|
||||
}
|
||||
/// Get current stack pointer, weak granularity guarantees.
|
||||
pub fn current_sp() -> usize {
|
||||
let sp: usize;
|
||||
unsafe {
|
||||
core::arch::asm!("mov {}, esp", out(reg) sp);
|
||||
}
|
||||
sp
|
||||
}
|
||||
@@ -4,9 +4,9 @@ pub use self::aarch64::*;
|
||||
pub mod aarch64;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub use self::x86::*;
|
||||
pub use self::i686::*;
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub mod x86;
|
||||
pub mod i686;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use self::x86_64::*;
|
||||
@@ -0,0 +1,402 @@
|
||||
use core::mem::offset_of;
|
||||
use core::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use syscall::data::{Sigcontrol, SigProcControl};
|
||||
use syscall::error::*;
|
||||
use syscall::flag::*;
|
||||
|
||||
use crate::proc::{fork_inner, FdGuard};
|
||||
use crate::signal::{tmp_disable_signals, SigStack};
|
||||
use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT};
|
||||
use crate::Tcb;
|
||||
|
||||
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||
pub(crate) const STACK_TOP: usize = 1 << 47;
|
||||
pub(crate) const STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct SigArea {
|
||||
pub tmp_rip: usize,
|
||||
pub tmp_rsp: usize,
|
||||
pub tmp_rax: usize,
|
||||
pub tmp_rdx: usize,
|
||||
|
||||
pub altstack_top: usize,
|
||||
pub altstack_bottom: usize,
|
||||
pub disable_signals_depth: u64,
|
||||
pub pctl: usize, // TODO: find out how to correctly reference that static
|
||||
}
|
||||
|
||||
#[repr(C, align(16))]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ArchIntRegs {
|
||||
pub ymm_upper: [u128; 16],
|
||||
pub fxsave: [u128; 29],
|
||||
pub r15: usize, // fxsave "available" +0
|
||||
pub r14: usize, // available +8
|
||||
pub r13: usize, // available +16
|
||||
pub r12: usize, // available +24
|
||||
pub rbp: usize, // available +32
|
||||
pub rbx: usize, // available +40
|
||||
pub r11: usize, // outside fxsave, and so on
|
||||
pub r10: usize,
|
||||
pub r9: usize,
|
||||
pub r8: usize,
|
||||
pub rax: usize,
|
||||
pub rcx: usize,
|
||||
pub rdx: usize,
|
||||
pub rsi: usize,
|
||||
pub rdi: usize,
|
||||
pub rflags: usize,
|
||||
pub rip: usize,
|
||||
pub rsp: usize,
|
||||
}
|
||||
|
||||
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||
/// is already initialized as if it was a thread.
|
||||
pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = FdGuard::new(syscall::dup(open_via_dup, b"regs/env")?);
|
||||
|
||||
env.fsbase = 0;
|
||||
env.gsbase = 0;
|
||||
|
||||
let _ = syscall::write(*file, &mut env)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
// Copy environment registers.
|
||||
{
|
||||
let cur_env_regs_fd = FdGuard::new(syscall::dup(cur_pid_fd, b"regs/env")?);
|
||||
let new_env_regs_fd = FdGuard::new(syscall::dup(new_pid_fd, b"regs/env")?);
|
||||
|
||||
let mut env_regs = syscall::EnvRegisters::default();
|
||||
let _ = syscall::read(*cur_env_regs_fd, &mut env_regs)?;
|
||||
let _ = syscall::write(*new_env_regs_fd, &env_regs)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe extern "sysv64" fn fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
}
|
||||
|
||||
unsafe extern "sysv64" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
let _ = syscall::close(new_pid_fd);
|
||||
}
|
||||
|
||||
asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
push rbx
|
||||
push rbp
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
sub rsp, 32
|
||||
|
||||
stmxcsr [rsp+16]
|
||||
fnstcw [rsp+24]
|
||||
|
||||
mov rdi, rsp
|
||||
call {fork_impl}
|
||||
|
||||
add rsp, 80
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
"] <= [fork_impl = sym fork_impl]);
|
||||
asmfunction!(__relibc_internal_fork_ret: ["
|
||||
mov rdi, [rsp]
|
||||
mov rsi, [rsp + 8]
|
||||
call {child_hook}
|
||||
|
||||
ldmxcsr [rsp+16]
|
||||
fldcw [rsp+24]
|
||||
|
||||
xor rax, rax
|
||||
|
||||
add rsp, 32
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbp
|
||||
pop rbx
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
"] <= [child_hook = sym child_hook]);
|
||||
asmfunction!(__relibc_internal_rlct_clone_ret: ["
|
||||
# Load registers
|
||||
pop rax
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop r8
|
||||
pop r9
|
||||
|
||||
sub rsp, 8
|
||||
|
||||
mov DWORD PTR [rsp], 0x00001F80
|
||||
ldmxcsr [rsp]
|
||||
mov WORD PTR [rsp], 0x037F
|
||||
fldcw [rsp]
|
||||
|
||||
add rsp, 8
|
||||
|
||||
# Call entry point
|
||||
call rax
|
||||
|
||||
ret
|
||||
"] <= []);
|
||||
|
||||
asmfunction!(__relibc_internal_sigentry: ["
|
||||
// Save some registers
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_rsp}], rsp
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_rax}], rax
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_rdx}], rdx
|
||||
|
||||
// First, select signal, always pick first available bit
|
||||
|
||||
// Read first signal word
|
||||
mov rax, fs:[{tcb_sc_off} + {sc_word}]
|
||||
mov rdx, rax
|
||||
shr rdx, 32
|
||||
and eax, edx
|
||||
bsf eax, eax
|
||||
jnz 2f
|
||||
|
||||
// Read second signal word
|
||||
mov rax, fs:[{tcb_sc_off} + {sc_word} + 8]
|
||||
mov rdx, rax
|
||||
shr rdx, 32
|
||||
and eax, edx
|
||||
bsf eax, eax
|
||||
jz 6f
|
||||
add eax, 32
|
||||
2:
|
||||
sub rsp, {REDZONE_SIZE}
|
||||
and rsp, -{STACK_ALIGN}
|
||||
|
||||
// By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or
|
||||
// not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then
|
||||
// skip the sigaltstack logic.
|
||||
mov edx, eax
|
||||
add edx, edx
|
||||
lea rdx, [{pctl_off_actions} + edx * 8]
|
||||
add rdx, fs:[{tcb_sa_off} + {sa_off_pctl}]
|
||||
|
||||
// scale factor 16 doesn't exist, so we premultiplied edx by 2
|
||||
bt qword ptr [rdx], 56
|
||||
jnc 4f
|
||||
|
||||
// Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent
|
||||
// to setting 'top' to usize::MAX and 'bottom' to 0.
|
||||
|
||||
// If current RSP is above altstack region, switch to altstack
|
||||
mov rdx, fs:[{tcb_sa_off} + {sa_altstack_top}]
|
||||
cmp rsp, rdx
|
||||
cmova rsp, rdx
|
||||
|
||||
// If current RSP is below altstack region, also switch to altstack
|
||||
cmp rsp, fs:[{tcb_sa_off} + {sa_altstack_bottom}]
|
||||
cmovbe rsp, rdx
|
||||
|
||||
.p2align 4
|
||||
4:
|
||||
// Now that we have a stack, we can finally start initializing the signal stack!
|
||||
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_rsp}]
|
||||
push fs:[{tcb_sc_off} + {sc_saved_rip}]
|
||||
push fs:[{tcb_sc_off} + {sc_saved_rflags}]
|
||||
|
||||
push rdi
|
||||
push rsi
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_rdx}]
|
||||
push rcx
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_rax}]
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push rbx
|
||||
push rbp
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
sub rsp, (29 + 16) * 16 // fxsave region minus available bytes
|
||||
fxsave64 [rsp + 16 * 16]
|
||||
|
||||
// TODO: self-modifying?
|
||||
cmp byte ptr [rip + {supports_avx}], 0
|
||||
je 5f
|
||||
|
||||
// Prefer vextractf128 over vextracti128 since the former only requires AVX version 1.
|
||||
vextractf128 [rsp + 15 * 16], ymm0, 1
|
||||
vextractf128 [rsp + 14 * 16], ymm1, 1
|
||||
vextractf128 [rsp + 13 * 16], ymm2, 1
|
||||
vextractf128 [rsp + 12 * 16], ymm3, 1
|
||||
vextractf128 [rsp + 11 * 16], ymm4, 1
|
||||
vextractf128 [rsp + 10 * 16], ymm5, 1
|
||||
vextractf128 [rsp + 9 * 16], ymm6, 1
|
||||
vextractf128 [rsp + 8 * 16], ymm7, 1
|
||||
vextractf128 [rsp + 7 * 16], ymm8, 1
|
||||
vextractf128 [rsp + 6 * 16], ymm9, 1
|
||||
vextractf128 [rsp + 5 * 16], ymm10, 1
|
||||
vextractf128 [rsp + 4 * 16], ymm11, 1
|
||||
vextractf128 [rsp + 3 * 16], ymm12, 1
|
||||
vextractf128 [rsp + 2 * 16], ymm13, 1
|
||||
vextractf128 [rsp + 16], ymm14, 1
|
||||
vextractf128 [rsp], ymm15, 1
|
||||
5:
|
||||
push rax // selected signal
|
||||
sub rsp, 8
|
||||
|
||||
mov rdi, rsp
|
||||
call {inner}
|
||||
|
||||
add rsp, 16
|
||||
|
||||
fxrstor64 [rsp]
|
||||
|
||||
cmp byte ptr [rip + {supports_avx}], 0
|
||||
je 6f
|
||||
|
||||
vinsertf128 ymm0, ymm0, [rsp + 15 * 16], 1
|
||||
vinsertf128 ymm1, ymm1, [rsp + 14 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 13 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 12 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 11 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 10 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 9 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 8 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 7 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 6 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 5 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 4 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 3 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 2 * 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp + 16], 1
|
||||
vinsertf128 ymm2, ymm2, [rsp], 1
|
||||
6:
|
||||
add rsp, (29 + 16) * 16
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbp
|
||||
pop rbx
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rax
|
||||
pop rcx
|
||||
pop rdx
|
||||
pop rsi
|
||||
pop rdi
|
||||
|
||||
popfq
|
||||
pop qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
|
||||
|
||||
// x86 lacks atomic instructions for setting both the stack and instruction pointer
|
||||
// simultaneously, except the slow microcoded IRETQ instruction. Thus, we let the arch_pre
|
||||
// function emulate atomicity between the pop rsp and indirect jump.
|
||||
|
||||
.globl __relibc_internal_sigentry_crit_first
|
||||
__relibc_internal_sigentry_crit_first:
|
||||
|
||||
pop rsp
|
||||
|
||||
.globl __relibc_internal_sigentry_crit_second
|
||||
__relibc_internal_sigentry_crit_second:
|
||||
jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
|
||||
6:
|
||||
ud2
|
||||
// Spurious signal
|
||||
"] <= [
|
||||
inner = sym inner_c,
|
||||
sa_tmp_rip = const offset_of!(SigArea, tmp_rip),
|
||||
sa_tmp_rsp = const offset_of!(SigArea, tmp_rsp),
|
||||
sa_tmp_rax = const offset_of!(SigArea, tmp_rax),
|
||||
sa_tmp_rdx = const offset_of!(SigArea, tmp_rdx),
|
||||
sa_altstack_top = const offset_of!(SigArea, altstack_top),
|
||||
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
|
||||
sc_saved_rflags = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||
sc_saved_rip = const offset_of!(Sigcontrol, saved_ip),
|
||||
sc_word = const offset_of!(Sigcontrol, word),
|
||||
tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
|
||||
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||
pctl_off_actions = const offset_of!(SigProcControl, actions),
|
||||
//pctl = sym PROC_CONTROL_STRUCT,
|
||||
sa_off_pctl = const offset_of!(SigArea, pctl),
|
||||
supports_avx = sym SUPPORTS_AVX,
|
||||
REDZONE_SIZE = const 128,
|
||||
STACK_ALIGN = const 16,
|
||||
]);
|
||||
|
||||
extern "C" {
|
||||
fn __relibc_internal_sigentry_crit_first();
|
||||
fn __relibc_internal_sigentry_crit_second();
|
||||
}
|
||||
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) {
|
||||
// It is impossible to update RSP and RIP atomically on x86_64, without using IRETQ, which is
|
||||
// almost as slow as calling a SIGRETURN syscall would be. Instead, we abuse the fact that
|
||||
// signals are disabled in the prologue of the signal trampoline, which allows us to emulate
|
||||
// atomicity inside the critical section, consisting of one instruction at 'crit_first', and
|
||||
// one at 'crit_second', see asm.
|
||||
|
||||
if stack.regs.rip == __relibc_internal_sigentry_crit_first as usize {
|
||||
// Reexecute pop rsp and jump steps. This case needs to be different from the one below,
|
||||
// since rsp has not been overwritten with the previous context's stack, just yet. At this
|
||||
// point, we know [rsp+0] contains the saved RSP, and [rsp-8] contains the saved RIP.
|
||||
let stack_ptr = stack.regs.rsp as *const usize;
|
||||
stack.regs.rsp = stack_ptr.read();
|
||||
stack.regs.rip = stack_ptr.sub(1).read();
|
||||
} else if stack.regs.rip == __relibc_internal_sigentry_crit_second as usize {
|
||||
// Almost finished, just reexecute the jump before tmp_rip is overwritten by this
|
||||
// deeper-level signal.
|
||||
stack.regs.rip = area.tmp_rip;
|
||||
}
|
||||
}
|
||||
|
||||
static SUPPORTS_AVX: AtomicU8 = AtomicU8::new(1); // FIXME
|
||||
|
||||
pub unsafe fn manually_enter_trampoline() {
|
||||
let c = &Tcb::current().unwrap().os_specific.control;
|
||||
c.control_flags.store(c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release);
|
||||
c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86?
|
||||
|
||||
core::arch::asm!("
|
||||
lea rax, [rip + 2f]
|
||||
mov fs:[{tcb_sc_off} + {sc_saved_rip}], rax
|
||||
jmp __relibc_internal_sigentry
|
||||
2:
|
||||
",
|
||||
out("rax") _,
|
||||
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
|
||||
sc_saved_rip = const offset_of!(Sigcontrol, saved_ip),
|
||||
);
|
||||
}
|
||||
|
||||
/// Get current stack pointer, weak granularity guarantees.
|
||||
pub fn current_sp() -> usize {
|
||||
let sp: usize;
|
||||
unsafe {
|
||||
core::arch::asm!("mov {}, rsp", out(reg) sp);
|
||||
}
|
||||
sp
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
#![no_std]
|
||||
#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell)]
|
||||
#![forbid(unreachable_patterns)]
|
||||
|
||||
use generic_rt::{ExpectTlsFree, GenericTcb};
|
||||
|
||||
use self::signal::RtSigarea;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! asmfunction(
|
||||
($name:ident $(-> $ret:ty)? : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => {
|
||||
::core::arch::global_asm!(concat!("
|
||||
.p2align 4
|
||||
.section .text.", stringify!($name), ", \"ax\", @progbits
|
||||
.globl ", stringify!($name), "
|
||||
.type ", stringify!($name), ", @function
|
||||
", stringify!($name), ":
|
||||
", $($asmstmt, "\n",)* "
|
||||
.size ", stringify!($name), ", . - ", stringify!($name), "
|
||||
"), $($decl = $(sym $symname)?$(const $constval)?),*);
|
||||
|
||||
extern "C" {
|
||||
pub fn $name() $(-> $ret)?;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
pub mod arch;
|
||||
pub mod proc;
|
||||
|
||||
// TODO: Replace auxvs with a non-stack-based interface, but keep getauxval for compatibility
|
||||
#[path = "../../src/platform/auxv_defs.rs"]
|
||||
pub mod auxv_defs;
|
||||
|
||||
pub mod signal;
|
||||
pub mod sync;
|
||||
pub mod sys;
|
||||
pub mod thread;
|
||||
|
||||
pub type Tcb = GenericTcb<RtSigarea>;
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Redox aarch64
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub unsafe fn tcb_activate(tls_end: usize, tls_len: usize) {
|
||||
// Uses ABI page
|
||||
let abi_ptr = tls_end - tls_len - 16;
|
||||
core::ptr::write(abi_ptr as *mut usize, tls_end);
|
||||
core::arch::asm!(
|
||||
"msr tpidr_el0, {}",
|
||||
in(reg) abi_ptr,
|
||||
);
|
||||
}
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Redox x86
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub unsafe fn tcb_activate(tls_end: usize, _tls_len: usize) {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = syscall::open(
|
||||
"thisproc:current/regs/env",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR,
|
||||
)
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
|
||||
let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase");
|
||||
|
||||
env.gsbase = tls_end as u32;
|
||||
|
||||
let _ = syscall::write(file, &env).expect_notls("failed to write gsbase");
|
||||
|
||||
let _ = syscall::close(file);
|
||||
}
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Redox x86_64
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub unsafe fn tcb_activate(tls_end_and_tcb_start: usize, _tls_len: usize) {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = syscall::open(
|
||||
"thisproc:current/regs/env",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR,
|
||||
)
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
|
||||
let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase");
|
||||
|
||||
env.fsbase = tls_end_and_tcb_start as u64;
|
||||
|
||||
let _ = syscall::write(file, &env).expect_notls("failed to write fsbase");
|
||||
|
||||
let _ = syscall::close(file);
|
||||
}
|
||||
|
||||
/// Initialize redox-rt in situations where relibc is not used
|
||||
pub fn initialize_freestanding() {
|
||||
// TODO: This code is a hack! Integrate the ld_so TCB code into generic-rt, and then use that
|
||||
// (this function will need pointers to the ELF structs normally passed in auxvs), so the TCB
|
||||
// is initialized properly.
|
||||
|
||||
// TODO: TLS
|
||||
let page = unsafe {
|
||||
&mut *(syscall::fmap(!0, &syscall::Map {
|
||||
offset: 0,
|
||||
size: syscall::PAGE_SIZE,
|
||||
flags: syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE | syscall::MapFlags::MAP_PRIVATE,
|
||||
address: 0,
|
||||
}).unwrap() as *mut Tcb)
|
||||
};
|
||||
page.tcb_ptr = page;
|
||||
page.tcb_len = syscall::PAGE_SIZE;
|
||||
page.tls_end = (page as *mut Tcb).cast();
|
||||
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
unsafe {
|
||||
tcb_activate(page as *mut Tcb as usize, 0)
|
||||
}
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
unsafe {
|
||||
let abi_ptr = core::ptr::addr_of_mut!(page.tcb_ptr);
|
||||
core::arch::asm!("msr tpidr_el0, {}", in(reg) abi_ptr);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(array_chunks, int_roundings, let_chains, slice_ptr_get)]
|
||||
#![forbid(unreachable_patterns)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use core::mem::size_of;
|
||||
use crate::{arch::*, auxv_defs::*};
|
||||
|
||||
use alloc::{boxed::Box, collections::BTreeMap, vec};
|
||||
|
||||
@@ -27,9 +22,6 @@ use syscall::{
|
||||
PAGE_SIZE, PROT_EXEC, PROT_READ, PROT_WRITE,
|
||||
};
|
||||
|
||||
pub use self::arch::*;
|
||||
mod arch;
|
||||
|
||||
pub enum FexecResult {
|
||||
Normal {
|
||||
addrspace_handle: FdGuard,
|
||||
@@ -429,20 +421,17 @@ where
|
||||
|
||||
push(argc)?;
|
||||
|
||||
unsafe {
|
||||
deactivate_tcb(*open_via_dup)?;
|
||||
if let Ok(sighandler_fd) = syscall::dup(*open_via_dup, b"sighandler").map(FdGuard::new) {
|
||||
let _ = syscall::write(*sighandler_fd, &SetSighandlerData {
|
||||
user_handler: 0,
|
||||
excp_handler: 0,
|
||||
thread_control_addr: 0,
|
||||
proc_control_addr: 0,
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
let current_sigaction_fd = FdGuard::new(syscall::dup(*open_via_dup, b"sigactions")?);
|
||||
let empty_sigaction_fd = FdGuard::new(syscall::dup(*current_sigaction_fd, b"empty")?);
|
||||
let sigaction_selection_fd =
|
||||
FdGuard::new(syscall::dup(*open_via_dup, b"current-sigactions")?);
|
||||
|
||||
let _ = syscall::write(
|
||||
*sigaction_selection_fd,
|
||||
&usize::to_ne_bytes(*empty_sigaction_fd),
|
||||
)?;
|
||||
unsafe {
|
||||
deactivate_tcb(*open_via_dup)?;
|
||||
}
|
||||
|
||||
// TODO: Restore old name if exec failed?
|
||||
@@ -713,55 +702,26 @@ pub fn create_set_addr_space_buf(
|
||||
buf
|
||||
}
|
||||
|
||||
#[path = "../../../auxv_defs.rs"]
|
||||
pub mod auxv_defs;
|
||||
|
||||
use auxv_defs::*;
|
||||
|
||||
/// Spawns a new context which will not share the same address space as the current one. File
|
||||
/// descriptors from other schemes are reobtained with `dup`, and grants referencing such file
|
||||
/// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW.
|
||||
pub fn fork_impl() -> Result<usize> {
|
||||
let mut old_mask = 0_u64;
|
||||
syscall::sigprocmask(syscall::SIG_SETMASK, None, Some(&mut old_mask))?;
|
||||
let mut old_mask = crate::signal::get_sigmask()?;
|
||||
let pid = unsafe { Error::demux(__relibc_internal_fork_wrapper())? };
|
||||
|
||||
if pid == 0 {
|
||||
syscall::sigprocmask(syscall::SIG_SETMASK, Some(&old_mask), None)?;
|
||||
crate::signal::set_sigmask(Some(old_mask), None)?;
|
||||
}
|
||||
Ok(pid)
|
||||
}
|
||||
|
||||
fn fork_inner(initial_rsp: *mut usize) -> Result<usize> {
|
||||
pub fn fork_inner(initial_rsp: *mut usize) -> Result<usize> {
|
||||
let (cur_filetable_fd, new_pid_fd, new_pid);
|
||||
|
||||
{
|
||||
let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?);
|
||||
(new_pid_fd, new_pid) = new_context()?;
|
||||
|
||||
// Reuse the same sigaltstack and signal entry (all memory will be re-mapped CoW later).
|
||||
{
|
||||
let cur_sighandler_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sighandler")?);
|
||||
let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?);
|
||||
|
||||
let mut sighandler_buf = SetSighandlerData::default();
|
||||
|
||||
let _ = syscall::read(*cur_sighandler_fd, &mut sighandler_buf)?;
|
||||
let _ = syscall::write(*new_sighandler_fd, &sighandler_buf)?;
|
||||
}
|
||||
|
||||
// Reuse the same sigactions (by value).
|
||||
{
|
||||
let cur_sigaction_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sigactions")?);
|
||||
let new_sigaction_fd = FdGuard::new(syscall::dup(*cur_sigaction_fd, b"copy")?);
|
||||
let new_sigaction_sel_fd =
|
||||
FdGuard::new(syscall::dup(*new_pid_fd, b"current-sigactions")?);
|
||||
|
||||
let _ = syscall::write(
|
||||
*new_sigaction_sel_fd,
|
||||
&usize::to_ne_bytes(*new_sigaction_fd),
|
||||
)?;
|
||||
}
|
||||
copy_str(*cur_pid_fd, *new_pid_fd, "name")?;
|
||||
|
||||
// Copy existing files into new file table, but do not reuse the same file table (i.e. new
|
||||
@@ -808,7 +768,7 @@ fn fork_inner(initial_rsp: *mut usize) -> Result<usize> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut buf;
|
||||
let buf;
|
||||
|
||||
// TODO: write! using some #![no_std] Cursor type (tracking the length)?
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
@@ -851,6 +811,17 @@ fn fork_inner(initial_rsp: *mut usize) -> Result<usize> {
|
||||
);
|
||||
let _ = syscall::write(*new_addr_space_sel_fd, &buf)?;
|
||||
}
|
||||
{
|
||||
// Reuse the same sigaltstack and signal entry (all memory will be re-mapped CoW later).
|
||||
//
|
||||
// Do this after the address space is cloned, since the kernel will get a shared
|
||||
// reference to the TCB and whatever pages stores the signal proc control struct.
|
||||
{
|
||||
let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?);
|
||||
let _ = syscall::write(*new_sighandler_fd, &crate::signal::current_setsighandler_struct())?;
|
||||
}
|
||||
|
||||
}
|
||||
copy_env_regs(*cur_pid_fd, *new_pid_fd)?;
|
||||
}
|
||||
// Copy the file table. We do this last to ensure that all previously used file descriptors are
|
||||
@@ -0,0 +1,496 @@
|
||||
use core::cell::{Cell, UnsafeCell};
|
||||
use core::ffi::c_int;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use syscall::{RawAction, ENOMEM, EPERM, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ};
|
||||
use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH, data::AtomicU64};
|
||||
|
||||
use crate::{arch::*, Tcb};
|
||||
use crate::sync::Mutex;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
|
||||
|
||||
pub fn sighandler_function() -> usize {
|
||||
// TODO: HWCAP?
|
||||
|
||||
__relibc_internal_sigentry as usize
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SigStack {
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
|
||||
_pad: [usize; 1], // pad to 16 bytes alignment
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
_pad: [usize; 3], // pad to 16 bytes alignment
|
||||
|
||||
sig_num: usize,
|
||||
|
||||
// x86_64: 864 bytes
|
||||
// i686: 512 bytes
|
||||
// aarch64: 272 bytes (SIMD TODO)
|
||||
pub regs: ArchIntRegs,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn inner(stack: &mut SigStack) {
|
||||
let os = &Tcb::current().unwrap().os_specific;
|
||||
|
||||
let sig_idx = stack.sig_num;
|
||||
|
||||
// Commenting out this line will stress test how the signal code responds to 'interrupt spraying'.
|
||||
os.control.word[sig_idx / 32].fetch_and(!(1 << (sig_idx % 32)), Ordering::Relaxed);
|
||||
|
||||
// asm counts from 0
|
||||
stack.sig_num += 1;
|
||||
|
||||
arch_pre(stack, &mut *os.arch.get());
|
||||
|
||||
let sigaction = {
|
||||
let mut guard = SIGACTIONS_LOCK.lock();
|
||||
let action = convert_old(&PROC_CONTROL_STRUCT.actions[stack.sig_num - 1]);
|
||||
if action.flags.contains(SigactionFlags::RESETHAND) {
|
||||
// TODO: other things that must be set
|
||||
drop(guard);
|
||||
sigaction(stack.sig_num as u8, Some(&Sigaction {
|
||||
kind: SigactionKind::Default,
|
||||
mask: 0,
|
||||
flags: SigactionFlags::empty(),
|
||||
}), None);
|
||||
}
|
||||
action
|
||||
};
|
||||
|
||||
let handler = match sigaction.kind {
|
||||
SigactionKind::Ignore => {
|
||||
panic!("ctl {:x?} signal {}", os.control, stack.sig_num)
|
||||
}
|
||||
SigactionKind::Default => {
|
||||
syscall::exit(stack.sig_num);
|
||||
unreachable!();
|
||||
}
|
||||
SigactionKind::Handled { handler } => handler,
|
||||
};
|
||||
|
||||
// Set sigmask to sa_mask and unmark the signal as pending.
|
||||
let prev_sigallow_lo = os.control.word[0].load(Ordering::Relaxed) >> 32;
|
||||
let prev_sigallow_hi = os.control.word[1].load(Ordering::Relaxed) >> 32;
|
||||
let prev_sigallow = prev_sigallow_lo | (prev_sigallow_hi << 32);
|
||||
|
||||
let mut sigallow_inside = !sigaction.mask & prev_sigallow;
|
||||
if !sigaction.flags.contains(SigactionFlags::NODEFER) {
|
||||
sigallow_inside &= !sig_bit(stack.sig_num);
|
||||
}
|
||||
let sigallow_inside_lo = sigallow_inside & 0xffff_ffff;
|
||||
let sigallow_inside_hi = sigallow_inside >> 32;
|
||||
|
||||
//let _ = syscall::write(1, &alloc::format!("WORD0 {:x?}\n", os.control.word).as_bytes());
|
||||
let prev_w0 = os.control.word[0].fetch_add((sigallow_inside_lo << 32).wrapping_sub(prev_sigallow_lo << 32), Ordering::Relaxed);
|
||||
let prev_w1 = os.control.word[1].fetch_add((sigallow_inside_hi << 32).wrapping_sub(prev_sigallow_hi << 32), Ordering::Relaxed);
|
||||
//let _ = syscall::write(1, &alloc::format!("WORD1 {:x?}\n", os.control.word).as_bytes());
|
||||
|
||||
// TODO: If sa_mask caused signals to be unblocked, deliver one or all of those first?
|
||||
|
||||
// Re-enable signals again.
|
||||
let control_flags = &os.control.control_flags;
|
||||
control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release);
|
||||
core::sync::atomic::compiler_fence(Ordering::Acquire);
|
||||
|
||||
// Call handler, either sa_handler or sa_siginfo depending on flag.
|
||||
if sigaction.flags.contains(SigactionFlags::SIGINFO) && let Some(sigaction) = handler.sigaction {
|
||||
//let _ = syscall::write(1, alloc::format!("SIGACTION {:p}\n", sigaction).as_bytes());
|
||||
sigaction(stack.sig_num as c_int, core::ptr::null_mut(), core::ptr::null_mut());
|
||||
} else if let Some(handler) = handler.handler {
|
||||
//let _ = syscall::write(1, alloc::format!("HANDLER {:p}\n", handler).as_bytes());
|
||||
handler(stack.sig_num as c_int);
|
||||
}
|
||||
//let _ = syscall::write(1, alloc::format!("RETURNED HANDLER\n").as_bytes());
|
||||
|
||||
// Disable signals while we modify the sigmask again
|
||||
control_flags.store(control_flags.load(Ordering::Relaxed) | SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release);
|
||||
core::sync::atomic::compiler_fence(Ordering::Acquire);
|
||||
|
||||
// Update allowset again.
|
||||
//let _ = syscall::write(1, &alloc::format!("WORD2 {:x?}\n", os.control.word).as_bytes());
|
||||
|
||||
let prev_w0 = os.control.word[0].fetch_add((prev_sigallow_lo << 32).wrapping_sub(sigallow_inside_lo << 32), Ordering::Relaxed);
|
||||
let prev_w1 = os.control.word[1].fetch_add((prev_sigallow_hi << 32).wrapping_sub(sigallow_inside_hi << 32), Ordering::Relaxed);
|
||||
//let _ = syscall::write(1, &alloc::format!("WORD3 {:x?}\n", os.control.word).as_bytes());
|
||||
|
||||
// TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered
|
||||
// here? And would it be possible to tail-call-optimize that?
|
||||
|
||||
//let _ = syscall::write(1, alloc::format!("will return to {:x?}\n", stack.regs.eip).as_bytes());
|
||||
|
||||
// And re-enable them again
|
||||
control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release);
|
||||
core::sync::atomic::compiler_fence(Ordering::Acquire);
|
||||
}
|
||||
#[cfg(not(target_arch = "x86"))]
|
||||
pub(crate) unsafe extern "C" fn inner_c(stack: usize) {
|
||||
inner(&mut *(stack as *mut SigStack))
|
||||
}
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub(crate) unsafe extern "fastcall" fn inner_fastcall(stack: usize) {
|
||||
inner(&mut *(stack as *mut SigStack))
|
||||
}
|
||||
|
||||
pub fn get_sigmask() -> Result<u64> {
|
||||
let mut mask = 0;
|
||||
modify_sigmask(Some(&mut mask), Option::<fn(u32, bool) -> u32>::None)?;
|
||||
Ok(mask)
|
||||
}
|
||||
pub fn set_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> {
|
||||
modify_sigmask(old, new.map(move |newmask| move |_, upper| if upper { newmask >> 32 } else { newmask } as u32))
|
||||
}
|
||||
pub fn or_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> {
|
||||
// Parsing nightmare... :)
|
||||
modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask | if upper { newmask >> 32 } else { newmask } as u32))
|
||||
}
|
||||
pub fn andn_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> {
|
||||
modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask & !if upper { newmask >> 32 } else { newmask } as u32))
|
||||
}
|
||||
fn modify_sigmask(old: Option<&mut u64>, op: Option<impl FnMut(u32, bool) -> u32>) -> Result<()> {
|
||||
let _guard = tmp_disable_signals();
|
||||
let ctl = current_sigctl();
|
||||
|
||||
let mut words = ctl.word.each_ref().map(|w| w.load(Ordering::Relaxed));
|
||||
|
||||
if let Some(old) = old {
|
||||
*old = !combine_allowset(words);
|
||||
}
|
||||
let Some(mut op) = op else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let mut can_raise = 0;
|
||||
let mut cant_raise = 0;
|
||||
|
||||
//let _ = syscall::write(1, &alloc::format!("OLDWORD {:x?}\n", ctl.word).as_bytes());
|
||||
for i in 0..2 {
|
||||
let old_allow_bits = words[i] & 0xffff_ffff_0000_0000;
|
||||
let new_allow_bits = u64::from(!op(!((old_allow_bits >> 32) as u32), i == 1)) << 32;
|
||||
|
||||
ctl.word[i].fetch_add(new_allow_bits.wrapping_sub(old_allow_bits), Ordering::Relaxed);
|
||||
}
|
||||
//let _ = syscall::write(1, &alloc::format!("NEWWORD {:x?}\n", ctl.word).as_bytes());
|
||||
|
||||
// TODO: Prioritize cant_raise realtime signals?
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub enum SigactionKind {
|
||||
#[default]
|
||||
Default,
|
||||
|
||||
Ignore,
|
||||
Handled {
|
||||
handler: SignalHandler,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct Sigaction {
|
||||
pub kind: SigactionKind,
|
||||
pub mask: u64,
|
||||
pub flags: SigactionFlags,
|
||||
}
|
||||
|
||||
impl Sigaction {
|
||||
fn ip(&self) -> usize {
|
||||
unsafe {
|
||||
match self.kind {
|
||||
SigactionKind::Handled { handler } => if self.flags.contains(SigactionFlags::SIGINFO) {
|
||||
handler.sigaction.map_or(0, |a| a as usize)
|
||||
} else {
|
||||
handler.handler.map_or(0, |a| a as usize)
|
||||
}
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MASK_DONTCARE: u64 = !0;
|
||||
|
||||
fn convert_old(action: &RawAction) -> Sigaction {
|
||||
let old_first = action.first.load(Ordering::Relaxed);
|
||||
let old_mask = action.user_data.load(Ordering::Relaxed);
|
||||
|
||||
let handler = (old_first & !(u64::from(STORED_FLAGS) << 32)) as usize;
|
||||
let flags = SigactionFlags::from_bits_retain(((old_first >> 32) as u32) & STORED_FLAGS);
|
||||
|
||||
let kind = if handler == default_handler as usize {
|
||||
SigactionKind::Default
|
||||
} else if flags.contains(SigactionFlags::IGNORED) {
|
||||
SigactionKind::Ignore
|
||||
} else {
|
||||
SigactionKind::Handled { handler: unsafe { core::mem::transmute(handler as usize) } }
|
||||
};
|
||||
|
||||
Sigaction {
|
||||
mask: old_mask,
|
||||
flags,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> {
|
||||
if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let _sigguard = tmp_disable_signals();
|
||||
let ctl = current_sigctl();
|
||||
|
||||
let _guard = SIGACTIONS_LOCK.lock();
|
||||
|
||||
let action = &PROC_CONTROL_STRUCT.actions[usize::from(signal) - 1];
|
||||
|
||||
if let Some(old) = old {
|
||||
*old = convert_old(action);
|
||||
}
|
||||
|
||||
let Some(new) = new else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let explicit_handler = new.ip();
|
||||
|
||||
let (mask, flags, handler) = match (usize::from(signal), new.kind) {
|
||||
(_, SigactionKind::Ignore) | (SIGURG | SIGWINCH, SigactionKind::Default) => {
|
||||
// TODO: POSIX specifies that pending signals shall be discarded if set to SIG_IGN by
|
||||
// sigaction.
|
||||
// TODO: handle tmp_disable_signals
|
||||
(MASK_DONTCARE, SigactionFlags::IGNORED, if matches!(new.kind, SigactionKind::Default) {
|
||||
default_handler as usize
|
||||
} else {
|
||||
0
|
||||
})
|
||||
}
|
||||
// TODO: Handle pending signals before these flags are set.
|
||||
(SIGTSTP | SIGTTOU | SIGTTIN, SigactionKind::Default) => (MASK_DONTCARE, SigactionFlags::SIG_SPECIFIC, default_handler as usize),
|
||||
(SIGCHLD, SigactionKind::Default) => {
|
||||
let nocldstop_bit = new.flags & SigactionFlags::SIG_SPECIFIC;
|
||||
(MASK_DONTCARE, SigactionFlags::IGNORED | nocldstop_bit, default_handler as usize)
|
||||
}
|
||||
|
||||
(_, SigactionKind::Default) => {
|
||||
(new.mask, new.flags, default_handler as usize)
|
||||
},
|
||||
(_, SigactionKind::Handled { .. }) => {
|
||||
(new.mask, new.flags, explicit_handler)
|
||||
}
|
||||
};
|
||||
let new_first = (handler as u64) | (u64::from(flags.bits() & STORED_FLAGS) << 32);
|
||||
action.first.store(new_first, Ordering::Relaxed);
|
||||
action.user_data.store(mask, Ordering::Relaxed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn current_sigctl() -> &'static Sigcontrol {
|
||||
&unsafe { Tcb::current() }.unwrap().os_specific.control
|
||||
}
|
||||
|
||||
pub struct TmpDisableSignalsGuard { _inner: () }
|
||||
|
||||
pub fn tmp_disable_signals() -> TmpDisableSignalsGuard {
|
||||
unsafe {
|
||||
let ctl = ¤t_sigctl().control_flags;
|
||||
ctl.store(ctl.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release);
|
||||
core::sync::atomic::compiler_fence(Ordering::Acquire);
|
||||
|
||||
// TODO: fence?
|
||||
(*Tcb::current().unwrap().os_specific.arch.get()).disable_signals_depth += 1;
|
||||
}
|
||||
|
||||
TmpDisableSignalsGuard { _inner: () }
|
||||
}
|
||||
impl Drop for TmpDisableSignalsGuard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let depth = &mut (*Tcb::current().unwrap().os_specific.arch.get()).disable_signals_depth;
|
||||
*depth -= 1;
|
||||
|
||||
if *depth == 0 {
|
||||
let ctl = ¤t_sigctl().control_flags;
|
||||
ctl.store(ctl.load(Ordering::Relaxed) & !syscall::flag::INHIBIT_DELIVERY.bits(), Ordering::Release);
|
||||
core::sync::atomic::compiler_fence(Ordering::Acquire);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
// Some flags are ignored by the rt, but they match relibc's 1:1 to simplify conversion.
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct SigactionFlags: u32 {
|
||||
const NOCLDWAIT = 2;
|
||||
const RESTORER = 4;
|
||||
const SIGINFO = 0x0200_0000;
|
||||
const ONSTACK = 0x0400_0000;
|
||||
const RESTART = 0x0800_0000;
|
||||
const NODEFER = 0x1000_0000;
|
||||
const RESETHAND = 0x2000_0000;
|
||||
const SIG_SPECIFIC = 0x4000_0000;
|
||||
const IGNORED = 0x8000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
const STORED_FLAGS: u32 = 0xfe00_0000;
|
||||
|
||||
fn default_handler(sig: c_int) {
|
||||
syscall::exit(sig as usize);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub union SignalHandler {
|
||||
pub handler: Option<extern "C" fn(c_int)>,
|
||||
pub sigaction: Option<unsafe extern "C" fn(c_int, *const (), *mut ())>,
|
||||
}
|
||||
|
||||
static SIGACTIONS_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
pub(crate) static PROC_CONTROL_STRUCT: SigProcControl = SigProcControl {
|
||||
pending: AtomicU64::new(0),
|
||||
actions: [const {
|
||||
RawAction {
|
||||
first: AtomicU64::new(0),
|
||||
user_data: AtomicU64::new(0),
|
||||
}
|
||||
}; 64],
|
||||
};
|
||||
|
||||
fn combine_allowset([lo, hi]: [u64; 2]) -> u64 {
|
||||
(lo >> 32) | ((hi >> 32) << 32)
|
||||
}
|
||||
|
||||
const fn sig_bit(sig: usize) -> u64 {
|
||||
//assert_ne!(sig, 32);
|
||||
//assert_ne!(sig, 0);
|
||||
1 << (sig - 1)
|
||||
}
|
||||
|
||||
pub fn setup_sighandler(area: &RtSigarea) {
|
||||
{
|
||||
let mut sigactions = SIGACTIONS_LOCK.lock();
|
||||
for (sig_idx, action) in PROC_CONTROL_STRUCT.actions.iter().enumerate() {
|
||||
let sig = sig_idx + 1;
|
||||
let bits = if matches!(sig, SIGTSTP | SIGTTIN | SIGTTOU) {
|
||||
SigactionFlags::SIG_SPECIFIC
|
||||
} else if matches!(sig, SIGCHLD | SIGURG | SIGWINCH) {
|
||||
SigactionFlags::IGNORED
|
||||
} else {
|
||||
SigactionFlags::empty()
|
||||
};
|
||||
action.first.store((u64::from(bits.bits()) << 32) | default_handler as u64, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
let arch = unsafe { &mut *area.arch.get() };
|
||||
{
|
||||
// The asm decides whether to use the altstack, based on whether the saved stack pointer
|
||||
// was already on that stack. Thus, setting the altstack to the entire address space, is
|
||||
// equivalent to not using any altstack at all (the default).
|
||||
arch.altstack_top = usize::MAX;
|
||||
arch.altstack_bottom = 0;
|
||||
#[cfg(not(target_arch = "x86"))]
|
||||
{
|
||||
arch.pctl = core::ptr::addr_of!(PROC_CONTROL_STRUCT) as usize;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx;
|
||||
CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
let data = current_setsighandler_struct();
|
||||
|
||||
let fd = syscall::open(
|
||||
"thisproc:current/sighandler",
|
||||
syscall::O_WRONLY | syscall::O_CLOEXEC,
|
||||
)
|
||||
.expect("failed to open thisproc:current/sighandler");
|
||||
syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler");
|
||||
let _ = syscall::close(fd);
|
||||
|
||||
// TODO: Inherited set of ignored signals
|
||||
set_sigmask(Some(0), None);
|
||||
}
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RtSigarea {
|
||||
pub control: Sigcontrol,
|
||||
pub arch: UnsafeCell<crate::arch::SigArea>,
|
||||
}
|
||||
pub fn current_setsighandler_struct() -> SetSighandlerData {
|
||||
SetSighandlerData {
|
||||
user_handler: sighandler_function(),
|
||||
excp_handler: 0, // TODO
|
||||
thread_control_addr: core::ptr::addr_of!(unsafe { Tcb::current() }.unwrap().os_specific.control) as usize,
|
||||
proc_control_addr: &PROC_CONTROL_STRUCT as *const SigProcControl as usize,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, PartialEq)]
|
||||
pub enum Sigaltstack {
|
||||
#[default]
|
||||
Disabled,
|
||||
|
||||
Enabled { onstack: bool, base: *mut (), size: usize },
|
||||
}
|
||||
pub unsafe fn sigaltstack(new: Option<&Sigaltstack>, old_out: Option<&mut Sigaltstack>) -> Result<()> {
|
||||
let _g = tmp_disable_signals();
|
||||
let tcb = &mut *Tcb::current().unwrap().os_specific.arch.get();
|
||||
|
||||
let old = if tcb.altstack_bottom == 0 && tcb.altstack_top == usize::MAX {
|
||||
Sigaltstack::Disabled
|
||||
} else {
|
||||
Sigaltstack::Enabled {
|
||||
base: tcb.altstack_bottom as *mut (),
|
||||
size: tcb.altstack_top - tcb.altstack_bottom,
|
||||
onstack: (tcb.altstack_bottom..tcb.altstack_top).contains(&crate::arch::current_sp()),
|
||||
}
|
||||
};
|
||||
|
||||
if matches!(old, Sigaltstack::Enabled { onstack: true, .. }) && new != Some(&old) {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
|
||||
if let Some(old_out) = old_out {
|
||||
*old_out = old;
|
||||
}
|
||||
if let Some(new) = new {
|
||||
match *new {
|
||||
Sigaltstack::Disabled => {
|
||||
tcb.altstack_bottom = 0;
|
||||
tcb.altstack_top = usize::MAX;
|
||||
}
|
||||
Sigaltstack::Enabled { onstack: true, .. } => return Err(Error::new(EINVAL)),
|
||||
Sigaltstack::Enabled { base, size, onstack: false } => {
|
||||
if size < MIN_SIGALTSTACK_SIZE {
|
||||
return Err(Error::new(ENOMEM));
|
||||
}
|
||||
|
||||
tcb.altstack_bottom = base as usize;
|
||||
tcb.altstack_top = base as usize + size;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub const MIN_SIGALTSTACK_SIZE: usize = 8192;
|
||||
|
||||
pub fn currently_pending() -> u64 {
|
||||
let control = &unsafe { Tcb::current().unwrap() }.os_specific.control;
|
||||
let w0 = control.word[0].load(Ordering::Relaxed);
|
||||
let w1 = control.word[1].load(Ordering::Relaxed);
|
||||
let pending_blocked_lo = w0 & !(w0 >> 32);
|
||||
let pending_unblocked_hi = w1 & !(w0 >> 32);
|
||||
pending_blocked_lo | (pending_unblocked_hi << 32)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// TODO: Share code for simple futex-based mutex between relibc's Mutex<()> and this.
|
||||
|
||||
use core::cell::UnsafeCell;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
pub struct Mutex<T> {
|
||||
pub lockword: AtomicU32,
|
||||
pub inner: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
const UNLOCKED: u32 = 0;
|
||||
const LOCKED: u32 = 1;
|
||||
const WAITING: u32 = 2;
|
||||
|
||||
unsafe impl<T: Send> Send for Mutex<T> {}
|
||||
unsafe impl<T: Send> Sync for Mutex<T> {}
|
||||
|
||||
impl<T> Mutex<T> {
|
||||
pub const fn new(t: T) -> Self {
|
||||
Self {
|
||||
lockword: AtomicU32::new(0),
|
||||
inner: UnsafeCell::new(t),
|
||||
}
|
||||
}
|
||||
pub fn lock(&self) -> MutexGuard<'_, T> {
|
||||
while self.lockword.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed).is_err() {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
MutexGuard { lock: self }
|
||||
}
|
||||
}
|
||||
pub struct MutexGuard<'l, T> {
|
||||
lock: &'l Mutex<T>,
|
||||
}
|
||||
impl<T> Deref for MutexGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.lock.inner.get() }
|
||||
}
|
||||
}
|
||||
impl<T> DerefMut for MutexGuard<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.lock.inner.get() }
|
||||
}
|
||||
}
|
||||
impl<T> Drop for MutexGuard<'_, T> {
|
||||
fn drop(&mut self) {
|
||||
self.lock.lockword.store(UNLOCKED, Ordering::Release);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use syscall::error::{Result, Error, EINTR};
|
||||
|
||||
use crate::arch::manually_enter_trampoline;
|
||||
use crate::signal::tmp_disable_signals;
|
||||
|
||||
#[inline]
|
||||
fn wrapper(mut f: impl FnMut() -> Result<usize>) -> Result<usize> {
|
||||
loop {
|
||||
let res = f();
|
||||
|
||||
if res == Err(Error::new(EINTR)) {
|
||||
unsafe {
|
||||
manually_enter_trampoline();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: uninitialized memory?
|
||||
#[inline]
|
||||
pub fn posix_read(fd: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
wrapper(|| syscall::read(fd, buf))
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_write(fd: usize, buf: &[u8]) -> Result<usize> {
|
||||
wrapper(|| syscall::write(fd, buf))
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_kill(pid: usize, sig: usize) -> Result<()> {
|
||||
match wrapper(|| syscall::kill(pid, sig)) {
|
||||
Ok(_) | Err(Error { errno: EINTR }) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_killpg(pgrp: usize, sig: usize) -> Result<()> {
|
||||
match wrapper(|| syscall::kill(usize::wrapping_neg(pgrp), sig)) {
|
||||
Ok(_) | Err(Error { errno: EINTR }) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
use syscall::SetSighandlerData;
|
||||
use syscall::{Result, O_CLOEXEC};
|
||||
|
||||
use crate::arch::*;
|
||||
use crate::proc::*;
|
||||
use crate::signal::sighandler_function;
|
||||
|
||||
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
|
||||
pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result<usize> {
|
||||
let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?);
|
||||
let (new_pid_fd, new_pid) = new_context()?;
|
||||
|
||||
copy_str(*cur_pid_fd, *new_pid_fd, "name")?;
|
||||
|
||||
// Inherit existing address space
|
||||
{
|
||||
let cur_addr_space_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"addrspace")?);
|
||||
let new_addr_space_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?);
|
||||
|
||||
let buf = create_set_addr_space_buf(
|
||||
*cur_addr_space_fd,
|
||||
__relibc_internal_rlct_clone_ret as usize,
|
||||
stack as usize,
|
||||
);
|
||||
let _ = syscall::write(*new_addr_space_sel_fd, &buf)?;
|
||||
}
|
||||
|
||||
// Inherit reference to file table
|
||||
{
|
||||
let cur_filetable_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"filetable")?);
|
||||
let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-filetable")?);
|
||||
|
||||
let _ = syscall::write(
|
||||
*new_filetable_sel_fd,
|
||||
&usize::to_ne_bytes(*cur_filetable_fd),
|
||||
)?;
|
||||
}
|
||||
|
||||
// Since the signal handler is not yet initialized, signals specifically targeting the thread
|
||||
// (relibc is only required to implement thread-specific signals that already originate from
|
||||
// the same process) will be discarded. Process-specific signals will ignore this new thread,
|
||||
// until it has initialized its own signal handler.
|
||||
|
||||
// Unblock context.
|
||||
let start_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"start")?);
|
||||
let _ = syscall::write(*start_fd, &[0])?;
|
||||
|
||||
Ok(new_pid)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
sys_includes = ["stdint.h", "sys/types.h", "time.h", "bits/pthread.h"]
|
||||
sys_includes = ["bits/signal.h", "stdint.h", "sys/types.h", "time.h", "bits/pthread.h"]
|
||||
include_guard = "_RELIBC_SIGNAL_H"
|
||||
trailer = "#include <bits/signal.h>"
|
||||
language = "C"
|
||||
@@ -15,3 +15,4 @@ prefix_with_name = true
|
||||
|
||||
[export.rename]
|
||||
"timespec" = "struct timespec"
|
||||
"sigaction" = "struct sigaction"
|
||||
|
||||
@@ -58,7 +58,8 @@ pub const SIGSYS: usize = 31;
|
||||
pub const SIGUNUSED: usize = SIGSYS;
|
||||
pub const NSIG: usize = 32;
|
||||
|
||||
pub const SIGRTMIN: usize = 34;
|
||||
pub const SIGRTMIN: usize = 35; // TODO: decrease to 34
|
||||
pub const SIGRTMAX: usize = 64;
|
||||
|
||||
pub const SA_NOCLDSTOP: usize = 1;
|
||||
pub const SA_NOCLDWAIT: usize = 2;
|
||||
|
||||
+38
-37
@@ -7,11 +7,13 @@ use cbitset::BitSet;
|
||||
use crate::{
|
||||
header::{errno, time::timespec},
|
||||
platform::{self, types::*, Pal, PalSignal, Sys},
|
||||
pthread,
|
||||
pthread::{self, Errno, ResultExt},
|
||||
};
|
||||
|
||||
pub use self::sys::*;
|
||||
|
||||
use super::errno::EFAULT;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "linux.rs"]
|
||||
pub mod sys;
|
||||
@@ -33,6 +35,7 @@ pub const SIG_SETMASK: c_int = 2;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
/// cbindgen:ignore
|
||||
pub struct sigaction {
|
||||
pub sa_handler: Option<extern "C" fn(c_int)>,
|
||||
pub sa_flags: c_ulong,
|
||||
@@ -50,7 +53,7 @@ pub struct sigaltstack {
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct siginfo_t {
|
||||
pub struct siginfo {
|
||||
pub si_signo: c_int,
|
||||
pub si_errno: c_int,
|
||||
pub si_code: c_int,
|
||||
@@ -58,7 +61,10 @@ pub struct siginfo_t {
|
||||
_si_align: [usize; 0],
|
||||
}
|
||||
|
||||
/// cbindgen:ignore
|
||||
pub type sigset_t = c_ulonglong;
|
||||
/// cbindgen:ignore
|
||||
pub type siginfo_t = siginfo;
|
||||
|
||||
pub type stack_t = sigaltstack;
|
||||
|
||||
@@ -107,17 +113,13 @@ pub unsafe extern "C" fn sigaction(
|
||||
act: *const sigaction,
|
||||
oact: *mut sigaction,
|
||||
) -> c_int {
|
||||
let act_opt = act.as_ref().map(|act| {
|
||||
let mut act_clone = act.clone();
|
||||
act_clone.sa_flags |= SA_RESTORER as c_ulong;
|
||||
act_clone.sa_restorer = Some(__restore_rt);
|
||||
act_clone
|
||||
});
|
||||
Sys::sigaction(sig, act_opt.as_ref(), oact.as_mut())
|
||||
Sys::sigaction(sig, act.as_ref(), oact.as_mut())
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int {
|
||||
pub unsafe extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int {
|
||||
if signo <= 0 || signo as usize > NSIG {
|
||||
platform::ERRNO.set(errno::EINVAL);
|
||||
return -1;
|
||||
@@ -131,20 +133,13 @@ pub extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
|
||||
if !ss.is_null() {
|
||||
if (*ss).ss_flags != SS_DISABLE as c_int {
|
||||
return errno::EINVAL;
|
||||
}
|
||||
if (*ss).ss_size < MINSIGSTKSZ {
|
||||
return errno::ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
Sys::sigaltstack(ss, old_ss)
|
||||
Sys::sigaltstack(ss.as_ref(), old_ss.as_mut())
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sigdelset(set: *mut sigset_t, signo: c_int) -> c_int {
|
||||
pub unsafe extern "C" fn sigdelset(set: *mut sigset_t, signo: c_int) -> c_int {
|
||||
if signo <= 0 || signo as usize > NSIG {
|
||||
platform::ERRNO.set(errno::EINVAL);
|
||||
return -1;
|
||||
@@ -222,11 +217,6 @@ pub unsafe extern "C" fn sigismember(set: *const sigset_t, signo: c_int) -> c_in
|
||||
0
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// Defined in assembly inside platform/x/mod.rs
|
||||
fn __restore_rt();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn signal(
|
||||
sig: c_int,
|
||||
@@ -234,8 +224,8 @@ pub extern "C" fn signal(
|
||||
) -> Option<extern "C" fn(c_int)> {
|
||||
let sa = sigaction {
|
||||
sa_handler: func,
|
||||
sa_flags: SA_RESTART as c_ulong,
|
||||
sa_restorer: Some(__restore_rt),
|
||||
sa_flags: SA_RESTART as _,
|
||||
sa_restorer: None, // set by platform if applicable
|
||||
sa_mask: sigset_t::default(),
|
||||
};
|
||||
let mut old_sa = mem::MaybeUninit::uninit();
|
||||
@@ -257,7 +247,9 @@ pub unsafe extern "C" fn sigpause(sig: c_int) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sigpending(set: *mut sigset_t) -> c_int {
|
||||
Sys::sigpending(set)
|
||||
(|| Sys::sigpending(set.as_mut().ok_or(Errno(EFAULT))?))()
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
const BELOW_SIGRTMIN_MASK: sigset_t = (1 << SIGRTMIN) - 1;
|
||||
@@ -270,14 +262,23 @@ pub unsafe extern "C" fn sigprocmask(
|
||||
set: *const sigset_t,
|
||||
oset: *mut sigset_t,
|
||||
) -> c_int {
|
||||
let set = set.as_ref().map(|&block| block & !RLCT_SIGNAL_MASK);
|
||||
(|| {
|
||||
let set = set.as_ref().map(|&block| block & !RLCT_SIGNAL_MASK);
|
||||
let mut oset = oset.as_mut();
|
||||
|
||||
Sys::sigprocmask(
|
||||
how,
|
||||
set.as_ref()
|
||||
.map_or(core::ptr::null(), |r| r as *const sigset_t),
|
||||
oset,
|
||||
)
|
||||
Sys::sigprocmask(
|
||||
how,
|
||||
set.as_ref(),
|
||||
oset.as_deref_mut(), // as_deref_mut for lifetime reasons
|
||||
)?;
|
||||
|
||||
if let Some(oset) = oset {
|
||||
*oset &= !RLCT_SIGNAL_MASK;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
})()
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -316,7 +317,7 @@ pub unsafe extern "C" fn sigset(
|
||||
let mut sa = sigaction {
|
||||
sa_handler: func,
|
||||
sa_flags: 0 as c_ulong,
|
||||
sa_restorer: Some(__restore_rt),
|
||||
sa_restorer: None, // set by platform if applicable
|
||||
sa_mask: sigset_t::default(),
|
||||
};
|
||||
sigemptyset(&mut sa.sa_mask);
|
||||
|
||||
@@ -1,38 +1,5 @@
|
||||
use core::arch::global_asm;
|
||||
|
||||
// x8 is register, 119 is SIGRETURN
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
global_asm!(
|
||||
"
|
||||
.global __restore_rt
|
||||
__restore_rt:
|
||||
mov x8, #119
|
||||
svc 0
|
||||
"
|
||||
);
|
||||
// Needs to be defined in assembly because it can't have a function prologue
|
||||
// eax is register, 119 is SIGRETURN
|
||||
#[cfg(target_arch = "x86")]
|
||||
global_asm!(
|
||||
"
|
||||
.global __restore_rt
|
||||
__restore_rt:
|
||||
mov eax, 119
|
||||
int 0x80
|
||||
"
|
||||
);
|
||||
// Needs to be defined in assembly because it can't have a function prologue
|
||||
// rax is register, 119 is SIGRETURN
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
global_asm!(
|
||||
"
|
||||
.global __restore_rt
|
||||
__restore_rt:
|
||||
mov rax, 119
|
||||
syscall
|
||||
"
|
||||
);
|
||||
|
||||
pub const SIGHUP: usize = 1;
|
||||
pub const SIGINT: usize = 2;
|
||||
pub const SIGQUIT: usize = 3;
|
||||
@@ -66,17 +33,17 @@ pub const SIGPWR: usize = 30;
|
||||
pub const SIGSYS: usize = 31;
|
||||
pub const NSIG: usize = 32;
|
||||
|
||||
pub const SIGRTMIN: usize = 34;
|
||||
pub const SIGRTMIN: usize = 35;
|
||||
pub const SIGRTMAX: usize = 64;
|
||||
|
||||
pub const SA_NOCLDSTOP: usize = 0x00000001;
|
||||
pub const SA_NOCLDWAIT: usize = 0x00000002;
|
||||
pub const SA_SIGINFO: usize = 0x00000004;
|
||||
pub const SA_RESTORER: usize = 0x04000000;
|
||||
pub const SA_ONSTACK: usize = 0x08000000;
|
||||
pub const SA_RESTART: usize = 0x10000000;
|
||||
pub const SA_NODEFER: usize = 0x40000000;
|
||||
pub const SA_RESETHAND: usize = 0x80000000;
|
||||
pub const SA_NOCLDWAIT: usize = 0x0000_0002;
|
||||
pub const SA_RESTORER: usize = 0x0000_0004; // TODO: remove
|
||||
pub const SA_SIGINFO: usize = 0x0200_0000;
|
||||
pub const SA_ONSTACK: usize = 0x0400_0000;
|
||||
pub const SA_RESTART: usize = 0x0800_0000;
|
||||
pub const SA_NODEFER: usize = 0x1000_0000;
|
||||
pub const SA_RESETHAND: usize = 0x2000_0000;
|
||||
pub const SA_NOCLDSTOP: usize = 0x4000_0000;
|
||||
|
||||
pub const SS_ONSTACK: usize = 0x00000001;
|
||||
pub const SS_DISABLE: usize = 0x00000002;
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
use super::{
|
||||
debug::{RTLDDebug, _r_debug},
|
||||
linker::Symbol,
|
||||
tcb::{round_up, Master},
|
||||
tcb::Master,
|
||||
};
|
||||
use crate::{
|
||||
header::{errno::STR_ERROR, sys_mman},
|
||||
@@ -170,7 +170,7 @@ impl DSO {
|
||||
for ph in elf.program_headers.iter() {
|
||||
let voff = ph.p_vaddr % ph.p_align;
|
||||
let vaddr = (ph.p_vaddr - voff) as usize;
|
||||
let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
|
||||
let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize);
|
||||
|
||||
match ph.p_type {
|
||||
program_header::PT_DYNAMIC => {
|
||||
@@ -253,7 +253,7 @@ impl DSO {
|
||||
for ph in elf.program_headers.iter() {
|
||||
let voff = ph.p_vaddr % ph.p_align;
|
||||
let vaddr = (ph.p_vaddr - voff) as usize;
|
||||
let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
|
||||
let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize);
|
||||
|
||||
match ph.p_type {
|
||||
program_header::PT_LOAD => {
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ use super::{
|
||||
callbacks::LinkerCallbacks,
|
||||
debug::{RTLDState, _dl_debug_state, _r_debug},
|
||||
dso::{is_pie_enabled, DSO},
|
||||
tcb::{round_up, Master, Tcb},
|
||||
tcb::{Master, Tcb},
|
||||
ExpectTlsFree, PATH_SEP,
|
||||
};
|
||||
|
||||
@@ -453,7 +453,7 @@ impl Linker {
|
||||
{
|
||||
let voff = ph.p_vaddr % ph.p_align;
|
||||
let vaddr = (ph.p_vaddr - voff) as usize;
|
||||
let vsize = round_up((ph.p_memsz + voff) as usize, ph.p_align as usize);
|
||||
let vsize = ((ph.p_memsz + voff) as usize).next_multiple_of(ph.p_align as usize);
|
||||
let mut prot = 0;
|
||||
if ph.p_flags & program_header::PF_R == program_header::PF_R {
|
||||
prot |= sys_mman::PROT_READ;
|
||||
|
||||
+2
-35
@@ -22,47 +22,14 @@ pub mod linker;
|
||||
pub mod start;
|
||||
pub mod tcb;
|
||||
|
||||
pub use generic_rt::{panic_notls, ExpectTlsFree};
|
||||
|
||||
static mut STATIC_TCB_MASTER: Master = Master {
|
||||
ptr: ptr::null_mut(),
|
||||
len: 0,
|
||||
offset: 0,
|
||||
};
|
||||
|
||||
fn panic_notls(msg: impl core::fmt::Display) -> ! {
|
||||
eprintln!("panicked in ld.so: {}", msg);
|
||||
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
pub trait ExpectTlsFree {
|
||||
type Unwrapped;
|
||||
|
||||
fn expect_notls(self, msg: &str) -> Self::Unwrapped;
|
||||
}
|
||||
impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> {
|
||||
type Unwrapped = T;
|
||||
|
||||
fn expect_notls(self, msg: &str) -> T {
|
||||
match self {
|
||||
Ok(t) => t,
|
||||
Err(err) => panic_notls(format_args!(
|
||||
"{}: expect failed for Result with err: {:?}",
|
||||
msg, err
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> ExpectTlsFree for Option<T> {
|
||||
type Unwrapped = T;
|
||||
|
||||
fn expect_notls(self, msg: &str) -> T {
|
||||
match self {
|
||||
Some(t) => t,
|
||||
None => panic_notls(format_args!("{}: expect failed for Option", msg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn static_init(sp: &'static Stack) {
|
||||
let mut phdr_opt = None;
|
||||
|
||||
+45
-116
@@ -1,5 +1,13 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::{arch::asm, cell::UnsafeCell, mem, ptr, slice, sync::atomic::AtomicBool};
|
||||
use core::{
|
||||
arch::asm,
|
||||
cell::UnsafeCell,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
ptr, slice,
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
use generic_rt::GenericTcb;
|
||||
use goblin::error::{Error, Result};
|
||||
|
||||
use super::ExpectTlsFree;
|
||||
@@ -29,18 +37,17 @@ impl Master {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
type OsSpecific = ();
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
type OsSpecific = redox_rt::signal::RtSigarea;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
// FIXME: Only return &Tcb, and use interior mutability, since it contains the Pthread struct
|
||||
pub struct Tcb {
|
||||
/// Pointer to the end of static TLS. Must be the first member
|
||||
pub tls_end: *mut u8,
|
||||
/// Size of the memory allocated for the static TLS in bytes (multiple of page size)
|
||||
pub tls_len: usize,
|
||||
/// Pointer to this structure
|
||||
pub tcb_ptr: *mut Tcb,
|
||||
/// Size of the memory allocated for this structure in bytes (should be same as page size)
|
||||
pub tcb_len: usize,
|
||||
pub generic: GenericTcb<OsSpecific>,
|
||||
/// Pointer to a list of initial TLS data
|
||||
pub masters_ptr: *mut Master,
|
||||
/// Size of the masters list in bytes (multiple of mem::size_of::<Master>())
|
||||
@@ -55,21 +62,31 @@ pub struct Tcb {
|
||||
pub pthread: Pthread,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
const _: () = {
|
||||
if mem::size_of::<Tcb>() > syscall::PAGE_SIZE {
|
||||
panic!("too large TCB!");
|
||||
}
|
||||
};
|
||||
|
||||
impl Tcb {
|
||||
/// Create a new TCB
|
||||
pub unsafe fn new(size: usize) -> Result<&'static mut Self> {
|
||||
let page_size = Sys::getpagesize();
|
||||
let (abi_page, tls, tcb_page) = Self::os_new(round_up(size, page_size))?;
|
||||
let (abi_page, tls, tcb_page) = Self::os_new(size.next_multiple_of(page_size))?;
|
||||
|
||||
let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self;
|
||||
trace!("New TCB: {:p}", tcb_ptr);
|
||||
ptr::write(
|
||||
tcb_ptr,
|
||||
Self {
|
||||
tls_end: tls.as_mut_ptr().add(tls.len()),
|
||||
tls_len: tls.len(),
|
||||
tcb_ptr,
|
||||
tcb_len: tcb_page.len(),
|
||||
generic: GenericTcb {
|
||||
tls_end: tls.as_mut_ptr().add(tls.len()),
|
||||
tls_len: tls.len(),
|
||||
tcb_ptr: tcb_ptr.cast(),
|
||||
tcb_len: tcb_page.len(),
|
||||
os_specific: OsSpecific::default(),
|
||||
},
|
||||
masters_ptr: ptr::null_mut(),
|
||||
masters_len: 0,
|
||||
num_copied_masters: 0,
|
||||
@@ -92,13 +109,7 @@ impl Tcb {
|
||||
|
||||
/// Get the current TCB
|
||||
pub unsafe fn current() -> Option<&'static mut Self> {
|
||||
let tcb_ptr = Self::arch_read(offset_of!(Self, tcb_ptr)) as *mut Self;
|
||||
let tcb_len = Self::arch_read(offset_of!(Self, tcb_len));
|
||||
if tcb_ptr.is_null() || tcb_len < mem::size_of::<Self>() {
|
||||
None
|
||||
} else {
|
||||
Some(&mut *tcb_ptr)
|
||||
}
|
||||
Some(&mut *GenericTcb::<OsSpecific>::current_ptr()?.cast())
|
||||
}
|
||||
|
||||
/// A slice for all of the TLS data
|
||||
@@ -218,50 +229,6 @@ impl Tcb {
|
||||
Ok((abi, tls, tcb))
|
||||
}
|
||||
|
||||
/// Architecture specific code to read a usize from the TCB - aarch64
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
unsafe fn arch_read(offset: usize) -> usize {
|
||||
let abi_ptr: usize;
|
||||
asm!(
|
||||
"mrs {}, tpidr_el0",
|
||||
out(reg) abi_ptr,
|
||||
);
|
||||
|
||||
let tcb_ptr = *(abi_ptr as *const usize);
|
||||
*((tcb_ptr + offset) as *const usize)
|
||||
}
|
||||
|
||||
/// Architecture specific code to read a usize from the TCB - x86
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "x86")]
|
||||
unsafe fn arch_read(offset: usize) -> usize {
|
||||
let value;
|
||||
asm!(
|
||||
"
|
||||
mov {}, gs:[{}]
|
||||
",
|
||||
out(reg) value,
|
||||
in(reg) offset,
|
||||
);
|
||||
value
|
||||
}
|
||||
|
||||
/// Architecture specific code to read a usize from the TCB - x86_64
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe fn arch_read(offset: usize) -> usize {
|
||||
let value;
|
||||
asm!(
|
||||
"
|
||||
mov {}, fs:[{}]
|
||||
",
|
||||
out(reg) value,
|
||||
in(reg) offset,
|
||||
);
|
||||
value
|
||||
}
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Linux x86_64
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) {
|
||||
@@ -269,59 +236,21 @@ impl Tcb {
|
||||
syscall!(ARCH_PRCTL, ARCH_SET_FS, tls_end);
|
||||
}
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Redox aarch64
|
||||
#[cfg(all(target_os = "redox", target_arch = "aarch64"))]
|
||||
#[cfg(target_os = "redox")]
|
||||
unsafe fn os_arch_activate(tls_end: usize, tls_len: usize) {
|
||||
// Uses ABI page
|
||||
let abi_ptr = tls_end - tls_len - 16;
|
||||
ptr::write(abi_ptr as *mut usize, tls_end);
|
||||
asm!(
|
||||
"msr tpidr_el0, {}",
|
||||
in(reg) abi_ptr,
|
||||
);
|
||||
}
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Redox x86
|
||||
#[cfg(all(target_os = "redox", target_arch = "x86"))]
|
||||
unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = syscall::open(
|
||||
"thisproc:current/regs/env",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR,
|
||||
)
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
|
||||
let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase");
|
||||
|
||||
env.gsbase = tls_end as u32;
|
||||
|
||||
let _ = syscall::write(file, &env).expect_notls("failed to write gsbase");
|
||||
|
||||
let _ = syscall::close(file);
|
||||
}
|
||||
|
||||
/// OS and architecture specific code to activate TLS - Redox x86_64
|
||||
#[cfg(all(target_os = "redox", target_arch = "x86_64"))]
|
||||
unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = syscall::open(
|
||||
"thisproc:current/regs/env",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR,
|
||||
)
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
|
||||
let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase");
|
||||
|
||||
env.fsbase = tls_end as u64;
|
||||
|
||||
let _ = syscall::write(file, &env).expect_notls("failed to write fsbase");
|
||||
|
||||
let _ = syscall::close(file);
|
||||
redox_rt::tcb_activate(tls_end, tls_len)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn round_up(value: usize, alignment: usize) -> usize {
|
||||
return (value + alignment - 1) & (!(alignment - 1));
|
||||
impl Deref for Tcb {
|
||||
type Target = GenericTcb<OsSpecific>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.generic
|
||||
}
|
||||
}
|
||||
impl DerefMut for Tcb {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.generic
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@ extern crate alloc;
|
||||
extern crate cbitset;
|
||||
extern crate goblin;
|
||||
extern crate memchr;
|
||||
#[macro_use]
|
||||
extern crate memoffset;
|
||||
extern crate posix_regex;
|
||||
extern crate rand;
|
||||
|
||||
|
||||
@@ -352,22 +352,3 @@ macro_rules! strto_float_impl {
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! asmfunction(
|
||||
($name:ident : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => {
|
||||
::core::arch::global_asm!(concat!("
|
||||
.p2align 4
|
||||
.section .text.", stringify!($name), ", \"ax\", @progbits
|
||||
.globl ", stringify!($name), "
|
||||
.type ", stringify!($name), ", @function
|
||||
", stringify!($name), ":
|
||||
", $($asmstmt, "\n",)* "
|
||||
.size ", stringify!($name), ", . - ", stringify!($name), "
|
||||
"), $($decl = $(sym $symname)?$(const $constval)?),*);
|
||||
|
||||
extern "C" {
|
||||
pub fn $name();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2,12 +2,15 @@ use core::mem;
|
||||
|
||||
use super::{
|
||||
super::{types::*, PalSignal},
|
||||
e, Sys,
|
||||
e, e_raw, Sys,
|
||||
};
|
||||
use crate::header::{
|
||||
signal::{sigaction, siginfo_t, sigset_t, stack_t, NSIG},
|
||||
sys_time::itimerval,
|
||||
time::timespec,
|
||||
use crate::{
|
||||
header::{
|
||||
signal::{sigaction, siginfo_t, sigset_t, stack_t, NSIG, SA_RESTORER},
|
||||
sys_time::itimerval,
|
||||
time::timespec,
|
||||
},
|
||||
pthread::Errno,
|
||||
};
|
||||
|
||||
impl PalSignal for Sys {
|
||||
@@ -36,34 +39,67 @@ impl PalSignal for Sys {
|
||||
e(syscall!(SETITIMER, which, new, old)) as c_int
|
||||
}
|
||||
|
||||
fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> c_int {
|
||||
e(unsafe {
|
||||
fn sigaction(
|
||||
sig: c_int,
|
||||
act: Option<&sigaction>,
|
||||
oact: Option<&mut sigaction>,
|
||||
) -> Result<(), Errno> {
|
||||
extern "C" {
|
||||
fn __restore_rt();
|
||||
}
|
||||
let act = act.map(|act| {
|
||||
let mut act_clone = act.clone();
|
||||
act_clone.sa_flags |= SA_RESTORER as c_ulong;
|
||||
act_clone.sa_restorer = Some(__restore_rt);
|
||||
act_clone
|
||||
});
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
RT_SIGACTION,
|
||||
sig,
|
||||
act.map_or_else(core::ptr::null, |x| x as *const _),
|
||||
act.as_ref().map_or_else(core::ptr::null, |x| x as *const _),
|
||||
oact.map_or_else(core::ptr::null_mut, |x| x as *mut _),
|
||||
mem::size_of::<sigset_t>()
|
||||
)
|
||||
}) as c_int
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
|
||||
e(syscall!(SIGALTSTACK, ss, old_ss)) as c_int
|
||||
unsafe fn sigaltstack(ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<(), Errno> {
|
||||
e_raw(syscall!(
|
||||
SIGALTSTACK,
|
||||
ss.map_or_else(core::ptr::null, |x| x as *const _),
|
||||
old_ss.map_or_else(core::ptr::null_mut, |x| x as *mut _)
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn sigpending(set: *mut sigset_t) -> c_int {
|
||||
e(syscall!(RT_SIGPENDING, set, NSIG / 8)) as c_int
|
||||
fn sigpending(set: &mut sigset_t) -> Result<(), Errno> {
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
RT_SIGPENDING,
|
||||
set as *mut sigset_t as usize,
|
||||
mem::size_of::<sigset_t>()
|
||||
)
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int {
|
||||
e(syscall!(
|
||||
RT_SIGPROCMASK,
|
||||
how,
|
||||
set,
|
||||
oset,
|
||||
mem::size_of::<sigset_t>()
|
||||
)) as c_int
|
||||
fn sigprocmask(
|
||||
how: c_int,
|
||||
set: Option<&sigset_t>,
|
||||
oset: Option<&mut sigset_t>,
|
||||
) -> Result<(), Errno> {
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
RT_SIGPROCMASK,
|
||||
how,
|
||||
set.map_or_else(core::ptr::null, |x| x as *const _),
|
||||
oset.map_or_else(core::ptr::null_mut, |x| x as *mut _),
|
||||
mem::size_of::<sigset_t>()
|
||||
)
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn sigsuspend(set: *const sigset_t) -> c_int {
|
||||
|
||||
+2
-2
@@ -33,7 +33,7 @@ pub mod rlb;
|
||||
pub mod auxv_defs;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub use redox_exec::auxv_defs;
|
||||
pub use redox_rt::auxv_defs;
|
||||
|
||||
use self::types::*;
|
||||
pub mod types;
|
||||
@@ -306,7 +306,7 @@ pub fn init(auxvs: Box<[[usize; 2]]>) {
|
||||
if let Some(mask) = get_auxv(&auxvs, AT_REDOX_INHERITED_SIGPROCMASK_HI) {
|
||||
inherited_sigprocmask |= (mask as u64) << 32;
|
||||
}
|
||||
syscall::sigprocmask(syscall::SIG_SETMASK, Some(&inherited_sigprocmask), None).unwrap();
|
||||
redox_rt::signal::set_sigmask(Some(inherited_sigprocmask), None).unwrap();
|
||||
}
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub fn init(auxvs: Box<[[usize; 2]]>) {}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use super::super::{types::*, Pal};
|
||||
use crate::header::{
|
||||
signal::{sigaction, siginfo_t, sigset_t, stack_t},
|
||||
sys_time::itimerval,
|
||||
time::timespec,
|
||||
use crate::{
|
||||
header::{
|
||||
signal::{sigaction, siginfo_t, sigset_t, stack_t},
|
||||
sys_time::itimerval,
|
||||
time::timespec,
|
||||
},
|
||||
pthread::Errno,
|
||||
};
|
||||
|
||||
pub trait PalSignal: Pal {
|
||||
@@ -16,13 +19,21 @@ pub trait PalSignal: Pal {
|
||||
|
||||
unsafe fn setitimer(which: c_int, new: *const itimerval, old: *mut itimerval) -> c_int;
|
||||
|
||||
fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> c_int;
|
||||
fn sigaction(
|
||||
sig: c_int,
|
||||
act: Option<&sigaction>,
|
||||
oact: Option<&mut sigaction>,
|
||||
) -> Result<(), Errno>;
|
||||
|
||||
unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int;
|
||||
unsafe fn sigaltstack(ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<(), Errno>;
|
||||
|
||||
unsafe fn sigpending(set: *mut sigset_t) -> c_int;
|
||||
fn sigpending(set: &mut sigset_t) -> Result<(), Errno>;
|
||||
|
||||
unsafe fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int;
|
||||
fn sigprocmask(
|
||||
how: c_int,
|
||||
set: Option<&sigset_t>,
|
||||
oset: Option<&mut sigset_t>,
|
||||
) -> Result<(), Errno>;
|
||||
|
||||
unsafe fn sigsuspend(set: *const sigset_t) -> c_int;
|
||||
|
||||
|
||||
+3
-155
@@ -9,12 +9,9 @@ use syscall::{
|
||||
|
||||
use crate::sync::rwlock::Rwlock;
|
||||
|
||||
use super::{
|
||||
extra::{create_set_addr_space_buf, FdGuard},
|
||||
signal::sighandler_function,
|
||||
};
|
||||
use redox_rt::{proc::FdGuard, signal::sighandler_function};
|
||||
|
||||
pub use redox_exec::*;
|
||||
pub use redox_rt::proc::*;
|
||||
|
||||
static CLONE_LOCK: Rwlock = Rwlock::new(crate::pthread::Pshared::Private);
|
||||
|
||||
@@ -35,153 +32,4 @@ pub fn wrlock() -> impl Drop {
|
||||
|
||||
Guard
|
||||
}
|
||||
|
||||
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
|
||||
pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result<usize> {
|
||||
let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?);
|
||||
let (new_pid_fd, new_pid) = new_context()?;
|
||||
|
||||
copy_str(*cur_pid_fd, *new_pid_fd, "name")?;
|
||||
|
||||
// Inherit existing address space
|
||||
{
|
||||
let cur_addr_space_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"addrspace")?);
|
||||
let new_addr_space_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?);
|
||||
|
||||
let buf = create_set_addr_space_buf(
|
||||
*cur_addr_space_fd,
|
||||
__relibc_internal_rlct_clone_ret as usize,
|
||||
stack as usize,
|
||||
);
|
||||
let _ = syscall::write(*new_addr_space_sel_fd, &buf)?;
|
||||
}
|
||||
|
||||
// Inherit file table
|
||||
{
|
||||
let cur_filetable_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"filetable")?);
|
||||
let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-filetable")?);
|
||||
|
||||
let _ = syscall::write(
|
||||
*new_filetable_sel_fd,
|
||||
&usize::to_ne_bytes(*cur_filetable_fd),
|
||||
)?;
|
||||
}
|
||||
|
||||
// Inherit sigactions (on Linux, CLONE_THREAD requires CLONE_SIGHAND which implies the sigactions
|
||||
// table is reused).
|
||||
{
|
||||
let cur_sigaction_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sigactions")?);
|
||||
let new_sigaction_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-sigactions")?);
|
||||
|
||||
let _ = syscall::write(
|
||||
*new_sigaction_sel_fd,
|
||||
&usize::to_ne_bytes(*cur_sigaction_fd),
|
||||
)?;
|
||||
}
|
||||
// Inherit sighandler, but not the sigaltstack.
|
||||
{
|
||||
let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?);
|
||||
let data = SetSighandlerData {
|
||||
entry: sighandler_function(),
|
||||
altstack_base: 0,
|
||||
altstack_len: 0,
|
||||
};
|
||||
let _ = syscall::write(*new_sighandler_fd, &data)?;
|
||||
}
|
||||
|
||||
// Sigprocmask starts as "block all", and is initialized when the thread has actually returned
|
||||
// from clone_ret.
|
||||
|
||||
// TODO: Should some of these registers be inherited?
|
||||
//copy_env_regs(*cur_pid_fd, *new_pid_fd)?;
|
||||
|
||||
// Unblock context.
|
||||
let start_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"start")?);
|
||||
let _ = syscall::write(*start_fd, &[0])?;
|
||||
|
||||
Ok(new_pid)
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __relibc_internal_rlct_clone_ret();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.globl __relibc_internal_rlct_clone_ret
|
||||
.type __relibc_internal_rlct_clone_ret, @function
|
||||
.p2align 6
|
||||
__relibc_internal_rlct_clone_ret:
|
||||
# Load registers
|
||||
ldp x8, x0, [sp], #16
|
||||
ldp x1, x2, [sp], #16
|
||||
ldp x3, x4, [sp], #16
|
||||
|
||||
# Call entry point
|
||||
blr x8
|
||||
|
||||
ret
|
||||
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
|
||||
"
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.globl __relibc_internal_rlct_clone_ret
|
||||
.type __relibc_internal_rlct_clone_ret, @function
|
||||
.p2align 6
|
||||
__relibc_internal_rlct_clone_ret:
|
||||
# Load registers
|
||||
pop eax
|
||||
|
||||
sub esp, 8
|
||||
|
||||
mov DWORD PTR [esp], 0x00001F80
|
||||
# TODO: ldmxcsr [esp]
|
||||
mov WORD PTR [esp], 0x037F
|
||||
fldcw [esp]
|
||||
|
||||
add esp, 8
|
||||
|
||||
# Call entry point
|
||||
call eax
|
||||
|
||||
ret
|
||||
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
|
||||
"
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.globl __relibc_internal_rlct_clone_ret
|
||||
.type __relibc_internal_rlct_clone_ret, @function
|
||||
.p2align 6
|
||||
__relibc_internal_rlct_clone_ret:
|
||||
# Load registers
|
||||
pop rax
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop r8
|
||||
pop r9
|
||||
|
||||
sub rsp, 8
|
||||
|
||||
mov DWORD PTR [rsp], 0x00001F80
|
||||
ldmxcsr [rsp]
|
||||
mov WORD PTR [rsp], 0x037F
|
||||
fldcw [rsp]
|
||||
|
||||
add rsp, 8
|
||||
|
||||
# Call entry point
|
||||
call rax
|
||||
|
||||
ret
|
||||
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
|
||||
"
|
||||
);
|
||||
pub use redox_rt::thread::*;
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use redox_exec::{ExtraInfo, FdGuard, FexecResult};
|
||||
use redox_rt::proc::{ExtraInfo, FdGuard, FexecResult, InterpOverride};
|
||||
use syscall::{data::Stat, error::*, flag::*};
|
||||
|
||||
fn fexec_impl(
|
||||
@@ -20,11 +20,11 @@ fn fexec_impl(
|
||||
envs: &[&[u8]],
|
||||
total_args_envs_size: usize,
|
||||
extrainfo: &ExtraInfo,
|
||||
interp_override: Option<redox_exec::InterpOverride>,
|
||||
interp_override: Option<InterpOverride>,
|
||||
) -> Result<usize> {
|
||||
let memory = FdGuard::new(syscall::open("memory:", 0)?);
|
||||
|
||||
let addrspace_selection_fd = match redox_exec::fexec_impl(
|
||||
let addrspace_selection_fd = match redox_rt::proc::fexec_impl(
|
||||
exec_file,
|
||||
open_via_dup,
|
||||
&memory,
|
||||
@@ -88,7 +88,7 @@ pub enum Executable<'a> {
|
||||
pub fn execve(
|
||||
exec: Executable<'_>,
|
||||
arg_env: ArgEnv,
|
||||
interp_override: Option<redox_exec::InterpOverride>,
|
||||
interp_override: Option<InterpOverride>,
|
||||
) -> Result<usize> {
|
||||
// NOTE: We must omit O_CLOEXEC and close manually, otherwise it will be closed before we
|
||||
// have even read it!
|
||||
@@ -305,8 +305,7 @@ pub fn execve(
|
||||
|
||||
unreachable!()
|
||||
} else {
|
||||
let mut sigprocmask = 0_u64;
|
||||
syscall::sigprocmask(syscall::SIG_SETMASK, None, Some(&mut sigprocmask)).unwrap();
|
||||
let sigprocmask = redox_rt::signal::get_sigmask().unwrap();
|
||||
|
||||
let extrainfo = ExtraInfo {
|
||||
cwd: Some(&cwd),
|
||||
|
||||
@@ -3,7 +3,7 @@ use core::{ptr, slice};
|
||||
use crate::platform::{sys::e, types::*};
|
||||
use syscall::{error::*, F_SETFD, F_SETFL};
|
||||
|
||||
pub use redox_exec::*;
|
||||
pub use redox_rt::proc::FdGuard;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t {
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
use core::{slice, str};
|
||||
|
||||
use redox_rt::sys::{posix_read, posix_write};
|
||||
use syscall::{Error, Result, WaitFlags, EMFILE};
|
||||
|
||||
use crate::{
|
||||
header::{
|
||||
errno::EINVAL, signal::sigaction, sys_stat::UTIME_NOW, sys_uio::iovec, time::timespec,
|
||||
errno::EINVAL,
|
||||
signal::{sigaction, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK},
|
||||
sys_stat::UTIME_NOW,
|
||||
sys_uio::iovec,
|
||||
time::timespec,
|
||||
},
|
||||
platform::types::*,
|
||||
platform::{types::*, PalSignal},
|
||||
};
|
||||
|
||||
use super::Sys;
|
||||
|
||||
pub type RawResult = usize;
|
||||
|
||||
pub fn open(path: &str, oflag: c_int, mode: mode_t) -> Result<usize> {
|
||||
@@ -141,10 +148,7 @@ pub unsafe extern "C" fn redox_dup2_v1(
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_read_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult {
|
||||
Error::mux(syscall::read(
|
||||
fd,
|
||||
slice::from_raw_parts_mut(dst_base, dst_len),
|
||||
))
|
||||
Error::mux(posix_read(fd, slice::from_raw_parts_mut(dst_base, dst_len)))
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_write_v1(
|
||||
@@ -152,7 +156,7 @@ pub unsafe extern "C" fn redox_write_v1(
|
||||
src_base: *const u8,
|
||||
src_len: usize,
|
||||
) -> RawResult {
|
||||
Error::mux(syscall::write(fd, slice::from_raw_parts(src_base, src_len)))
|
||||
Error::mux(posix_write(fd, slice::from_raw_parts(src_base, src_len)))
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_fsync_v1(fd: usize) -> RawResult {
|
||||
@@ -249,7 +253,11 @@ pub unsafe extern "C" fn redox_sigaction_v1(
|
||||
new: *const sigaction,
|
||||
old: *mut sigaction,
|
||||
) -> RawResult {
|
||||
Error::mux(super::signal::sigaction_impl(signal as i32, new.as_ref(), old.as_mut()).map(|()| 0))
|
||||
Error::mux(
|
||||
Sys::sigaction(signal as c_int, new.as_ref(), old.as_mut())
|
||||
.map(|()| 0)
|
||||
.map_err(Into::into),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -258,7 +266,11 @@ pub unsafe extern "C" fn redox_sigprocmask_v1(
|
||||
new: *const u64,
|
||||
old: *mut u64,
|
||||
) -> RawResult {
|
||||
Error::mux(super::signal::sigprocmask_impl(how as i32, new, old).map(|()| 0))
|
||||
Error::mux(
|
||||
Sys::sigprocmask(how as c_int, new.as_ref(), old.as_mut())
|
||||
.map(|()| 0)
|
||||
.map_err(Into::into),
|
||||
)
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_mmap_v1(
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
fs::File,
|
||||
header::{
|
||||
dirent::dirent,
|
||||
errno::{EBADR, EINVAL, EIO, ENOENT, ENOMEM, ENOSYS, EPERM, ERANGE},
|
||||
errno::{EBADF, EBADFD, EBADR, EINVAL, EIO, ENOENT, ENOMEM, ENOSYS, EPERM, ERANGE},
|
||||
fcntl, limits,
|
||||
sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE},
|
||||
sys_random,
|
||||
@@ -27,7 +27,7 @@ use crate::{
|
||||
pthread::{self, Errno, ResultExt},
|
||||
};
|
||||
|
||||
pub use redox_exec::FdGuard;
|
||||
pub use redox_rt::proc::FdGuard;
|
||||
|
||||
use super::{types::*, Pal, Read, ERRNO};
|
||||
|
||||
@@ -217,7 +217,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn exit(status: c_int) -> ! {
|
||||
let _ = syscall::exit(status as usize);
|
||||
let _ = syscall::exit((status as usize) << 8);
|
||||
loop {}
|
||||
}
|
||||
|
||||
@@ -824,7 +824,8 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn read(fd: c_int, buf: &mut [u8]) -> Result<ssize_t, Errno> {
|
||||
Ok(syscall::read(fd as usize, buf)? as ssize_t)
|
||||
let fd = usize::try_from(fd).map_err(|_| Errno(EBADF))?;
|
||||
Ok(redox_rt::sys::posix_read(fd, buf)? as ssize_t)
|
||||
}
|
||||
fn pread(fd: c_int, buf: &mut [u8], offset: off_t) -> Result<ssize_t, Errno> {
|
||||
unsafe {
|
||||
@@ -1124,7 +1125,8 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn write(fd: c_int, buf: &[u8]) -> Result<ssize_t, Errno> {
|
||||
Ok(syscall::write(fd as usize, buf)? as ssize_t)
|
||||
let fd = usize::try_from(fd).map_err(|_| Errno(EBADFD))?;
|
||||
Ok(redox_rt::sys::posix_write(fd, buf)? as ssize_t)
|
||||
}
|
||||
fn pwrite(fd: c_int, buf: &[u8], offset: off_t) -> Result<ssize_t, Errno> {
|
||||
unsafe {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec};
|
||||
use redox_rt::signal::tmp_disable_signals;
|
||||
use syscall::{data::Stat, error::*, flag::*};
|
||||
|
||||
use super::{libcscheme, FdGuard};
|
||||
@@ -19,7 +20,7 @@ const PATH_MAX: usize = 4096;
|
||||
// and after acquiring the locks. (TODO: ArcSwap? That will need to be ported to no_std first,
|
||||
// though).
|
||||
pub fn chdir(path: &str) -> Result<()> {
|
||||
let _siglock = SignalMask::lock();
|
||||
let _siglock = tmp_disable_signals();
|
||||
let mut cwd_guard = CWD.lock();
|
||||
|
||||
let canonicalized =
|
||||
@@ -40,13 +41,13 @@ pub fn chdir(path: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
pub fn clone_cwd() -> Option<Box<str>> {
|
||||
let _siglock = SignalMask::lock();
|
||||
let _siglock = tmp_disable_signals();
|
||||
CWD.lock().clone()
|
||||
}
|
||||
|
||||
// TODO: MaybeUninit
|
||||
pub fn getcwd(buf: &mut [u8]) -> Option<usize> {
|
||||
let _siglock = SignalMask::lock();
|
||||
let _siglock = tmp_disable_signals();
|
||||
let cwd_guard = CWD.lock();
|
||||
let cwd = cwd_guard.as_deref().unwrap_or("").as_bytes();
|
||||
|
||||
@@ -61,9 +62,8 @@ pub fn getcwd(buf: &mut [u8]) -> Option<usize> {
|
||||
Some(cwd.len())
|
||||
}
|
||||
|
||||
// TODO: Move cwd from kernel to libc. It is passed via auxiliary vectors.
|
||||
pub fn canonicalize(path: &str) -> Result<String> {
|
||||
let _siglock = SignalMask::lock();
|
||||
let _siglock = tmp_disable_signals();
|
||||
let cwd = CWD.lock();
|
||||
canonicalize_using_cwd(cwd.as_deref(), path).ok_or(Error::new(ENOENT))
|
||||
}
|
||||
@@ -72,29 +72,10 @@ pub fn canonicalize(path: &str) -> Result<String> {
|
||||
static CWD: Mutex<Option<Box<str>>> = Mutex::new(None);
|
||||
|
||||
pub fn setcwd_manual(cwd: Box<str>) {
|
||||
let _siglock = SignalMask::lock();
|
||||
let _siglock = tmp_disable_signals();
|
||||
*CWD.lock() = Some(cwd);
|
||||
}
|
||||
|
||||
/// RAII guard able to magically fix signal unsafety, by disabling signals during a critical
|
||||
/// section.
|
||||
pub struct SignalMask {
|
||||
oldset: u64,
|
||||
}
|
||||
impl SignalMask {
|
||||
pub fn lock() -> Self {
|
||||
let mut oldset = 0;
|
||||
syscall::sigprocmask(syscall::SIG_SETMASK, Some(&!0), Some(&mut oldset))
|
||||
.expect("failed to run sigprocmask");
|
||||
Self { oldset }
|
||||
}
|
||||
}
|
||||
impl Drop for SignalMask {
|
||||
fn drop(&mut self) {
|
||||
let _ = syscall::sigprocmask(syscall::SIG_SETMASK, Some(&self.oldset), None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(path: &str, flags: usize) -> Result<usize> {
|
||||
// TODO: SYMLOOP_MAX
|
||||
const MAX_LEVEL: usize = 64;
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
use syscall::error::*;
|
||||
|
||||
use crate::{fork_inner, FdGuard};
|
||||
|
||||
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||
pub(crate) const STACK_TOP: usize = 1 << 47;
|
||||
pub(crate) const STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||
/// is already initialized as if it was a thread.
|
||||
pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = FdGuard::new(syscall::dup(open_via_dup, b"regs/env")?);
|
||||
|
||||
env.tpidr_el0 = 0;
|
||||
|
||||
let _ = syscall::write(*file, &mut env)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
// Copy environment registers.
|
||||
{
|
||||
let cur_env_regs_fd = FdGuard::new(syscall::dup(cur_pid_fd, b"regs/env")?);
|
||||
let new_env_regs_fd = FdGuard::new(syscall::dup(new_pid_fd, b"regs/env")?);
|
||||
|
||||
let mut env_regs = syscall::EnvRegisters::default();
|
||||
let _ = syscall::read(*cur_env_regs_fd, &mut env_regs)?;
|
||||
let _ = syscall::write(*new_env_regs_fd, &env_regs)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __relibc_internal_fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
let _ = syscall::close(new_pid_fd);
|
||||
}
|
||||
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.p2align 6
|
||||
.globl __relibc_internal_fork_wrapper
|
||||
.type __relibc_internal_fork_wrapper, @function
|
||||
__relibc_internal_fork_wrapper:
|
||||
stp x29, x30, [sp, #-16]!
|
||||
stp x27, x28, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x19, x20, [sp, #-16]!
|
||||
|
||||
sub sp, sp, #32
|
||||
|
||||
//TODO: store floating point regs
|
||||
|
||||
mov x0, sp
|
||||
bl __relibc_internal_fork_impl
|
||||
b 2f
|
||||
|
||||
.size __relibc_internal_fork_wrapper, . - __relibc_internal_fork_wrapper
|
||||
|
||||
.p2align 6
|
||||
.globl __relibc_internal_fork_ret
|
||||
.type __relibc_internal_fork_ret, @function
|
||||
__relibc_internal_fork_ret:
|
||||
ldp x0, x1, [sp]
|
||||
bl __relibc_internal_fork_hook
|
||||
|
||||
//TODO: load floating point regs
|
||||
|
||||
mov x0, xzr
|
||||
|
||||
.p2align 4
|
||||
2:
|
||||
add sp, sp, #32
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
ldp x29, x30, [sp], #16
|
||||
|
||||
ret
|
||||
|
||||
.size __relibc_internal_fork_ret, . - __relibc_internal_fork_ret"
|
||||
);
|
||||
|
||||
extern "C" {
|
||||
pub(crate) fn __relibc_internal_fork_wrapper() -> usize;
|
||||
pub(crate) fn __relibc_internal_fork_ret();
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
use syscall::error::*;
|
||||
|
||||
use crate::{fork_inner, FdGuard};
|
||||
|
||||
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||
pub(crate) const STACK_TOP: usize = 1 << 31;
|
||||
pub(crate) const STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||
/// is already initialized as if it was a thread.
|
||||
pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = FdGuard::new(syscall::dup(open_via_dup, b"regs/env")?);
|
||||
|
||||
env.fsbase = 0;
|
||||
env.gsbase = 0;
|
||||
|
||||
let _ = syscall::write(*file, &mut env)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
// Copy environment registers.
|
||||
{
|
||||
let cur_env_regs_fd = FdGuard::new(syscall::dup(cur_pid_fd, b"regs/env")?);
|
||||
let new_env_regs_fd = FdGuard::new(syscall::dup(new_pid_fd, b"regs/env")?);
|
||||
|
||||
let mut env_regs = syscall::EnvRegisters::default();
|
||||
let _ = syscall::read(*cur_env_regs_fd, &mut env_regs)?;
|
||||
let _ = syscall::write(*new_env_regs_fd, &env_regs)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "cdecl" fn __relibc_internal_fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "cdecl" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
let _ = syscall::close(new_pid_fd);
|
||||
}
|
||||
|
||||
//TODO: x86
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.p2align 6
|
||||
.globl __relibc_internal_fork_wrapper
|
||||
.type __relibc_internal_fork_wrapper, @function
|
||||
__relibc_internal_fork_wrapper:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
// Push preserved registers
|
||||
push ebx
|
||||
push edi
|
||||
push esi
|
||||
push ebp
|
||||
|
||||
sub esp, 32
|
||||
|
||||
//TODO stmxcsr [esp+16]
|
||||
fnstcw [esp+24]
|
||||
|
||||
push esp
|
||||
call __relibc_internal_fork_impl
|
||||
pop esp
|
||||
jmp 2f
|
||||
|
||||
.size __relibc_internal_fork_wrapper, . - __relibc_internal_fork_wrapper
|
||||
|
||||
.p2align 6
|
||||
.globl __relibc_internal_fork_ret
|
||||
.type __relibc_internal_fork_ret, @function
|
||||
__relibc_internal_fork_ret:
|
||||
// Arguments already on the stack
|
||||
call __relibc_internal_fork_hook
|
||||
|
||||
//TODO ldmxcsr [esp+16]
|
||||
fldcw [esp+24]
|
||||
|
||||
xor eax, eax
|
||||
|
||||
.p2align 4
|
||||
2:
|
||||
add esp, 32
|
||||
|
||||
// Pop preserved registers
|
||||
pop ebp
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebx
|
||||
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
.size __relibc_internal_fork_ret, . - __relibc_internal_fork_ret"
|
||||
);
|
||||
|
||||
extern "cdecl" {
|
||||
pub(crate) fn __relibc_internal_fork_wrapper() -> usize;
|
||||
pub(crate) fn __relibc_internal_fork_ret();
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
use syscall::error::*;
|
||||
|
||||
use crate::{fork_inner, FdGuard};
|
||||
|
||||
// Setup a stack starting from the very end of the address space, and then growing downwards.
|
||||
pub(crate) const STACK_TOP: usize = 1 << 47;
|
||||
pub(crate) const STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
|
||||
/// is already initialized as if it was a thread.
|
||||
pub unsafe fn deactivate_tcb(open_via_dup: usize) -> Result<()> {
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = FdGuard::new(syscall::dup(open_via_dup, b"regs/env")?);
|
||||
|
||||
env.fsbase = 0;
|
||||
env.gsbase = 0;
|
||||
|
||||
let _ = syscall::write(*file, &mut env)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
// Copy environment registers.
|
||||
{
|
||||
let cur_env_regs_fd = FdGuard::new(syscall::dup(cur_pid_fd, b"regs/env")?);
|
||||
let new_env_regs_fd = FdGuard::new(syscall::dup(new_pid_fd, b"regs/env")?);
|
||||
|
||||
let mut env_regs = syscall::EnvRegisters::default();
|
||||
let _ = syscall::read(*cur_env_regs_fd, &mut env_regs)?;
|
||||
let _ = syscall::write(*new_env_regs_fd, &env_regs)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "sysv64" fn __relibc_internal_fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "sysv64" fn __relibc_internal_fork_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
let _ = syscall::close(new_pid_fd);
|
||||
}
|
||||
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.p2align 6
|
||||
.globl __relibc_internal_fork_wrapper
|
||||
.type __relibc_internal_fork_wrapper, @function
|
||||
__relibc_internal_fork_wrapper:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
push rbx
|
||||
push rbp
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
sub rsp, 32
|
||||
|
||||
stmxcsr [rsp+16]
|
||||
fnstcw [rsp+24]
|
||||
|
||||
mov rdi, rsp
|
||||
call __relibc_internal_fork_impl
|
||||
jmp 2f
|
||||
|
||||
.size __relibc_internal_fork_wrapper, . - __relibc_internal_fork_wrapper
|
||||
|
||||
.p2align 6
|
||||
.globl __relibc_internal_fork_ret
|
||||
.type __relibc_internal_fork_ret, @function
|
||||
__relibc_internal_fork_ret:
|
||||
mov rdi, [rsp]
|
||||
mov rsi, [rsp + 8]
|
||||
call __relibc_internal_fork_hook
|
||||
|
||||
ldmxcsr [rsp+16]
|
||||
fldcw [rsp+24]
|
||||
|
||||
xor rax, rax
|
||||
|
||||
.p2align 4
|
||||
2:
|
||||
add rsp, 32
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbp
|
||||
pop rbx
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
.size __relibc_internal_fork_ret, . - __relibc_internal_fork_ret"
|
||||
);
|
||||
|
||||
extern "sysv64" {
|
||||
pub(crate) fn __relibc_internal_fork_wrapper() -> usize;
|
||||
pub(crate) fn __relibc_internal_fork_ret();
|
||||
}
|
||||
+134
-183
@@ -1,5 +1,6 @@
|
||||
use core::mem;
|
||||
use syscall::{self, number::SYS_SIGRETURN, Result, SetSighandlerData, SignalStack};
|
||||
use redox_rt::signal::{Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler};
|
||||
use syscall::{self, Result};
|
||||
|
||||
use super::{
|
||||
super::{types::*, Pal, PalSignal},
|
||||
@@ -8,11 +9,15 @@ use super::{
|
||||
use crate::{
|
||||
header::{
|
||||
errno::{EINVAL, ENOSYS},
|
||||
signal::{sigaction, siginfo_t, sigset_t, stack_t},
|
||||
signal::{
|
||||
sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN,
|
||||
SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK,
|
||||
},
|
||||
sys_time::{itimerval, ITIMER_REAL},
|
||||
time::timespec,
|
||||
},
|
||||
platform::ERRNO,
|
||||
pthread::Errno,
|
||||
};
|
||||
|
||||
impl PalSignal for Sys {
|
||||
@@ -48,11 +53,11 @@ impl PalSignal for Sys {
|
||||
}
|
||||
|
||||
fn kill(pid: pid_t, sig: c_int) -> c_int {
|
||||
e(syscall::kill(pid as usize, sig as usize)) as c_int
|
||||
e(redox_rt::sys::posix_kill(pid as usize, sig as usize).map(|()| 0)) as c_int
|
||||
}
|
||||
|
||||
fn killpg(pgrp: pid_t, sig: c_int) -> c_int {
|
||||
e(syscall::kill(-(pgrp as isize) as usize, sig as usize)) as c_int
|
||||
e(redox_rt::sys::posix_killpg(pgrp as usize, sig as usize).map(|()| 0)) as c_int
|
||||
}
|
||||
|
||||
fn raise(sig: c_int) -> c_int {
|
||||
@@ -104,21 +109,137 @@ impl PalSignal for Sys {
|
||||
0
|
||||
}
|
||||
|
||||
fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> c_int {
|
||||
e(sigaction_impl(sig, act, oact).map(|()| 0)) as c_int
|
||||
fn sigaction(
|
||||
sig: c_int,
|
||||
c_act: Option<&sigaction>,
|
||||
c_oact: Option<&mut sigaction>,
|
||||
) -> Result<(), Errno> {
|
||||
let sig = u8::try_from(sig).map_err(|_| syscall::Error::new(syscall::EINVAL))?;
|
||||
|
||||
let new_action = c_act.map(|c_act| {
|
||||
let handler = c_act.sa_handler.map_or(0, |f| f as usize);
|
||||
|
||||
let kind = if handler == SIG_DFL {
|
||||
SigactionKind::Default
|
||||
} else if handler == SIG_IGN {
|
||||
SigactionKind::Ignore
|
||||
} else {
|
||||
SigactionKind::Handled {
|
||||
handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as c_ulong != 0 {
|
||||
SignalHandler {
|
||||
sigaction: unsafe { core::mem::transmute(c_act.sa_handler) },
|
||||
}
|
||||
} else {
|
||||
SignalHandler {
|
||||
handler: c_act.sa_handler,
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Sigaction {
|
||||
kind,
|
||||
mask: c_act.sa_mask,
|
||||
flags: SigactionFlags::from_bits_retain(c_act.sa_flags as u32),
|
||||
}
|
||||
});
|
||||
let mut old_action = c_oact.as_ref().map(|_| Sigaction::default());
|
||||
|
||||
redox_rt::signal::sigaction(sig, new_action.as_ref(), old_action.as_mut())?;
|
||||
|
||||
if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) {
|
||||
*c_oact = match old_action.kind {
|
||||
SigactionKind::Ignore => sigaction {
|
||||
sa_handler: unsafe { core::mem::transmute(SIG_IGN) },
|
||||
sa_flags: 0,
|
||||
sa_restorer: None,
|
||||
sa_mask: 0,
|
||||
},
|
||||
SigactionKind::Default => sigaction {
|
||||
sa_handler: unsafe { core::mem::transmute(SIG_DFL) },
|
||||
sa_flags: 0,
|
||||
sa_restorer: None,
|
||||
sa_mask: 0,
|
||||
},
|
||||
SigactionKind::Handled { handler } => sigaction {
|
||||
sa_handler: if old_action.flags.contains(SigactionFlags::SIGINFO) {
|
||||
unsafe { core::mem::transmute(handler.sigaction) }
|
||||
} else {
|
||||
unsafe { handler.handler }
|
||||
},
|
||||
sa_restorer: None,
|
||||
sa_flags: old_action.flags.bits().into(),
|
||||
sa_mask: old_action.mask,
|
||||
},
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
|
||||
unimplemented!()
|
||||
unsafe fn sigaltstack(
|
||||
new_c: Option<&stack_t>,
|
||||
old_c: Option<&mut stack_t>,
|
||||
) -> Result<(), Errno> {
|
||||
let new = new_c
|
||||
.map(|c_stack| {
|
||||
let flags = usize::try_from(c_stack.ss_flags).map_err(|_| Errno(EINVAL))?;
|
||||
if flags != flags & (SS_DISABLE | SS_ONSTACK) {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
|
||||
Ok(if flags & SS_DISABLE == SS_DISABLE {
|
||||
Sigaltstack::Disabled
|
||||
} else {
|
||||
Sigaltstack::Enabled {
|
||||
onstack: false,
|
||||
base: c_stack.ss_sp.cast(),
|
||||
size: c_stack.ss_size,
|
||||
}
|
||||
})
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let mut old = old_c.as_ref().map(|_| Sigaltstack::default());
|
||||
redox_rt::signal::sigaltstack(new.as_ref(), old.as_mut())?;
|
||||
|
||||
if let (Some(old_c_stack), Some(old)) = (old_c, old) {
|
||||
*old_c_stack = match old {
|
||||
Sigaltstack::Disabled => stack_t {
|
||||
ss_sp: core::ptr::null_mut(),
|
||||
ss_size: 0,
|
||||
ss_flags: SS_DISABLE.try_into().unwrap(),
|
||||
},
|
||||
Sigaltstack::Enabled {
|
||||
onstack,
|
||||
base,
|
||||
size,
|
||||
} => stack_t {
|
||||
ss_sp: base.cast(),
|
||||
ss_size: size,
|
||||
ss_flags: SS_ONSTACK.try_into().unwrap(),
|
||||
},
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn sigpending(set: *mut sigset_t) -> c_int {
|
||||
ERRNO.set(ENOSYS);
|
||||
-1
|
||||
fn sigpending(set: &mut sigset_t) -> Result<(), Errno> {
|
||||
*set = redox_rt::signal::currently_pending();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int {
|
||||
e(sigprocmask_impl(how, set, oset).map(|()| 0)) as c_int
|
||||
fn sigprocmask(
|
||||
how: c_int,
|
||||
set: Option<&sigset_t>,
|
||||
oset: Option<&mut sigset_t>,
|
||||
) -> Result<(), Errno> {
|
||||
Ok(match how {
|
||||
SIG_SETMASK => redox_rt::signal::set_sigmask(set.copied(), oset)?,
|
||||
SIG_BLOCK => redox_rt::signal::or_sigmask(set.copied(), oset)?,
|
||||
SIG_UNBLOCK => redox_rt::signal::andn_sigmask(set.copied(), oset)?,
|
||||
|
||||
_ => return Err(Errno(EINVAL)),
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn sigsuspend(set: *const sigset_t) -> c_int {
|
||||
@@ -135,173 +256,3 @@ impl PalSignal for Sys {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sigaction_impl(
|
||||
sig: i32,
|
||||
act: Option<&sigaction>,
|
||||
oact: Option<&mut sigaction>,
|
||||
) -> Result<()> {
|
||||
let new_opt = act.map(|act| {
|
||||
let sa_handler = unsafe { mem::transmute(act.sa_handler) };
|
||||
syscall::SigAction {
|
||||
sa_handler,
|
||||
sa_mask: act.sa_mask as u64,
|
||||
sa_flags: syscall::SigActionFlags::from_bits(act.sa_flags as usize)
|
||||
.expect("sigaction: invalid bit pattern"),
|
||||
}
|
||||
});
|
||||
let mut old_opt = oact.as_ref().map(|_| syscall::SigAction::default());
|
||||
syscall::sigaction(sig as usize, new_opt.as_ref(), old_opt.as_mut())?;
|
||||
if let (Some(old), Some(oact)) = (old_opt, oact) {
|
||||
oact.sa_handler = unsafe { mem::transmute(old.sa_handler) };
|
||||
oact.sa_mask = old.sa_mask as sigset_t;
|
||||
oact.sa_flags = old.sa_flags.bits() as c_ulong;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) unsafe fn sigprocmask_impl(
|
||||
how: i32,
|
||||
set: *const sigset_t,
|
||||
oset: *mut sigset_t,
|
||||
) -> Result<()> {
|
||||
syscall::sigprocmask(how as usize, set.as_ref(), oset.as_mut())?;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
|
||||
|
||||
pub fn sighandler_function() -> usize {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
// Check OSXSAVE bit
|
||||
// TODO: HWCAP?
|
||||
if CPUID_EAX1_ECX.load(core::sync::atomic::Ordering::Relaxed) & (1 << 27) != 0 {
|
||||
__relibc_internal_sigentry_xsave as usize
|
||||
} else {
|
||||
__relibc_internal_sigentry_fxsave as usize
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "aarch64"))]
|
||||
{
|
||||
__relibc_internal_sigentry as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_sighandler() {
|
||||
use core::mem::size_of;
|
||||
|
||||
// TODO
|
||||
let altstack_base = 0_usize;
|
||||
let altstack_len = 0_usize;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx;
|
||||
CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
let data = SetSighandlerData {
|
||||
entry: sighandler_function(),
|
||||
altstack_base,
|
||||
altstack_len,
|
||||
};
|
||||
|
||||
let fd = syscall::open(
|
||||
"thisproc:current/sighandler",
|
||||
syscall::O_WRONLY | syscall::O_CLOEXEC,
|
||||
)
|
||||
.expect("failed to open thisproc:current/sighandler");
|
||||
syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler");
|
||||
let _ = syscall::close(fd);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SigStack {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fx: [u8; 4096],
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
fx: [u8; 512],
|
||||
|
||||
kernel_pushed: SignalStack,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn inner(stack: &mut SigStack) {
|
||||
let handler: extern "C" fn(c_int) = core::mem::transmute(stack.kernel_pushed.sa_handler);
|
||||
handler(stack.kernel_pushed.sig_num as c_int)
|
||||
}
|
||||
#[cfg(not(target_arch = "x86"))]
|
||||
unsafe extern "C" fn inner_c(stack: usize) {
|
||||
inner(&mut *(stack as *mut SigStack))
|
||||
}
|
||||
#[cfg(target_arch = "x86")]
|
||||
unsafe extern "fastcall" fn inner_fastcall(stack: usize) {
|
||||
inner(&mut *(stack as *mut SigStack))
|
||||
}
|
||||
|
||||
// TODO: is the memset necessary?
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
asmfunction!(__relibc_internal_sigentry_xsave: ["
|
||||
sub rsp, 4096
|
||||
|
||||
cld
|
||||
mov rdi, rsp
|
||||
xor eax, eax
|
||||
mov ecx, 4096
|
||||
rep stosb
|
||||
|
||||
mov eax, 0xffffffff
|
||||
mov edx, eax
|
||||
xsave [rsp]
|
||||
|
||||
mov rdi, rsp
|
||||
call {inner}
|
||||
|
||||
mov eax, 0xffffffff
|
||||
mov edx, eax
|
||||
xrstor [rsp]
|
||||
add rsp, 4096
|
||||
|
||||
mov eax, {SYS_SIGRETURN}
|
||||
syscall
|
||||
"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
asmfunction!(__relibc_internal_sigentry_fxsave: ["
|
||||
sub rsp, 4096
|
||||
|
||||
fxsave64 [rsp]
|
||||
|
||||
mov rdi, rsp
|
||||
call {inner}
|
||||
|
||||
fxrstor64 [rsp]
|
||||
add rsp, 4096
|
||||
|
||||
mov eax, {SYS_SIGRETURN}
|
||||
syscall
|
||||
"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]);
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
asmfunction!(__relibc_internal_sigentry: ["
|
||||
sub esp, 512
|
||||
fxsave [esp]
|
||||
|
||||
mov ecx, esp
|
||||
call {inner}
|
||||
|
||||
add esp, 512
|
||||
fxrstor [esp]
|
||||
|
||||
mov eax, {SYS_SIGRETURN}
|
||||
int 0x80
|
||||
"] <= [inner = sym inner_fastcall, SYS_SIGRETURN = const SYS_SIGRETURN]);
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
asmfunction!(__relibc_internal_sigentry: ["
|
||||
mov x0, sp
|
||||
bl {inner}
|
||||
|
||||
mov x8, {SYS_SIGRETURN}
|
||||
svc 0
|
||||
"] <= [inner = sym inner_c, SYS_SIGRETURN = const SYS_SIGRETURN]);
|
||||
|
||||
+18
-8
@@ -92,6 +92,12 @@ impl From<syscall::Error> for Errno {
|
||||
Errno(value.errno)
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
impl From<Errno> for syscall::Error {
|
||||
fn from(value: Errno) -> Self {
|
||||
syscall::Error::new(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ResultExt<T> {
|
||||
fn or_minus_one_errno(self) -> T;
|
||||
@@ -130,13 +136,15 @@ pub(crate) unsafe fn create(
|
||||
) -> Result<pthread_t, Errno> {
|
||||
let attrs = attrs.copied().unwrap_or_default();
|
||||
|
||||
let mut procmask = 0_u64;
|
||||
let mut current_sigmask = 0_u64;
|
||||
#[cfg(target_os = "redox")]
|
||||
syscall::sigprocmask(syscall::SIG_SETMASK, None, Some(&mut procmask))
|
||||
.expect("failed to obtain sigprocmask for caller");
|
||||
{
|
||||
current_sigmask =
|
||||
redox_rt::signal::get_sigmask().expect("failed to obtain sigprocmask for caller");
|
||||
}
|
||||
|
||||
// Create a locked mutex, unlocked by the thread after it has started.
|
||||
let synchronization_mutex = Mutex::locked(procmask);
|
||||
let synchronization_mutex = Mutex::locked(current_sigmask);
|
||||
let synchronization_mutex = &synchronization_mutex;
|
||||
|
||||
let stack_size = attrs.stacksize.next_multiple_of(Sys::getpagesize());
|
||||
@@ -242,8 +250,10 @@ unsafe extern "C" fn new_thread_shim(
|
||||
(&*mutex).manual_unlock();
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
syscall::sigprocmask(syscall::SIG_SETMASK, Some(&procmask), None)
|
||||
.expect("failed to set procmask in child thread");
|
||||
{
|
||||
redox_rt::signal::set_sigmask(Some(procmask), None)
|
||||
.expect("failed to set procmask in child thread");
|
||||
}
|
||||
|
||||
let retval = entry_point(arg);
|
||||
|
||||
@@ -316,8 +326,8 @@ unsafe fn dealloc_thread(thread: &Pthread) {
|
||||
OS_TID_TO_PTHREAD.lock().remove(&thread.os_tid.get().read());
|
||||
//drop(Box::from_raw(thread as *const Pthread as *mut Pthread));
|
||||
}
|
||||
pub const SIGRT_RLCT_CANCEL: usize = 32;
|
||||
pub const SIGRT_RLCT_TIMER: usize = 33;
|
||||
pub const SIGRT_RLCT_CANCEL: usize = 33;
|
||||
pub const SIGRT_RLCT_TIMER: usize = 34;
|
||||
|
||||
unsafe extern "C" fn cancel_sighandler(_: c_int) {
|
||||
cancel_current_thread();
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@ use core::{intrinsics, ptr};
|
||||
|
||||
use crate::{
|
||||
header::{libgen, stdio, stdlib},
|
||||
ld_so::{self, linker::Linker},
|
||||
ld_so::{self, linker::Linker, tcb::Tcb},
|
||||
platform::{self, get_auxvs, types::*, Pal, Sys},
|
||||
sync::mutex::Mutex,
|
||||
ALLOCATOR,
|
||||
@@ -157,6 +157,8 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
|
||||
//TODO: load root object
|
||||
tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
redox_rt::signal::setup_sighandler(&tcb.os_specific);
|
||||
}
|
||||
|
||||
// Set up argc and argv
|
||||
@@ -182,8 +184,6 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
|
||||
platform::OUR_ENVIRON = copy_string_array(envp, len);
|
||||
platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
platform::sys::signal::setup_sighandler();
|
||||
|
||||
let auxvs = get_auxvs(sp.auxv().cast());
|
||||
crate::platform::init(auxvs);
|
||||
|
||||
@@ -157,6 +157,7 @@ NAMES=\
|
||||
$(EXPECT_NAMES) \
|
||||
dirent/main \
|
||||
pwd \
|
||||
sigchld \
|
||||
stdio/tempnam \
|
||||
stdio/tmpnam \
|
||||
stdlib/bsearch \
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "test_helpers.h"
|
||||
|
||||
volatile sig_atomic_t atomic = 0;
|
||||
volatile sig_atomic_t atomic2 = 0;
|
||||
|
||||
void action(int sig, siginfo_t *info, void *context) {
|
||||
(void)context;
|
||||
|
||||
assert(sig == SIGCHLD);
|
||||
assert(info != NULL);
|
||||
atomic += 1;
|
||||
}
|
||||
void handler(int sig) {
|
||||
assert(sig == SIGPIPE);
|
||||
atomic2 += 1;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int fds[2];
|
||||
int status = pipe(fds);
|
||||
ERROR_IF(pipe, status, == -1);
|
||||
|
||||
int child = fork();
|
||||
ERROR_IF(fork, child, == -1);
|
||||
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
status = sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
ERROR_IF(sigprocmask, status, == -1);
|
||||
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_sigaction = action;
|
||||
status = sigaction(SIGCHLD, &sa, NULL);
|
||||
ERROR_IF(sigaction, status, == -1);
|
||||
|
||||
sa.sa_handler = handler;
|
||||
status = sigaction(SIGPIPE, &sa, NULL);
|
||||
ERROR_IF(sigaction, status, == -1);
|
||||
|
||||
if (child == 0) {
|
||||
status = close(fds[1]);
|
||||
ERROR_IF(close, status, == -1);
|
||||
|
||||
char buf[1];
|
||||
status = read(fds[0], buf, 1);
|
||||
ERROR_IF(read, status, == -1);
|
||||
puts("Child exiting.");
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
int waitpid_stat;
|
||||
|
||||
close(fds[0]);
|
||||
ERROR_IF(close, status, == -1);
|
||||
|
||||
puts("Sending SIGSTOP...");
|
||||
status = kill(child, SIGSTOP);
|
||||
ERROR_IF(kill, status, == -1);
|
||||
|
||||
while (atomic == 0) {
|
||||
status = sched_yield();
|
||||
ERROR_IF(sched_yield, status, == -1);
|
||||
}
|
||||
puts("First handler ran, checking status.");
|
||||
|
||||
status = waitpid(child, &waitpid_stat, WUNTRACED);
|
||||
ERROR_IF(waitpid, status, == -1);
|
||||
assert(WIFSTOPPED(waitpid_stat));
|
||||
assert(WSTOPSIG(waitpid_stat) == SIGSTOP);
|
||||
puts("Correct, sending SIGCONT...");
|
||||
|
||||
status = write(fds[1], "C", 1);
|
||||
ERROR_IF(write, status, == -1);
|
||||
|
||||
status = kill(child, SIGCONT);
|
||||
ERROR_IF(kill, status, == -1);
|
||||
|
||||
while (atomic == 1) {
|
||||
status = sched_yield();
|
||||
ERROR_IF(sched_yield, status, == -1);
|
||||
}
|
||||
puts("Second handler ran, checking status.");
|
||||
|
||||
status = waitpid(child, &waitpid_stat, 0);
|
||||
ERROR_IF(waitpid, status, == -1);
|
||||
assert(WIFEXITED(waitpid_stat));
|
||||
assert(WEXITSTATUS(waitpid_stat) == 0);
|
||||
puts("Child exited.");
|
||||
|
||||
puts("Writing to (broken) pipe.");
|
||||
status = write(fds[1], "B", 1);
|
||||
ERROR_IF(write, status, != -1);
|
||||
assert(errno == EPIPE);
|
||||
|
||||
while (atomic2 == 0) {
|
||||
status = sched_yield();
|
||||
ERROR_IF(sched_yield, status, == -1);
|
||||
}
|
||||
puts("SIGSTOP handler successfully executed.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user