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 cpu;
pub mod device; pub mod device;
mod error; mod error;
pub mod log;
pub mod prelude; pub mod prelude;
pub mod sync;
pub mod task; pub mod task;
pub mod timer; pub mod timer;
pub mod user; pub mod user;
mod util; mod util;
pub mod log;
pub mod vm; pub mod vm;
pub mod sync;
pub use self::error::Error; pub use self::error::Error;
use alloc::sync::Arc; use alloc::sync::Arc;

View File

@ -59,4 +59,4 @@ macro_rules! error {
$crate::log_print!($($arg)*); $crate::log_print!($($arg)*);
$crate::log_print!("\n"); $crate::log_print!("\n");
}; };
} }

View File

@ -2,4 +2,4 @@ mod spin;
mod wait; mod wait;
pub use self::spin::{SpinLock, SpinLockGuard}; 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. /// A spin lock.
pub struct SpinLock<T: ?Sized> { pub struct SpinLock<T: ?Sized> {
val: T, val: T,
} }
impl<T> SpinLock<T> { impl<T> SpinLock<T> {
@ -11,8 +11,8 @@ impl<T> SpinLock<T> {
todo!() todo!()
} }
/// Acquire the spin lock. /// Acquire the spin lock.
/// ///
/// This method runs in a busy loop until the lock can be acquired. /// This method runs in a busy loop until the lock can be acquired.
/// After acquiring the spin lock, all interrupts are disabled. /// After acquiring the spin lock, all interrupts are disabled.
pub fn lock<'a>(&self) -> SpinLockGuard<'a, T> { pub fn lock<'a>(&self) -> SpinLockGuard<'a, T> {
@ -25,7 +25,7 @@ unsafe impl<T: ?Sized + Send> Sync for SpinLock<T> {}
/// The guard of a spin lock. /// The guard of a spin lock.
pub struct SpinLockGuard<'a, T: ?Sized + 'a> { pub struct SpinLockGuard<'a, T: ?Sized + 'a> {
lock: &'a SpinLock<T> lock: &'a SpinLock<T>,
} }
impl<'a, T> Deref for SpinLockGuard<'a, 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 { fn deref_mut(&mut self) -> &mut Self::Target {
todo!() todo!()
} }
@ -44,4 +44,4 @@ impl <'a, T> DerefMut for SpinLockGuard<'a, T> {
impl<'a, T: ?Sized> !Send for SpinLockGuard<'a, T> {} impl<'a, T: ?Sized> !Send for SpinLockGuard<'a, T> {}
unsafe impl<T: ?Sized + Sync> Sync for SpinLockGuard<'_, T> {} unsafe impl<T: ?Sized + Sync> Sync for SpinLockGuard<'_, T> {}

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@ pub struct Process {
task: Arc<Task>, task: Arc<Task>,
exit_code: i32, exit_code: i32,
// user_space: Option<Arc<UserSpace>>, // user_space: Option<Arc<UserSpace>>,
// TODO: childs, parent, files, // TODO: childs, parent, files,
} }
impl Process { impl Process {
@ -27,7 +27,11 @@ impl Process {
let pid = new_pid(); let pid = new_pid();
let task = spawn_user_task_from_elf(elf_file_content); let task = spawn_user_task_from_elf(elf_file_content);
let exit_code = 0; 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 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}; 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 { loop {
let user_event = user_mode.execute(); let user_event = user_mode.execute();
let context = user_mode.context_mut(); 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.") 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 { match user_event {
UserEvent::Syscall => syscall_handler(context), UserEvent::Syscall => syscall_handler(context),
UserEvent::Fault => todo!(), UserEvent::Fault => todo!(),
UserEvent::Exception => todo!(), UserEvent::Exception => todo!(),
} }
} }
pub enum HandlerResult {
Exit,
Continue,
}

View File

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