From f3ab8219bcd1e24f72f37884497bd9d6192cdb32 Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Mon, 21 Nov 2022 19:09:23 +0800 Subject: [PATCH] support running busybox shell --- src/Cargo.lock | 41 ++++++ src/kxos-frame/src/device/serial.rs | 12 +- src/kxos-frame/src/lib.rs | 1 + src/kxos-frame/src/sync/wait.rs | 1 - src/kxos-std/Cargo.toml | 2 + src/kxos-std/src/fs/fcntl.rs | 17 +-- src/kxos-std/src/fs/file.rs | 16 ++- src/kxos-std/src/fs/file_table.rs | 21 ++- src/kxos-std/src/fs/ioctl/mod.rs | 30 ++--- src/kxos-std/src/fs/ioctl/termio.rs | 45 ------- src/kxos-std/src/fs/stdio.rs | 128 ++++++++++++++++-- src/kxos-std/src/lib.rs | 4 + src/kxos-std/src/process/mod.rs | 11 +- src/kxos-std/src/syscall/close.rs | 17 +++ src/kxos-std/src/syscall/constants.rs | 2 + src/kxos-std/src/syscall/getuid.rs | 2 +- src/kxos-std/src/syscall/ioctl.rs | 44 +------ src/kxos-std/src/syscall/lseek.rs | 11 ++ src/kxos-std/src/syscall/mod.rs | 82 +++++++----- src/kxos-std/src/syscall/munmap.rs | 11 ++ src/kxos-std/src/syscall/openat.rs | 22 ++++ src/kxos-std/src/syscall/read.rs | 33 +++++ src/kxos-std/src/syscall/rt_sigaction.rs | 7 +- src/kxos-std/src/syscall/setpgid.rs | 2 +- src/kxos-std/src/syscall/waitid.rs | 2 + src/kxos-std/src/syscall/write.rs | 28 ++-- src/kxos-std/src/tty/line_discipline.rs | 85 ++++++++++++ src/kxos-std/src/tty/mod.rs | 118 +++++++++++++++++ src/kxos-std/src/tty/termio.rs | 158 +++++++++++++++++++++++ src/kxos-std/src/user_apps.rs | 15 ++- src/kxos-user/busybox/README.md | 6 + src/kxos-user/busybox/busybox | 4 +- 32 files changed, 794 insertions(+), 184 deletions(-) delete mode 100644 src/kxos-std/src/fs/ioctl/termio.rs create mode 100644 src/kxos-std/src/syscall/close.rs create mode 100644 src/kxos-std/src/syscall/lseek.rs create mode 100644 src/kxos-std/src/syscall/munmap.rs create mode 100644 src/kxos-std/src/syscall/read.rs create mode 100644 src/kxos-std/src/tty/line_discipline.rs create mode 100644 src/kxos-std/src/tty/mod.rs create mode 100644 src/kxos-std/src/tty/termio.rs create mode 100644 src/kxos-user/busybox/README.md diff --git a/src/Cargo.lock b/src/Cargo.lock index f3f809f13..7f4fb839f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "autocfg" version = "1.1.0" @@ -155,7 +161,9 @@ dependencies = [ "kxos-typeflags-util", "kxos-virtio", "lazy_static", + "ringbuffer", "spin 0.9.4", + "vte", "xmas-elf", ] @@ -253,6 +261,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ringbuffer" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310a2514cb46bb500a2f2ad70c79c51c5a475cc23faa245d2c675faabe889370" + [[package]] name = "runner-utils" version = "0.0.2" @@ -353,12 +367,39 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + [[package]] name = "volatile" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c" +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/src/kxos-frame/src/device/serial.rs b/src/kxos-frame/src/device/serial.rs index 0582e7d9d..764016a2f 100644 --- a/src/kxos-frame/src/device/serial.rs +++ b/src/kxos-frame/src/device/serial.rs @@ -3,13 +3,23 @@ use spin::Mutex; use uart_16550::SerialPort; lazy_static! { - pub(crate) static ref SERIAL: Mutex = { + pub static ref SERIAL: Mutex = { let mut serial_port = unsafe { SerialPort::new(0x3F8) }; serial_port.init(); Mutex::new(serial_port) }; } +/// read a char from the keyboard input. +/// FIXME: this function should **NOT** block. If no char receives, this function should return None immediately. +/// However, the receive function on SERIAL will block until a char is received, which will block the whole kernel. +/// A more correct implementation should be added once interrupt is ready. We should register the kerboard interrupt +/// handler to wake up foreground processes which wait on IOEVENTS. +pub fn receive_char() -> Option { + let byte = SERIAL.lock().receive(); + Some(byte) +} + #[doc(hidden)] pub fn _print(args: ::core::fmt::Arguments) { use core::fmt::Write; diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index 45aab530e..dd09c5df2 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -40,6 +40,7 @@ use bootloader::{ boot_info::{FrameBuffer, MemoryRegionKind}, BootInfo, }; +pub use device::serial::receive_char; pub use mm::address::{align_down, align_up, is_aligned, virt_to_phys}; pub use trap::{allocate_irq, IrqAllocateHandle, TrapFrame}; use trap::{IrqCallbackHandle, IrqLine}; diff --git a/src/kxos-frame/src/sync/wait.rs b/src/kxos-frame/src/sync/wait.rs index b888f6d57..6be13418c 100644 --- a/src/kxos-frame/src/sync/wait.rs +++ b/src/kxos-frame/src/sync/wait.rs @@ -1,6 +1,5 @@ use core::sync::atomic::{AtomicBool, Ordering}; -use crate::prelude::*; use alloc::{collections::VecDeque, sync::Arc}; use bitflags::bitflags; use spin::mutex::Mutex; diff --git a/src/kxos-std/Cargo.toml b/src/kxos-std/Cargo.toml index 1fd63d9de..a8dc8db24 100644 --- a/src/kxos-std/Cargo.toml +++ b/src/kxos-std/Cargo.toml @@ -19,8 +19,10 @@ xmas-elf = "0.8.0" # goblin = {version= "0.5.3", default-features = false, features = ["elf64"]} # data-structures bitflags = "1.3" +ringbuffer = "0.10.0" spin = "0.9.4" +vte = "0.10" [dependencies.lazy_static] version = "1.0" diff --git a/src/kxos-std/src/fs/fcntl.rs b/src/kxos-std/src/fs/fcntl.rs index 844fb6266..ba0e18c5a 100644 --- a/src/kxos-std/src/fs/fcntl.rs +++ b/src/kxos-std/src/fs/fcntl.rs @@ -1,15 +1,5 @@ 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)] @@ -34,3 +24,10 @@ macro_rules! define_fcntl_cmd { } } } + +define_fcntl_cmd! { + F_DUPFD = 0, + F_GETFD = 1, + F_SETFD = 2, + F_DUPFD_CLOEXEC = 1030 +} diff --git a/src/kxos-std/src/fs/file.rs b/src/kxos-std/src/fs/file.rs index e2fad1d9c..bd337aa76 100644 --- a/src/kxos-std/src/fs/file.rs +++ b/src/kxos-std/src/fs/file.rs @@ -1,5 +1,6 @@ use crate::prelude::*; -use core::{any::Any, fmt::Debug}; +use crate::tty::get_console; +use core::any::Any; use super::events::IoEvents; use super::ioctl::IoctlCmd; @@ -7,7 +8,7 @@ use super::ioctl::IoctlCmd; pub type FileDescripter = i32; /// The basic operations defined on a file -pub trait File: Send + Sync + Debug + Any { +pub trait File: Send + Sync + Any { fn read(&self, buf: &mut [u8]) -> Result { panic!("read unsupported"); } @@ -16,8 +17,15 @@ pub trait File: Send + Sync + Debug + Any { panic!("write unsupported"); } - fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { - panic!("ioctl unsupported"); + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + match cmd { + IoctlCmd::TCGETS => { + // FIXME: only a work around + let tty = get_console(); + tty.ioctl(cmd, arg) + } + _ => panic!("Ioctl unsupported"), + } } fn poll(&self) -> IoEvents { diff --git a/src/kxos-std/src/fs/file_table.rs b/src/kxos-std/src/fs/file_table.rs index ea4923e91..0e7f212a0 100644 --- a/src/kxos-std/src/fs/file_table.rs +++ b/src/kxos-std/src/fs/file_table.rs @@ -5,7 +5,7 @@ use super::{ stdio::{Stderr, Stdin, Stdout, FD_STDERR, FD_STDIN, FD_STDOUT}, }; -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct FileTable { table: BTreeMap>, } @@ -19,9 +19,12 @@ impl FileTable { 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); + let stdin = Stdin::new_with_default_console(); + let stdout = Stdout::new_with_default_console(); + let stderr = Stderr::new_with_default_console(); + 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 } } @@ -47,6 +50,16 @@ impl FileTable { self.table.iter().map(|(fd, _)| fd.clone()).max().unwrap() } + pub fn insert(&mut self, item: Arc) -> FileDescripter { + let fd = self.max_fd() + 1; + self.table.insert(fd, item); + fd + } + + pub fn close_file(&mut self, fd: FileDescripter) { + self.table.remove(&fd); + } + 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 index 487adc76e..f74aea6f9 100644 --- a/src/kxos-std/src/fs/ioctl/mod.rs +++ b/src/kxos-std/src/fs/ioctl/mod.rs @@ -1,22 +1,5 @@ -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)] @@ -40,3 +23,16 @@ macro_rules! define_ioctl_cmd { } } } + +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 +} diff --git a/src/kxos-std/src/fs/ioctl/termio.rs b/src/kxos-std/src/fs/ioctl/termio.rs deleted file mode 100644 index 99001baad..000000000 --- a/src/kxos-std/src/fs/ioctl/termio.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! 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/stdio.rs b/src/kxos-std/src/fs/stdio.rs index 5be619ee0..9f583cb0e 100644 --- a/src/kxos-std/src/fs/stdio.rs +++ b/src/kxos-std/src/fs/stdio.rs @@ -1,18 +1,128 @@ +use super::events::IoEvents; +use crate::prelude::*; +use crate::tty::{get_console, Tty}; + 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; +pub struct Stdin { + console: Option>, + bind_to_console: bool, +} -#[derive(Debug)] -pub struct Stdout; +pub struct Stdout { + console: Option>, + bind_to_console: bool, +} -#[derive(Debug)] -pub struct Stderr; +pub struct Stderr { + console: Option>, + bind_to_console: bool, +} -impl File for Stdin {} -impl File for Stdout {} -impl File for Stderr {} +impl File for Stdin { + fn poll(&self) -> IoEvents { + if self.bind_to_console { + let console = self.console.as_ref().unwrap(); + console.poll() + } else { + todo!() + } + } + + fn read(&self, buf: &mut [u8]) -> Result { + if self.bind_to_console { + let console = self.console.as_ref().unwrap(); + console.read(buf) + } else { + todo!() + } + } + + fn ioctl(&self, cmd: super::ioctl::IoctlCmd, arg: usize) -> Result { + if self.bind_to_console { + let console = self.console.as_ref().unwrap(); + console.ioctl(cmd, arg) + } else { + todo!() + } + } +} +impl File for Stdout { + fn ioctl(&self, cmd: super::ioctl::IoctlCmd, arg: usize) -> Result { + if self.bind_to_console { + let console = self.console.as_ref().unwrap(); + console.ioctl(cmd, arg) + } else { + todo!() + } + } + + fn write(&self, buf: &[u8]) -> Result { + if self.bind_to_console { + let console = self.console.as_ref().unwrap(); + console.write(buf) + } else { + todo!() + } + } +} + +impl File for Stderr { + fn ioctl(&self, cmd: super::ioctl::IoctlCmd, arg: usize) -> Result { + if self.bind_to_console { + let console = self.console.as_ref().unwrap(); + console.ioctl(cmd, arg) + } else { + todo!() + } + } + + fn write(&self, buf: &[u8]) -> Result { + if self.bind_to_console { + let console = self.console.as_ref().unwrap(); + console.write(buf) + } else { + todo!() + } + } +} + +impl Stdin { + /// FIXME: console should be file under devfs. + /// reimplement the function when devfs is enabled. + pub fn new_with_default_console() -> Self { + let console = get_console(); + Self { + console: Some(console.clone()), + bind_to_console: true, + } + } +} + +impl Stdout { + /// FIXME: console should be file under devfs. + /// reimplement the function when devfs is enabled. + pub fn new_with_default_console() -> Self { + let console = get_console(); + Self { + console: Some(console.clone()), + bind_to_console: true, + } + } +} + +impl Stderr { + /// FIXME: console should be file under devfs. + /// reimplement the function when devfs is enabled. + pub fn new_with_default_console() -> Self { + let console = get_console(); + Self { + console: Some(console.clone()), + bind_to_console: true, + } + } +} diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index de6f4227c..c56094f57 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -9,6 +9,7 @@ #![feature(exclusive_range_pattern)] #![feature(btree_drain_filter)] #![feature(const_option)] +#![feature(extend_one)] use crate::{prelude::*, user_apps::UserApp}; use kxos_frame::{info, println}; @@ -32,6 +33,7 @@ pub mod prelude; mod process; pub mod rights; pub mod syscall; +pub mod tty; mod user_apps; mod util; pub mod vm; @@ -67,6 +69,8 @@ pub fn init_process() { envp, } = app; info!("[kxos-std/lib.rs] spwan {:?} process", app_name); + print!("\n"); + print!("BusyBox v1.35.0 built-in shell (ash)\n\n"); Process::spawn_user_process(app_name.clone(), app_content, argv, Vec::new()); } diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index f552d09b8..cd5a69c78 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicI32, Ordering}; use self::name::ProcessName; use self::process_group::ProcessGroup; @@ -14,6 +14,7 @@ use self::status::ProcessStatus; use self::task::create_user_task_from_elf; use crate::fs::file_table::FileTable; use crate::prelude::*; +use crate::tty::get_console; use kxos_frame::sync::WaitQueue; use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace}; @@ -156,6 +157,9 @@ impl Process { envp: Vec, ) -> Arc { let process = Process::create_user_process(filename, elf_file_content, argv, envp); + // FIXME: How to determine the fg process group? + let pgid = process.pgid(); + get_console().set_fg(pgid); process.send_to_scheduler(); process } @@ -295,8 +299,9 @@ impl Process { /// remove current process from old process group. pub fn set_process_group(&self, process_group: Weak) { if let Some(old_process_group) = &*self.process_group().lock() { - let old_process_group = old_process_group.upgrade().unwrap(); - old_process_group.remove_process(self.pid()); + if let Some(old_process_group) = old_process_group.upgrade() { + old_process_group.remove_process(self.pid()); + } } let _ = self.process_group.lock().insert(process_group); } diff --git a/src/kxos-std/src/syscall/close.rs b/src/kxos-std/src/syscall/close.rs new file mode 100644 index 000000000..b81e786c1 --- /dev/null +++ b/src/kxos-std/src/syscall/close.rs @@ -0,0 +1,17 @@ +use super::SyscallReturn; +use super::SYS_CLOSE; +use crate::{fs::file::FileDescripter, prelude::*}; + +pub fn sys_close(fd: FileDescripter) -> Result { + debug!("[syscall][id={}][SYS_CLOSE]", SYS_CLOSE); + debug!("fd = {}", fd); + let current = current!(); + let mut file_table = current.file_table().lock(); + match file_table.get_file(fd) { + None => return_errno!(Errno::EBADF), + Some(_) => { + file_table.close_file(fd); + Ok(SyscallReturn::Return(0)) + } + } +} diff --git a/src/kxos-std/src/syscall/constants.rs b/src/kxos-std/src/syscall/constants.rs index 35274c661..e175eb88b 100644 --- a/src/kxos-std/src/syscall/constants.rs +++ b/src/kxos-std/src/syscall/constants.rs @@ -1,3 +1,5 @@ +//! constants used in syscall + /// LONGEST ALLOWED FILENAME pub const MAX_FILENAME_LEN: usize = 128; pub const MAX_ARGV_NUMBER: usize = 128; diff --git a/src/kxos-std/src/syscall/getuid.rs b/src/kxos-std/src/syscall/getuid.rs index 60059bdd6..9838547e5 100644 --- a/src/kxos-std/src/syscall/getuid.rs +++ b/src/kxos-std/src/syscall/getuid.rs @@ -4,6 +4,6 @@ use super::SyscallReturn; pub fn sys_getuid() -> Result { debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID); - // TODO: getuid only return a fake uid now"); + // TODO: getuid only return a fake uid now; Ok(SyscallReturn::Return(0)) } diff --git a/src/kxos-std/src/syscall/ioctl.rs b/src/kxos-std/src/syscall/ioctl.rs index e355a1009..69da32c5e 100644 --- a/src/kxos-std/src/syscall/ioctl.rs +++ b/src/kxos-std/src/syscall/ioctl.rs @@ -1,8 +1,5 @@ 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; @@ -15,40 +12,13 @@ pub fn sys_ioctl(fd: FileDescripter, cmd: u32, arg: Vaddr) -> Result { - if fd == 0 || fd == 1 { - let termio = KernelTermios::fake_kernel_termios(); - write_val_to_user(arg, &termio)?; - } else { - todo!() - } + let current = current!(); + let file_table = current.file_table().lock(); + match file_table.get_file(fd) { + None => return_errno_with_message!(Errno::EBADF, "Fd does not exist"), + Some(file) => { + let res = file.ioctl(ioctl_cmd, arg)?; + return Ok(SyscallReturn::Return(res as _)); } - 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/lseek.rs b/src/kxos-std/src/syscall/lseek.rs new file mode 100644 index 000000000..5ef794ccb --- /dev/null +++ b/src/kxos-std/src/syscall/lseek.rs @@ -0,0 +1,11 @@ +use crate::{fs::file::FileDescripter, prelude::*}; + +use super::SyscallReturn; +use super::SYS_LSEEK; + +pub fn sys_lseek(fd: FileDescripter, offset: usize, whence: u32) -> Result { + debug!("[syscall][id={}][SYS_LSEEK]", SYS_LSEEK); + debug!("fd = {}, offset = {}, whence = {}", fd, offset, whence); + // TODO: do lseek + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index c12ee9a88..ea797868b 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -5,6 +5,7 @@ use crate::syscall::access::sys_access; use crate::syscall::arch_prctl::sys_arch_prctl; use crate::syscall::brk::sys_brk; use crate::syscall::clone::sys_clone; +use crate::syscall::close::sys_close; use crate::syscall::execve::sys_execve; use crate::syscall::exit::sys_exit; use crate::syscall::exit_group::sys_exit_group; @@ -23,12 +24,15 @@ 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::lseek::sys_lseek; use crate::syscall::lstat::sys_lstat; use crate::syscall::mmap::sys_mmap; use crate::syscall::mprotect::sys_mprotect; +use crate::syscall::munmap::sys_munmap; use crate::syscall::openat::sys_openat; use crate::syscall::poll::sys_poll; use crate::syscall::prctl::sys_prctl; +use crate::syscall::read::sys_read; use crate::syscall::readlink::sys_readlink; use crate::syscall::rt_sigaction::sys_rt_sigaction; use crate::syscall::rt_sigprocmask::sys_rt_sigprocmask; @@ -41,13 +45,13 @@ use crate::syscall::wait4::sys_wait4; use crate::syscall::waitid::sys_waitid; use crate::syscall::write::sys_write; use crate::syscall::writev::sys_writev; -use crate::{define_syscall_nums, syscall_handler}; use kxos_frame::cpu::CpuContext; mod access; mod arch_prctl; mod brk; mod clone; +mod close; mod constants; mod execve; mod exit; @@ -67,12 +71,15 @@ mod gettid; mod getuid; mod ioctl; mod kill; +mod lseek; mod lstat; mod mmap; mod mprotect; +mod munmap; mod openat; mod poll; mod prctl; +mod read; mod readlink; mod rt_sigaction; mod rt_sigprocmask; @@ -86,13 +93,47 @@ mod waitid; mod write; mod writev; +macro_rules! define_syscall_nums { + ( $( $name: ident = $num: expr ),+ ) => { + $( + const $name: u64 = $num; + )* + } +} + +/// This macro is used to define syscall handler. +/// The first param is ths number of parameters, +/// The second param is the function name of syscall handler, +/// The third is optional, means the args(if parameter number > 0), +/// The third is optional, means if cpu context is required. +macro_rules! syscall_handler { + (0, $fn_name: ident) => { $fn_name() }; + (0, $fn_name: ident, $context: expr) => { $fn_name($context) }; + (1, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _) }; + (1, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $context) }; + (2, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _)}; + (2, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $context)}; + (3, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _)}; + (3, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $context)}; + (4, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _)}; + (4, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _), $context}; + (5, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _)}; + (5, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $context)}; + (6, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _)}; + (6, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _, $context)}; +} + define_syscall_nums!( + SYS_READ = 0, SYS_WRITE = 1, + SYS_CLOSE = 3, SYS_FSTAT = 5, SYS_LSTAT = 6, SYS_POLL = 7, + SYS_LSEEK = 8, SYS_MMAP = 9, SYS_MPROTECT = 10, + SYS_MUNMAP = 11, SYS_BRK = 12, SYS_RT_SIGACTION = 13, SYS_RT_SIGPROCMASK = 14, @@ -135,6 +176,7 @@ pub struct SyscallArgument { } /// Syscall return +#[derive(Debug, Clone, Copy)] pub enum SyscallReturn { /// return isize, this value will be used to set rax Return(isize), @@ -166,11 +208,13 @@ pub fn handle_syscall(context: &mut CpuContext) { match syscall_return { Ok(return_value) => { + debug!("syscall return: {:?}", return_value); if let SyscallReturn::Return(return_value) = return_value { context.gp_regs.rax = return_value as u64; } } Err(err) => { + debug!("syscall return error: {:?}", err); let errno = err.error() as i32; context.gp_regs.rax = (-errno) as u64 } @@ -183,12 +227,16 @@ pub fn syscall_dispatch( context: &mut CpuContext, ) -> Result { match syscall_number { + SYS_READ => syscall_handler!(3, sys_read, args), SYS_WRITE => syscall_handler!(3, sys_write, args), + SYS_CLOSE => syscall_handler!(1, sys_close, 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_LSEEK => syscall_handler!(3, sys_lseek, args), SYS_MMAP => syscall_handler!(6, sys_mmap, args), SYS_MPROTECT => syscall_handler!(3, sys_mprotect, args), + SYS_MUNMAP => syscall_handler!(2, sys_munmap, 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), @@ -226,35 +274,3 @@ pub fn syscall_dispatch( _ => panic!("Unsupported syscall number: {}", syscall_number), } } - -/// This macro is used to define syscall handler. -/// The first param is ths number of parameters, -/// The second param is the function name of syscall handler, -/// The third is optional, means the args(if parameter number > 0), -/// The third is optional, means if cpu context is required. -#[macro_export] -macro_rules! syscall_handler { - (0, $fn_name: ident) => { $fn_name() }; - (0, $fn_name: ident, $context: expr) => { $fn_name($context) }; - (1, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _) }; - (1, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $context) }; - (2, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _)}; - (2, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $context)}; - (3, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _)}; - (3, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $context)}; - (4, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _)}; - (4, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _), $context}; - (5, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _)}; - (5, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $context)}; - (6, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _)}; - (6, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _, $context)}; -} - -#[macro_export] -macro_rules! define_syscall_nums { - ( $( $name: ident = $num: expr ),+ ) => { - $( - const $name: u64 = $num; - )* - } -} diff --git a/src/kxos-std/src/syscall/munmap.rs b/src/kxos-std/src/syscall/munmap.rs new file mode 100644 index 000000000..9a6e556f5 --- /dev/null +++ b/src/kxos-std/src/syscall/munmap.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; + +use super::SyscallReturn; +use super::SYS_MUNMAP; + +pub fn sys_munmap(addr: Vaddr, len: usize) -> Result { + debug!("[syscall][id={}][SYS_READ]", SYS_MUNMAP); + debug!("addr = 0x{:x}, len = {}", addr, len); + //TODO: do munmap + Ok(SyscallReturn::Return(0)) +} diff --git a/src/kxos-std/src/syscall/openat.rs b/src/kxos-std/src/syscall/openat.rs index f70ce5ae4..889cc7433 100644 --- a/src/kxos-std/src/syscall/openat.rs +++ b/src/kxos-std/src/syscall/openat.rs @@ -1,7 +1,9 @@ +use crate::fs::file::File; use crate::fs::file::FileDescripter; use crate::memory::read_cstring_from_user; use crate::prelude::*; use crate::syscall::constants::MAX_FILENAME_LEN; +use crate::tty::get_console; use super::SyscallReturn; use super::SYS_OPENAT; @@ -22,8 +24,28 @@ pub fn sys_openat( ); // TODO: do real openat + + // Below are three special files we encountered when running busybox ash. + // We currently only return ENOENT, which means the file does not exist. if dirfd == AT_FDCWD && pathname == CString::new("/etc/passwd")? { return_errno!(Errno::ENOENT); } + + if dirfd == AT_FDCWD && pathname == CString::new("/etc/profile")? { + return_errno!(Errno::ENOENT); + } + + if dirfd == AT_FDCWD && pathname == CString::new("./trace")? { + return_errno!(Errno::ENOENT); + } + + if dirfd == AT_FDCWD && pathname == CString::new("/dev/tty")? { + let tty_file = get_console().clone() as Arc; + let current = current!(); + let mut file_table = current.file_table().lock(); + let fd = file_table.insert(tty_file); + debug!("openat fd = {}", fd); + return Ok(SyscallReturn::Return(fd as _)); + } todo!() } diff --git a/src/kxos-std/src/syscall/read.rs b/src/kxos-std/src/syscall/read.rs new file mode 100644 index 000000000..f362bf7d3 --- /dev/null +++ b/src/kxos-std/src/syscall/read.rs @@ -0,0 +1,33 @@ +use crate::memory::write_bytes_to_user; +use crate::{fs::file::FileDescripter, prelude::*}; + +use super::SyscallReturn; +use super::SYS_READ; + +pub fn sys_read(fd: FileDescripter, user_buf_addr: Vaddr, buf_len: usize) -> Result { + debug!("[syscall][id={}][SYS_READ]", SYS_READ); + debug!( + "fd = {}, user_buf_ptr = 0x{:x}, buf_len = 0x{:x}", + fd, user_buf_addr, buf_len + ); + let current = current!(); + let file_table = current.file_table().lock(); + let file = file_table.get_file(fd); + match file { + None => return_errno!(Errno::EBADF), + Some(file) => { + let mut read_buf = vec![0u8; buf_len]; + let read_len = file.read(&mut read_buf)?; + write_bytes_to_user(user_buf_addr, &read_buf)?; + debug!( + "read_len = {}, read_buf = {:?}", + read_len, + &read_buf[..read_len] + ); + // let read_str = core::str::from_utf8(&read_buf[..read_len - 1]).unwrap(); + // println!("str = {}" ,read_str); + // todo!(); + return Ok(SyscallReturn::Return(read_len as _)); + } + } +} diff --git a/src/kxos-std/src/syscall/rt_sigaction.rs b/src/kxos-std/src/syscall/rt_sigaction.rs index e10559083..45c327d63 100644 --- a/src/kxos-std/src/syscall/rt_sigaction.rs +++ b/src/kxos-std/src/syscall/rt_sigaction.rs @@ -18,8 +18,11 @@ pub fn sys_rt_sigaction( let sig_action_c = read_val_from_user::(sig_action_ptr)?; let sig_action = SigAction::try_from(sig_action_c).unwrap(); debug!( - "sig_num = {:?}, sig_action = {:x?}, old_sig_action_ptr = 0x{:x}, sigset_size = {}", - sig_num, sig_action, old_sig_action_ptr, sigset_size + "sig_num = {}, sig_action = {:x?}, old_sig_action_ptr = 0x{:x}, sigset_size = {}", + sig_num.sig_name(), + sig_action, + old_sig_action_ptr, + sigset_size ); let current = current!(); diff --git a/src/kxos-std/src/syscall/setpgid.rs b/src/kxos-std/src/syscall/setpgid.rs index b904d20cf..bcadf4106 100644 --- a/src/kxos-std/src/syscall/setpgid.rs +++ b/src/kxos-std/src/syscall/setpgid.rs @@ -6,7 +6,7 @@ use crate::{ use super::{SyscallReturn, SYS_SETPGID}; pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result { - debug!("[syscall][id={}][SYS_PRCTL]", SYS_SETPGID); + debug!("[syscall][id={}][SYS_SETPGID]", SYS_SETPGID); let current = current!(); // if pid is 0, pid should be the pid of current process let pid = if pid == 0 { current.pid() } else { pid }; diff --git a/src/kxos-std/src/syscall/waitid.rs b/src/kxos-std/src/syscall/waitid.rs index da1653c07..2f2100a55 100644 --- a/src/kxos-std/src/syscall/waitid.rs +++ b/src/kxos-std/src/syscall/waitid.rs @@ -4,6 +4,7 @@ use crate::process::{process_filter::ProcessFilter, wait::wait_child_exit}; use crate::process::wait::WaitOptions; use super::SyscallReturn; +use super::SYS_WAITID; pub fn sys_waitid( which: u64, @@ -13,6 +14,7 @@ pub fn sys_waitid( rusage_addr: u64, ) -> Result { // FIXME: what does infoq and rusage use for? + debug!("[syscall][id={}][SYS_WAITID]", SYS_WAITID); let process_filter = ProcessFilter::from_which_and_id(which, upid); let wait_options = WaitOptions::from_bits(options as u32).expect("Unknown wait options"); let (exit_code, pid) = wait_child_exit(process_filter, wait_options)?; diff --git a/src/kxos-std/src/syscall/write.rs b/src/kxos-std/src/syscall/write.rs index 4b6fb2599..da54895d0 100644 --- a/src/kxos-std/src/syscall/write.rs +++ b/src/kxos-std/src/syscall/write.rs @@ -1,3 +1,4 @@ +use crate::fs::file::FileDescripter; use crate::prelude::*; use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE}; @@ -7,7 +8,11 @@ use super::SyscallReturn; const STDOUT: u64 = 1; const STDERR: u64 = 2; -pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result { +pub fn sys_write( + fd: FileDescripter, + user_buf_ptr: Vaddr, + user_buf_len: u64, +) -> Result { // only suppprt STDOUT now. debug!("[syscall][id={}][SYS_WRITE]", SYS_WRITE); debug!( @@ -15,17 +20,16 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result return_errno!(Errno::EBADF), + Some(file) => { + let mut buffer = vec![0u8; user_buf_len as usize]; + read_bytes_from_user(user_buf_ptr as usize, &mut buffer)?; + debug!("write buf = {:?}", buffer); + let write_len = file.write(&buffer)?; + Ok(SyscallReturn::Return(write_len as _)) } - Ok(SyscallReturn::Return(user_buf_len as _)) - } else { - panic!("Unsupported fd number {}", fd); } } diff --git a/src/kxos-std/src/tty/line_discipline.rs b/src/kxos-std/src/tty/line_discipline.rs new file mode 100644 index 000000000..ddbbed19f --- /dev/null +++ b/src/kxos-std/src/tty/line_discipline.rs @@ -0,0 +1,85 @@ +use crate::{prelude::*, process::Pgid}; +use ringbuffer::{ConstGenericRingBuffer, RingBuffer, RingBufferRead, RingBufferWrite}; + +use super::termio::KernelTermios; + +// This implementation refers the implementation of linux +// https://elixir.bootlin.com/linux/latest/source/include/linux/tty_ldisc.h + +const BUFFER_CAPACITY: usize = 4096; + +#[derive(Debug)] +pub struct LineDiscipline { + /// The write buffer + buffer: ConstGenericRingBuffer, + /// The foreground process group + foreground: Option, + /// termios + termios: KernelTermios, +} + +impl LineDiscipline { + /// create a new line discipline + pub fn new() -> Self { + Self { + buffer: ConstGenericRingBuffer::new(), + foreground: None, + termios: KernelTermios::default(), + } + } + + /// push char to buffer + pub fn push_char(&mut self, mut item: u8) { + if self.termios.is_cooked_mode() { + todo!("We only support raw mode now. Cooked mode will be supported further."); + } + if self.termios.contains_icrnl() { + if item == b'\r' { + item = b'\n' + } + } + self.buffer.push(item); + } + + /// read all bytes buffered to dst, return the actual read length. + pub fn read(&mut self, dst: &mut [u8]) -> Result { + let len = self.buffer.len(); + let read_len = len.min(dst.len()); + for i in 0..read_len { + if let Some(content) = self.buffer.dequeue() { + dst[i] = content; + } else { + break; + } + } + Ok(read_len) + } + + /// write bytes to buffer, if flush to console, then write the content to console + pub fn write(&self, src: &[u8], flush_to_console: bool) -> Result { + todo!() + } + + /// set foreground process group + pub fn set_fg(&mut self, fg_pgid: Pgid) { + self.foreground = Some(fg_pgid); + } + + /// get foreground process group id + pub fn get_fg(&self) -> Option<&Pgid> { + self.foreground.as_ref() + } + + /// whether there is buffered data + pub fn is_empty(&self) -> bool { + self.buffer.len() == 0 + } + + pub fn get_termios(&self) -> &KernelTermios { + &self.termios + } + + pub fn set_termios(&mut self, termios: KernelTermios) { + self.termios = termios; + } +} diff --git a/src/kxos-std/src/tty/mod.rs b/src/kxos-std/src/tty/mod.rs new file mode 100644 index 000000000..8a548d4f6 --- /dev/null +++ b/src/kxos-std/src/tty/mod.rs @@ -0,0 +1,118 @@ +use kxos_frame::receive_char; + +use self::line_discipline::LineDiscipline; +use crate::fs::events::IoEvents; +use crate::fs::ioctl::IoctlCmd; +use crate::memory::{read_val_from_user, write_val_to_user}; +use crate::process::Pgid; +use crate::{fs::file::File, prelude::*}; + +pub mod line_discipline; +pub mod termio; + +lazy_static! { + static ref N_TTY: Arc = { + let name = CString::new("console").unwrap(); + Arc::new(Tty::new(name)) + }; +} + +pub struct Tty { + /// tty_name + name: CString, + /// line discipline + ldisc: Mutex, +} + +impl Tty { + pub fn new(name: CString) -> Self { + Tty { + name, + ldisc: Mutex::new(LineDiscipline::new()), + } + } + + pub fn set_fg(&self, pgid: Pgid) { + self.ldisc.lock().set_fg(pgid); + } +} + +impl File for Tty { + fn read(&self, buf: &mut [u8]) -> Result { + self.ldisc.lock().read(buf) + } + + fn write(&self, buf: &[u8]) -> Result { + if let Ok(content) = alloc::str::from_utf8(buf) { + print!("{content}"); + } else { + println!("Not utf-8 content: {:?}", buf); + } + Ok(buf.len()) + } + + fn poll(&self) -> IoEvents { + if !self.ldisc.lock().is_empty() { + return IoEvents::POLLIN; + } + loop { + // receive keyboard input + if let Some(byte) = receive_char() { + self.ldisc.lock().push_char(byte); + return IoEvents::POLLIN; + } else { + return IoEvents::empty(); + } + } + } + + fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { + match cmd { + IoctlCmd::TCGETS => { + // Get terminal attributes + let ldist_lock = self.ldisc.lock(); + let termios = ldist_lock.get_termios(); + debug!("get termios = {:?}", termios); + write_val_to_user(arg, termios)?; + Ok(0) + } + IoctlCmd::TIOCGPGRP => { + // FIXME: Get the process group ID of the foreground process group on this terminal. + let ldist_lock = self.ldisc.lock(); + let fg_pgid = ldist_lock.get_fg(); + match fg_pgid { + None => return_errno_with_message!(Errno::ENOENT, "No fg process group"), + Some(fg_pgid) => { + debug!("fg_pgid = {}", fg_pgid); + write_val_to_user(arg, fg_pgid)?; + Ok(0) + } + } + } + IoctlCmd::TIOCSPGRP => { + // Set the process group id of fg progress group + let pgid = read_val_from_user::(arg)?; + let mut ldist_lock = self.ldisc.lock(); + ldist_lock.set_fg(pgid); + Ok(0) + } + IoctlCmd::TCSETS => { + // Set terminal attributes + let termios = read_val_from_user(arg)?; + debug!("set termios = {:?}", termios); + let mut ldist_lock = self.ldisc.lock(); + ldist_lock.set_termios(termios); + Ok(0) + } + IoctlCmd::TIOCGWINSZ => { + // TODO:get window size + Ok(0) + } + _ => todo!(), + } + } +} + +pub fn get_console() -> &'static Arc { + &N_TTY +} diff --git a/src/kxos-std/src/tty/termio.rs b/src/kxos-std/src/tty/termio.rs new file mode 100644 index 000000000..a5fa1c80c --- /dev/null +++ b/src/kxos-std/src/tty/termio.rs @@ -0,0 +1,158 @@ +#![allow(non_camel_case_types)] + +use crate::prelude::*; + +// This definition is from occlum +const KERNEL_NCCS: usize = 19; + +type TcflagT = u32; +type CcT = u8; +type SpeedT = u32; + +bitflags! { + #[derive(Pod)] + #[repr(C)] + pub struct C_IFLAGS: u32 { + // https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/termbits-common.h + const IGNBRK = 0x001; /* Ignore break condition */ + const BRKINT = 0x002; /* Signal interrupt on break */ + const IGNPAR = 0x004; /* Ignore characters with parity errors */ + const PARMRK = 0x008; /* Mark parity and framing errors */ + const INPCK = 0x010; /* Enable input parity check */ + const ISTRIP = 0x020; /* Strip 8th bit off characters */ + const INLCR = 0x040; /* Map NL to CR on input */ + const IGNCR = 0x080; /* Ignore CR */ + const ICRNL = 0x100; /* Map CR to NL on input */ + const IXANY = 0x800; /* Any character will restart after stop */ + // https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/termbits.h + const IUCLC = 0x0200; + const IXON = 0x0400; + const IXOFF = 0x1000; + const IMAXBEL = 0x2000; + const IUTF8 = 0x4000; + } +} + +bitflags! { + #[repr(C)] + #[derive(Pod)] + pub struct C_OFLAGS: u32 { + const OPOST = 0x01; /* Perform output processing */ + const OCRNL = 0x08; + const ONOCR = 0x10; + const ONLRET= 0x20; + const OFILL = 0x40; + const OFDEL = 0x80; + } +} + +#[repr(u32)] +#[derive(Debug, Clone, Copy, Pod)] +pub enum C_CFLAGS { + B0 = 0x00000000, /* hang up */ + B50 = 0x00000001, + B75 = 0x00000002, + B110 = 0x00000003, + B134 = 0x00000004, + B150 = 0x00000005, + B200 = 0x00000006, + B300 = 0x00000007, + B600 = 0x00000008, + B1200 = 0x00000009, + B1800 = 0x0000000a, + B2400 = 0x0000000b, + B4800 = 0x0000000c, + B9600 = 0x0000000d, + B19200 = 0x0000000e, + B38400 = 0x0000000f, +} + +bitflags! { + #[repr(C)] + #[derive(Pod)] + pub struct C_LFLAGS: u32 { + const ISIG = 0x00001; + const ICANON= 0x00002; + const XCASE = 0x00004; + const ECHO = 0x00008; + const ECHOE = 0x00010; + const ECHOK = 0x00020; + const ECHONL= 0x00040; + const NOFLSH= 0x00080; + const TOSTOP= 0x00100; + const ECHOCTL= 0x00200; + const ECHOPRT= 0x00400; + const ECHOKE= 0x00800; + const FLUSHO= 0x01000; + const PENDIN= 0x04000; + const IEXTEN= 0x08000; + const EXTPROC= 0x10000; + } +} + +/* c_cc characters index*/ +#[repr(u32)] +#[derive(Debug, Clone, Copy, Pod)] +pub enum CC_C_CHAR { + VINTR = 0, + VQUIT = 1, + VERASE = 2, + VKILL = 3, + VEOF = 4, + VTIME = 5, + VMIN = 6, + VSWTC = 7, + VSTART = 8, + VSTOP = 9, + VSUSP = 10, + VEOL = 11, + VREPRINT = 12, + VDISCARD = 13, + VWERASE = 14, + VLNEXT = 15, + VEOL2 = 16, +} + +#[derive(Debug, Clone, Copy, Pod)] +#[repr(C)] +pub struct KernelTermios { + pub c_iflags: C_IFLAGS, + pub c_oflags: C_OFLAGS, + pub c_cflags: C_CFLAGS, + pub c_lflags: C_LFLAGS, + pub c_line: CcT, + pub c_cc: [CcT; KERNEL_NCCS], +} + +impl KernelTermios { + pub fn default() -> Self { + Self { + c_iflags: C_IFLAGS::ICRNL, + c_oflags: C_OFLAGS::empty(), + c_cflags: C_CFLAGS::B0, + c_lflags: C_LFLAGS::ICANON | C_LFLAGS::ECHO, + c_line: 0, + c_cc: [0; KERNEL_NCCS], + } + } + + fn new() -> Self { + KernelTermios { + c_iflags: C_IFLAGS::empty(), + c_oflags: C_OFLAGS::empty(), + c_cflags: C_CFLAGS::B0, + c_lflags: C_LFLAGS::empty(), + c_line: 0, + c_cc: [0; KERNEL_NCCS], + } + } + + pub fn is_cooked_mode(&self) -> bool { + self.c_lflags.contains(C_LFLAGS::ICANON) + } + + /// ICRNL means we should map \r to \n + pub fn contains_icrnl(&self) -> bool { + self.c_iflags.contains(C_IFLAGS::ICRNL) + } +} diff --git a/src/kxos-std/src/user_apps.rs b/src/kxos-std/src/user_apps.rs index bc2b0ca20..2180310c4 100644 --- a/src/kxos-std/src/user_apps.rs +++ b/src/kxos-std/src/user_apps.rs @@ -58,8 +58,19 @@ pub fn get_all_apps() -> Vec { // 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=/"]; + // -l option means the busybox is running as logging shell + let argv = ["/busybox", "sh", "-l"]; + // 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=root", "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 envp = [ + "SHELL=/bin/sh", + "PWD=/", + "LOGNAME=root", + "HOME=/", + "USER=root", + "PATH=", + "OLDPWD=/", + ]; + let argv = to_vec_cstring(&argv).unwrap(); let envp = to_vec_cstring(&envp).unwrap(); busybox.set_argv(argv); diff --git a/src/kxos-user/busybox/README.md b/src/kxos-user/busybox/README.md new file mode 100644 index 000000000..4bae99451 --- /dev/null +++ b/src/kxos-user/busybox/README.md @@ -0,0 +1,6 @@ +### How to compile this busybox +We don't include the source code of busybox here since the source code is really large. The busybox can be compiled with following commands. + +After download the source code of busybox 1.35.0 and unzip, then cd to the directory of busybox +1. ```make defconfig #set config to default``` +2. change the line in .config, `#CONFIG_STATIC is not set` => `CONFIG_STATIC=y`. We need a static-compiled busybox \ No newline at end of file diff --git a/src/kxos-user/busybox/busybox b/src/kxos-user/busybox/busybox index 8dda33827..fff51115c 100755 --- a/src/kxos-user/busybox/busybox +++ b/src/kxos-user/busybox/busybox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3019f1ee7431b4a7cbcbace4c114679430a6c1277081bed11a290aeb0bc9d6e -size 2644416 +oid sha256:be0c152c1e47d3109f808cda876c3a90a1ef959007741e126086552e1063eede +size 2701792