Merge pull request #21 from StevenJiang1110/main

Bug fix; Add user-mode fork test codes
This commit is contained in:
Tate, Hongliang Tian 2022-09-08 09:54:18 +08:00 committed by GitHub
commit ee407809a6
10 changed files with 111 additions and 33 deletions

1
.gitattributes vendored
View File

@ -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

View File

@ -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::<u8>, None).expect("Spawn first task failed");
unreachable!()
}
fn read_elf_content() -> &'static [u8] {

View File

@ -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<Arc<VmSpace>>,
}
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);
}

View File

@ -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::<u8>, 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

View File

@ -25,6 +25,7 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc<Task> {
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");

View File

@ -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

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

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

52
src/kxos-user/fork/fork.s Normal file
View File

@ -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:

View File

@ -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

View File

@ -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]