add syscall execve

This commit is contained in:
Jianfeng Jiang
2022-10-26 17:47:38 +08:00
parent 049f519a0e
commit 7ee9c9e74c
53 changed files with 544 additions and 152 deletions

2
.gitattributes vendored
View File

@ -1,3 +1,5 @@
src/kxos-user/hello_world/hello_world filter=lfs diff=lfs merge=lfs -text src/kxos-user/hello_world/hello_world filter=lfs diff=lfs merge=lfs -text
src/kxos-user/fork/fork filter=lfs diff=lfs merge=lfs -text src/kxos-user/fork/fork filter=lfs diff=lfs merge=lfs -text
src/kxos-user/hello_c/hello filter=lfs diff=lfs merge=lfs -text src/kxos-user/hello_c/hello filter=lfs diff=lfs merge=lfs -text
src/kxos-user/execve/execve filter=lfs diff=lfs merge=lfs -text
src/kxos-user/execve/hello filter=lfs diff=lfs merge=lfs -text

View File

@ -22,7 +22,7 @@ pub fn this_cpu() -> u32 {
} }
/// Cpu context, including both general-purpose registers and floating-point registers. /// Cpu context, including both general-purpose registers and floating-point registers.
#[derive(Clone, Default, Copy)] #[derive(Clone, Default, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct CpuContext { pub struct CpuContext {
pub gp_regs: GpRegs, pub gp_regs: GpRegs,
@ -31,7 +31,7 @@ pub struct CpuContext {
/// trap information, this field is all zero when it is syscall /// trap information, this field is all zero when it is syscall
pub trap_information: TrapInformation, pub trap_information: TrapInformation,
} }
#[derive(Clone, Default, Copy)] #[derive(Clone, Default, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct TrapInformation { pub struct TrapInformation {
pub cr2: u64, pub cr2: u64,
@ -195,7 +195,7 @@ impl Into<TrapFrame> for CpuContext {
} }
/// The floating-point state of CPU. /// The floating-point state of CPU.
#[derive(Clone, Copy)] #[derive(Clone, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct FpRegs { pub struct FpRegs {
//buf: Aligned<A16, [u8; 512]>, //buf: Aligned<A16, [u8; 512]>,

View File

@ -28,7 +28,7 @@ pub struct MemorySet {
impl MapArea { impl MapArea {
pub fn mapped_size(&self) -> usize { pub fn mapped_size(&self) -> usize {
self.mapper.len() self.size
} }
pub fn clone(&self) -> Self { pub fn clone(&self) -> Self {

View File

@ -134,6 +134,7 @@ impl<'a> UserMode<'a> {
} else { } else {
// x86_64_util::wrfsbase(self.context.fs_base); // x86_64_util::wrfsbase(self.context.fs_base);
*self.current.syscall_frame() = self.context.into(); *self.current.syscall_frame() = self.context.into();
self.current.syscall_frame().caller.rcx = self.context.gp_regs.rip;
} }
} }

View File

@ -90,6 +90,12 @@ impl VmSpace {
Ok(()) Ok(())
} }
/// clear all mappings
pub fn clear(&self) {
self.memory_set.lock().clear();
crate::x86_64_util::flush_tlb();
}
/// Update the VM protection permissions within the VM address range. /// Update the VM protection permissions within the VM address range.
/// ///
/// The entire specified VM range must have been mapped with physical /// The entire specified VM range must have been mapped with physical

View File

@ -223,3 +223,7 @@ pub fn enable_common_cpu_features() {
} }
debug!("xcr0: {:?}", xcr0); debug!("xcr0: {:?}", xcr0);
} }
pub fn flush_tlb() {
x86_64::instructions::tlb::flush_all();
}

View File

@ -0,0 +1 @@
pub mod stat;

View File

@ -0,0 +1,60 @@
#![allow(non_camel_case_types)]
type dev_t = usize;
type ino_t = usize;
type mode_t = u32;
type nlink_t = usize;
type uid_t = u32;
type gid_t = u32;
type off_t = u32;
type blksize_t = isize;
type blkcnt_t = isize;
type timespec = isize;
pub const S_IFMT: u32 = 0o170000;
pub const S_IFCHR: u32 = 0o020000;
pub const S_IFDIR: u32 = 0o040000;
pub const S_IFREG: u32 = 0o100000;
pub const S_IFLNK: u32 = 0o120000;
/// File Stat
#[derive(Debug, Clone, Copy, Pod, Default)]
pub struct Stat {
/// ID of device containing file
st_dev: dev_t,
/// Inode number
st_ino: ino_t,
/// File type and mode
st_mode: mode_t,
/// Number of hard links
st_nlink: nlink_t,
/// User ID of owner
st_uid: uid_t,
/// Group ID of owner
st_gid: gid_t,
/// Device ID (if special file)
st_rdev: dev_t,
/// Total size, in bytes
st_size: off_t,
/// Block size for filesystem I/O
st_blksize: blksize_t,
/// Number of 512B blocks allocated
st_blocks: blkcnt_t,
/// Time of last access
st_atime: timespec,
/// Time of last modification
st_mtime: timespec,
/// Time of last status change
st_ctime: timespec,
}
impl Stat {
/// We use the same stat as linux
pub fn stdout_stat() -> Self {
let mut stat = Stat::default();
stat.st_mode = S_IFCHR | 0o620;
stat.st_nlink = 1;
stat.st_blksize = 1024;
stat
}
}

View File

@ -9,16 +9,20 @@
#![feature(exclusive_range_pattern)] #![feature(exclusive_range_pattern)]
#![feature(btree_drain_filter)] #![feature(btree_drain_filter)]
use alloc::ffi::CString;
use kxos_frame::{debug, info, println}; use kxos_frame::{debug, info, println};
use process::Process; use process::Process;
use crate::user_apps::get_all_apps;
extern crate alloc; extern crate alloc;
pub mod driver; pub mod driver;
pub mod fs;
mod memory; mod memory;
pub mod prelude;
mod process; mod process;
pub mod syscall; pub mod syscall;
mod user_apps;
mod util; mod util;
#[macro_use] #[macro_use]
extern crate kxos_frame_pod_derive; extern crate kxos_frame_pod_derive;
@ -41,27 +45,16 @@ pub fn init_process() {
process.pid() process.pid()
); );
let hello_world_content = read_hello_world_content(); for app in get_all_apps() {
let hello_world_filename = CString::new("hello_world").unwrap(); let app_name = app.app_name();
let process = Process::spawn_user_process(hello_world_filename, hello_world_content); info!("[kxos-std/lib.rs] spwan {:?} process", app.app_name());
info!( let process = Process::spawn_user_process(app_name, app.app_content());
"[kxos-std/lib.rs] spwan hello world process, pid = {}", info!(
process.pid() "[kxos-std/lib.rs] {:?} process exits, pid = {}",
); app.app_name(),
process.pid()
let hello_c_content = read_hello_c_content(); );
// glibc requires the filename starts as "/" }
let hello_c_filename = CString::new("/hello_c").unwrap();
let process = Process::spawn_user_process(hello_c_filename, hello_c_content);
info!("spawn hello_c process, pid = {}", process.pid());
let fork_content = read_fork_content();
let fork_filename = CString::new("fork").unwrap();
let process = Process::spawn_user_process(fork_filename, fork_content);
info!(
"[kxos-std/lib.rs] spawn fork process, pid = {}",
process.pid()
);
loop { loop {
// We don't have preemptive scheduler now. // We don't have preemptive scheduler now.
@ -72,19 +65,7 @@ pub fn init_process() {
/// first process never return /// first process never return
pub fn run_first_process() -> ! { pub fn run_first_process() -> ! {
let elf_file_content = read_hello_world_content(); // let elf_file_content = read_hello_world_content();
Process::spawn_kernel_process(init_process); Process::spawn_kernel_process(init_process);
unreachable!() unreachable!()
} }
pub fn read_hello_world_content() -> &'static [u8] {
include_bytes!("../../kxos-user/hello_world/hello_world")
}
fn read_fork_content() -> &'static [u8] {
include_bytes!("../../kxos-user/fork/fork")
}
fn read_hello_c_content() -> &'static [u8] {
include_bytes!("../../kxos-user/hello_c/hello")
}

View File

@ -1,4 +1,4 @@
use alloc::collections::BTreeMap; use crate::prelude::*;
/// This implementation is from occlum. /// This implementation is from occlum.

View File

@ -1,19 +1,15 @@
//! This module is used to parse elf file content to get elf_load_info. //! This module is used to parse elf file content to get elf_load_info.
//! When create a process from elf file, we will use the elf_load_info to construct the VmSpace //! When create a process from elf file, we will use the elf_load_info to construct the VmSpace
use crate::prelude::*;
use core::{cmp::Ordering, ops::Range}; use core::{cmp::Ordering, ops::Range};
use alloc::ffi::CString;
use alloc::vec;
use alloc::vec::Vec;
use kxos_frame::{ use kxos_frame::{
config::PAGE_SIZE, vm::{VmIo, VmPerm, VmSpace},
vm::{Vaddr, VmIo, VmPerm, VmSpace},
Error, Error,
}; };
use xmas_elf::{ use xmas_elf::{
header, header,
program::{self, ProgramHeader, SegmentData}, program::{self, ProgramHeader, ProgramHeader64, SegmentData},
ElfFile, ElfFile,
}; };
@ -23,6 +19,7 @@ pub struct ElfLoadInfo<'a> {
entry_point: Vaddr, entry_point: Vaddr,
segments: Vec<ElfSegment<'a>>, segments: Vec<ElfSegment<'a>>,
init_stack: InitStack, init_stack: InitStack,
elf_header_info: ElfHeaderInfo,
} }
pub struct ElfSegment<'a> { pub struct ElfSegment<'a> {
@ -32,6 +29,17 @@ pub struct ElfSegment<'a> {
vm_perm: VmPerm, vm_perm: VmPerm,
} }
#[derive(Debug, Clone, Copy, Default)]
/// Info parsed from elf header. Used to set aux vector.
pub struct ElfHeaderInfo {
/// page header table offset
pub ph_off: u64,
/// number of program headers
pub ph_num: u16,
/// The size of a program header
pub ph_ent: usize,
}
impl<'a> ElfSegment<'a> { impl<'a> ElfSegment<'a> {
fn parse_elf_segment( fn parse_elf_segment(
segment: ProgramHeader<'a>, segment: ProgramHeader<'a>,
@ -92,9 +100,20 @@ impl<'a> ElfSegment<'a> {
page.map_page(vm_space, vm_perm)?; page.map_page(vm_space, vm_perm)?;
} }
} }
// copy segment // copy segment
vm_space.write_bytes(self.start_address(), self.data)?; vm_space.write_bytes(self.start_address(), self.data)?;
// The length of segment may be greater than the length of data
// In this case, the additional bytes should be zeroed.
let segment_len = self.end_address() - self.start_address();
let data_len = self.data.len();
if segment_len > data_len {
let zeroed_bytes = vec![0u8; segment_len - data_len];
let write_addr = self.start_address() + data_len;
vm_space
.write_bytes(write_addr, &zeroed_bytes)
.expect("Write zeroed bytes failed");
}
Ok(()) Ok(())
} }
@ -104,11 +123,17 @@ impl<'a> ElfSegment<'a> {
} }
impl<'a> ElfLoadInfo<'a> { impl<'a> ElfLoadInfo<'a> {
fn with_capacity(entry_point: Vaddr, capacity: usize, init_stack: InitStack) -> Self { fn with_capacity(
entry_point: Vaddr,
capacity: usize,
init_stack: InitStack,
elf_header_info: ElfHeaderInfo,
) -> Self {
Self { Self {
entry_point, entry_point,
segments: Vec::with_capacity(capacity), segments: Vec::with_capacity(capacity),
init_stack, init_stack,
elf_header_info,
} }
} }
@ -124,10 +149,12 @@ impl<'a> ElfLoadInfo<'a> {
check_elf_header(&elf_file)?; check_elf_header(&elf_file)?;
// init elf load info // init elf load info
let entry_point = elf_file.header.pt2.entry_point() as Vaddr; let entry_point = elf_file.header.pt2.entry_point() as Vaddr;
let elf_header_info = ElfHeaderInfo::parse_elf_header(&elf_file);
// FIXME: only contains load segment? // FIXME: only contains load segment?
let segments_count = elf_file.program_iter().count(); let segments_count = elf_file.program_iter().count();
let init_stack = InitStack::new_default_config(filename); let init_stack = InitStack::new_default_config(filename);
let mut elf_load_info = ElfLoadInfo::with_capacity(entry_point, segments_count, init_stack); let mut elf_load_info =
ElfLoadInfo::with_capacity(entry_point, segments_count, init_stack, elf_header_info);
// parse each segemnt // parse each segemnt
for segment in elf_file.program_iter() { for segment in elf_file.program_iter() {
@ -168,10 +195,22 @@ impl<'a> ElfLoadInfo<'a> {
pub fn init_stack(&mut self, vm_space: &VmSpace) { pub fn init_stack(&mut self, vm_space: &VmSpace) {
self.init_stack self.init_stack
.init(vm_space) .init(vm_space, &self.elf_header_info)
.expect("Init User Stack failed"); .expect("Init User Stack failed");
} }
/// This function will write the first page of elf file to the initial stack top.
/// This function must be called after init process initial stack.
/// This infomation is used to set Auxv vectors.
pub fn write_elf_first_page(&self, vm_space: &VmSpace, file_content: &[u8]) {
let write_len = PAGE_SIZE.min(file_content.len());
let write_content = &file_content[..write_len];
let write_addr = self.init_stack.init_stack_top() - PAGE_SIZE;
vm_space
.write_bytes(write_addr, write_content)
.expect("Write elf content failed");
}
/// return the perm of elf pages /// return the perm of elf pages
/// FIXME: Set the correct permission bit of user pages. /// FIXME: Set the correct permission bit of user pages.
fn perm() -> VmPerm { fn perm() -> VmPerm {
@ -228,6 +267,19 @@ impl<'a> ElfLoadInfo<'a> {
} }
} }
impl ElfHeaderInfo {
fn parse_elf_header(elf_file: &ElfFile) -> Self {
let ph_off = elf_file.header.pt2.ph_offset();
let ph_num = elf_file.header.pt2.ph_count();
let ph_ent = core::mem::size_of::<ProgramHeader64>();
ElfHeaderInfo {
ph_off,
ph_num,
ph_ent,
}
}
}
fn check_elf_header(elf_file: &ElfFile) -> Result<(), ElfError> { fn check_elf_header(elf_file: &ElfFile) -> Result<(), ElfError> {
let elf_header = elf_file.header; let elf_header = elf_file.header;
// 64bit // 64bit

View File

@ -2,17 +2,14 @@
//! The process initial stack, contains arguments, environmental variables and auxiliary vectors //! The process initial stack, contains arguments, environmental variables and auxiliary vectors
//! The data layout of init stack can be seen in Figure 3.9 in https://uclibc.org/docs/psABI-x86_64.pdf //! The data layout of init stack can be seen in Figure 3.9 in https://uclibc.org/docs/psABI-x86_64.pdf
use crate::prelude::*;
use core::mem; use core::mem;
use alloc::vec;
use alloc::{ffi::CString, vec::Vec};
use kxos_frame::{ use kxos_frame::{
config::PAGE_SIZE, vm::{VmIo, VmPerm, VmSpace},
debug,
vm::{Vaddr, VmIo, VmPerm, VmSpace},
AlignExt, AlignExt,
}; };
use super::elf::ElfHeaderInfo;
use super::{ use super::{
aux_vec::{AuxKey, AuxVec}, aux_vec::{AuxKey, AuxVec},
elf::ElfError, elf::ElfError,
@ -101,7 +98,6 @@ impl InitStack {
/// the user stack top(high address), used to setup rsp /// the user stack top(high address), used to setup rsp
pub fn user_stack_top(&self) -> Vaddr { pub fn user_stack_top(&self) -> Vaddr {
let stack_top = self.pos; let stack_top = self.pos;
debug!("user stack top: 0x{:x}", stack_top);
// ensure stack top is 16-bytes aligned // ensure stack top is 16-bytes aligned
debug_assert!(stack_top & !0xf == stack_top); debug_assert!(stack_top & !0xf == stack_top);
stack_top stack_top
@ -112,9 +108,14 @@ impl InitStack {
self.init_stack_top - self.init_stack_size self.init_stack_top - self.init_stack_size
} }
pub fn init(&mut self, vm_space: &VmSpace) -> Result<(), ElfError> { pub fn init(
&mut self,
vm_space: &VmSpace,
elf_header_info: &ElfHeaderInfo,
) -> Result<(), ElfError> {
self.map_and_zeroed(vm_space); self.map_and_zeroed(vm_space);
self.write_stack_content(vm_space); self.write_zero_page(vm_space); // This page is used to store page header table
self.write_stack_content(vm_space, elf_header_info);
self.debug_print_stack_content(vm_space); self.debug_print_stack_content(vm_space);
Ok(()) Ok(())
} }
@ -146,7 +147,11 @@ impl InitStack {
} }
} }
fn write_stack_content(&mut self, vm_space: &VmSpace) { fn write_zero_page(&mut self, vm_space: &VmSpace) {
self.pos -= PAGE_SIZE;
}
fn write_stack_content(&mut self, vm_space: &VmSpace, elf_header_info: &ElfHeaderInfo) {
// write envp string // write envp string
let envp_pointers = self.write_envp_strings(vm_space); let envp_pointers = self.write_envp_strings(vm_space);
// write argv string // write argv string
@ -157,6 +162,21 @@ impl InitStack {
self.aux_vec self.aux_vec
.set(AuxKey::AT_RANDOM, random_value_pointer) .set(AuxKey::AT_RANDOM, random_value_pointer)
.expect("Set random value failed"); .expect("Set random value failed");
self.aux_vec
.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)
.expect("Set Page Size failed");
self.aux_vec
.set(
AuxKey::AT_PHDR,
self.init_stack_top as u64 - PAGE_SIZE as u64 + elf_header_info.ph_off,
)
.unwrap();
self.aux_vec
.set(AuxKey::AT_PHNUM, elf_header_info.ph_num as u64)
.unwrap();
self.aux_vec
.set(AuxKey::AT_PHENT, elf_header_info.ph_ent as u64)
.unwrap();
self.adjust_stack_alignment(vm_space, &envp_pointers, &argv_pointers); self.adjust_stack_alignment(vm_space, &envp_pointers, &argv_pointers);
self.write_aux_vec(vm_space); self.write_aux_vec(vm_space);
self.write_envp_pointers(vm_space, envp_pointers); self.write_envp_pointers(vm_space, envp_pointers);
@ -251,6 +271,13 @@ impl InitStack {
pub fn envp(&self) -> u64 { pub fn envp(&self) -> u64 {
0 0
} }
/// returns the top address of init stack.
/// It should points to a fixed address.
pub const fn init_stack_top(&self) -> Vaddr {
self.init_stack_top
}
/// returns the u64 start address /// returns the u64 start address
fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> u64 { fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> u64 {
let start_address = (self.pos - 8).align_down(8); let start_address = (self.pos - 8).align_down(8);

View File

@ -1,10 +1,7 @@
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use kxos_frame::{ use crate::prelude::*;
config::PAGE_SIZE, use kxos_frame::vm::{VmPerm, VmSpace};
debug,
vm::{Vaddr, VmPerm, VmSpace},
};
use super::{init_stack::INIT_STACK_BASE, vm_page::VmPageRange}; use super::{init_stack::INIT_STACK_BASE, vm_page::VmPageRange};
use crate::syscall::mmap::MMapFlags; use crate::syscall::mmap::MMapFlags;
@ -52,6 +49,11 @@ impl MmapArea {
debug!("mmap area start: 0x{:x}, size: {}", current, len); debug!("mmap area start: 0x{:x}, size: {}", current, len);
current current
} }
/// Set mmap area to the default status. i.e., point current to base.
pub fn set_default(&self) {
self.current.store(self.base_addr, Ordering::Relaxed);
}
} }
impl Clone for MmapArea { impl Clone for MmapArea {

View File

@ -4,11 +4,8 @@ pub mod init_stack;
pub mod mmap_area; pub mod mmap_area;
pub mod user_heap; pub mod user_heap;
pub mod vm_page; pub mod vm_page;
use alloc::ffi::CString; use crate::prelude::*;
use kxos_frame::{ use kxos_frame::vm::{Pod, VmIo, VmSpace};
debug,
vm::{Pod, Vaddr, VmIo, VmSpace},
};
use crate::process::Process; use crate::process::Process;
@ -29,6 +26,8 @@ pub fn load_elf_to_vm_space<'a>(
elf_load_info.debug_check_map_result(vm_space); elf_load_info.debug_check_map_result(vm_space);
debug!("map elf success"); debug!("map elf success");
elf_load_info.init_stack(vm_space); elf_load_info.init_stack(vm_space);
elf_load_info.write_elf_first_page(vm_space, elf_file_content);
Ok(elf_load_info) Ok(elf_load_info)
} }

View File

@ -1,9 +1,7 @@
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use kxos_frame::{ use crate::prelude::*;
debug, use kxos_frame::vm::{VmPerm, VmSpace};
vm::{Vaddr, VmPerm, VmSpace},
};
use super::vm_page::{VmPage, VmPageRange}; use super::vm_page::{VmPage, VmPageRange};
@ -28,7 +26,11 @@ impl UserHeap {
match new_heap_end { match new_heap_end {
None => return self.current_heap_end.load(Ordering::Relaxed), None => return self.current_heap_end.load(Ordering::Relaxed),
Some(new_heap_end) => { Some(new_heap_end) => {
let current_heap_end = self.current_heap_end.swap(new_heap_end, Ordering::Relaxed); let current_heap_end = self.current_heap_end.load(Ordering::Acquire);
if new_heap_end < current_heap_end {
return current_heap_end;
}
self.current_heap_end.store(new_heap_end, Ordering::Release);
let start_page = VmPage::containing_address(current_heap_end - 1).next_page(); let start_page = VmPage::containing_address(current_heap_end - 1).next_page();
let end_page = VmPage::containing_address(new_heap_end); let end_page = VmPage::containing_address(new_heap_end);
if end_page >= start_page { if end_page >= start_page {
@ -50,6 +52,12 @@ impl UserHeap {
const fn user_heap_perm() -> VmPerm { const fn user_heap_perm() -> VmPerm {
VmPerm::RWXU VmPerm::RWXU
} }
/// Set heap to the default status. i.e., point the heap end to heap base.
pub fn set_default(&self) {
self.current_heap_end
.store(self.heap_base, Ordering::Relaxed);
}
} }
impl Clone for UserHeap { impl Clone for UserHeap {

View File

@ -1,11 +1,7 @@
//! A Page in virtual address space //! A Page in virtual address space
use crate::prelude::*;
use core::ops::Range; use core::ops::Range;
use kxos_frame::vm::{VmAllocOptions, VmFrameVec, VmIo, VmMapOptions, VmPerm, VmSpace};
use alloc::vec;
use kxos_frame::{
config::PAGE_SIZE,
vm::{Vaddr, VmAllocOptions, VmFrameVec, VmIo, VmMapOptions, VmPerm, VmSpace},
};
use super::elf::ElfError; use super::elf::ElfError;

View File

@ -0,0 +1,28 @@
#![allow(unused)]
pub(crate) use alloc::boxed::Box;
pub(crate) use alloc::collections::BTreeMap;
pub(crate) use alloc::collections::VecDeque;
pub(crate) use alloc::ffi::CString;
pub(crate) use alloc::sync::Arc;
pub(crate) use alloc::sync::Weak;
#[allow(unused)]
pub(crate) use alloc::vec;
pub(crate) use alloc::vec::Vec;
pub(crate) use bitflags::bitflags;
pub(crate) use core::ffi::CStr;
pub(crate) use kxos_frame::config::PAGE_SIZE;
pub(crate) use kxos_frame::vm::Vaddr;
#[allow(unused)]
pub(crate) use kxos_frame::{debug, error, info, trace, warn};
pub(crate) use spin::Mutex;
#[macro_export]
macro_rules! current {
() => {
crate::process::Process::current()
};
}
pub(crate) use crate::current;
pub(crate) use lazy_static::lazy_static;

View File

@ -1,17 +1,16 @@
use alloc::{boxed::Box, collections::VecDeque, sync::Arc}; use crate::prelude::*;
use kxos_frame::task::{set_scheduler, Scheduler, Task}; use kxos_frame::task::{set_scheduler, Scheduler, Task};
use spin::mutex::SpinMutex;
pub const TASK_INIT_CAPABILITY: usize = 16; pub const TASK_INIT_CAPABILITY: usize = 16;
pub struct FifoScheduler { pub struct FifoScheduler {
tasks: SpinMutex<VecDeque<Arc<Task>>>, tasks: Mutex<VecDeque<Arc<Task>>>,
} }
impl FifoScheduler { impl FifoScheduler {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tasks: SpinMutex::new(VecDeque::with_capacity(TASK_INIT_CAPABILITY)), tasks: Mutex::new(VecDeque::with_capacity(TASK_INIT_CAPABILITY)),
} }
} }
} }

View File

@ -1,11 +1,8 @@
use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering}; use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
use alloc::collections::BTreeMap; use crate::prelude::*;
use alloc::ffi::CString;
use alloc::sync::{Arc, Weak};
use kxos_frame::sync::WaitQueue; use kxos_frame::sync::WaitQueue;
use kxos_frame::{debug, task::Task, user::UserSpace, vm::VmSpace}; use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace};
use spin::Mutex;
use crate::memory::mmap_area::MmapArea; use crate::memory::mmap_area::MmapArea;
use crate::memory::user_heap::UserHeap; use crate::memory::user_heap::UserHeap;
@ -18,6 +15,7 @@ use self::user_vm_data::UserVm;
pub mod fifo_scheduler; pub mod fifo_scheduler;
pub mod process_filter; pub mod process_filter;
pub mod status; pub mod status;
pub mod table;
pub mod task; pub mod task;
pub mod user_vm_data; pub mod user_vm_data;
pub mod wait; pub mod wait;
@ -119,14 +117,16 @@ impl Process {
fn create_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc<Self> { fn create_user_process(filename: CString, elf_file_content: &'static [u8]) -> Arc<Self> {
let pid = new_pid(); let pid = new_pid();
Arc::new_cyclic(|weak_process_ref| { let user_process = Arc::new_cyclic(|weak_process_ref| {
let weak_process = weak_process_ref.clone(); let weak_process = weak_process_ref.clone();
let cloned_filename = Some(filename.clone()); let cloned_filename = Some(filename.clone());
let task = create_user_task_from_elf(filename, elf_file_content, weak_process); let task = create_user_task_from_elf(filename, elf_file_content, weak_process);
let user_space = task.user_space().map(|user_space| user_space.clone()); let user_space = task.user_space().map(|user_space| user_space.clone());
let user_vm = UserVm::new(); let user_vm = UserVm::new();
Process::new(pid, task, cloned_filename, Some(user_vm), user_space) Process::new(pid, task, cloned_filename, Some(user_vm), user_space)
}) });
table::add_process(pid, user_process.clone());
user_process
} }
fn create_kernel_process<F>(task_fn: F) -> Arc<Self> fn create_kernel_process<F>(task_fn: F) -> Arc<Self>
@ -134,11 +134,13 @@ impl Process {
F: Fn() + Send + Sync + 'static, F: Fn() + Send + Sync + 'static,
{ {
let pid = new_pid(); let pid = new_pid();
Arc::new_cyclic(|weak_process_ref| { let kernel_process = Arc::new_cyclic(|weak_process_ref| {
let weak_process = weak_process_ref.clone(); let weak_process = weak_process_ref.clone();
let task = Task::new(task_fn, weak_process, None).expect("spawn kernel task failed"); let task = Task::new(task_fn, weak_process, None).expect("spawn kernel task failed");
Process::new(pid, task, None, None, None) Process::new(pid, task, None, None, None)
}) });
table::add_process(pid, kernel_process.clone());
kernel_process
} }
/// returns the pid of the process /// returns the pid of the process
@ -265,6 +267,7 @@ impl Process {
pub fn reap_zombie_child(&self, pid: Pid) -> i32 { pub fn reap_zombie_child(&self, pid: Pid) -> i32 {
let child_process = self.children.lock().remove(&pid).unwrap(); let child_process = self.children.lock().remove(&pid).unwrap();
assert!(child_process.status() == ProcessStatus::Zombie); assert!(child_process.status() == ProcessStatus::Zombie);
table::delete_process(child_process.pid());
child_process.exit_code() child_process.exit_code()
} }

View File

@ -0,0 +1,38 @@
//! A global table stores the pid to process mapping.
//! This table can be used to get process with pid.
//! TODO: progress group, thread all need similar mapping
use crate::prelude::*;
use super::{Pid, Process};
lazy_static! {
static ref PROCESS_TABLE: Mutex<BTreeMap<Pid, Arc<Process>>> = Mutex::new(BTreeMap::new());
}
/// add a process to global table
pub fn add_process(pid: Pid, process: Arc<Process>) {
PROCESS_TABLE.lock().insert(pid, process);
}
/// delete a process from global table
pub fn delete_process(pid: Pid) {
PROCESS_TABLE.lock().remove(&pid);
}
/// get a process with pid
pub fn pid_to_process(pid: Pid) -> Option<Arc<Process>> {
PROCESS_TABLE
.lock()
.get(&pid)
.map(|process| process.clone())
}
/// get all processes
pub fn get_all_processes() -> Vec<Arc<Process>> {
PROCESS_TABLE
.lock()
.iter()
.map(|(_, process)| process.clone())
.collect()
}

View File

@ -1,17 +1,14 @@
use core::sync::atomic::AtomicUsize; use core::sync::atomic::AtomicUsize;
use alloc::{
ffi::CString,
sync::{Arc, Weak},
};
use kxos_frame::{ use kxos_frame::{
cpu::CpuContext, cpu::CpuContext,
debug,
task::Task, task::Task,
user::{UserEvent, UserMode, UserSpace}, user::{UserEvent, UserMode, UserSpace},
vm::VmSpace, vm::VmSpace,
}; };
use crate::prelude::*;
use crate::{memory::load_elf_to_vm_space, syscall::syscall_handler}; use crate::{memory::load_elf_to_vm_space, syscall::syscall_handler};
use super::Process; use super::Process;
@ -49,12 +46,12 @@ pub fn create_new_task(userspace: Arc<UserSpace>, parent: Weak<Process>) -> Arc<
debug!("[new task] rax = 0x{:x}", user_space.cpu_ctx.gp_regs.rax); debug!("[new task] rax = 0x{:x}", user_space.cpu_ctx.gp_regs.rax);
loop { loop {
let user_event = user_mode.execute(); let user_event = user_mode.execute();
debug!("return from user mode");
let context = user_mode.context_mut(); let context = user_mode.context_mut();
if let HandlerResult::Exit = handle_user_event(user_event, context) { if let HandlerResult::Exit = handle_user_event(user_event, context) {
// FIXME: How to set task status? How to set exit code of process? // FIXME: How to set task status? How to set exit code of process?
break; break;
} }
// debug!("before return to user space: {:#x?}", context);
} }
let current_process = Process::current(); let current_process = Process::current();
current_process.exit(); current_process.exit();

View File

@ -57,4 +57,10 @@ impl UserVm {
pub fn mmap_area(&self) -> &MmapArea { pub fn mmap_area(&self) -> &MmapArea {
&self.mmap_area &self.mmap_area
} }
/// Set user vm to the init status
pub fn set_default(&self) {
self.user_heap.set_default();
self.mmap_area.set_default();
}
} }

View File

@ -1,4 +1,4 @@
use bitflags::bitflags; use crate::prelude::*;
use super::{process_filter::ProcessFilter, ExitCode, Pid, Process}; use super::{process_filter::ProcessFilter, ExitCode, Pid, Process};

View File

@ -0,0 +1,13 @@
use super::constants::*;
use super::SyscallResult;
use crate::{memory::read_bytes_from_user, prelude::*, syscall::SYS_ACCESS};
pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> SyscallResult {
debug!("[syscall][id={}][SYS_ACCESS]", SYS_ACCESS);
let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN];
read_bytes_from_user(filename_ptr, &mut filename_buffer);
let filename = CString::from(CStr::from_bytes_until_nul(&filename_buffer).unwrap());
debug!("filename: {:?}", filename);
warn!("access currenly does not check and just return success");
SyscallResult::Return(0)
}

View File

@ -1,8 +1,10 @@
use kxos_frame::{cpu::CpuContext, debug}; use kxos_frame::cpu::CpuContext;
use crate::prelude::*;
use crate::syscall::{SyscallResult, SYS_ARCH_PRCTL}; use crate::syscall::{SyscallResult, SYS_ARCH_PRCTL};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Debug)]
pub enum ArchPrctlCode { pub enum ArchPrctlCode {
ARCH_SET_GS = 0x1001, ARCH_SET_GS = 0x1001,
ARCH_SET_FS = 0x1002, ARCH_SET_FS = 0x1002,
@ -19,7 +21,10 @@ impl TryFrom<u64> for ArchPrctlCode {
0x1002 => Ok(ArchPrctlCode::ARCH_SET_FS), 0x1002 => Ok(ArchPrctlCode::ARCH_SET_FS),
0x1003 => Ok(ArchPrctlCode::ARCH_GET_FS), 0x1003 => Ok(ArchPrctlCode::ARCH_GET_FS),
0x1004 => Ok(ArchPrctlCode::ARCH_GET_GS), 0x1004 => Ok(ArchPrctlCode::ARCH_GET_GS),
_ => Err("Unknown code for arch_prctl"), _ => {
debug!("value = 0x{:x}", value);
Err("Unknown code for arch_prctl")
}
} }
} }
} }
@ -27,6 +32,7 @@ impl TryFrom<u64> for ArchPrctlCode {
pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> SyscallResult { pub fn sys_arch_prctl(code: u64, addr: u64, context: &mut CpuContext) -> SyscallResult {
debug!("[syscall][id={}][SYS_ARCH_PRCTL]", SYS_ARCH_PRCTL); debug!("[syscall][id={}][SYS_ARCH_PRCTL]", SYS_ARCH_PRCTL);
let arch_prctl_code = ArchPrctlCode::try_from(code); let arch_prctl_code = ArchPrctlCode::try_from(code);
debug!("arch_prctl_code: {:?}", arch_prctl_code);
match arch_prctl_code { match arch_prctl_code {
Err(_) => SyscallResult::Return(-1), Err(_) => SyscallResult::Return(-1),
Ok(code) => { Ok(code) => {

View File

@ -1,4 +1,4 @@
use kxos_frame::debug; use crate::prelude::*;
use crate::{ use crate::{
process::Process, process::Process,

View File

@ -0,0 +1 @@
pub const MAX_FILENAME_LEN: usize = 128;

View File

@ -0,0 +1,53 @@
use kxos_frame::cpu::CpuContext;
use super::constants::*;
use super::SyscallResult;
use crate::{
memory::{load_elf_to_vm_space, read_bytes_from_user},
prelude::*,
process::Process,
syscall::SYS_EXECVE,
};
pub fn sys_execve(
filename_ptr: Vaddr,
argv_ptr_ptr: Vaddr,
envp_ptr_ptr: Vaddr,
context: &mut CpuContext,
) -> SyscallResult {
debug!("[syscall][id={}][SYS_EXECVE]", SYS_EXECVE);
let mut filename_buffer = vec![0u8; MAX_FILENAME_LEN];
read_bytes_from_user(filename_ptr, &mut filename_buffer);
let filename = CString::from(CStr::from_bytes_until_nul(&filename_buffer).unwrap());
debug!("filename: {:?}", filename);
if filename != CString::new("./hello").unwrap() {
panic!("Unknown filename.");
}
let elf_file_content = crate::user_apps::read_execve_hello_content();
let current = Process::current();
// Set process vm space to default
let vm_space = current
.vm_space()
.expect("[Internal Error] User process should have vm space");
vm_space.clear();
let user_vm = current
.user_vm()
.expect("[Internal Error] User process should have user vm");
user_vm.set_default();
// load elf content to new vm space
let elf_load_info =
load_elf_to_vm_space(filename, elf_file_content, &vm_space).expect("load elf failed");
debug!("load elf in execve succeeds");
// set cpu context to default
let defalut_content = CpuContext::default();
context.gp_regs = defalut_content.gp_regs;
context.fs_base = defalut_content.fs_base;
// set new entry point
context.gp_regs.rip = elf_load_info.entry_point();
debug!("entry_point: 0x{:x}", elf_load_info.entry_point());
// set new user stack top
context.gp_regs.rsp = elf_load_info.user_stack_top();
debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top());
SyscallResult::Return(0)
}

View File

@ -1,4 +1,4 @@
use kxos_frame::debug; use crate::prelude::*;
use crate::{process::Process, syscall::SYS_EXIT}; use crate::{process::Process, syscall::SYS_EXIT};

View File

@ -1,4 +1,4 @@
use kxos_frame::debug; use crate::prelude::*;
use crate::{ use crate::{
process::Process, process::Process,

View File

@ -1,13 +1,12 @@
use alloc::{sync::Arc, vec}; use crate::prelude::*;
use kxos_frame::{ use kxos_frame::{
cpu::CpuContext, cpu::CpuContext,
debug,
user::UserSpace, user::UserSpace,
vm::{VmIo, VmSpace}, vm::{VmIo, VmSpace},
}; };
use crate::{ use crate::{
process::{new_pid, task::create_new_task, Process}, process::{new_pid, table, task::create_new_task, Process},
syscall::SYS_FORK, syscall::SYS_FORK,
}; };
@ -67,6 +66,7 @@ fn fork(parent_context: CpuContext) -> Arc<Process> {
) )
}); });
Process::current().add_child(child.clone()); Process::current().add_child(child.clone());
table::add_process(child_pid, child.clone());
let pid = current.pid(); let pid = current.pid();
debug!("*********schedule child process, pid = {}**********", pid); debug!("*********schedule child process, pid = {}**********", pid);
child.send_to_scheduler(); child.send_to_scheduler();

View File

@ -1,11 +1,26 @@
use kxos_frame::{debug, warn}; use kxos_frame::vm::VmIo;
use crate::fs::stat::Stat;
use crate::prelude::*;
use crate::syscall::{SyscallResult, SYS_FSTAT}; use crate::syscall::{SyscallResult, SYS_FSTAT};
pub fn sys_fstat(fd: u64, stat_buf_addr: u64) -> SyscallResult { pub fn sys_fstat(fd: u64, stat_buf_addr: Vaddr) -> SyscallResult {
debug!("[syscall][id={}][SYS_FSTAT]", SYS_FSTAT); debug!("[syscall][id={}][SYS_FSTAT]", SYS_FSTAT);
debug!("fd = {}", fd); debug!("fd = {}", fd);
debug!("stat_buf_addr = 0x{:x}", stat_buf_addr); debug!("stat_buf_addr = 0x{:x}", stat_buf_addr);
let current = current!();
let vm_space = current
.vm_space()
.expect("[Internel Error] User process should have vm space");
if fd == 1 {
let stat = Stat::stdout_stat();
vm_space
.write_val(stat_buf_addr, &stat)
.expect("Write value failed");
return SyscallResult::Return(0);
}
warn!("TODO: fstat only returns fake result now."); warn!("TODO: fstat only returns fake result now.");
SyscallResult::Return(0) SyscallResult::Return(0)
} }

View File

@ -1,11 +1,8 @@
use crate::{memory::read_val_from_user, syscall::SYS_FUTEX}; use crate::{memory::read_val_from_user, syscall::SYS_FUTEX};
use super::SyscallResult; use super::SyscallResult;
use alloc::{sync::Arc, vec::Vec}; use crate::prelude::*;
use bitflags::bitflags; use kxos_frame::{cpu::num_cpus, sync::WaitQueue};
use kxos_frame::{cpu::num_cpus, debug, sync::WaitQueue, vm::Vaddr, warn};
use lazy_static::lazy_static;
use spin::Mutex;
type FutexBitSet = u32; type FutexBitSet = u32;
type FutexBucketRef = Arc<Mutex<FutexBucket>>; type FutexBucketRef = Arc<Mutex<FutexBucket>>;

View File

@ -1,4 +1,4 @@
use kxos_frame::{debug, info}; use crate::prelude::*;
use crate::{process::Process, syscall::SYS_GETPID}; use crate::{process::Process, syscall::SYS_GETPID};

View File

@ -1,4 +1,4 @@
use kxos_frame::debug; use crate::prelude::*;
use crate::{process::Process, syscall::SYS_GETTID}; use crate::{process::Process, syscall::SYS_GETTID};

View File

@ -1,10 +1,7 @@
//! This mod defines mmap flags and the handler to syscall mmap //! This mod defines mmap flags and the handler to syscall mmap
use bitflags::bitflags; use crate::prelude::*;
use kxos_frame::{ use kxos_frame::vm::VmPerm;
debug,
vm::{Vaddr, VmPerm},
};
use crate::{process::Process, syscall::SYS_MMAP}; use crate::{process::Process, syscall::SYS_MMAP};

View File

@ -1,13 +1,15 @@
//! Read the Cpu context content then dispatch syscall to corrsponding handler //! Read the Cpu context content then dispatch syscall to corrsponding handler
//! The each sub module contains functions that handle real syscall logic. //! The each sub module contains functions that handle real syscall logic.
use crate::prelude::*;
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use kxos_frame::cpu::CpuContext; use kxos_frame::cpu::CpuContext;
use kxos_frame::{debug, warn};
use crate::process::task::HandlerResult; use crate::process::task::HandlerResult;
use crate::syscall::access::sys_access;
use crate::syscall::arch_prctl::sys_arch_prctl; use crate::syscall::arch_prctl::sys_arch_prctl;
use crate::syscall::brk::sys_brk; use crate::syscall::brk::sys_brk;
use crate::syscall::execve::sys_execve;
use crate::syscall::exit::sys_exit; use crate::syscall::exit::sys_exit;
use crate::syscall::exit_group::sys_exit_group; use crate::syscall::exit_group::sys_exit_group;
use crate::syscall::fork::sys_fork; use crate::syscall::fork::sys_fork;
@ -25,8 +27,11 @@ use crate::syscall::waitid::sys_waitid;
use crate::syscall::write::sys_write; use crate::syscall::write::sys_write;
use crate::syscall::writev::sys_writev; use crate::syscall::writev::sys_writev;
mod access;
mod arch_prctl; mod arch_prctl;
mod brk; mod brk;
pub mod constants;
mod execve;
mod exit; mod exit;
mod exit_group; mod exit_group;
mod fork; mod fork;
@ -53,9 +58,11 @@ const SYS_BRK: u64 = 12;
const SYS_RT_SIGACTION: u64 = 13; const SYS_RT_SIGACTION: u64 = 13;
const SYS_RT_SIGPROCMASK: u64 = 14; const SYS_RT_SIGPROCMASK: u64 = 14;
const SYS_WRITEV: u64 = 20; const SYS_WRITEV: u64 = 20;
const SYS_ACCESS: u64 = 21;
const SYS_SCHED_YIELD: u64 = 24; const SYS_SCHED_YIELD: u64 = 24;
const SYS_GETPID: u64 = 39; const SYS_GETPID: u64 = 39;
const SYS_FORK: u64 = 57; const SYS_FORK: u64 = 57;
const SYS_EXECVE: u64 = 59;
const SYS_EXIT: u64 = 60; const SYS_EXIT: u64 = 60;
const SYS_WAIT4: u64 = 61; const SYS_WAIT4: u64 = 61;
const SYS_UNAME: u64 = 63; const SYS_UNAME: u64 = 63;
@ -79,6 +86,7 @@ pub struct SyscallArgument {
pub enum SyscallResult { pub enum SyscallResult {
Exit(i32), Exit(i32),
Return(i32), Return(i32),
ReturnNothing, // execve return nothing
} }
impl SyscallArgument { impl SyscallArgument {
@ -110,6 +118,7 @@ pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult {
HandlerResult::Continue HandlerResult::Continue
} }
SyscallResult::Exit(exit_code) => HandlerResult::Exit, SyscallResult::Exit(exit_code) => HandlerResult::Exit,
SyscallResult::ReturnNothing => HandlerResult::Continue,
} }
} }
@ -120,15 +129,17 @@ pub fn syscall_dispatch(
) -> SyscallResult { ) -> SyscallResult {
match syscall_number { match syscall_number {
SYS_WRITE => sys_write(args[0], args[1], args[2]), SYS_WRITE => sys_write(args[0], args[1], args[2]),
SYS_FSTAT => sys_fstat(args[0], args[1]), SYS_FSTAT => sys_fstat(args[0], args[1] as _),
SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]), SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]),
SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]), SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]),
SYS_BRK => sys_brk(args[0]), SYS_BRK => sys_brk(args[0]),
SYS_RT_SIGACTION => sys_rt_sigaction(), SYS_RT_SIGACTION => sys_rt_sigaction(),
SYS_RT_SIGPROCMASK => sys_rt_sigprocmask(), SYS_RT_SIGPROCMASK => sys_rt_sigprocmask(),
SYS_WRITEV => sys_writev(args[0], args[1], args[2]), SYS_WRITEV => sys_writev(args[0], args[1], args[2]),
SYS_ACCESS => sys_access(args[0] as _, args[1]),
SYS_GETPID => sys_getpid(), SYS_GETPID => sys_getpid(),
SYS_FORK => sys_fork(context.to_owned()), SYS_FORK => sys_fork(context.to_owned()),
SYS_EXECVE => sys_execve(args[0] as _, args[1] as _, args[2] as _, context),
SYS_EXIT => sys_exit(args[0] as _), SYS_EXIT => sys_exit(args[0] as _),
SYS_WAIT4 => sys_wait4(args[0], args[1], args[2]), SYS_WAIT4 => sys_wait4(args[0], args[1], args[2]),
SYS_UNAME => sys_uname(args[0]), SYS_UNAME => sys_uname(args[0]),

View File

@ -1,8 +1,6 @@
use kxos_frame::{ use kxos_frame::vm::VmPerm;
debug,
vm::{Vaddr, VmPerm}, use crate::prelude::*;
warn,
};
use crate::syscall::SYS_MPROTECT; use crate::syscall::SYS_MPROTECT;

View File

@ -1,7 +1,4 @@
use core::ffi::CStr; use crate::prelude::*;
use alloc::ffi::CString;
use kxos_frame::{debug, vm::Vaddr};
use crate::{ use crate::{
memory::{read_bytes_from_user, write_bytes_to_user}, memory::{read_bytes_from_user, write_bytes_to_user},

View File

@ -1,4 +1,4 @@
use kxos_frame::debug; use crate::prelude::*;
use crate::{process::Process, syscall::SYS_SCHED_YIELD}; use crate::{process::Process, syscall::SYS_SCHED_YIELD};

View File

@ -1,4 +1,4 @@
use kxos_frame::{debug, warn}; use crate::prelude::*;
use crate::syscall::{SyscallResult, SYS_TGKILL}; use crate::syscall::{SyscallResult, SYS_TGKILL};

View File

@ -1,8 +1,4 @@
use core::ffi::CStr; use crate::prelude::*;
use alloc::ffi::CString;
use kxos_frame::{debug, vm::Vaddr};
use lazy_static::lazy_static;
use crate::{ use crate::{
memory::write_val_to_user, memory::write_val_to_user,

View File

@ -5,8 +5,8 @@ use crate::{
}; };
use super::SyscallResult; use super::SyscallResult;
use crate::prelude::*;
use crate::process::wait::WaitOptions; use crate::process::wait::WaitOptions;
use kxos_frame::debug;
pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> SyscallResult { pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> SyscallResult {
debug!("[syscall][id={}][SYS_WAIT4]", SYS_WAIT4); debug!("[syscall][id={}][SYS_WAIT4]", SYS_WAIT4);

View File

@ -1,5 +1,4 @@
use alloc::vec; use crate::prelude::*;
use kxos_frame::{debug, info};
use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE}; use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE};

View File

@ -1,5 +1,4 @@
use alloc::vec; use crate::prelude::*;
use kxos_frame::{debug, info, vm::Vaddr};
use crate::{ use crate::{
memory::{read_bytes_from_user, read_val_from_user}, memory::{read_bytes_from_user, read_val_from_user},

View File

@ -0,0 +1,68 @@
use crate::prelude::*;
pub struct UserApp {
app_name: CString,
app_content: &'static [u8],
}
impl UserApp {
pub fn new(app_name: &str, app_content: &'static [u8]) -> Self {
let app_name = CString::new(app_name).unwrap();
UserApp {
app_name,
app_content,
}
}
pub fn app_name(&self) -> CString {
self.app_name.clone()
}
pub fn app_content(&self) -> &'static [u8] {
self.app_content
}
}
pub fn get_all_apps() -> Vec<UserApp> {
let mut res = Vec::new();
// Most simple hello world, written in assembly
let app1 = UserApp::new("hello_world", read_hello_world_content());
res.push(app1);
// Hello world, written in C language.
// Since glibc requires the app name starts with "/", and we don't have filesystem now.
// So we manually add a leading "/" for app written in C language.
let app2 = UserApp::new("/hello_c", read_hello_c_content());
res.push(app2);
// Fork process, written in assembly
let app3 = UserApp::new("fork", read_fork_content());
res.push(app3);
// Execve, written in C language.
let app4 = UserApp::new("/execve", read_execve_content());
res.push(app4);
res
}
fn read_hello_world_content() -> &'static [u8] {
include_bytes!("../../kxos-user/hello_world/hello_world")
}
fn read_hello_c_content() -> &'static [u8] {
include_bytes!("../../kxos-user/hello_c/hello")
}
fn read_fork_content() -> &'static [u8] {
include_bytes!("../../kxos-user/fork/fork")
}
fn read_execve_content() -> &'static [u8] {
include_bytes!("../../kxos-user/execve/execve")
}
pub fn read_execve_hello_content() -> &'static [u8] {
include_bytes!("../../kxos-user/execve/hello")
}

View File

@ -9,7 +9,7 @@ pub mod if_;
pub mod same; pub mod same;
pub mod set; pub mod set;
pub use crate::bool::{And, AndOp, False, Not, NotOp, Or, OrOp, True, IsFalse, IsTrue}; pub use crate::bool::{And, AndOp, False, IsFalse, IsTrue, Not, NotOp, Or, OrOp, True};
pub use crate::same::{SameAs, SameAsOp}; pub use crate::same::{SameAs, SameAsOp};
pub use crate::set::{Cons, Nil, Set, SetContain, SetContainOp, SetInclude, SetIncludeOp}; pub use crate::set::{Cons, Nil, Set, SetContain, SetContainOp, SetInclude, SetIncludeOp};
pub use assert::AssertTypeSame; pub use assert::AssertTypeSame;

View File

@ -3,10 +3,8 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::{ use crate::{
False, OrOp, True,
SameAs, SameAsOp,
And, AndOp,
if_::{If, IfOp}, if_::{If, IfOp},
And, AndOp, False, OrOp, SameAs, SameAsOp, True,
}; };
use std::ops::BitOr as Or; use std::ops::BitOr as Or;

View File

@ -0,0 +1,9 @@
.PHONY: build clean run
build: hello.c execve.c
@gcc -static hello.c -o hello
@gcc -static execve.c -o execve
clean:
@rm hello
@rm execve
run: build
@./execve

3
src/kxos-user/execve/execve Executable file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f98928f25e8223fd76d5d19db68e83913b48ea8b3cf6ae8d3120971e7271c93b
size 871952

View File

@ -0,0 +1,13 @@
#include <stdio.h>
#include <unistd.h>
int main() {
char* argv[] = { NULL };
char* envp[] = { NULL };
printf("Execve a new file ./hello:\n");
// flust the stdout content to ensure the content print to console
fflush(stdout);
execve("./hello", argv, envp);
printf("Should not print\n");
return 0;
}

3
src/kxos-user/execve/hello Executable file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7b1e30d140892a01630093a376819dcfb400754c9dbf71f845df945fc14fc861
size 871896

View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main() {
printf("Hello world from hello.c(execved in execve.c)!\n");
return 0;
}