add user-mode hello_world; support syscall exit

This commit is contained in:
jiang jianfeng 2022-08-17 16:40:55 +08:00
parent 40f5b81252
commit e6569edbe2
12 changed files with 92 additions and 35 deletions

View File

@ -15,14 +15,14 @@ pub mod config;
pub mod cpu;
pub mod device;
mod error;
pub mod log;
pub mod prelude;
pub mod sync;
pub mod task;
pub mod timer;
pub mod user;
mod util;
pub mod log;
pub mod vm;
pub mod sync;
pub use self::error::Error;
use alloc::sync::Arc;

View File

@ -2,4 +2,4 @@ mod spin;
mod wait;
pub use self::spin::{SpinLock, SpinLockGuard};
pub use self::wait::{WaitQueue};
pub use self::wait::WaitQueue;

View File

@ -2,7 +2,7 @@ use core::ops::{Deref, DerefMut};
/// A spin lock.
pub struct SpinLock<T: ?Sized> {
val: T,
val: T,
}
impl<T> SpinLock<T> {
@ -25,7 +25,7 @@ unsafe impl<T: ?Sized + Send> Sync for SpinLock<T> {}
/// The guard of a spin lock.
pub struct SpinLockGuard<'a, T: ?Sized + 'a> {
lock: &'a SpinLock<T>
lock: &'a SpinLock<T>,
}
impl<'a, T> Deref for SpinLockGuard<'a, T> {
@ -36,7 +36,7 @@ impl<'a, T> Deref for SpinLockGuard<'a, T> {
}
}
impl <'a, T> DerefMut for SpinLockGuard<'a, T> {
impl<'a, T> DerefMut for SpinLockGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
todo!()
}

View File

@ -23,6 +23,6 @@ pub fn run_first_process() {
Process::spawn_from_elf(elf_file_content);
}
fn read_elf_content<'a>() -> &'a [u8]{
todo!()
fn read_elf_content() -> &'static [u8] {
include_bytes!("../../kxos-user/hello_world/hello_world")
}

View File

@ -2,7 +2,7 @@ use core::ops::Range;
use alloc::vec::Vec;
use kxos_frame::{
vm::{Vaddr, VmIo, VmPerm, VmSpace, VmFrameVec, VmAllocOptions},
vm::{Vaddr, VmAllocOptions, VmFrameVec, VmIo, VmPerm, VmSpace},
Error,
};
use xmas_elf::{

View File

@ -1,6 +1,6 @@
use alloc::{boxed::Box, collections::VecDeque, sync::Arc};
use kxos_frame::task::{set_scheduler, Scheduler, Task};
use kxos_frame::sync::SpinLock;
use kxos_frame::task::{set_scheduler, Scheduler, Task};
pub const TASK_INIT_CAPABILITY: usize = 16;

View File

@ -27,7 +27,11 @@ impl Process {
let pid = new_pid();
let task = spawn_user_task_from_elf(elf_file_content);
let exit_code = 0;
Self { pid, task, exit_code }
Self {
pid,
task,
exit_code,
}
}
}

View File

@ -1,5 +1,10 @@
use alloc::sync::Arc;
use kxos_frame::{cpu::CpuContext, task::Task, user::{UserSpace, UserEvent}, vm::VmSpace};
use kxos_frame::{
cpu::CpuContext,
task::Task,
user::{UserEvent, UserSpace},
vm::VmSpace,
};
use crate::{memory::load_elf_to_vm_space, syscall::syscall_handler};
@ -22,7 +27,10 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc<Task> {
loop {
let user_event = user_mode.execute();
let context = user_mode.context_mut();
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?
break;
}
}
}
@ -30,10 +38,15 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc<Task> {
Task::spawn(user_task_entry, None::<u8>, Some(user_space)).expect("spawn user task failed.")
}
fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) {
fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) -> HandlerResult {
match user_event {
UserEvent::Syscall => syscall_handler(context),
UserEvent::Fault => todo!(),
UserEvent::Exception => todo!(),
}
}
pub enum HandlerResult {
Exit,
Continue,
}

View File

@ -1,11 +1,13 @@
use alloc::vec;
use alloc::{sync::Arc, vec::Vec};
use kxos_frame::Error;
use kxos_frame::cpu::CpuContext;
use kxos_frame::Error;
use kxos_frame::{task::Task, user::UserSpace, vm::VmIo};
use kxos_frame::info;
use crate::process::task::HandlerResult;
const SYS_WRITE: u64 = 64;
const SYS_EXIT: u64 = 93;
@ -14,6 +16,11 @@ pub struct SyscallFrame {
args: [u64; 6],
}
pub enum SyscallResult {
Exit(i32),
Return(i32),
}
impl SyscallFrame {
fn new_from_context(context: &CpuContext) -> Self {
let syscall_number = context.gp_regs.rax;
@ -25,20 +32,27 @@ impl SyscallFrame {
args[4] = context.gp_regs.r8;
args[5] = context.gp_regs.r9;
Self {
syscall_number, args,
syscall_number,
args,
}
}
}
pub fn syscall_handler(context: &mut CpuContext) {
pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult {
let syscall_frame = SyscallFrame::new_from_context(context);
let syscall_return = syscall_dispatch(syscall_frame.syscall_number, syscall_frame.args);
// FIXME: set return value?
context.gp_regs.rax = syscall_return as u64;
match syscall_return {
SyscallResult::Return(return_value) => {
// FIXME: set return value?
context.gp_regs.rax = return_value as u64;
HandlerResult::Continue
}
SyscallResult::Exit(exit_code) => HandlerResult::Exit,
}
}
pub fn syscall_dispatch(syscall_number: u64, args: [u64; 6]) -> isize {
pub fn syscall_dispatch(syscall_number: u64, args: [u64; 6]) -> SyscallResult {
match syscall_number {
SYS_WRITE => sys_write(args[0], args[1], args[2]),
SYS_EXIT => sys_exit(args[0] as _),
@ -46,27 +60,26 @@ pub fn syscall_dispatch(syscall_number: u64, args: [u64; 6]) -> isize {
}
}
pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> isize {
pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult {
// only suppprt STDOUT now.
const STDOUT: u64 = 1;
if fd == STDOUT {
let task = Task::current();
let user_space = task.user_space().expect("No user space attached");
let user_buffer = copy_bytes_from_user(user_space, user_buf_ptr as usize, user_buf_len as usize)
.expect("read user buffer failed");
let user_buffer =
copy_bytes_from_user(user_space, user_buf_ptr as usize, user_buf_len as usize)
.expect("read user buffer failed");
let content = alloc::str::from_utf8(user_buffer.as_slice()).expect("Invalid content");
// TODO: print content
info!("Message from user mode: {}", content);
0
SyscallResult::Return(0)
} else {
panic!("Unsupported fd number {}", fd);
}
}
pub fn sys_exit(exit_code: i32) -> isize {
// let current = Task::current();
// current.exit(exit_code);
todo!()
pub fn sys_exit(exit_code: i32) -> SyscallResult {
SyscallResult::Exit(exit_code)
}
fn copy_bytes_from_user(

View File

@ -0,0 +1,9 @@
.PHONY: build clean run
build: hello_world.s
@nasm -f elf64 hello_world.s -o hello_world.o
@ld hello_world.o -o hello_world
@rm hello_world.o
clean:
@rm hello_world
run: build
@./hello_world

View File

@ -0,0 +1,18 @@
global _start
section .text
_start:
mov rax, 1 ; syswrite
mov rdi, 1 ; fd
mov rsi, msg ; "Hello, world!\n",
mov rdx, msglen ; sizeof("Hello, world!\n")
syscall
mov rax, 60 ; sys_exit
mov rdi, 0 ; exit_code
syscall
section .rodata
msg: db "Hello, world!", 10
msglen: equ $ - msg