diff --git a/.gitattributes b/.gitattributes index 54859819..85f44d51 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ 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 diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs index 187cfd8d..532ada79 100644 --- a/src/kxos-std/src/lib.rs +++ b/src/kxos-std/src/lib.rs @@ -6,7 +6,7 @@ #![feature(const_btree_new)] #![feature(cstr_from_bytes_until_nul)] -use kxos_frame::println; +use kxos_frame::{info, println, task::Task}; use process::Process; extern crate alloc; @@ -20,15 +20,26 @@ pub fn init() { process::fifo_scheduler::init(); } -pub fn run_first_kernel_task() { - Process::spawn_kernel_task(|| { - println!("hello world from kernel"); +pub fn init_task() { + println!("[kernel] Hello world from init task!"); + + let process = Process::spawn_kernel_task(|| { + println!("[kernel] Hello world from kernel!"); }); + info!("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()); + + loop {} } -pub fn run_first_process() { +/// first process never return +pub fn run_first_process() -> ! { let elf_file_content = read_elf_content(); - Process::spawn_from_elf(elf_file_content); + Task::spawn(init_task, None::, None).expect("Spawn first task failed"); + unreachable!() } fn read_elf_content() -> &'static [u8] { diff --git a/src/kxos-std/src/memory/user_stack.rs b/src/kxos-std/src/memory/user_stack.rs index 321be355..a53a9ec0 100644 --- a/src/kxos-std/src/memory/user_stack.rs +++ b/src/kxos-std/src/memory/user_stack.rs @@ -1,5 +1,7 @@ -use alloc::sync::Arc; -use kxos_frame::vm::{Vaddr, VmPerm, VmSpace}; +use kxos_frame::{ + config::PAGE_SIZE, + vm::{Vaddr, VmPerm, VmSpace}, +}; use super::vm_page::VmPageRange; @@ -7,39 +9,41 @@ pub const USER_STACK_BASE: Vaddr = 0x0000_0000_1000_0000; pub const USER_STACK_SIZE: usize = 0x1000 * 16; // 64KB pub struct UserStack { - /// The low address of user stack - pub stack_base: Vaddr, + /// The high address of user stack + stack_top: Vaddr, stack_size: usize, - vm_space: Option>, } impl UserStack { /// initialize user stack on base addr - pub const fn new(stack_base: Vaddr, stack_size: usize) -> Self { + pub const fn new(stack_top: Vaddr, stack_size: usize) -> Self { Self { - stack_base, + stack_top, stack_size, - vm_space: None, } } /// This function only work for first process pub const fn new_default_config() -> Self { Self { - stack_base: USER_STACK_BASE, + // add a guard page at stack top + stack_top: USER_STACK_BASE - PAGE_SIZE, stack_size: USER_STACK_SIZE, - vm_space: None, } } /// the user stack top(high address), used to setup rsp pub const fn stack_top(&self) -> Vaddr { - self.stack_base + self.stack_size + self.stack_top + } + + /// the user stack bottom(low address) + const fn stack_bottom(&self) -> Vaddr { + self.stack_top - self.stack_size } pub fn map_and_zeroed(&self, vm_space: &VmSpace) { - let mut vm_page_range = - VmPageRange::new_range(self.stack_base..(self.stack_base + self.stack_size)); + let mut vm_page_range = VmPageRange::new_range(self.stack_bottom()..self.stack_top()); let vm_perm = UserStack::perm(); vm_page_range.map_zeroed(vm_space, vm_perm); } diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs index b9445d2c..f5fc912a 100644 --- a/src/kxos-std/src/process/mod.rs +++ b/src/kxos-std/src/process/mod.rs @@ -2,7 +2,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use alloc::sync::Arc; // use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace}; -use kxos_frame::{debug, task::Task}; +use kxos_frame::task::Task; use self::task::spawn_user_task_from_elf; @@ -39,8 +39,7 @@ impl Process { F: Fn() + Send + Sync + 'static, { let pid = new_pid(); - debug!("pid = {}", pid); - let task = Task::spawn(task_fn, None::, None).expect("spawn kernel task failed"); + let task = Task::spawn(task_fn, pid, None).expect("spawn kernel task failed"); let exit_code = 0; Self { pid, @@ -48,6 +47,10 @@ impl Process { exit_code, } } + + pub fn pid(&self) -> usize { + self.pid + } } /// create a new pid for new process diff --git a/src/kxos-std/src/process/task.rs b/src/kxos-std/src/process/task.rs index 16807f22..86b84eb0 100644 --- a/src/kxos-std/src/process/task.rs +++ b/src/kxos-std/src/process/task.rs @@ -25,6 +25,7 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc { 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"); diff --git a/src/kxos-user/fork/Makefile b/src/kxos-user/fork/Makefile new file mode 100644 index 00000000..96533759 --- /dev/null +++ b/src/kxos-user/fork/Makefile @@ -0,0 +1,7 @@ +.PHONY: build clean run +build: hello_world.s + @gcc -static -nostdlib fork.s -o fork +clean: + @rm fork +run: build + @./fork \ No newline at end of file diff --git a/src/kxos-user/fork/fork b/src/kxos-user/fork/fork new file mode 100755 index 00000000..a1859ce1 --- /dev/null +++ b/src/kxos-user/fork/fork @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ad189cc084511d777ec2bcb211ca7cdbfb55f00320953da71a6a37f46404dd6 +size 9488 diff --git a/src/kxos-user/fork/fork.s b/src/kxos-user/fork/fork.s new file mode 100644 index 00000000..ce988b9f --- /dev/null +++ b/src/kxos-user/fork/fork.s @@ -0,0 +1,52 @@ +.global _start + +.section .text +_start: + call print_hello_world + mov $57, %rax # syscall number of fork + syscall + + cmp $0, %rax + je _child # child process + jmp _parent # parent process +_parent: + call print_parent_message + call exit +_child: + call print_child_message + call exit +exit: + mov $60, %rax # syscall number of exit + mov $0, %rdi # exit code + syscall +print_hello_world: + mov $message, %rsi # address of message + mov $message_end, %rdx + sub %rsi, %rdx # calculate message len + jmp _print_message +print_parent_message: + mov $message_parent, %rsi # address of message + mov $message_parent_end, %rdx + sub %rsi, %rdx # calculate message len + jmp _print_message +print_child_message: + mov $message_child, %rsi # address of message + mov $message_child_end, %rdx + sub %rsi, %rdx # calculate message len + jmp _print_message +# never directly call _print_message +_print_message: + mov $1, %rax # syscall number of write + mov $1, %rdi # stdout + syscall + ret +.section .rodata +message: + .ascii "Hello, world\n" +message_end: +message_parent: + .ascii "Hello world from parent\n" +message_parent_end: +message_child: + .ascii "Hello world from child\n" +message_child_end: diff --git a/src/kxos-user/hello_world/hello_world.s b/src/kxos-user/hello_world/hello_world.s index 0baea631..58e8783c 100644 --- a/src/kxos-user/hello_world/hello_world.s +++ b/src/kxos-user/hello_world/hello_world.s @@ -2,20 +2,18 @@ .section .text _start: - call print_message - call print_message - call print_message + call print_message + call print_message + call print_message mov $60, %rax # syscall number of exit - mov $0, %rdi # exit code + mov $0, %rdi # exit code syscall print_message: mov $1, %rax # syscall number of write mov $1, %rdi # stdout - mov $message, %rsi # address of message - mov $message, %r11 - mov $message_end, %r12 - sub %r11, %r12 # calculate message len - mov %r12, %rdx # number of bytes + mov $message, %rsi # address of message + mov $message_end, %rdx + sub %rsi, %rdx # calculate message len syscall ret .section .rodata diff --git a/src/src/main.rs b/src/src/main.rs index 6ec11ab8..4c4cfc9d 100644 --- a/src/src/main.rs +++ b/src/src/main.rs @@ -20,8 +20,6 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { kxos_std::init(); kxos_std::run_first_process(); - - loop {} } #[cfg(not(test))] #[panic_handler]