diff --git a/src/kxos-frame/src/cpu.rs b/src/kxos-frame/src/cpu.rs index 7b1567c3..2cf5076b 100644 --- a/src/kxos-frame/src/cpu.rs +++ b/src/kxos-frame/src/cpu.rs @@ -73,7 +73,7 @@ impl From for CpuContext { rax: syscall.caller.rax as u64, rcx: syscall.caller.rcx as u64, rsp: syscall.callee.rsp as u64, - rip: 0, + rip: syscall.caller.rcx as u64, rflag: 0, }, fs_base: 0, diff --git a/src/kxos-frame/src/lib.rs b/src/kxos-frame/src/lib.rs index 1e151488..ec132f1f 100644 --- a/src/kxos-frame/src/lib.rs +++ b/src/kxos-frame/src/lib.rs @@ -83,6 +83,7 @@ pub fn init(boot_info: &'static mut BootInfo) { } fn general_handler(trap_frame: TrapFrame) { println!("{:?}", trap_frame); + println!("rip = 0x{:x}", trap_frame.rip); panic!("couldn't handler trap right now"); } diff --git a/src/kxos-frame/src/mm/memory_set.rs b/src/kxos-frame/src/mm/memory_set.rs index 4dcdd92e..b49fb87c 100644 --- a/src/kxos-frame/src/mm/memory_set.rs +++ b/src/kxos-frame/src/mm/memory_set.rs @@ -113,7 +113,7 @@ impl MapArea { let offset = current_start_address - va.0; let copy_len = (va.0 + PAGE_SIZE - current_start_address).min(remain); let src = &data[processed..processed + copy_len]; - let dst = &mut pa.start_pa().kvaddr().get_bytes_array()[offset..copy_len]; + let dst = &mut pa.start_pa().kvaddr().get_bytes_array()[offset..(offset + copy_len)]; dst.copy_from_slice(src); processed += copy_len; remain -= copy_len; @@ -134,7 +134,7 @@ impl MapArea { let offset = start - va.0; let copy_len = (va.0 + PAGE_SIZE - start).min(remain); let src = &mut data[processed..processed + copy_len]; - let dst = &pa.start_pa().kvaddr().get_bytes_array()[offset..copy_len]; + let dst = &pa.start_pa().kvaddr().get_bytes_array()[offset..(offset + copy_len)]; src.copy_from_slice(dst); processed += copy_len; remain -= copy_len; diff --git a/src/kxos-frame/src/task/task.rs b/src/kxos-frame/src/task/task.rs index 3850aee5..9c2523aa 100644 --- a/src/kxos-frame/src/task/task.rs +++ b/src/kxos-frame/src/task/task.rs @@ -12,7 +12,6 @@ use crate::vm::{VmAllocOptions, VmFrameVec}; use crate::{prelude::*, UPSafeCell}; use super::processor::{current_task, schedule}; -use super::scheduler::add_task; core::arch::global_asm!(include_str!("switch.S")); #[derive(Debug, Default, Clone, Copy)] @@ -182,6 +181,55 @@ impl Task { Ok(arc_self) } + + /// create a new task data structure without schedule it + pub fn new( + task_fn: F, + task_data: T, + user_space: Option>, + ) -> Result> + where + F: Fn() + Send + Sync + 'static, + T: Any + Send + Sync, + { + /// all task will entering this function + /// this function is mean to executing the task_fn in Task + fn kernel_task_entry() { + let current_task = current_task() + .expect("no current task, it should have current task in kernel task entry"); + current_task.func.call(()); + current_task.exit(); + } + let result = Self { + func: Box::new(task_fn), + data: Box::new(task_data), + user_space, + task_inner: unsafe { + UPSafeCell::new(TaskInner { + task_status: TaskStatus::Runnable, + ctx: TaskContext::default(), + is_from_trap: false, + }) + }, + exit_code: 0, + kstack: KernelStack::new(), + }; + + result.task_inner.exclusive_access().task_status = TaskStatus::Runnable; + result.task_inner.exclusive_access().ctx.rip = kernel_task_entry as usize; + result.task_inner.exclusive_access().ctx.regs.rsp = + result.kstack.frame.end_pa().unwrap().kvaddr().0 as usize + - size_of::() + - size_of::(); + + Ok(Arc::new(result)) + } + + /// send the task to schedule + pub fn send_to_scheduler(self: &Arc) { + switch_to_task(self.clone()); + } + pub(crate) fn syscall_frame(&self) -> &mut SyscallFrame { unsafe { &mut *(self @@ -214,7 +262,7 @@ impl Task { } /// Returns the task data. - pub fn data(&self) -> &dyn Any { + pub fn data(&self) -> &Box { &self.data } diff --git a/src/kxos-frame/src/user.rs b/src/kxos-frame/src/user.rs index b431143f..8a5e40d4 100644 --- a/src/kxos-frame/src/user.rs +++ b/src/kxos-frame/src/user.rs @@ -116,6 +116,7 @@ impl<'a> UserMode<'a> { if !self.executed { self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip as usize; self.current.syscall_frame().callee.rsp = self.user_space.cpu_ctx.gp_regs.rsp as usize; + self.current.syscall_frame().caller.rax = self.user_space.cpu_ctx.gp_regs.rax as usize; self.executed = true; } else { if self.current.inner_exclusive_access().is_from_trap { @@ -141,8 +142,8 @@ impl<'a> UserMode<'a> { UserEvent::Exception } else { self.context = CpuContext::from(*self.current.syscall_frame()); - println!("[kernel] syscall id:{}", self.context.gp_regs.rax); - println!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); + debug!("[kernel] syscall id:{}", self.context.gp_regs.rax); + debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp); UserEvent::Syscall } } diff --git a/src/kxos-frame/src/vm/space.rs b/src/kxos-frame/src/vm/space.rs index d0e4d6ef..7d2a4434 100644 --- a/src/kxos-frame/src/vm/space.rs +++ b/src/kxos-frame/src/vm/space.rs @@ -98,6 +98,15 @@ impl Default for VmSpace { } } +impl Clone for VmSpace { + fn clone(&self) -> Self { + let memory_set = self.memory_set.exclusive_access().clone(); + VmSpace { + memory_set: unsafe { UPSafeCell::new(memory_set) }, + } + } +} + impl VmIo for VmSpace { fn read_bytes(&self, vaddr: usize, buf: &mut [u8]) -> Result<()> { self.memory_set.exclusive_access().read_bytes(vaddr, buf) diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index 532ada79..55479ffa 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -6,9 +6,11 @@ #![feature(const_btree_new)] #![feature(cstr_from_bytes_until_nul)] -use kxos_frame::{info, println, task::Task}; +use kxos_frame::{info, println}; use process::Process; +use crate::process::current_pid; + extern crate alloc; mod memory; @@ -20,28 +22,44 @@ pub fn init() { process::fifo_scheduler::init(); } -pub fn init_task() { - println!("[kernel] Hello world from init task!"); +pub fn init_process() { + println!("[kernel] Spawn init process!"); - let process = Process::spawn_kernel_task(|| { + let process = Process::spawn_kernel_process(|| { println!("[kernel] Hello world from kernel!"); + let pid = current_pid(); + info!("current pid = {}", pid); }); - info!("spawn kernel process, pid = {}", process.pid()); + info!( + "[kxos-std/lib.rs] spawn kernel process, pid = {}", + process.pid() + ); - let elf_file_content = read_elf_content(); - let process = Process::spawn_from_elf(elf_file_content); - info!("spwan user process, pid = {}", process.pid()); + let hello_world_content = read_hello_world_content(); + let process = Process::spawn_user_process(hello_world_content); + info!( + "[kxos-std/lib.rs] spwan hello world process, pid = {}", + process.pid() + ); + + let fork_content = read_fork_content(); + let process = Process::spawn_user_process(fork_content); + info!("spawn fork process, pid = {}", process.pid()); loop {} } /// first process never return pub fn run_first_process() -> ! { - let elf_file_content = read_elf_content(); - Task::spawn(init_task, None::, None).expect("Spawn first task failed"); + let elf_file_content = read_hello_world_content(); + Process::spawn_kernel_process(init_process); unreachable!() } -fn read_elf_content() -> &'static [u8] { +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") +} diff --git a/src/kxos-std/src/memory/elf.rs b/src/kxos-std/src/memory/elf.rs index 8e215826..89bc2cd0 100644 --- a/src/kxos-std/src/memory/elf.rs +++ b/src/kxos-std/src/memory/elf.rs @@ -4,6 +4,7 @@ use alloc::vec; use alloc::vec::Vec; use kxos_frame::{ config::PAGE_SIZE, + debug, vm::{Vaddr, VmAllocOptions, VmFrameVec, VmIo, VmMapOptions, VmPerm, VmSpace}, Error, }; @@ -161,6 +162,10 @@ impl<'a> ElfLoadInfo<'a> { pub fn copy_and_map(&self, vm_space: &VmSpace) -> Result<(), ElfError> { for segment in self.segments.iter() { + debug!( + "map segment: 0x{:x}-0x{:x}", + segment.range.start, segment.range.end + ); segment.copy_and_map(vm_space)?; } Ok(()) diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index f5fc912a..453ec30b 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -1,59 +1,264 @@ -use core::sync::atomic::{AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering}; -use alloc::sync::Arc; +use alloc::vec; +use alloc::{ + sync::{Arc, Weak}, + vec::Vec, +}; +use kxos_frame::cpu::CpuContext; // use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace}; -use kxos_frame::task::Task; +use kxos_frame::{ + debug, + task::Task, + user::UserSpace, + vm::{VmIo, VmSpace}, +}; +use spin::Mutex; -use self::task::spawn_user_task_from_elf; +use crate::process::task::create_forked_task; + +use self::status::ProcessStatus; +use self::task::create_user_task_from_elf; pub mod fifo_scheduler; +pub mod status; pub mod task; -// static PROCESSES: SpinLock>> = SpinLock::new(BTreeMap::new()); static PID_ALLOCATOR: AtomicUsize = AtomicUsize::new(0); +const CHILDREN_CAPACITY: usize = 16; + /// Process stands for a set of tasks that shares the same userspace. /// Currently, we only support one task inside a process. pub struct Process { + // Immutable Part pid: usize, task: Arc, - exit_code: i32, - // user_space: Option>, - // TODO: childs, parent, files, + user_space: Option>, + + // Mutable Part + /// The exit code + exit_code: AtomicI32, + /// Process status + status: Mutex, + /// Parent process + parent: Mutex>>, + /// Children processes + children: Mutex>>, } impl Process { - pub fn spawn_from_elf(elf_file_content: &[u8]) -> Self { - let pid = new_pid(); - let task = spawn_user_task_from_elf(elf_file_content); - let exit_code = 0; + fn new(pid: usize, task: Arc, user_space: Option>) -> Self { + let parent = if pid == 0 { + debug!("Init process does not has parent"); + None + } else { + debug!("All process except init should have parent"); + let current_process = current_process(); + Some(Arc::downgrade(¤t_process)) + }; + let children = Vec::with_capacity(CHILDREN_CAPACITY); Self { pid, task, - exit_code, + user_space, + exit_code: AtomicI32::new(0), + status: Mutex::new(ProcessStatus::Runnable), + parent: Mutex::new(parent), + children: Mutex::new(children), } } - pub fn spawn_kernel_task(task_fn: F) -> Self + /// init a user process and send the process to scheduler + pub fn spawn_user_process(elf_file_content: &'static [u8]) -> Arc { + let process = Process::create_user_process(elf_file_content); + process.send_to_scheduler(); + process + } + + /// init a kernel process and send the process to scheduler + pub fn spawn_kernel_process(task_fn: F) -> Arc + where + F: Fn() + Send + Sync + 'static, + { + let process = Process::create_kernel_process(task_fn); + process.send_to_scheduler(); + process + } + + fn create_user_process(elf_file_content: &'static [u8]) -> Arc { + let pid = new_pid(); + + Arc::new_cyclic(|weak_process_ref| { + let weak_process = weak_process_ref.clone(); + let task = create_user_task_from_elf(elf_file_content, weak_process); + let user_space = task.user_space().map(|user_space| user_space.clone()); + + Process::new(pid, task, user_space) + }) + } + + fn create_kernel_process(task_fn: F) -> Arc where F: Fn() + Send + Sync + 'static, { let pid = new_pid(); - let task = Task::spawn(task_fn, pid, None).expect("spawn kernel task failed"); - let exit_code = 0; - Self { - pid, - task, - exit_code, - } + Arc::new_cyclic(|weak_process_ref| { + let weak_process = weak_process_ref.clone(); + let task = Task::new(task_fn, weak_process, None).expect("spawn kernel task failed"); + Process::new(pid, task, None) + }) } pub fn pid(&self) -> usize { self.pid } + + fn add_child(&self, child: Arc) { + // debug!("==============Add child: {}", child.pid()); + self.children.lock().push(child); + } + + fn set_parent(&self, parent: Weak) { + let _ = self.parent.lock().insert(parent); + } + + pub fn set_exit_code(&self, exit_code: i32) { + self.exit_code.store(exit_code, Ordering::Relaxed); + } + + /// Exit current process + /// Set the status of current process as Zombie + /// Move all children to init process + pub fn exit(&self) { + self.status.lock().set_zombie(); + // move children to the init process + let current_process = current_process(); + if !current_process.is_init_process() { + let init_process = get_init_process(); + for child in self.children.lock().drain(..) { + child.set_parent(Arc::downgrade(&init_process)); + init_process.add_child(child); + } + } + } + + fn is_init_process(&self) -> bool { + self.pid == 0 + } + + /// start to run current process + fn send_to_scheduler(self: &Arc) { + self.task.send_to_scheduler(); + } + + fn user_space(&self) -> Option<&Arc> { + self.user_space.as_ref() + } + + pub fn has_child(&self) -> bool { + self.children.lock().len() != 0 + } + + pub fn get_child_process(&self) -> Arc { + let children_lock = self.children.lock(); + let child_len = children_lock.len(); + assert_eq!(1, child_len, "Process can only have one child now"); + children_lock + .iter() + .nth(0) + .expect("[Internal Error]") + .clone() + } + + /// WorkAround: This function only create a new process, but did not schedule the process to run + pub fn fork(parent_context: CpuContext) -> Arc { + let child_pid = new_pid(); + let current = current_process(); + let parent_user_space = match current.user_space() { + None => None, + Some(user_space) => Some(user_space.clone()), + } + .expect("User task should always have user space"); + + // child process vm space + // FIXME: COPY ON WRITE can be used here + let parent_vm_space = parent_user_space.vm_space(); + let child_vm_space = parent_user_space.vm_space().clone(); + check_fork_vm_space(parent_vm_space, &child_vm_space); + + // child process cpu context + let mut child_cpu_context = parent_context.clone(); + debug!("parent cpu context: {:?}", child_cpu_context.gp_regs); + child_cpu_context.gp_regs.rax = 0; // Set return value of child process + + let child_user_space = Arc::new(UserSpace::new(child_vm_space, child_cpu_context)); + debug!("before spawn child task"); + debug!("current pid: {}", current_pid()); + debug!("child process pid: {}", child_pid); + debug!("rip = 0x{:x}", child_cpu_context.gp_regs.rip); + + let child = Arc::new_cyclic(|child_process_ref| { + let weak_child_process = child_process_ref.clone(); + let child_task = create_forked_task(child_user_space.clone(), weak_child_process); + Process::new(child_pid, child_task, Some(child_user_space)) + }); + current_process().add_child(child.clone()); + // child.send_to_scheduler(); + child + } +} + +pub fn current_process() -> Arc { + let task = Task::current(); + let process = task + .data() + .downcast_ref::>() + .expect("[Internal Error] Task data should points to weak"); + process + .upgrade() + .expect("[Internal Error] current process cannot be None") +} + +pub fn current_pid() -> usize { + let process = current_process(); + let pid = process.pid(); + pid +} + +/// Get the init process +pub fn get_init_process() -> Arc { + let mut current_process = current_process(); + while current_process.pid() != 0 { + let process = current_process + .parent + .lock() + .as_ref() + .map(|current| current.upgrade()) + .flatten() + .expect("[Internal Error] init process cannot be None"); + current_process = process; + } + current_process } /// create a new pid for new process fn new_pid() -> usize { PID_ALLOCATOR.fetch_add(1, Ordering::Release) } + +/// debug use +fn check_fork_vm_space(parent_vm_space: &VmSpace, child_vm_space: &VmSpace) { + let mut buffer1 = vec![0u8; 0x78]; + let mut buffer2 = vec![0u8; 0x78]; + parent_vm_space + .read_bytes(0x401000, &mut buffer1) + .expect("read buffer1 failed"); + child_vm_space + .read_bytes(0x401000, &mut buffer2) + .expect("read buffer1 failed"); + for len in 0..buffer1.len() { + assert_eq!(buffer1[len], buffer2[len]); + } + debug!("check fork vm space succeed."); +} diff --git a/src/kxos-std/src/process/status.rs b/src/kxos-std/src/process/status.rs new file mode 100644 index 00000000..be41b700 --- /dev/null +++ b/src/kxos-std/src/process/status.rs @@ -0,0 +1,11 @@ +#[derive(Debug, Clone, Copy)] +pub enum ProcessStatus { + Runnable, + Zombie, +} + +impl ProcessStatus { + pub fn set_zombie(&mut self) { + *self = ProcessStatus::Zombie; + } +} diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index 86b84eb0..c3b41d76 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -1,4 +1,6 @@ -use alloc::sync::Arc; +use core::sync::atomic::AtomicUsize; + +use alloc::sync::{Arc, Weak}; use kxos_frame::{ cpu::CpuContext, debug, @@ -7,9 +9,17 @@ use kxos_frame::{ vm::VmSpace, }; -use crate::{memory::load_elf_to_vm_space, syscall::syscall_handler}; +use crate::{ + memory::load_elf_to_vm_space, + process::{current_pid, current_process}, + syscall::syscall_handler, +}; -pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc { +use super::Process; + +static COUNTER: AtomicUsize = AtomicUsize::new(0); + +pub fn create_user_task_from_elf(elf_file_content: &[u8], process: Weak) -> Arc { let vm_space = VmSpace::new(); let elf_load_info = load_elf_to_vm_space(elf_file_content, &vm_space).expect("Load Elf failed"); let mut cpu_ctx = CpuContext::default(); @@ -20,12 +30,46 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc { cpu_ctx.gp_regs.rsp = elf_load_info.user_stack_top(); let user_space = Arc::new(UserSpace::new(vm_space, cpu_ctx)); - fn user_task_entry() { let cur = Task::current(); let user_space = cur.user_space().expect("user task should have user space"); let mut user_mode = UserMode::new(user_space); - debug!("in user task"); + + loop { + let user_event = user_mode.execute(); + debug!("return from user mode"); + debug!("current pid = {}", current_pid()); + let context = user_mode.context_mut(); + if let HandlerResult::Exit = handle_user_event(user_event, context) { + // FIXME: How to set task status? How to set exit code of process? + break; + } + } + let current_process = current_process(); + // Work Around: We schedule all child tasks to run when current process exit. + if current_process.has_child() { + debug!("*********schedule child process**********"); + let child_process = current_process.get_child_process(); + child_process.send_to_scheduler(); + debug!("*********return to parent process*********"); + } + // exit current process + current_process.exit(); + } + + Task::new(user_task_entry, process, Some(user_space)).expect("spawn user task failed.") +} + +pub fn create_forked_task(userspace: Arc, process: Weak) -> Arc { + fn user_task_entry() { + let cur = Task::current(); + let user_space = cur.user_space().expect("user task should have user space"); + let mut user_mode = UserMode::new(user_space); + debug!("In forked task"); + debug!("[forked task] pid = {}", current_pid()); + debug!("[forked task] rip = 0x{:x}", user_space.cpu_ctx.gp_regs.rip); + debug!("[forked task] rsp = 0x{:x}", user_space.cpu_ctx.gp_regs.rsp); + debug!("[forked task] rax = 0x{:x}", user_space.cpu_ctx.gp_regs.rax); loop { let user_event = user_mode.execute(); debug!("return from user mode"); @@ -37,8 +81,7 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc { } } - // FIXME: set the correct type when task has no data - Task::spawn(user_task_entry, None::, Some(user_space)).expect("spawn user task failed.") + Task::new(user_task_entry, process, Some(userspace)).expect("spawn task failed") } fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) -> HandlerResult { diff --git a/src/kxos-std/src/syscall/mod.rs b/src/kxos-std/src/syscall/mod.rs index b5716c19..87b899ed 100644 --- a/src/kxos-std/src/syscall/mod.rs +++ b/src/kxos-std/src/syscall/mod.rs @@ -1,14 +1,18 @@ +use alloc::borrow::ToOwned; use alloc::vec; use alloc::{sync::Arc, vec::Vec}; use kxos_frame::cpu::CpuContext; -use kxos_frame::Error; +use kxos_frame::{debug, Error}; use kxos_frame::{task::Task, user::UserSpace, vm::VmIo}; use kxos_frame::info; use crate::process::task::HandlerResult; +use crate::process::{current_pid, current_process, Process}; const SYS_WRITE: u64 = 1; +const SYS_GETPID: u64 = 39; +const SYS_FORK: u64 = 57; const SYS_EXIT: u64 = 60; pub struct SyscallArgument { @@ -40,7 +44,7 @@ impl SyscallArgument { pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult { let syscall_frame = SyscallArgument::new_from_context(context); - let syscall_return = syscall_dispatch(syscall_frame.syscall_number, syscall_frame.args); + let syscall_return = syscall_dispatch(syscall_frame.syscall_number, syscall_frame.args, context.to_owned()); match syscall_return { SyscallResult::Return(return_value) => { @@ -52,9 +56,11 @@ pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult { } } -pub fn syscall_dispatch(syscall_number: u64, args: [u64; 6]) -> SyscallResult { +pub fn syscall_dispatch(syscall_number: u64, args: [u64; 6], context: CpuContext) -> SyscallResult { match syscall_number { SYS_WRITE => sys_write(args[0], args[1], args[2]), + SYS_GETPID => sys_getpid(), + SYS_FORK => sys_fork(context), SYS_EXIT => sys_exit(args[0] as _), _ => panic!("Unsupported syscall number: {}", syscall_number), } @@ -62,6 +68,7 @@ pub fn syscall_dispatch(syscall_number: u64, args: [u64; 6]) -> SyscallResult { pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult { // only suppprt STDOUT now. + debug!("[syscall][id={}][SYS_WRITE]", SYS_WRITE); const STDOUT: u64 = 1; if fd == STDOUT { let task = Task::current(); @@ -77,7 +84,22 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult } } +pub fn sys_getpid() -> SyscallResult { + debug!("[syscall][id={}][SYS_GETPID]", SYS_GETPID); + let pid = current_pid(); + info!("[sys_getpid]: pid = {}", pid); + SyscallResult::Return(pid as i32) +} + +pub fn sys_fork(parent_context: CpuContext) -> SyscallResult { + debug!("[syscall][id={}][SYS_FORK]", SYS_FORK); + let child_process = Process::fork(parent_context); + SyscallResult::Return(child_process.pid() as i32) +} + pub fn sys_exit(exit_code: i32) -> SyscallResult { + debug!("[syscall][id={}][SYS_EXIT]", SYS_EXIT); + current_process().set_exit_code(exit_code); SyscallResult::Exit(exit_code) } @@ -88,6 +110,8 @@ fn copy_bytes_from_user( ) -> Result, Error> { let vm_space = user_space.vm_space(); let mut buffer = vec![0u8; user_buf_len]; + debug!("user_buf_ptr: 0x{:x}", user_buf_ptr); + debug!("user_buf_len: {}", user_buf_len); vm_space.read_bytes(user_buf_ptr, &mut buffer)?; Ok(buffer) } diff --git a/src/kxos-user/fork/Makefile b/src/kxos-user/fork/Makefile index 96533759..f4790cb8 100644 --- a/src/kxos-user/fork/Makefile +++ b/src/kxos-user/fork/Makefile @@ -1,5 +1,5 @@ .PHONY: build clean run -build: hello_world.s +build: fork.s @gcc -static -nostdlib fork.s -o fork clean: @rm fork diff --git a/src/kxos-user/fork/fork b/src/kxos-user/fork/fork index a1859ce1..5203ceb5 100755 --- a/src/kxos-user/fork/fork +++ b/src/kxos-user/fork/fork @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ad189cc084511d777ec2bcb211ca7cdbfb55f00320953da71a6a37f46404dd6 -size 9488 +oid sha256:6d1d5aa2ef1105eb716219002763836a47e95cef22997064f6f60bfd4c7a43de +size 9528 diff --git a/src/kxos-user/fork/fork.s b/src/kxos-user/fork/fork.s index ce988b9f..3441629a 100644 --- a/src/kxos-user/fork/fork.s +++ b/src/kxos-user/fork/fork.s @@ -9,16 +9,22 @@ _start: cmp $0, %rax je _child # child process jmp _parent # parent process -_parent: +_parent: + call get_pid call print_parent_message call exit _child: + call get_pid call print_child_message call exit exit: mov $60, %rax # syscall number of exit mov $0, %rdi # exit code - syscall + syscall +get_pid: + mov $39, %rax + syscall + ret print_hello_world: mov $message, %rsi # address of message mov $message_end, %rdx @@ -40,9 +46,9 @@ _print_message: mov $1, %rdi # stdout syscall ret -.section .rodata +.section .rodata message: - .ascii "Hello, world\n" + .ascii "Hello, world in fork\n" message_end: message_parent: .ascii "Hello world from parent\n" diff --git a/src/kxos-user/hello_world/hello_world b/src/kxos-user/hello_world/hello_world index 33b035c6..eef6650f 100755 --- a/src/kxos-user/hello_world/hello_world +++ b/src/kxos-user/hello_world/hello_world @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ac54a2485e87769b102225e0a2d7c25e449a01bd0b2504a164fe1ce205acb13 -size 9072 +oid sha256:f56fb5cf05f234578b13c8d73f2d29568f6f513602f1ea0b71a0dbf0cf8f60f8 +size 9104 diff --git a/src/kxos-user/hello_world/hello_world.s b/src/kxos-user/hello_world/hello_world.s index 58e8783c..3cf6c075 100644 --- a/src/kxos-user/hello_world/hello_world.s +++ b/src/kxos-user/hello_world/hello_world.s @@ -8,6 +8,10 @@ _start: mov $60, %rax # syscall number of exit mov $0, %rdi # exit code syscall +get_pid: + mov $39, %rax + syscall + ret print_message: mov $1, %rax # syscall number of write mov $1, %rdi # stdout