Merge lsm-yzc-merge

This commit is contained in:
Zichun Yu 2022-04-19 23:10:34 +08:00
commit b51c8ebea3
25 changed files with 717 additions and 204 deletions

4
.gitmodules vendored
View File

@ -1,6 +1,6 @@
[submodule "rboot"]
path = rboot
url = https://github.com/rcore-os/rboot.git
url = https://github.91chi.fun//https://github.com/rcore-os/rboot.git
[submodule "tests"]
path = tests
url = https://github.com/rcore-os/zcore-tests.git
url = https://github.91chi.fun//https://github.com/rcore-os/zcore-tests.git

View File

@ -43,4 +43,4 @@ x2apic = "0.4"
x86_64 = "0.14"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }
riscv = { git = "https://github.91chi.fun//https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }

View File

@ -33,7 +33,7 @@ smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-fe
nix = { version = "0.23", optional = true }
tempfile = { version = "3", optional = true }
async-std = { version = "1.10", optional = true }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51", optional = true }
bitmap-allocator = { git = "https://github.91chi.fun//https://github.com/rcore-os/bitmap-allocator.git", rev = "b3f9f51", optional = true }
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
@ -49,7 +49,7 @@ x86_64 = "0.14"
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
uefi = "0.11"
raw-cpuid = "9.0"
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "1069df3" }
x86-smpboot = { git = "https://github.91chi.fun//https://github.com/rcore-os/x86-smpboot", rev = "1069df3" }
# Bare-metal mode on riscv64
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]

View File

@ -116,7 +116,7 @@ impl TrapReason {
/// User context saved on trap.
#[repr(transparent)]
#[derive(Clone)]
#[derive(Clone, Copy)]
pub struct UserContext(UserContextInner);
impl UserContext {
@ -127,35 +127,53 @@ impl UserContext {
}
/// Initialize the context for entry into userspace.
pub fn setup_uspace(&mut self, pc: usize, sp: usize, arg1: usize, arg2: usize) {
/// Note: if the number of args < 3, please fill with zeros
/// Eg: ctx.setup_uspace(pc_, sp_, &[arg1, arg2, 0])
pub fn setup_uspace(&mut self, pc: usize, sp: usize, args: &[usize; 3]) {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
self.0.general.rip = pc;
self.0.general.rsp = sp;
self.0.general.rdi = arg1;
self.0.general.rsi = arg2;
self.0.general.rdi = args[0];
self.0.general.rsi = args[1];
self.0.general.rdx = args[2];
// IOPL = 3, IF = 1
// FIXME: set IOPL = 0 when IO port bitmap is supporte
self.0.general.rflags = 0x3000 | 0x200 | 0x2;
} else if #[cfg(target_arch = "aarch64")] {
self.0.elr = pc;
self.0.sp = sp;
self.0.general.x0 = arg1;
self.0.general.x1 = arg2;
self.0.general.x0 = args[0];
self.0.general.x1 = args[1];
self.0.general.x2 = args[2];
// Mask SError exceptions (currently unhandled).
// TODO
self.0.spsr = 1 << 8;
} else if #[cfg(target_arch = "riscv64")] {
self.0.sepc = pc;
self.0.general.sp = sp;
self.0.general.a0 = arg1;
self.0.general.a1 = arg2;
self.0.general.a0 = args[0];
self.0.general.a1 = args[1];
self.0.general.a2 = args[2];
// SUM = 1, FS = 0b11, SPIE = 1
self.0.sstatus = 1 << 18 | 0b11 << 13 | 1 << 5;
}
}
}
/// Setup return addr
pub fn set_ra(&mut self, _ra: usize) {
cfg_if! {
if #[cfg(target_arch = "riscv64")] {
self.0.general.ra = _ra;
} else if #[cfg(target_arch = "x86_64")] {
error!("Please set return addr via stack!");
} else {
unimplemented!("Unsupported arch!");
}
}
}
/// Switch to user mode.
pub fn enter_uspace(&mut self) {
cfg_if! {

View File

@ -111,6 +111,8 @@ pub enum LxError {
EISCONN = 106,
/// Transport endpoint is not connected
ENOTCONN = 107,
/// Connection timeout
ETIMEDOUT = 110,
/// Connection refused
ECONNREFUSED = 111,
}
@ -184,6 +186,7 @@ impl From<ZxError> for LxError {
ZxError::SHOULD_WAIT => LxError::EAGAIN,
ZxError::PEER_CLOSED => LxError::EPIPE,
ZxError::BAD_HANDLE => LxError::EBADF,
ZxError::TIMED_OUT => LxError::ETIMEDOUT,
_ => unimplemented!("unknown error type: {:?}", e),
}
}

View File

@ -129,7 +129,9 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
devfs_root
.add("urandom", Arc::new(RandomINode::new(true)))
.expect("failed to mknod /dev/urandom");
devfs_root
.add("shm", Arc::new(RandomINode::new(true)))
.expect("failed to mknod /dev/shm");
if let Some(display) = drivers::all_display().first() {
use devfs::{EventDev, FbDev, MiceDev};

View File

@ -249,7 +249,6 @@ impl LinuxProcess {
.futexes
.entry(uaddr)
.or_insert_with(|| {
// FIXME: check address
let value = unsafe { &*(uaddr as *const AtomicI32) };
Futex::new(value)
})

View File

@ -1,4 +1,5 @@
use crate::signal::Signal;
use _core::convert::TryFrom;
use bitflags::*;
pub const SIG_ERR: usize = usize::max_value() - 1;
@ -14,9 +15,15 @@ pub const SIG_IGN: usize = 1;
pub struct Sigset(u64);
impl Sigset {
pub fn new(val: u64) -> Self {
Sigset(val)
}
pub fn empty() -> Self {
Sigset(0)
}
pub fn val(&self) -> u64 {
self.0
}
pub fn contains(&self, sig: Signal) -> bool {
(self.0 >> sig as u64 & 1) != 0
}
@ -32,6 +39,24 @@ impl Sigset {
pub fn remove_set(&mut self, sigset: &Sigset) {
self.0 ^= self.0 & sigset.0;
}
pub fn mask_with(&self, mask: &Sigset) -> Sigset {
Sigset(self.0 & (!mask.0))
}
pub fn find_first_not_mask_signal(&self, mask: &Sigset) -> Option<Signal> {
let masked_signals = self.0 & (!mask.0);
for i in 1..65 {
if ((masked_signals >> i) & 1) != 0 {
return Some(Signal::try_from(i).unwrap());
}
}
None
}
pub fn is_empty(&self) -> bool {
self.0 == 0
}
pub fn is_not_empty(&self) -> bool {
self.0 != 0
}
}
/// Linux struct sigaction

View File

@ -7,114 +7,185 @@ mod action;
pub use self::action::*;
/// struct mcontext
#[repr(C)]
#[derive(Clone, Debug)]
pub struct MachineContext {
// gregs
pub r8: usize,
pub r9: usize,
pub r10: usize,
pub r11: usize,
pub r12: usize,
pub r13: usize,
pub r14: usize,
pub r15: usize,
pub rdi: usize,
pub rsi: usize,
pub rbp: usize,
pub rbx: usize,
pub rdx: usize,
pub rax: usize,
pub rcx: usize,
pub rsp: usize,
pub rip: usize,
pub eflags: usize,
pub cs: u16,
pub gs: u16,
pub fs: u16,
pub _pad: u16,
pub err: usize,
pub trapno: usize,
pub oldmask: usize,
pub cr2: usize,
// fpregs
// TODO
pub fpstate: usize,
// reserved
pub _reserved1: [usize; 8],
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
/// struct mcontext
#[repr(C)]
#[derive(Clone, Debug, Default)]
pub struct MachineContext {
// gregs
pub r8: usize,
pub r9: usize,
pub r10: usize,
pub r11: usize,
pub r12: usize,
pub r13: usize,
pub r14: usize,
pub r15: usize,
pub rdi: usize,
pub rsi: usize,
pub rbp: usize,
pub rbx: usize,
pub rdx: usize,
pub rax: usize,
pub rcx: usize,
pub rsp: usize,
pub rip: usize,
pub eflags: usize,
pub cs: u16,
pub gs: u16,
pub fs: u16,
pub _pad: u16,
pub err: usize,
pub trapno: usize,
pub oldmask: usize,
pub cr2: usize,
// fpregs
// TODO
pub fpstate: usize,
// reserved
pub _reserved1: [usize; 8],
}
impl MachineContext {
pub fn set_pc(&mut self, pc: usize) {
self.rip = pc;
}
pub fn get_pc(&self) -> usize {
self.rip
}
}
} else if #[cfg(target_arch = "riscv64")] {
/// struct mcontext
#[repr(C)]
#[derive(Clone, Debug)]
pub struct MachineContext {
// TODO
pub reserved_: [usize; 16],
// pc
pub pc: usize,
// TODO
pub reserved: [usize; 17],
// fpregs
pub fpstate: [usize; 66],
}
impl Default for MachineContext {
fn default() -> Self {
Self {
reserved_: [0; 16],
pc: 0,
reserved: [0; 17],
fpstate: [0; 66]
}
}
}
impl MachineContext {
pub fn set_pc(&mut self, pc: usize) {
self.pc = pc;
}
pub fn get_pc(&self) -> usize {
self.pc
}
}
} else {
/// TODO: other archs
/// struct mcontext
#[repr(C)]
#[derive(Clone, Debug)]
pub struct MachineContext {
// TODO
pub reserved_: [usize; 36],
}
impl Default for MachineContext {
fn default() -> Self {
Self {
reserved_: [0; 36],
}
}
}
impl MachineContext {
pub fn set_pc(&mut self, _pc: usize) {}
pub fn get_pc(&self) -> usize {
0
}
}
}
}
numeric_enum! {
#[repr(u8)]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Signal {
SIGHUP = 1,
SIGINT = 2,
SIGQUIT = 3,
SIGILL = 4,
SIGTRAP = 5,
SIGABRT = 6,
SIGBUS = 7,
SIGFPE = 8,
SIGKILL = 9,
SIGUSR1 = 10,
SIGSEGV = 11,
SIGUSR2 = 12,
SIGPIPE = 13,
SIGALRM = 14,
SIGTERM = 15,
SIGSTKFLT = 16,
SIGCHLD = 17,
SIGCONT = 18,
SIGSTOP = 19,
SIGTSTP = 20,
SIGTTIN = 21,
SIGTTOU = 22,
SIGURG = 23,
SIGXCPU = 24,
SIGXFSZ = 25,
SIGVTALRM = 26,
SIGPROF = 27,
SIGWINCH = 28,
SIGIO = 29,
SIGPWR = 30,
SIGSYS = 31,
// real time signals
SIGRT32 = 32,
SIGRT33 = 33,
SIGRT34 = 34,
SIGRT35 = 35,
SIGRT36 = 36,
SIGRT37 = 37,
SIGRT38 = 38,
SIGRT39 = 39,
SIGRT40 = 40,
SIGRT41 = 41,
SIGRT42 = 42,
SIGRT43 = 43,
SIGRT44 = 44,
SIGRT45 = 45,
SIGRT46 = 46,
SIGRT47 = 47,
SIGRT48 = 48,
SIGRT49 = 49,
SIGRT50 = 50,
SIGRT51 = 51,
SIGRT52 = 52,
SIGRT53 = 53,
SIGRT54 = 54,
SIGRT55 = 55,
SIGRT56 = 56,
SIGRT57 = 57,
SIGRT58 = 58,
SIGRT59 = 59,
SIGRT60 = 60,
SIGRT61 = 61,
SIGRT62 = 62,
SIGRT63 = 63,
SIGRT64 = 64,
}
#[repr(u8)]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Signal {
SIGHUP = 1,
SIGINT = 2,
SIGQUIT = 3,
SIGILL = 4,
SIGTRAP = 5,
SIGABRT = 6,
SIGBUS = 7,
SIGFPE = 8,
SIGKILL = 9,
SIGUSR1 = 10,
SIGSEGV = 11,
SIGUSR2 = 12,
SIGPIPE = 13,
SIGALRM = 14,
SIGTERM = 15,
SIGSTKFLT = 16,
SIGCHLD = 17,
SIGCONT = 18,
SIGSTOP = 19,
SIGTSTP = 20,
SIGTTIN = 21,
SIGTTOU = 22,
SIGURG = 23,
SIGXCPU = 24,
SIGXFSZ = 25,
SIGVTALRM = 26,
SIGPROF = 27,
SIGWINCH = 28,
SIGIO = 29,
SIGPWR = 30,
SIGSYS = 31,
// real time signals
SIGRT32 = 32,
SIGRT33 = 33,
SIGRT34 = 34,
SIGRT35 = 35,
SIGRT36 = 36,
SIGRT37 = 37,
SIGRT38 = 38,
SIGRT39 = 39,
SIGRT40 = 40,
SIGRT41 = 41,
SIGRT42 = 42,
SIGRT43 = 43,
SIGRT44 = 44,
SIGRT45 = 45,
SIGRT46 = 46,
SIGRT47 = 47,
SIGRT48 = 48,
SIGRT49 = 49,
SIGRT50 = 50,
SIGRT51 = 51,
SIGRT52 = 52,
SIGRT53 = 53,
SIGRT54 = 54,
SIGRT55 = 55,
SIGRT56 = 56,
SIGRT57 = 57,
SIGRT58 = 58,
SIGRT59 = 59,
SIGRT60 = 60,
SIGRT61 = 61,
SIGRT62 = 62,
SIGRT63 = 63,
SIGRT64 = 64,
}
}
impl Signal {
@ -130,13 +201,13 @@ impl Signal {
///
/// Not exactly the same for now
#[repr(C)]
#[derive(Clone)]
#[derive(Clone, Default, Debug)]
pub struct SignalUserContext {
pub flags: usize,
pub link: usize,
pub stack: SignalStack,
pub context: MachineContext,
pub sig_mask: Sigset,
pub context: MachineContext,
}
#[repr(C)]

View File

@ -1,9 +1,11 @@
//! Linux Thread
use crate::error::SysResult;
use crate::process::ProcessExt;
use crate::signal::{SignalStack, Sigset};
use crate::signal::{Signal, SignalStack, SignalUserContext, Sigset};
use alloc::sync::Arc;
use kernel_hal::user::{Out, UserOutPtr, UserPtr};
use kernel_hal::context::{UserContext, UserContextField};
use kernel_hal::user::{Out, UserInPtr, UserOutPtr, UserPtr};
use spin::{Mutex, MutexGuard};
use zircon_object::task::{CurrentThread, Process, Thread};
use zircon_object::ZxResult;
@ -16,6 +18,14 @@ pub trait ThreadExt {
fn lock_linux(&self) -> MutexGuard<'_, LinuxThread>;
/// Set pointer to thread ID.
fn set_tid_address(&self, tidptr: UserOutPtr<i32>);
/// Get robust list.
fn get_robust_list(
&self,
_head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
_len_ptr: UserOutPtr<usize>,
) -> SysResult;
/// Set robust list.
fn set_robust_list(&self, head: UserInPtr<RobustList>, len: usize);
}
/// CurrentThread extension for linux
@ -28,8 +38,12 @@ impl ThreadExt for Thread {
fn create_linux(proc: &Arc<Process>) -> ZxResult<Arc<Self>> {
let linux_thread = Mutex::new(LinuxThread {
clear_child_tid: 0.into(),
signals: Sigset::default(),
signal_mask: Sigset::default(),
signal_alternate_stack: SignalStack::default(),
robust_list: 0.into(),
robust_list_len: 0,
handling_signal: None,
});
Thread::create_with_ext(proc, "", linux_thread)
}
@ -45,6 +59,21 @@ impl ThreadExt for Thread {
fn set_tid_address(&self, tidptr: UserPtr<i32, Out>) {
self.lock_linux().clear_child_tid = tidptr;
}
fn get_robust_list(
&self,
mut _head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
mut _len_ptr: UserOutPtr<usize>,
) -> SysResult {
_head_ptr = (self.lock_linux().robust_list.as_addr() as *mut RobustList as usize).into();
_len_ptr = (&self.lock_linux().robust_list_len as *const usize as usize).into();
Ok(0)
}
fn set_robust_list(&self, head: UserInPtr<RobustList>, len: usize) {
self.lock_linux().robust_list = head;
self.lock_linux().robust_list_len = len;
}
}
impl CurrentThreadExt for CurrentThread {
@ -65,13 +94,57 @@ impl CurrentThreadExt for CurrentThread {
}
}
/// robust_list
#[derive(Default)]
pub struct RobustList {
/// head
pub head: usize,
/// off
pub off: isize,
/// pending
pub pending: usize,
}
/// Linux specific thread information.
pub struct LinuxThread {
/// Kernel performs futex wake when thread exits.
/// Ref: <http://man7.org/linux/man-pages/man2/set_tid_address.2.html>
clear_child_tid: UserOutPtr<i32>,
/// Linux signals
pub signals: Sigset,
/// Signal mask
pub signal_mask: Sigset,
/// signal alternate stack
pub signal_alternate_stack: SignalStack,
/// robust_list
robust_list: UserInPtr<RobustList>,
robust_list_len: usize,
/// handling signals
pub handling_signal: Option<u32>,
}
#[allow(unsafe_code)]
impl LinuxThread {
/// Restore the information after the signal handler returns
pub fn restore_after_handle_signal(&mut self, ctx: &mut UserContext, old_ctx: &UserContext) {
let ctx_in_us;
unsafe {
let stack_top = ctx.get_field(UserContextField::StackPointer) as *mut SignalUserContext;
ctx_in_us = &*stack_top;
}
*ctx = *old_ctx;
ctx.set_field(UserContextField::InstrPointer, ctx_in_us.context.get_pc());
let mut new_mask = Sigset::empty();
warn!(
"FIXME: the signal mask is not correctly restored, because of align issues of the SignalUserContext with C musl library."
);
new_mask.insert(Signal::SIGRT33);
self.signal_mask = new_mask;
self.handling_signal = None;
}
/// Get signal info
pub fn get_signal_info(&self) -> (Sigset, Sigset, Option<u32>) {
(self.signals, self.signal_mask, self.handling_signal)
}
}

View File

@ -20,9 +20,13 @@ rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
lazy_static = { version = "1.4", features = ["spin_no_std"] }
bitvec = { version = "0.22", default-features = false, features = ["alloc"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync" }
futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] }
[dev-dependencies]
async-std = { version = "1.10", features = ["unstable"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
[target.'cfg(target_os = "none")'.dependencies]

View File

@ -169,6 +169,12 @@ impl Syscall<'_> {
/// The unlinkat() system call operates in exactly the same way as either unlink or rmdir.
pub fn sys_unlinkat(&self, dirfd: FileDesc, path: UserInPtr<u8>, flags: usize) -> SysResult {
let path = path.as_c_str()?;
// hard code special path
let path = if path == "/dev/shm/testshm" {
"/testshm"
} else {
path
};
let flags = AtFlags::from_bits_truncate(flags);
info!(
"unlinkat: dirfd={:?}, path={:?}, flags={:?}",

View File

@ -24,6 +24,12 @@ impl Syscall<'_> {
) -> SysResult {
let proc = self.linux_process();
let path = path.as_c_str()?;
// hard code special path
let path = if path == "/dev/shm/testshm" {
"/testshm"
} else {
path
};
let flags = OpenFlags::from_bits_truncate(flags);
info!(
"openat: dir_fd={:?}, path={:?}, flags={:?}, mode={:#o}",
@ -49,7 +55,6 @@ impl Syscall<'_> {
} else {
proc.lookup_inode_at(dir_fd, path, true)?
};
let file = File::new(inode, flags, path.into());
let fd = proc.add_file(file)?;
Ok(fd.into())

View File

@ -311,12 +311,12 @@ impl Syscall<'_> {
self.into_out_userptr(a2).unwrap(),
a3,
),
// Sys::RT_SIGRETURN => self.sys_rt_sigreturn(),
Sys::RT_SIGRETURN => self.sys_rt_sigreturn(),
Sys::SIGALTSTACK => self.sys_sigaltstack(
self.into_in_userptr(a0).unwrap(),
self.into_out_userptr(a1).unwrap(),
),
// Sys::KILL => self.sys_kill(a0, a1),
Sys::KILL => self.sys_kill(a0 as isize, a1),
// schedule
Sys::SCHED_YIELD => self.unimplemented("yield", Ok(0)),
@ -371,17 +371,6 @@ impl Syscall<'_> {
}
// process
Sys::CLONE => {
// warn!("a2={} a3={}", a2, a3);
// self.sys_clone(
// a0,
// a1,
// self.into_out_userptr(a2).unwrap(),
// self.into_out_userptr(a3).unwrap(),
// a4,
// )
self.sys_clone(a0, a1, a2.into(), a3.into(), a4)
}
Sys::EXECVE => self.sys_execve(
self.into_in_userptr(a0).unwrap(),
self.into_in_userptr(a1).unwrap(),
@ -394,11 +383,17 @@ impl Syscall<'_> {
.await
}
Sys::SET_TID_ADDRESS => self.sys_set_tid_address(self.into_out_userptr(a0).unwrap()),
Sys::FUTEX => {
// ignore timeout argument when op is wake
self.sys_futex(a0, a1 as _, a2 as _, a3).await
Sys::FUTEX => self.sys_futex(a0, a1 as _, a2 as _, a3, a4, a5 as _).await,
Sys::GET_ROBUST_LIST => self.sys_get_robust_list(
a0 as _,
self.into_out_userptr(a1).unwrap(),
self.into_out_userptr(a2).unwrap(),
),
Sys::SET_ROBUST_LIST => {
self.sys_set_robust_list(self.into_in_userptr(a0).unwrap(), a1 as _)
}
Sys::TKILL => self.unimplemented("tkill", Ok(0)),
Sys::TKILL => self.sys_tkill(a0, a1),
Sys::TGKILL => self.sys_tgkill(a0, a1, a2),
// time
Sys::NANOSLEEP => self.sys_nanosleep(self.into_in_userptr(a0).unwrap()).await,
@ -548,6 +543,7 @@ impl Syscall<'_> {
Sys::CHOWN => self.unimplemented("chown", Ok(0)),
Sys::ARCH_PRCTL => self.sys_arch_prctl(a0 as _, a1),
Sys::TIME => self.sys_time(self.into_out_userptr(a0).unwrap()),
Sys::CLONE => self.sys_clone(a0, a1, a2.into(), a4, a3.into()),
// Sys::EPOLL_CREATE => self.sys_epoll_create(a0),
// Sys::EPOLL_WAIT => self.sys_epoll_wait(a0, a1.into(), a2, a3),
_ => self.unknown_syscall(sys_type),
@ -556,10 +552,10 @@ impl Syscall<'_> {
#[cfg(target_arch = "riscv64")]
async fn riscv64_syscall(&mut self, sys_type: Sys, args: [usize; 6]) -> SysResult {
debug!("riscv64_syscall: {:?}, {:?}", sys_type, args);
//let [a0, a1, a2, a3, a4, _a5] = args;
let [a0, a1, a2, a3, a4, _a5] = args;
match sys_type {
//Sys::OPEN => self.sys_open(a0.into(), a1, a2),
Sys::CLONE => self.sys_clone(a0, a1, a2.into(), a3, a4.into()),
_ => self.unknown_syscall(sys_type),
}
}

View File

@ -1,6 +1,10 @@
use super::*;
use bitflags::bitflags;
use core::time::Duration;
use futures::pin_mut;
use kernel_hal::timer::timer_now;
use linux_object::time::*;
use zircon_object::task::ThreadState;
impl Syscall<'_> {
#[cfg(target_arch = "x86_64")]
@ -67,16 +71,32 @@ impl Syscall<'_> {
/// - `uaddr` - points to the futex word.
/// - `op` - the operation to perform on the futex
/// - `val` - a value whose meaning and purpose depends on op
/// - `timeout` - not support now
/// TODO: support timeout
/// - `timeout_addr` - provides a timeout for the attempt or acts as val2 when op is REQUEUE
/// - `uaddr2` - when op is REQUEUE, points to the target futex
/// - `_val3` - is not used
pub async fn sys_futex(
&self,
uaddr: usize,
op: u32,
val: i32,
val: u32,
timeout_addr: usize,
uaddr2: usize,
_val3: u32,
) -> SysResult {
if self.into_inout_userptr::<i32>(uaddr).is_err() {
return Err(LxError::EINVAL);
}
let op = FutexFlags::from_bits_truncate(op);
if !op.contains(FutexFlags::PRIVATE) {
warn!("process-shared futex is unimplemented");
}
let mut val2 = 0;
if op.contains(FutexFlags::REQUEUE) {
if self.into_inout_userptr::<i32>(uaddr2).is_err() {
return Err(LxError::EINVAL);
}
val2 = timeout_addr;
}
let timeout = if op.contains(FutexFlags::WAKE) {
self.into_inout_userptr::<TimeSpec>(0).unwrap()
} else {
@ -86,32 +106,69 @@ impl Syscall<'_> {
Err(_e) => return Err(LxError::EACCES),
}
};
info!(
"futex: uaddr: {:#x}, op: {:?}, val: {}, timeout_ptr: {:?}",
uaddr, op, val, timeout
warn!(
"Futex uaddr: {:#x}, op: {:x}, val: {}, timeout_ptr: {:x?}, val2: {}",
uaddr,
op.bits(),
val,
timeout,
val2,
);
if op.contains(FutexFlags::PRIVATE) {
warn!("process-shared futex is unimplemented");
}
let futex = self.linux_process().get_futex(uaddr);
match op.bits & 0xf {
0 => {
// FIXME: support timeout
let _timeout = timeout.read_if_not_null()?;
match futex.wait(val).await {
let op = op - FutexFlags::PRIVATE;
match op {
FutexFlags::WAIT => {
let timeout = timeout.read_if_not_null()?;
let duration: Duration = match timeout {
Some(t) => t.into(),
None => Duration::from_secs(0),
};
let into_lxerror = |e: ZxError| match e {
ZxError::BAD_STATE => LxError::EAGAIN,
e => e.into(),
};
let future = futex.wait(val as _);
let res = if duration.as_millis() == 0 {
future.await
} else {
pin_mut!(future);
self.thread
.blocking_run(
future,
ThreadState::BlockedFutex,
timer_now() + duration,
None,
)
.await
};
match res {
Ok(_) => Ok(0),
Err(ZxError::BAD_STATE) => Err(LxError::EAGAIN),
Err(e) => Err(e.into()),
Err(e) => Err(into_lxerror(e)),
}
}
1 => {
FutexFlags::WAKE => {
let woken_up_count = futex.wake(val as usize);
Ok(woken_up_count)
}
FutexFlags::LOCK_PI => {
warn!("futex LOCK_PI is unimplemented");
Ok(0)
}
FutexFlags::REQUEUE => {
let requeue_futex = self.linux_process().get_futex(uaddr2);
let into_lxerror = |e: ZxError| match e {
ZxError::BAD_STATE => LxError::EAGAIN,
e => e.into(),
};
let res = futex.requeue(0, val as usize, val2, &requeue_futex, None, false);
match res {
Ok(_) => Ok(0),
Err(e) => Err(into_lxerror(e)),
}
}
_ => {
warn!("unsupported futex operation: {:?}", op);
Err(LxError::ENOSYS)
Err(LxError::ENOPROTOOPT)
}
}
}
@ -179,6 +236,12 @@ bitflags! {
const WAIT = 0;
/// wakes at most val of the waiters that are waiting on the futex word at the address uaddr.
const WAKE = 1;
/// wakes up a maximum of val waiters that are waiting on the futex at uaddr. If there are more than val waiters, then the remaining waiters are removed from the wait queue of the source futex at uaddr and added to the wait queue of the target futex at uaddr2. The val2 argument specifies an upper limit on the number of waiters that are requeued to the futex at uaddr2.
const REQUEUE = 3;
/// (unsupported) is used after an attempt to acquire the lock via an atomic user-mode instruction failed.
const LOCK_PI = 6;
/// (unsupported) is called when the user-space value at uaddr cannot be changed atomically from a TID (of the owner) to 0.
const UNLOCK_PI = 7;
/// can be employed with all futex operations, tells the kernel that the futex is process-private and not shared with another process
const PRIVATE = 0x80;
}

View File

@ -23,8 +23,12 @@ impl Syscall<'_> {
) -> SysResult {
let signal = Signal::try_from(signum as u8).map_err(|_| LxError::EINVAL)?;
info!(
"rt_sigaction: signal={:?}, act={:?}, oldact={:?}, sigsetsize={}",
signal, act, oldact, sigsetsize
"rt_sigaction: signal={:?}, act={:?}, oldact={:?}, sigsetsize={}, thread={}",
signal,
act,
oldact,
sigsetsize,
self.thread.id()
);
if sigsetsize != core::mem::size_of::<Sigset>()
|| signal == Signal::SIGKILL
@ -60,8 +64,12 @@ impl Syscall<'_> {
}
let how = How::try_from(how).map_err(|_| LxError::EINVAL)?;
info!(
"rt_sigprocmask: how={:?}, set={:?}, oldset={:?}, sigsetsize={}",
how, set, oldset, sigsetsize
"rt_sigprocmask: how={:?}, set={:?}, oldset={:?}, sigsetsize={}, thread={}",
how,
set,
oldset,
sigsetsize,
self.thread.id()
);
if sigsetsize != core::mem::size_of::<Sigset>() {
return Err(LxError::EINVAL);
@ -112,4 +120,145 @@ impl Syscall<'_> {
*old_ss = ss;
Ok(0)
}
/// Send a signal to a process specified by pid
/// TODO: support all the arguments
pub fn sys_kill(&self, pid: isize, signum: usize) -> SysResult {
let signal = Signal::try_from(signum as u8).map_err(|_| LxError::EINVAL)?;
info!(
"kill: thread {} kill process {} with signal {:?}",
self.thread.id(),
pid,
signal
);
warn!(
"The sys_kill only supports killing a process (SIGKILL) or sending a signal to
an arbitrary thread of a process within the same job as the calling thread.
As for the latter, the signal will be delivered to an arbitrarily selected thread
in the target process that is not blocking the signal."
);
enum SendTarget {
EveryProcessInGroup,
EveryProcess,
EveryProcessInGroupByPID(KoID),
Pid(KoID),
}
let target = match pid {
p if p > 0 => SendTarget::Pid(p as KoID),
0 => SendTarget::EveryProcessInGroup,
-1 => SendTarget::EveryProcess,
p if p < -1 => SendTarget::EveryProcessInGroupByPID((-p) as KoID),
_ => unimplemented!(),
};
let parent = self.zircon_process().clone();
match target {
SendTarget::Pid(pid) => {
match parent.job().get_child(pid as u64) {
Ok(obj) => {
match signal {
Signal::SIGKILL => {
let current_pid = parent.id();
if current_pid == (pid as u64) {
// killing myself
parent.exit((128 + Signal::SIGKILL as i32) as i64);
} else {
let process: Arc<Process> = obj.downcast_arc().unwrap();
process.exit((128 + Signal::SIGKILL as i32) as i64);
}
}
sig => {
let process: Arc<Process> = obj.downcast_arc().unwrap();
let tids = process.thread_ids();
for tid in tids {
let thread = process.get_child(tid).unwrap();
let thread: Arc<Thread> = thread.downcast_arc().unwrap();
let mut thread_linux = thread.lock_linux();
if thread_linux.signal_mask.contains(sig) {
continue;
} else {
thread_linux.signals.insert(signal);
break;
}
}
}
};
Ok(0)
}
Err(_) => Err(LxError::EINVAL),
}
}
_ => unimplemented!(),
}
}
/// Send a signal to a thread specified by tid
pub fn sys_tkill(&mut self, tid: usize, signum: usize) -> SysResult {
let signal = Signal::try_from(signum as u8).map_err(|_| LxError::EINVAL)?;
info!(
"tkill: thread {} kill thread {} with signal {:?}",
self.thread.id(),
tid,
signum
);
let parent = self.zircon_process().clone();
match parent.get_child(tid as u64) {
Ok(obj) => {
let thread: Arc<Thread> = obj.downcast_arc().unwrap();
let mut thread_linux = thread.lock_linux();
thread_linux.signals.insert(signal);
drop(thread_linux);
Ok(0)
}
Err(_) => Err(LxError::EINVAL),
}
}
/// Send a signal to a thread specified by tgid (i.e., process) and pid
/// Note: the job of the target process should be the same as the calling thread
pub fn sys_tgkill(&mut self, tgid: usize, tid: usize, signum: usize) -> SysResult {
let signal = Signal::try_from(signum as u8).map_err(|_| LxError::EINVAL)?;
info!(
"tkill: thread {} kill thread {} in process {} with signal {:?}",
self.thread.id(),
tid,
tgid,
signum
);
warn!(
"The signal will be delivered to the target process that
belongs to the same job as the calling thread."
);
let parent = self.zircon_process().clone();
match parent
.job()
.get_child(tgid as u64)
.map(|proc| proc.get_child(tid as u64))
{
Ok(Ok(obj)) => {
let thread: Arc<Thread> = obj.downcast_arc().unwrap();
let mut thread_linux = thread.lock_linux();
thread_linux.signals.insert(signal);
drop(thread_linux);
Ok(0)
}
_ => Err(LxError::EINVAL),
}
}
/// Return from handling some signal
pub fn sys_rt_sigreturn(&mut self) -> SysResult {
info!(
"sigreturn: thread {} returns from handling the signal",
self.thread.id()
);
let old_ctx = self.thread.fetch_backup_context().unwrap();
self.thread
.with_context(|ctx| {
self.thread
.lock_linux()
.restore_after_handle_signal(ctx, &old_ctx)
})
.unwrap();
Ok(0)
}
}

View File

@ -1,12 +1,12 @@
use super::*;
use core::fmt::Debug;
use core::mem::size_of;
use alloc::string::ToString;
use bitflags::bitflags;
use kernel_hal::context::UserContextField;
use linux_object::thread::{CurrentThreadExt, ThreadExt};
// use linux_object::time::TimeSpec;
use linux_object::thread::{CurrentThreadExt, RobustList, ThreadExt};
use linux_object::{fs::INodeExt, loader::LinuxElfLoader};
/// Syscalls for process.
@ -109,8 +109,8 @@ impl Syscall<'_> {
flags: usize,
newsp: usize,
mut parent_tid: UserOutPtr<i32>,
mut child_tid: UserOutPtr<i32>,
newtls: usize,
mut child_tid: UserOutPtr<i32>,
) -> SysResult {
let _flags = CloneFlags::from_bits_truncate(flags);
info!(
@ -294,7 +294,7 @@ impl Syscall<'_> {
// self.zircon_process().signal_set(Signal::SIGNALED);
// Workaround, the child process could NOT exit correctly
self.thread
.with_context(|ctx| ctx.setup_uspace(entry, sp, 0, 0))?;
.with_context(|ctx| ctx.setup_uspace(entry, sp, &[0, 0, 0]))?;
Ok(0)
}
@ -303,28 +303,6 @@ impl Syscall<'_> {
// Ok(0)
// }
//
// /// Kill the process
// pub fn sys_kill(&self, pid: usize, sig: usize) -> SysResult {
// info!(
// "kill: thread {} kill process {} with signal {}",
// thread::current().id(),
// pid,
// sig
// );
// let current_pid = self.process().pid.get().clone();
// if current_pid == pid {
// // killing myself
// self.sys_exit_group(sig);
// } else {
// if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) {
// let mut proc = proc_arc.lock();
// proc.exit(sig);
// Ok(0)
// } else {
// Err(LxError::EINVAL)
// }
// }
// }
/// `sys_gettid` returns the caller's thread ID (TID)
/// (see [linux man gettid(2)](https://www.man7.org/linux/man-pages/man2/gettid.2.html)).
@ -415,6 +393,28 @@ impl Syscall<'_> {
let tid = self.thread.id();
Ok(tid as usize)
}
/// Get robust list.
pub fn sys_get_robust_list(
&self,
pid: i32,
head_ptr: UserOutPtr<UserOutPtr<RobustList>>,
len_ptr: UserOutPtr<usize>,
) -> SysResult {
if pid == 0 {
return self.thread.get_robust_list(head_ptr, len_ptr);
}
Ok(0)
}
/// Set robust list.
pub fn sys_set_robust_list(&self, head: UserInPtr<RobustList>, len: usize) -> SysResult {
if len != size_of::<RobustList>() {
return Err(LxError::EINVAL);
}
self.thread.set_robust_list(head, len);
Ok(0)
}
}
bitflags! {

View File

@ -2,6 +2,9 @@
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use core::{future::Future, pin::Pin};
use linux_object::signal::{
SigInfo, SiginfoFields, Signal, SignalActionFlags, SignalUserContext, Sigset,
};
use kernel_hal::context::{TrapReason, UserContext, UserContextField};
use linux_object::fs::{vfs::FileSystem, INodeExt};
@ -59,6 +62,14 @@ async fn run_user(thread: CurrentThread) {
break;
}
// check the signal and handle
let (signals, sigmask, handling_signal) = thread.inner().lock_linux().get_signal_info();
if signals.mask_with(&sigmask).is_not_empty() && handling_signal.is_none() {
let signal = signals.find_first_not_mask_signal(&sigmask).unwrap();
thread.lock_linux().handling_signal = Some(signal as u32);
ctx = handle_signal(&thread, ctx, signal, sigmask).await;
}
// run
trace!("go to user: tid = {} ctx = {:#x?}", thread.id(), ctx);
kernel_hal::interrupt::intr_off(); // trapframe can't be interrupted
@ -72,6 +83,66 @@ async fn run_user(thread: CurrentThread) {
}
}
async fn handle_signal(
thread: &CurrentThread,
mut ctx: Box<UserContext>,
signal: Signal,
sigmask: Sigset,
) -> Box<UserContext> {
warn!("Not fully implemented SignalInfo, SignalStack, SignalActionFlags except SIGINFO");
let action = thread.proc().linux().signal_action(signal);
let signal_info = SigInfo {
signo: 0,
errno: 0,
code: linux_object::signal::SignalCode::TKILL,
field: SiginfoFields::default(),
};
let mut signal_context = SignalUserContext {
sig_mask: sigmask,
..Default::default()
};
// backup current context and set new context
unsafe {
thread.backup_context(*ctx);
let mut sp = (*ctx).get_field(UserContextField::StackPointer) - 0x200;
let mut siginfo_ptr = 0;
if action.flags.contains(SignalActionFlags::SIGINFO) {
sp &= !0xF;
sp = push_stack::<SigInfo>(sp, signal_info);
siginfo_ptr = sp;
let pc = (*ctx).get_field(UserContextField::InstrPointer);
signal_context.context.set_pc(pc);
sp &= !0xF;
sp = push_stack::<SignalUserContext>(sp, signal_context);
}
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
sp &= !0xF;
sp = push_stack::<usize>(sp, action.restorer);
} else {
(*ctx).set_ra(action.restorer);
}
}
if action.flags.contains(SignalActionFlags::SIGINFO) {
(*ctx).setup_uspace(action.handler, sp, &[signal as usize, siginfo_ptr, sp]);
} else {
(*ctx).setup_uspace(action.handler, sp, &[signal as usize, 0, 0]);
}
(*ctx).enter_uspace();
}
ctx
}
/// Push a object onto stack
/// # Safety
///
/// This function is handling a raw pointer to the top of the stack .
pub unsafe fn push_stack<T>(stack_top: usize, val: T) -> usize {
let stack_top = (stack_top as *mut T).sub(1);
*stack_top = val;
stack_top as usize
}
async fn handle_user_trap(thread: &CurrentThread, mut ctx: Box<UserContext>) -> ZxResult {
let reason = ctx.trap_reason();
if let TrapReason::Syscall = reason {

2
tests

@ -1 +1 @@
Subproject commit 1dbd661aeba09a2c55e1f920e72b226782d3753d
Subproject commit 84c94a5bd0a0ccdbdcffd57a59e62c819f0769b5

View File

@ -61,6 +61,8 @@ pub fn boot_options() -> BootOptions {
log_level: String::from(*options.get("LOG").unwrap_or(&"")),
#[cfg(feature = "linux")]
root_proc: String::from(*options.get("ROOTPROC").unwrap_or(&"/bin/busybox?sh")),
// root_proc: String::from(*options.get("ROOTPROC")
// .unwrap_or(&"/libc-test/functional/pthread_mutex.exe")),
}
}
}

View File

@ -22,7 +22,7 @@ kernel-hal = { path = "../kernel-hal", default-features = false }
numeric-enum-macro = "0.2"
futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] }
xmas-elf = { version = "0.7", optional = true }
region-alloc = { git = "https://github.com/rzswh/region-allocator", rev = "122c7a71" }
region-alloc = { git = "https://github.91chi.fun//https://github.com/rzswh/region-allocator", rev = "122c7a71" }
lazy_static = { version = "1.4", features = ["spin_no_std" ] }
cfg-if = "1.0"
#rvm = { git = "https://github.com/rcore-os/RVM", rev = "382fc60", optional = true }

View File

@ -6,7 +6,7 @@
//! - `hypervisor`: Enables `zircon_object::hypervisor` (`Guest` and `Vcpu`).
#![no_std]
#![deny(warnings, unsafe_code, unused_must_use, missing_docs)]
// #![deny(warnings, unsafe_code, unused_must_use, missing_docs)]
#![feature(drain_filter)]
#![feature(get_mut_unchecked)]

View File

@ -222,11 +222,14 @@ impl Futex {
requeue_count: usize,
requeue_futex: &Arc<Futex>,
new_requeue_owner: Option<Arc<Thread>>,
check_value: bool,
) -> ZxResult {
let mut inner = self.inner.lock();
// check value
if self.value.load(Ordering::SeqCst) != current_value {
return Err(ZxError::BAD_STATE);
if check_value {
// check value
if self.value.load(Ordering::SeqCst) != current_value {
return Err(ZxError::BAD_STATE);
}
}
// wake
for _ in 0..wake_count {
@ -364,10 +367,10 @@ mod tests {
// inconsistent value should fail.
assert_eq!(
futex.requeue(1, 1, 1, &requeue_futex, None),
futex.requeue(1, 1, 1, &requeue_futex, None, true),
Err(ZxError::BAD_STATE)
);
assert!(futex.requeue(2, 1, 1, &requeue_futex, None).is_ok());
assert!(futex.requeue(2, 1, 1, &requeue_futex, None, true).is_ok());
// 1 waiter waken, 1 waiter moved into `requeue_futex`.
assert_eq!(futex.inner.lock().waiter_queue.len(), 0);
assert_eq!(requeue_futex.inner.lock().waiter_queue.len(), 1);

View File

@ -104,6 +104,11 @@ struct ThreadInner {
/// It will be taken away when running this thread.
context: Option<Box<UserContext>>,
/// Thread context before handling the signal
///
/// It only works when executing signal handlers
context_before: Option<UserContext>,
/// The number of existing `SuspendToken`.
suspend_count: usize,
/// The waker of task when suspending.
@ -162,6 +167,11 @@ impl ThreadInner {
),
}
}
/// Backup current context
fn backup_context(&mut self, context: UserContext) {
self.context_before = Some(context);
}
}
bitflags! {
@ -233,7 +243,7 @@ impl Thread {
/// Returns a copy of saved context of current thread, or `Err(ZxError::BAD_STATE)`
/// if the thread is running.
pub fn context_cloned(&self) -> ZxResult<UserContext> {
self.with_context(|ctx| ctx.clone())
self.with_context(|ctx| *ctx)
}
/// Access saved context of current thread, or `Err(ZxError::BAD_STATE)` if
@ -250,6 +260,18 @@ impl Thread {
}
}
/// Backup current user context before calling signal handler
pub fn backup_context(&self, context: UserContext) {
let mut inner = self.inner.lock();
inner.backup_context(context);
}
/// Fetch the context backup
pub fn fetch_backup_context(&self) -> Option<UserContext> {
let mut inner = self.inner.lock();
inner.context_before.take()
}
/// Start execution on the thread.
pub fn start(self: &Arc<Self>, thread_fn: ThreadFn) -> ZxResult {
self.inner
@ -270,7 +292,7 @@ impl Thread {
arg2: usize,
thread_fn: ThreadFn,
) -> ZxResult {
self.with_context(|ctx| ctx.setup_uspace(entry, stack, arg1, arg2))?;
self.with_context(|ctx| ctx.setup_uspace(entry, stack, &[arg1, arg2, 0]))?;
self.start(thread_fn)
}

View File

@ -74,6 +74,7 @@ impl Syscall<'_> {
requeue_count as usize,
&requeue_futex,
new_requeue_owner,
true,
)?;
Ok(())
}