From 9cf8fe1777de4f7cea4d2c1521c1dd6a0ea5ceca Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Tue, 15 Nov 2022 14:08:21 +0800 Subject: [PATCH] running busybox ash until poll --- .gitattributes | 3 +- src/kxos-std/src/error.rs | 6 +++ src/kxos-std/src/fs/events.rs | 13 +++++ src/kxos-std/src/fs/fcntl.rs | 36 +++++++++++++ src/kxos-std/src/fs/file.rs | 26 ++++++++++ src/kxos-std/src/fs/file_table.rs | 53 ++++++++++++++++++++ src/kxos-std/src/fs/ioctl/mod.rs | 42 ++++++++++++++++ src/kxos-std/src/fs/ioctl/termio.rs | 45 +++++++++++++++++ src/kxos-std/src/fs/mod.rs | 7 +++ src/kxos-std/src/fs/poll.rs | 45 +++++++++++++++++ src/kxos-std/src/fs/stat.rs | 9 ++++ src/kxos-std/src/fs/stdio.rs | 18 +++++++ src/kxos-std/src/lib.rs | 21 ++++---- src/kxos-std/src/process/clone.rs | 3 ++ src/kxos-std/src/process/mod.rs | 32 ++++++++++-- src/kxos-std/src/syscall/fcntl.rs | 27 ++++++++++ src/kxos-std/src/syscall/getcwd.rs | 15 ++++++ src/kxos-std/src/syscall/ioctl.rs | 54 ++++++++++++++++++++ src/kxos-std/src/syscall/lstat.rs | 24 +++++++++ src/kxos-std/src/syscall/mod.rs | 30 ++++++++--- src/kxos-std/src/syscall/openat.rs | 29 +++++++++++ src/kxos-std/src/syscall/poll.rs | 64 ++++++++++++++++++++++++ src/kxos-std/src/syscall/rt_sigaction.rs | 2 - src/kxos-std/src/user_apps.rs | 39 ++++++++++++--- src/kxos-user/busybox/busybox | 3 ++ 25 files changed, 615 insertions(+), 31 deletions(-) create mode 100644 src/kxos-std/src/fs/events.rs create mode 100644 src/kxos-std/src/fs/fcntl.rs create mode 100644 src/kxos-std/src/fs/file.rs create mode 100644 src/kxos-std/src/fs/file_table.rs create mode 100644 src/kxos-std/src/fs/ioctl/mod.rs create mode 100644 src/kxos-std/src/fs/ioctl/termio.rs create mode 100644 src/kxos-std/src/fs/poll.rs create mode 100644 src/kxos-std/src/fs/stdio.rs create mode 100644 src/kxos-std/src/syscall/fcntl.rs create mode 100644 src/kxos-std/src/syscall/getcwd.rs create mode 100644 src/kxos-std/src/syscall/ioctl.rs create mode 100644 src/kxos-std/src/syscall/lstat.rs create mode 100644 src/kxos-std/src/syscall/openat.rs create mode 100644 src/kxos-std/src/syscall/poll.rs create mode 100755 src/kxos-user/busybox/busybox diff --git a/.gitattributes b/.gitattributes index 9aecc4572..8675e119a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,4 +4,5 @@ src/kxos-user/hello_c/hello filter=lfs diff=lfs merge=lfs -text src/kxos-user/execve/execve filter=lfs diff=lfs merge=lfs -text src/kxos-user/execve/hello filter=lfs diff=lfs merge=lfs -text src/kxos-user/fork_c/fork filter=lfs diff=lfs merge=lfs -text -src/kxos-user/signal_c/signal_test filter=lfs diff=lfs merge=lfs -text \ No newline at end of file +src/kxos-user/signal_c/signal_test filter=lfs diff=lfs merge=lfs -text +src/kxos-user/busybox/busybox filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/src/kxos-std/src/error.rs b/src/kxos-std/src/error.rs index ed69337b3..7f2c91f83 100644 --- a/src/kxos-std/src/error.rs +++ b/src/kxos-std/src/error.rs @@ -211,6 +211,12 @@ impl From for Error { } } +impl From for Error { + fn from(_: alloc::ffi::NulError) -> Self { + Error::with_message(Errno::E2BIG, "Cannot find null in cstring") + } +} + #[macro_export] macro_rules! return_errno { ($errno: expr) => { diff --git a/src/kxos-std/src/fs/events.rs b/src/kxos-std/src/fs/events.rs new file mode 100644 index 000000000..b414fc020 --- /dev/null +++ b/src/kxos-std/src/fs/events.rs @@ -0,0 +1,13 @@ +use crate::prelude::*; + +bitflags! { + pub struct IoEvents: u32 { + const POLLIN = 0x0001; + const POLLPRI = 0x0002; + const POLLOUT = 0x0004; + const POLLERR = 0x0008; + const POLLHUP = 0x0010; + const POLLNVAL = 0x0020; + const POLLRDHUP = 0x2000; + } +} diff --git a/src/kxos-std/src/fs/fcntl.rs b/src/kxos-std/src/fs/fcntl.rs new file mode 100644 index 000000000..844fb6266 --- /dev/null +++ b/src/kxos-std/src/fs/fcntl.rs @@ -0,0 +1,36 @@ +use crate::prelude::*; + +use crate::define_fcntl_cmd; + +define_fcntl_cmd! { + F_DUPFD = 0, + F_GETFD = 1, + F_SETFD = 2, + F_DUPFD_CLOEXEC = 1030 +} + +#[macro_export] +macro_rules! define_fcntl_cmd { + ($($name: ident = $value: expr),*) => { + #[repr(i32)] + #[derive(Debug, Clone, Copy)] + #[allow(non_camel_case_types)] + pub enum FcntlCmd { + $($name = $value,)* + } + + $( + pub const $name: i32 = $value; + )* + + impl TryFrom for FcntlCmd { + type Error = Error; + fn try_from(value: i32) -> Result { + match value { + $($name => Ok(FcntlCmd::$name),)* + _ => return_errno!(Errno::EINVAL), + } + } + } + } +} diff --git a/src/kxos-std/src/fs/file.rs b/src/kxos-std/src/fs/file.rs new file mode 100644 index 000000000..e2fad1d9c --- /dev/null +++ b/src/kxos-std/src/fs/file.rs @@ -0,0 +1,26 @@ +use crate::prelude::*; +use core::{any::Any, fmt::Debug}; + +use super::events::IoEvents; +use super::ioctl::IoctlCmd; + +pub type FileDescripter = i32; + +/// The basic operations defined on a file +pub trait File: Send + Sync + Debug + Any { + fn read(&self, buf: &mut [u8]) -> Result { + panic!("read unsupported"); + } + + fn write(&self, buf: &[u8]) -> Result { + panic!("write unsupported"); + } + + fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { + panic!("ioctl unsupported"); + } + + fn poll(&self) -> IoEvents { + IoEvents::empty() + } +} diff --git a/src/kxos-std/src/fs/file_table.rs b/src/kxos-std/src/fs/file_table.rs new file mode 100644 index 000000000..ea4923e91 --- /dev/null +++ b/src/kxos-std/src/fs/file_table.rs @@ -0,0 +1,53 @@ +use crate::prelude::*; + +use super::{ + file::{File, FileDescripter}, + stdio::{Stderr, Stdin, Stdout, FD_STDERR, FD_STDIN, FD_STDOUT}, +}; + +#[derive(Debug, Clone)] +pub struct FileTable { + table: BTreeMap>, +} + +impl FileTable { + pub fn new() -> Self { + Self { + table: BTreeMap::new(), + } + } + + pub fn new_with_stdio() -> Self { + let mut table = BTreeMap::new(); + table.insert(FD_STDIN, Arc::new(Stdin) as Arc); + table.insert(FD_STDOUT, Arc::new(Stdout) as Arc); + table.insert(FD_STDERR, Arc::new(Stderr) as Arc); + Self { table } + } + + pub fn dup(&mut self, fd: FileDescripter, new_fd: Option) -> Result<()> { + let file = self.table.get(&fd).map_or_else( + || return_errno_with_message!(Errno::ENOENT, "No such file"), + |f| Ok(f.clone()), + )?; + let new_fd = if let Some(new_fd) = new_fd { + new_fd + } else { + self.max_fd() + 1 + }; + if self.table.contains_key(&new_fd) { + return_errno_with_message!(Errno::EBADF, "Fd exists"); + } + self.table.insert(new_fd, file); + + Ok(()) + } + + fn max_fd(&self) -> FileDescripter { + self.table.iter().map(|(fd, _)| fd.clone()).max().unwrap() + } + + pub fn get_file(&self, fd: FileDescripter) -> Option<&Arc> { + self.table.get(&fd) + } +} diff --git a/src/kxos-std/src/fs/ioctl/mod.rs b/src/kxos-std/src/fs/ioctl/mod.rs new file mode 100644 index 000000000..487adc76e --- /dev/null +++ b/src/kxos-std/src/fs/ioctl/mod.rs @@ -0,0 +1,42 @@ +pub mod termio; + +use crate::define_ioctl_cmd; +use crate::prelude::*; + +define_ioctl_cmd! { + // Get terminal attributes + TCGETS = 0x5401, + TCSETS = 0x5402, + // Get the process group ID of the foreground process group on this terminal + TIOCGPGRP = 0x540f, + // Set the foreground process group ID of this terminal. + TIOCSPGRP = 0x5410, + // Set window size + TIOCGWINSZ = 0x5413, + TIOCSWINSZ = 0x5414 +} + +#[macro_export] +macro_rules! define_ioctl_cmd { + ($($name: ident = $value: expr),*) => { + #[repr(u32)] + #[derive(Debug, Clone, Copy)] + pub enum IoctlCmd { + $($name = $value,)* + } + + $( + pub const $name: u32 = $value; + )* + + impl TryFrom for IoctlCmd { + type Error = Error; + fn try_from(value: u32) -> Result { + match value { + $($name => Ok(IoctlCmd::$name),)* + _ => return_errno!(Errno::EINVAL), + } + } + } + } +} diff --git a/src/kxos-std/src/fs/ioctl/termio.rs b/src/kxos-std/src/fs/ioctl/termio.rs new file mode 100644 index 000000000..99001baad --- /dev/null +++ b/src/kxos-std/src/fs/ioctl/termio.rs @@ -0,0 +1,45 @@ +//! This definition is from occlum +const KERNEL_NCCS: usize = 19; + +type TcflagT = u32; +type CcT = u8; +type SpeedT = u32; + +#[derive(Debug, Clone, Copy, Pod)] +#[repr(C)] +pub struct KernelTermios { + pub c_iflags: TcflagT, + pub c_oflags: TcflagT, + pub c_cflags: TcflagT, + pub c_lflags: TcflagT, + pub c_line: CcT, + pub c_cc: [CcT; KERNEL_NCCS], +} + +impl KernelTermios { + /// TODO: This fake result is from whitley + pub fn fake_kernel_termios() -> Self { + let mut termios = KernelTermios::new(); + termios.c_iflags = 0x6d02; + termios.c_oflags = 0x5; + termios.c_cflags = 0x4bf; + termios.c_lflags = 0x8acb; + termios.c_line = 0; + termios.c_cc = [ + 0x03, 0x1c, 0x7f, 0x15, 0x04, 0x00, 0x01, 0x00, 0x11, 0x13, 0x1a, 0xff, 0x12, 0x0f, + 0x17, 0x16, 0xff, 0x00, 0x00, + ]; + termios + } + + fn new() -> Self { + KernelTermios { + c_iflags: 0, + c_oflags: 0, + c_cflags: 0, + c_lflags: 0, + c_line: 0, + c_cc: [0; KERNEL_NCCS], + } + } +} diff --git a/src/kxos-std/src/fs/mod.rs b/src/kxos-std/src/fs/mod.rs index 4f22af63a..c8beb460b 100644 --- a/src/kxos-std/src/fs/mod.rs +++ b/src/kxos-std/src/fs/mod.rs @@ -1 +1,8 @@ +pub mod events; +pub mod fcntl; +pub mod file; +pub mod file_table; +pub mod ioctl; +pub mod poll; pub mod stat; +pub mod stdio; diff --git a/src/kxos-std/src/fs/poll.rs b/src/kxos-std/src/fs/poll.rs new file mode 100644 index 000000000..8f64fa612 --- /dev/null +++ b/src/kxos-std/src/fs/poll.rs @@ -0,0 +1,45 @@ +#![allow(non_camel_case_types)] + +use super::events::IoEvents; +use super::file::FileDescripter; +pub type c_nfds = u64; + +// https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/poll.h +#[derive(Debug, Clone, Copy, Pod)] +#[repr(C)] +pub struct c_pollfd { + fd: FileDescripter, + events: i16, + revents: i16, +} + +#[derive(Debug, Clone, Copy)] +pub struct PollFd { + pub fd: FileDescripter, + pub events: IoEvents, + pub revents: IoEvents, +} + +impl From for PollFd { + fn from(raw: c_pollfd) -> Self { + let events = IoEvents::from_bits_truncate(raw.events as _); + let revents = IoEvents::from_bits_truncate(raw.revents as _); + Self { + fd: raw.fd, + events, + revents, + } + } +} + +impl From for c_pollfd { + fn from(raw: PollFd) -> Self { + let events = raw.events.bits() as i16; + let revents = raw.revents.bits() as i16; + Self { + fd: raw.fd, + events, + revents, + } + } +} diff --git a/src/kxos-std/src/fs/stat.rs b/src/kxos-std/src/fs/stat.rs index 73db144f3..bb5b06c4d 100644 --- a/src/kxos-std/src/fs/stat.rs +++ b/src/kxos-std/src/fs/stat.rs @@ -58,4 +58,13 @@ impl Stat { stat.st_blksize = 1024; stat } + + /// Fake stat for a dir + pub fn fake_dir_stat() -> Self { + let mut stat = Stat::default(); + stat.st_mode = S_IFDIR | 0o755; + stat.st_nlink = 20; + stat.st_blksize = 4096; + stat + } } diff --git a/src/kxos-std/src/fs/stdio.rs b/src/kxos-std/src/fs/stdio.rs new file mode 100644 index 000000000..5be619ee0 --- /dev/null +++ b/src/kxos-std/src/fs/stdio.rs @@ -0,0 +1,18 @@ +use super::file::{File, FileDescripter}; + +pub const FD_STDIN: FileDescripter = 0; +pub const FD_STDOUT: FileDescripter = 1; +pub const FD_STDERR: FileDescripter = 2; + +#[derive(Debug)] +pub struct Stdin; + +#[derive(Debug)] +pub struct Stdout; + +#[derive(Debug)] +pub struct Stderr; + +impl File for Stdin {} +impl File for Stdout {} +impl File for Stderr {} diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index 19ae2ecfb..de6f4227c 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -10,7 +10,7 @@ #![feature(btree_drain_filter)] #![feature(const_option)] -use crate::prelude::*; +use crate::{prelude::*, user_apps::UserApp}; use kxos_frame::{info, println}; use process::Process; @@ -59,16 +59,15 @@ pub fn init_process() { process.pid() ); - for app in get_all_apps() { - let app_name = app.app_name(); - info!("[kxos-std/lib.rs] spwan {:?} process", app.app_name()); - let argv = vec![app_name.clone()]; - let process = Process::spawn_user_process(app_name, app.app_content(), argv, Vec::new()); - info!( - "[kxos-std/lib.rs] {:?} process exits, pid = {}", - app.app_name(), - process.pid() - ); + for app in get_all_apps().into_iter().last() { + let UserApp { + app_name, + app_content, + argv, + envp, + } = app; + info!("[kxos-std/lib.rs] spwan {:?} process", app_name); + Process::spawn_user_process(app_name.clone(), app_content, argv, Vec::new()); } loop { diff --git a/src/kxos-std/src/process/clone.rs b/src/kxos-std/src/process/clone.rs index aa4b373d5..7a17af55a 100644 --- a/src/kxos-std/src/process/clone.rs +++ b/src/kxos-std/src/process/clone.rs @@ -127,6 +127,8 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result< debug!("child process pid: {}", child_pid); debug!("rip = 0x{:x}", child_cpu_context.gp_regs.rip); + let child_file_table = current.file_table.lock().clone(); + // inherit parent's sig disposition let child_sig_dispositions = current.sig_dispositions().lock().clone(); // sig queue is set empty @@ -144,6 +146,7 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result< child_user_vm, Some(child_user_space), None, + child_file_table, child_sig_dispositions, child_sig_queues, child_sig_mask, diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index 8c63073a2..f552d09b8 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -12,6 +12,7 @@ use self::signal::sig_queues::SigQueues; use self::signal::signals::kernel::KernelSignal; use self::status::ProcessStatus; use self::task::create_user_task_from_elf; +use crate::fs::file_table::FileTable; use crate::prelude::*; use kxos_frame::sync::WaitQueue; use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace}; @@ -30,10 +31,10 @@ pub mod table; pub mod task; pub mod wait; -static PID_ALLOCATOR: AtomicUsize = AtomicUsize::new(0); +static PID_ALLOCATOR: AtomicI32 = AtomicI32::new(0); -pub type Pid = usize; -pub type Pgid = usize; +pub type Pid = i32; +pub type Pgid = i32; pub type ExitCode = i32; /// Process stands for a set of tasks that shares the same userspace. @@ -45,7 +46,10 @@ pub struct Process { filename: Option, user_space: Option>, user_vm: Option, + /// wait for child status changed waiting_children: WaitQueue, + /// wait for io events + poll_queue: WaitQueue, // Mutable Part /// The exit code @@ -55,11 +59,13 @@ pub struct Process { /// Parent process parent: Mutex>>, /// Children processes - children: Mutex>>, + children: Mutex>>, /// Process group process_group: Mutex>>, /// Process name process_name: Mutex>, + /// File table + file_table: Mutex, // Signal sig_dispositions: Mutex, @@ -91,6 +97,7 @@ impl Process { user_vm: Option, user_space: Option>, process_group: Option>, + file_table: FileTable, sig_dispositions: SigDispositions, sig_queues: SigQueues, sig_mask: SigMask, @@ -105,6 +112,7 @@ impl Process { }; let children = BTreeMap::new(); let waiting_children = WaitQueue::new(); + let poll_queue = WaitQueue::new(); let process_name = exec_filename.as_ref().map(|filename| { let mut process_name = ProcessName::new(); process_name.set_name(filename).unwrap(); @@ -117,12 +125,14 @@ impl Process { user_space, user_vm, waiting_children, + poll_queue, exit_code: AtomicI32::new(0), status: Mutex::new(ProcessStatus::Runnable), parent: Mutex::new(parent), children: Mutex::new(children), process_group: Mutex::new(process_group), process_name: Mutex::new(process_name), + file_table: Mutex::new(file_table), sig_dispositions: Mutex::new(sig_dispositions), sig_queues: Mutex::new(sig_queues), sig_mask: Mutex::new(sig_mask), @@ -134,6 +144,10 @@ impl Process { &self.waiting_children } + pub fn poll_queue(&self) -> &WaitQueue { + &self.poll_queue + } + /// init a user process and send the process to scheduler pub fn spawn_user_process( filename: CString, @@ -175,6 +189,7 @@ impl Process { create_user_task_from_elf(filename, elf_file_content, weak_process, argv, envp); let user_space = task.user_space().map(|user_space| user_space.clone()); let user_vm = UserVm::new(); + let file_table = FileTable::new_with_stdio(); let sig_dispositions = SigDispositions::new(); let sig_queues = SigQueues::new(); let sig_mask = SigMask::new_empty(); @@ -185,6 +200,7 @@ impl Process { Some(user_vm), user_space, None, + file_table, sig_dispositions, sig_queues, sig_mask, @@ -208,6 +224,7 @@ impl Process { let kernel_process = Arc::new_cyclic(|weak_process_ref| { let weak_process = weak_process_ref.clone(); let task = Task::new(task_fn, weak_process, None).expect("spawn kernel task failed"); + let file_table = FileTable::new(); let sig_dispositions = SigDispositions::new(); let sig_queues = SigQueues::new(); let sig_mask = SigMask::new_empty(); @@ -218,6 +235,7 @@ impl Process { None, None, None, + file_table, sig_dispositions, sig_queues, sig_mask, @@ -283,6 +301,10 @@ impl Process { let _ = self.process_group.lock().insert(process_group); } + pub fn file_table(&self) -> &Mutex { + &self.file_table + } + /// create a new process group for the process and add it to globle table. /// Then set the process group for current process. fn create_and_set_process_group(self: &Arc) { @@ -388,7 +410,7 @@ impl Process { child_process.exit_code() } - pub fn children(&self) -> &Mutex>> { + pub fn children(&self) -> &Mutex>> { &self.children } diff --git a/src/kxos-std/src/syscall/fcntl.rs b/src/kxos-std/src/syscall/fcntl.rs new file mode 100644 index 000000000..ee24eb546 --- /dev/null +++ b/src/kxos-std/src/syscall/fcntl.rs @@ -0,0 +1,27 @@ +use super::{SyscallReturn, SYS_FCNTL}; +use crate::fs::fcntl::FcntlCmd; +use crate::{fs::file::FileDescripter, prelude::*}; + +pub fn sys_fcntl(fd: FileDescripter, cmd: i32, arg: u64) -> Result { + debug!("[syscall][id={}][SYS_FCNTL]", SYS_FCNTL); + let fcntl_cmd = FcntlCmd::try_from(cmd)?; + debug!("fd = {}, cmd = {:?}, arg = {}", fd, fcntl_cmd, arg); + match fcntl_cmd { + FcntlCmd::F_DUPFD_CLOEXEC => { + // FIXME: deal with the cloexec flag + let current = current!(); + let mut file_table = current.file_table().lock(); + let new_fd = arg as FileDescripter; + file_table.dup(fd, Some(new_fd))?; + return Ok(SyscallReturn::Return(new_fd as _)); + } + FcntlCmd::F_SETFD => { + if arg != 1 { + panic!("Unknown setfd argument"); + } + // TODO: Set cloexec + return Ok(SyscallReturn::Return(0)); + } + _ => todo!(), + } +} diff --git a/src/kxos-std/src/syscall/getcwd.rs b/src/kxos-std/src/syscall/getcwd.rs new file mode 100644 index 000000000..fe64cc94b --- /dev/null +++ b/src/kxos-std/src/syscall/getcwd.rs @@ -0,0 +1,15 @@ +use crate::memory::write_bytes_to_user; +use crate::prelude::*; + +use super::SyscallReturn; +use super::SYS_GETCWD; + +pub fn sys_getcwd(buf: Vaddr, len: usize) -> Result { + debug!("[syscall][id={}][SYS_GETCWD]", SYS_GETCWD); + // TODO: getcwd only return a fake result now + let fake_cwd = CString::new("/")?; + let bytes = fake_cwd.as_bytes_with_nul(); + let write_len = len.min(bytes.len()); + write_bytes_to_user(buf, &bytes[..write_len])?; + Ok(SyscallReturn::Return(write_len as _)) +} diff --git a/src/kxos-std/src/syscall/ioctl.rs b/src/kxos-std/src/syscall/ioctl.rs new file mode 100644 index 000000000..e355a1009 --- /dev/null +++ b/src/kxos-std/src/syscall/ioctl.rs @@ -0,0 +1,54 @@ +use crate::fs::file::FileDescripter; +use crate::fs::ioctl::termio::KernelTermios; +use crate::fs::ioctl::IoctlCmd; +use crate::memory::read_val_from_user; +use crate::memory::write_val_to_user; +use crate::prelude::*; + +use super::SyscallReturn; +use super::SYS_IOCTL; + +pub fn sys_ioctl(fd: FileDescripter, cmd: u32, arg: Vaddr) -> Result { + debug!("[syscall][id={}][SYS_IOCTL]", SYS_IOCTL); + let ioctl_cmd = IoctlCmd::try_from(cmd)?; + debug!( + "fd = {}, ioctl_cmd = {:?}, arg = 0x{:x}", + fd, ioctl_cmd, arg + ); + match ioctl_cmd { + IoctlCmd::TCGETS => { + if fd == 0 || fd == 1 { + let termio = KernelTermios::fake_kernel_termios(); + write_val_to_user(arg, &termio)?; + } else { + todo!() + } + } + IoctlCmd::TIOCGPGRP => { + // FIXME: Get the process group ID of the foreground process group on this terminal. + // We currently only return the pgid of current process + let current = current!(); + let pgid = current.pgid(); + write_val_to_user(arg, &pgid)?; + } + IoctlCmd::TIOCSPGRP => { + let pgid = read_val_from_user::(arg)?; + debug!("set foreground process group id: {}", pgid); + // TODO: Set the foreground process group + } + IoctlCmd::TCSETS => { + if fd == 0 || fd == 1 { + let termio = read_val_from_user::(arg)?; + debug!("termio = {:x?}", termio); + // TODO: Set termios + } else { + todo!() + } + } + IoctlCmd::TIOCGWINSZ => { + // TODO:get window size + } + _ => todo!(), + } + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/lstat.rs b/src/kxos-std/src/syscall/lstat.rs new file mode 100644 index 000000000..0662f1b3b --- /dev/null +++ b/src/kxos-std/src/syscall/lstat.rs @@ -0,0 +1,24 @@ +use crate::fs::stat::Stat; +use crate::memory::read_cstring_from_user; +use crate::memory::write_val_to_user; +use crate::prelude::*; +use crate::syscall::constants::MAX_FILENAME_LEN; + +use super::SyscallReturn; +use super::SYS_LSTAT; + +pub fn sys_lstat(filename_ptr: Vaddr, stat_buf_ptr: Vaddr) -> Result { + debug!("[syscall][id={}][SYS_LSTAT]", SYS_LSTAT); + let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?; + debug!( + "filename = {:?}, stat_buf_ptr = 0x{:x}", + filename, stat_buf_ptr + ); + // TODO: only return a fake result here + if filename == CString::new(".")? || filename == CString::new("/")? { + let stat = Stat::fake_dir_stat(); + write_val_to_user(stat_buf_ptr, &stat)?; + return Ok(SyscallReturn::Return(0)); + } + todo!() +} diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index 35f181b1b..c12ee9a88 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -8,9 +8,11 @@ use crate::syscall::clone::sys_clone; use crate::syscall::execve::sys_execve; use crate::syscall::exit::sys_exit; use crate::syscall::exit_group::sys_exit_group; +use crate::syscall::fcntl::sys_fcntl; use crate::syscall::fork::sys_fork; use crate::syscall::fstat::sys_fstat; use crate::syscall::futex::sys_futex; +use crate::syscall::getcwd::sys_getcwd; use crate::syscall::getegid::sys_getegid; use crate::syscall::geteuid::sys_geteuid; use crate::syscall::getgid::sys_getgid; @@ -19,9 +21,13 @@ use crate::syscall::getpid::sys_getpid; use crate::syscall::getppid::sys_getppid; use crate::syscall::gettid::sys_gettid; use crate::syscall::getuid::sys_getuid; +use crate::syscall::ioctl::sys_ioctl; use crate::syscall::kill::sys_kill; +use crate::syscall::lstat::sys_lstat; use crate::syscall::mmap::sys_mmap; use crate::syscall::mprotect::sys_mprotect; +use crate::syscall::openat::sys_openat; +use crate::syscall::poll::sys_poll; use crate::syscall::prctl::sys_prctl; use crate::syscall::readlink::sys_readlink; use crate::syscall::rt_sigaction::sys_rt_sigaction; @@ -46,9 +52,11 @@ mod constants; mod execve; mod exit; mod exit_group; +mod fcntl; mod fork; mod fstat; mod futex; +mod getcwd; mod getegid; mod geteuid; mod getgid; @@ -57,9 +65,13 @@ mod getpid; mod getppid; mod gettid; mod getuid; +mod ioctl; mod kill; +mod lstat; mod mmap; mod mprotect; +mod openat; +mod poll; mod prctl; mod readlink; mod rt_sigaction; @@ -77,16 +89,18 @@ mod writev; define_syscall_nums!( SYS_WRITE = 1, SYS_FSTAT = 5, + SYS_LSTAT = 6, + SYS_POLL = 7, SYS_MMAP = 9, SYS_MPROTECT = 10, SYS_BRK = 12, SYS_RT_SIGACTION = 13, SYS_RT_SIGPROCMASK = 14, SYS_RT_SIGRETRUN = 15, + SYS_IOCTL = 16, SYS_WRITEV = 20, SYS_ACCESS = 21, SYS_SCHED_YIELD = 24, - SYS_IOCTL = 29, SYS_GETPID = 39, SYS_CLONE = 56, SYS_FORK = 57, @@ -96,6 +110,7 @@ define_syscall_nums!( SYS_KILL = 62, SYS_UNAME = 63, SYS_FCNTL = 72, + SYS_GETCWD = 79, SYS_READLINK = 89, SYS_GETUID = 102, SYS_GETGID = 104, @@ -106,12 +121,12 @@ define_syscall_nums!( SYS_GETPGRP = 111, SYS_PRCTL = 157, SYS_ARCH_PRCTL = 158, - SYS_GETCWD = 183, SYS_GETTID = 186, SYS_FUTEX = 202, SYS_EXIT_GROUP = 231, SYS_TGKILL = 234, - SYS_WAITID = 247 + SYS_WAITID = 247, + SYS_OPENAT = 257 ); pub struct SyscallArgument { @@ -170,16 +185,18 @@ pub fn syscall_dispatch( match syscall_number { SYS_WRITE => syscall_handler!(3, sys_write, args), SYS_FSTAT => syscall_handler!(2, sys_fstat, args), + SYS_LSTAT => syscall_handler!(2, sys_lstat, args), + SYS_POLL => syscall_handler!(3, sys_poll, args), SYS_MMAP => syscall_handler!(6, sys_mmap, args), SYS_MPROTECT => syscall_handler!(3, sys_mprotect, args), SYS_BRK => syscall_handler!(1, sys_brk, args), SYS_RT_SIGACTION => syscall_handler!(4, sys_rt_sigaction, args), SYS_RT_SIGPROCMASK => syscall_handler!(4, sys_rt_sigprocmask, args), SYS_RT_SIGRETRUN => syscall_handler!(0, sys_rt_sigreturn, context), + SYS_IOCTL => syscall_handler!(3, sys_ioctl, args), SYS_WRITEV => syscall_handler!(3, sys_writev, args), SYS_ACCESS => syscall_handler!(2, sys_access, args), SYS_SCHED_YIELD => syscall_handler!(0, sys_sched_yield), - SYS_IOCTL => todo!(), SYS_GETPID => syscall_handler!(0, sys_getpid), SYS_CLONE => syscall_handler!(5, sys_clone, args, context.clone()), SYS_FORK => syscall_handler!(0, sys_fork, context.clone()), @@ -188,7 +205,8 @@ pub fn syscall_dispatch( SYS_WAIT4 => syscall_handler!(3, sys_wait4, args), SYS_KILL => syscall_handler!(2, sys_kill, args), SYS_UNAME => syscall_handler!(1, sys_uname, args), - SYS_FCNTL => todo!(), + SYS_FCNTL => syscall_handler!(3, sys_fcntl, args), + SYS_GETCWD => syscall_handler!(2, sys_getcwd, args), SYS_READLINK => syscall_handler!(3, sys_readlink, args), SYS_GETUID => syscall_handler!(0, sys_getuid), SYS_GETGID => syscall_handler!(0, sys_getgid), @@ -199,12 +217,12 @@ pub fn syscall_dispatch( SYS_GETPGRP => syscall_handler!(0, sys_getpgrp), SYS_PRCTL => syscall_handler!(5, sys_prctl, args), SYS_ARCH_PRCTL => syscall_handler!(2, sys_arch_prctl, args, context), - SYS_GETCWD => todo!(), SYS_GETTID => syscall_handler!(0, sys_gettid), SYS_FUTEX => syscall_handler!(6, sys_futex, args), SYS_EXIT_GROUP => syscall_handler!(1, sys_exit_group, args), SYS_TGKILL => syscall_handler!(3, sys_tgkill, args), SYS_WAITID => syscall_handler!(5, sys_waitid, args), + SYS_OPENAT => syscall_handler!(4, sys_openat, args), _ => panic!("Unsupported syscall number: {}", syscall_number), } } diff --git a/src/kxos-std/src/syscall/openat.rs b/src/kxos-std/src/syscall/openat.rs new file mode 100644 index 000000000..f70ce5ae4 --- /dev/null +++ b/src/kxos-std/src/syscall/openat.rs @@ -0,0 +1,29 @@ +use crate::fs::file::FileDescripter; +use crate::memory::read_cstring_from_user; +use crate::prelude::*; +use crate::syscall::constants::MAX_FILENAME_LEN; + +use super::SyscallReturn; +use super::SYS_OPENAT; + +const AT_FDCWD: FileDescripter = -100; + +pub fn sys_openat( + dirfd: FileDescripter, + pathname_addr: Vaddr, + flags: i32, + mode: u16, +) -> Result { + debug!("[syscall][id={}][SYS_OPENAT]", SYS_OPENAT); + let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?; + debug!( + "dirfd = {}, pathname = {:?}, flags = {}, mode = {}", + dirfd, pathname, flags, mode + ); + + // TODO: do real openat + if dirfd == AT_FDCWD && pathname == CString::new("/etc/passwd")? { + return_errno!(Errno::ENOENT); + } + todo!() +} diff --git a/src/kxos-std/src/syscall/poll.rs b/src/kxos-std/src/syscall/poll.rs new file mode 100644 index 000000000..a0b772367 --- /dev/null +++ b/src/kxos-std/src/syscall/poll.rs @@ -0,0 +1,64 @@ +use core::time::Duration; + +use crate::fs::poll::{c_pollfd, PollFd}; +use crate::memory::{read_val_from_user, write_val_to_user}; +use crate::{fs::poll::c_nfds, prelude::*}; + +use super::SyscallReturn; +use super::SYS_POLL; + +pub fn sys_poll(fds: Vaddr, nfds: c_nfds, timeout: i32) -> Result { + debug!("[syscall][id={}][SYS_POLL]", SYS_POLL); + + let mut read_addr = fds; + let mut pollfds = Vec::with_capacity(nfds as _); + for _ in 0..nfds { + let c_poll_fd = read_val_from_user::(read_addr)?; + let poll_fd = PollFd::from(c_poll_fd); + pollfds.push(poll_fd); + // FIXME: do we need to respect align of c_pollfd here? + read_addr += core::mem::size_of::(); + } + let timeout = if timeout == 0 { + None + } else { + Some(Duration::from_millis(timeout as _)) + }; + debug!( + "poll_fds = {:?}, nfds = {}, timeout = {:?}", + pollfds, nfds, timeout + ); + let current = current!(); + // FIXME: respect timeout parameter + let ready_files = current.poll_queue().wait_until(|| { + let mut ready_files = 0; + for pollfd in &mut pollfds { + let file_table = current.file_table().lock(); + let file = file_table.get_file(pollfd.fd); + match file { + None => return Some(Err(Error::new(Errno::EBADF))), + Some(file) => { + let file_events = file.poll(); + let polled_events = pollfd.events.intersection(file_events); + if !polled_events.is_empty() { + ready_files += 1; + pollfd.revents |= polled_events; + } + } + } + } + if ready_files > 0 { + return Some(Ok(ready_files)); + } else { + return None; + } + })?; + let mut write_addr = fds; + for pollfd in pollfds { + let c_poll_fd = c_pollfd::from(pollfd); + write_val_to_user(write_addr, &c_poll_fd)?; + // FIXME: do we need to respect align of c_pollfd here? + write_addr += core::mem::size_of::(); + } + Ok(SyscallReturn::Return(ready_files)) +} diff --git a/src/kxos-std/src/syscall/rt_sigaction.rs b/src/kxos-std/src/syscall/rt_sigaction.rs index fedd74e8b..e10559083 100644 --- a/src/kxos-std/src/syscall/rt_sigaction.rs +++ b/src/kxos-std/src/syscall/rt_sigaction.rs @@ -25,9 +25,7 @@ pub fn sys_rt_sigaction( let current = current!(); let mut sig_dispositions = current.sig_dispositions().lock(); let old_action = sig_dispositions.get(sig_num); - debug!("old_action = {:x?}", old_action); let old_action_c = old_action.to_c(); - debug!("old_action_c = {:x?}", old_action_c); sig_dispositions.set(sig_num, sig_action); if old_sig_action_ptr != 0 { write_val_to_user(old_sig_action_ptr, &old_action_c)?; diff --git a/src/kxos-std/src/user_apps.rs b/src/kxos-std/src/user_apps.rs index 7daec2a53..bc2b0ca20 100644 --- a/src/kxos-std/src/user_apps.rs +++ b/src/kxos-std/src/user_apps.rs @@ -1,8 +1,10 @@ use crate::prelude::*; pub struct UserApp { - app_name: CString, - app_content: &'static [u8], + pub app_name: CString, + pub app_content: &'static [u8], + pub argv: Vec, + pub envp: Vec, } impl UserApp { @@ -11,15 +13,17 @@ impl UserApp { UserApp { app_name, app_content, + argv: Vec::new(), + envp: Vec::new(), } } - pub fn app_name(&self) -> CString { - self.app_name.clone() + pub fn set_argv(&mut self, argv: Vec) { + self.argv = argv; } - pub fn app_content(&self) -> &'static [u8] { - self.app_content + pub fn set_envp(&mut self, envp: Vec) { + self.envp = envp; } } @@ -52,6 +56,16 @@ pub fn get_all_apps() -> Vec { let signal_test = UserApp::new("/signal_test", read_signal_test_content()); res.push(signal_test); + // busybox + let mut busybox = UserApp::new("/busybox", read_busybox_content()); + let argv = ["./busybox", "sh"]; + let envp = ["SHELL=/bin/bash", "COLORTERM=truecolor", "TERM_PROGRAM_VERSION=1.73.0", "LC_ADDRESS=zh_CN.UTF-8", "LC_NAME=zh_CN.UTF-8", "LC_MONETARY=zh_CN.UTF-8", "PWD=/", "LOGNAME=jiangjf", "XDG_SESSION_TYPE=tty", "VSCODE_GIT_ASKPASS_NODE=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/node", "MOTD_SHOWN=pam", "HOME=/home/jiangjf", "LC_PAPER=zh_CN.UTF-8", "LANG=en_US.UTF-8", "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35", "GIT_ASKPASS=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/extensions/git/dist/askpass.sh", "SSH_CONNECTION=30.177.3.156 54687 30.77.178.76 22", "VSCODE_GIT_ASKPASS_EXTRA_ARGS=", "LESSCLOSE=/usr/bin/lesspipe %s %s", "XDG_SESSION_CLASS=user", "TERM=xterm-256color", "LC_IDENTIFICATION=zh_CN.UTF-8", "LESSOPEN=| /usr/bin/lesspipe %s", "USER=jiangjf", "VSCODE_GIT_IPC_HANDLE=/run/user/1015/vscode-git-623b69fb06.sock", "SHLVL=2", "LC_TELEPHONE=zh_CN.UTF-8", "LC_MEASUREMENT=zh_CN.UTF-8", "XDG_SESSION_ID=8884", "XDG_RUNTIME_DIR=/run/user/1015", "SSH_CLIENT=30.177.3.156 54687 22", "LC_TIME=zh_CN.UTF-8", "VSCODE_GIT_ASKPASS_MAIN=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/extensions/git/dist/askpass-main.js", "XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop", "BROWSER=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/bin/helpers/browser.sh", "PATH=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/bin/remote-cli:/home/jiangjf/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin", "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1015/bus", "LC_NUMERIC=zh_CN.UTF-8", "TERM_PROGRAM=vscode", "VSCODE_IPC_HOOK_CLI=/run/user/1015/vscode-ipc-ed06ed64-441d-4b59-a8fe-90ce2cf29a8a.sock", "OLDPWD=/"]; + let argv = to_vec_cstring(&argv).unwrap(); + let envp = to_vec_cstring(&envp).unwrap(); + busybox.set_argv(argv); + busybox.set_envp(envp); + res.push(busybox); + res } @@ -82,3 +96,16 @@ fn read_fork_c_content() -> &'static [u8] { fn read_signal_test_content() -> &'static [u8] { include_bytes!("../../kxos-user/signal_c/signal_test") } + +fn read_busybox_content() -> &'static [u8] { + include_bytes!("../../kxos-user/busybox/busybox") +} + +fn to_vec_cstring(raw_strs: &[&str]) -> Result> { + let mut res = Vec::new(); + for raw_str in raw_strs { + let cstring = CString::new(*raw_str)?; + res.push(cstring); + } + Ok(res) +} diff --git a/src/kxos-user/busybox/busybox b/src/kxos-user/busybox/busybox new file mode 100755 index 000000000..8dda33827 --- /dev/null +++ b/src/kxos-user/busybox/busybox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c3019f1ee7431b4a7cbcbace4c114679430a6c1277081bed11a290aeb0bc9d6e +size 2644416