mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 10:53:25 +00:00
support running busybox shell
This commit is contained in:
41
src/Cargo.lock
generated
41
src/Cargo.lock
generated
@ -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"
|
||||
|
@ -3,13 +3,23 @@ use spin::Mutex;
|
||||
use uart_16550::SerialPort;
|
||||
|
||||
lazy_static! {
|
||||
pub(crate) static ref SERIAL: Mutex<SerialPort> = {
|
||||
pub static ref SERIAL: Mutex<SerialPort> = {
|
||||
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<u8> {
|
||||
let byte = SERIAL.lock().receive();
|
||||
Some(byte)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: ::core::fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<usize> {
|
||||
panic!("read unsupported");
|
||||
}
|
||||
@ -16,8 +17,15 @@ pub trait File: Send + Sync + Debug + Any {
|
||||
panic!("write unsupported");
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||
panic!("ioctl unsupported");
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
match cmd {
|
||||
IoctlCmd::TCGETS => {
|
||||
// FIXME: only a work around
|
||||
let tty = get_console();
|
||||
tty.ioctl(cmd, arg)
|
||||
}
|
||||
_ => panic!("Ioctl unsupported"),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&self) -> IoEvents {
|
||||
|
@ -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<FileDescripter, Arc<dyn File>>,
|
||||
}
|
||||
@ -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<dyn File>);
|
||||
table.insert(FD_STDOUT, Arc::new(Stdout) as Arc<dyn File>);
|
||||
table.insert(FD_STDERR, Arc::new(Stderr) as Arc<dyn File>);
|
||||
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<dyn File>);
|
||||
table.insert(FD_STDOUT, Arc::new(stdout) as Arc<dyn File>);
|
||||
table.insert(FD_STDERR, Arc::new(stderr) as Arc<dyn File>);
|
||||
Self { table }
|
||||
}
|
||||
|
||||
@ -47,6 +50,16 @@ impl FileTable {
|
||||
self.table.iter().map(|(fd, _)| fd.clone()).max().unwrap()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, item: Arc<dyn File>) -> 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<dyn File>> {
|
||||
self.table.get(&fd)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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],
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Arc<Tty>>,
|
||||
bind_to_console: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stdout;
|
||||
pub struct Stdout {
|
||||
console: Option<Arc<Tty>>,
|
||||
bind_to_console: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stderr;
|
||||
pub struct Stderr {
|
||||
console: Option<Arc<Tty>>,
|
||||
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<usize> {
|
||||
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<i32> {
|
||||
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<i32> {
|
||||
if self.bind_to_console {
|
||||
let console = self.console.as_ref().unwrap();
|
||||
console.ioctl(cmd, arg)
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
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<i32> {
|
||||
if self.bind_to_console {
|
||||
let console = self.console.as_ref().unwrap();
|
||||
console.ioctl(cmd, arg)
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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<CString>,
|
||||
) -> Arc<Self> {
|
||||
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,9 +299,10 @@ impl Process {
|
||||
/// remove current process from old process group.
|
||||
pub fn set_process_group(&self, process_group: Weak<ProcessGroup>) {
|
||||
if let Some(old_process_group) = &*self.process_group().lock() {
|
||||
let old_process_group = old_process_group.upgrade().unwrap();
|
||||
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);
|
||||
}
|
||||
|
||||
|
17
src/kxos-std/src/syscall/close.rs
Normal file
17
src/kxos-std/src/syscall/close.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use super::SyscallReturn;
|
||||
use super::SYS_CLOSE;
|
||||
use crate::{fs::file::FileDescripter, prelude::*};
|
||||
|
||||
pub fn sys_close(fd: FileDescripter) -> Result<SyscallReturn> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -4,6 +4,6 @@ use super::SyscallReturn;
|
||||
|
||||
pub fn sys_getuid() -> Result<SyscallReturn> {
|
||||
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))
|
||||
}
|
||||
|
@ -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<SyscallRetu
|
||||
"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::<i32>(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::<KernelTermios>(arg)?;
|
||||
debug!("termio = {:x?}", termio);
|
||||
// TODO: Set termios
|
||||
} else {
|
||||
todo!()
|
||||
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::TIOCGWINSZ => {
|
||||
// TODO:get window size
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
11
src/kxos-std/src/syscall/lseek.rs
Normal file
11
src/kxos-std/src/syscall/lseek.rs
Normal file
@ -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<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_LSEEK]", SYS_LSEEK);
|
||||
debug!("fd = {}, offset = {}, whence = {}", fd, offset, whence);
|
||||
// TODO: do lseek
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
@ -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<SyscallReturn> {
|
||||
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;
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
11
src/kxos-std/src/syscall/munmap.rs
Normal file
11
src/kxos-std/src/syscall/munmap.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use super::SYS_MUNMAP;
|
||||
|
||||
pub fn sys_munmap(addr: Vaddr, len: usize) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_READ]", SYS_MUNMAP);
|
||||
debug!("addr = 0x{:x}, len = {}", addr, len);
|
||||
//TODO: do munmap
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
@ -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<dyn File>;
|
||||
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!()
|
||||
}
|
||||
|
33
src/kxos-std/src/syscall/read.rs
Normal file
33
src/kxos-std/src/syscall/read.rs
Normal file
@ -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<SyscallReturn> {
|
||||
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 _));
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,11 @@ pub fn sys_rt_sigaction(
|
||||
let sig_action_c = read_val_from_user::<sigaction_t>(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!();
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
use super::{SyscallReturn, SYS_SETPGID};
|
||||
|
||||
pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result<SyscallReturn> {
|
||||
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 };
|
||||
|
@ -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<SyscallReturn> {
|
||||
// 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)?;
|
||||
|
@ -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<SyscallReturn> {
|
||||
pub fn sys_write(
|
||||
fd: FileDescripter,
|
||||
user_buf_ptr: Vaddr,
|
||||
user_buf_len: u64,
|
||||
) -> Result<SyscallReturn> {
|
||||
// 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<Syscal
|
||||
fd, user_buf_ptr, user_buf_len
|
||||
);
|
||||
|
||||
if fd == STDOUT || fd == STDERR {
|
||||
let current = current!();
|
||||
let file_table = current.file_table().lock();
|
||||
match file_table.get_file(fd) {
|
||||
None => 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)?;
|
||||
let content = alloc::str::from_utf8(buffer.as_slice())?; // TODO: print content
|
||||
if fd == STDOUT {
|
||||
print!("{}", content);
|
||||
} else {
|
||||
print!("{}", content);
|
||||
}
|
||||
Ok(SyscallReturn::Return(user_buf_len as _))
|
||||
} else {
|
||||
panic!("Unsupported fd number {}", fd);
|
||||
debug!("write buf = {:?}", buffer);
|
||||
let write_len = file.write(&buffer)?;
|
||||
Ok(SyscallReturn::Return(write_len as _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
85
src/kxos-std/src/tty/line_discipline.rs
Normal file
85
src/kxos-std/src/tty/line_discipline.rs
Normal file
@ -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<u8, BUFFER_CAPACITY>,
|
||||
/// The foreground process group
|
||||
foreground: Option<Pgid>,
|
||||
/// 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<usize> {
|
||||
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<usize> {
|
||||
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;
|
||||
}
|
||||
}
|
118
src/kxos-std/src/tty/mod.rs
Normal file
118
src/kxos-std/src/tty/mod.rs
Normal file
@ -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<Tty> = {
|
||||
let name = CString::new("console").unwrap();
|
||||
Arc::new(Tty::new(name))
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Tty {
|
||||
/// tty_name
|
||||
name: CString,
|
||||
/// line discipline
|
||||
ldisc: Mutex<LineDiscipline>,
|
||||
}
|
||||
|
||||
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<usize> {
|
||||
self.ldisc.lock().read(buf)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
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<i32> {
|
||||
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::<i32>(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<Tty> {
|
||||
&N_TTY
|
||||
}
|
158
src/kxos-std/src/tty/termio.rs
Normal file
158
src/kxos-std/src/tty/termio.rs
Normal file
@ -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)
|
||||
}
|
||||
}
|
@ -58,8 +58,19 @@ pub fn get_all_apps() -> Vec<UserApp> {
|
||||
|
||||
// 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);
|
||||
|
6
src/kxos-user/busybox/README.md
Normal file
6
src/kxos-user/busybox/README.md
Normal file
@ -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
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c3019f1ee7431b4a7cbcbace4c114679430a6c1277081bed11a290aeb0bc9d6e
|
||||
size 2644416
|
||||
oid sha256:be0c152c1e47d3109f808cda876c3a90a1ef959007741e126086552e1063eede
|
||||
size 2701792
|
||||
|
Reference in New Issue
Block a user