mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-27 19:33:23 +00:00
add syscall execve
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -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
|
||||||
|
@ -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]>,
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
1
src/kxos-std/src/fs/mod.rs
Normal file
1
src/kxos-std/src/fs/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod stat;
|
60
src/kxos-std/src/fs/stat.rs
Normal file
60
src/kxos-std/src/fs/stat.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use alloc::collections::BTreeMap;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// This implementation is from occlum.
|
/// This implementation is from occlum.
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
28
src/kxos-std/src/prelude.rs
Normal file
28
src/kxos-std/src/prelude.rs
Normal 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;
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
38
src/kxos-std/src/process/table.rs
Normal file
38
src/kxos-std/src/process/table.rs
Normal 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()
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
13
src/kxos-std/src/syscall/access.rs
Normal file
13
src/kxos-std/src/syscall/access.rs
Normal 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)
|
||||||
|
}
|
@ -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) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use kxos_frame::debug;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
process::Process,
|
process::Process,
|
||||||
|
1
src/kxos-std/src/syscall/constants.rs
Normal file
1
src/kxos-std/src/syscall/constants.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub const MAX_FILENAME_LEN: usize = 128;
|
53
src/kxos-std/src/syscall/execve.rs
Normal file
53
src/kxos-std/src/syscall/execve.rs
Normal 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)
|
||||||
|
}
|
@ -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};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use kxos_frame::debug;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
process::Process,
|
process::Process,
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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>>;
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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]),
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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},
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use kxos_frame::{debug, warn};
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::syscall::{SyscallResult, SYS_TGKILL};
|
use crate::syscall::{SyscallResult, SYS_TGKILL};
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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},
|
||||||
|
68
src/kxos-std/src/user_apps.rs
Normal file
68
src/kxos-std/src/user_apps.rs
Normal 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")
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
9
src/kxos-user/execve/Makefile
Normal file
9
src/kxos-user/execve/Makefile
Normal 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
3
src/kxos-user/execve/execve
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:f98928f25e8223fd76d5d19db68e83913b48ea8b3cf6ae8d3120971e7271c93b
|
||||||
|
size 871952
|
13
src/kxos-user/execve/execve.c
Normal file
13
src/kxos-user/execve/execve.c
Normal 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
3
src/kxos-user/execve/hello
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:7b1e30d140892a01630093a376819dcfb400754c9dbf71f845df945fc14fc861
|
||||||
|
size 871896
|
6
src/kxos-user/execve/hello.c
Normal file
6
src/kxos-user/execve/hello.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("Hello world from hello.c(execved in execve.c)!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user