Merge pull request #17 from StevenJiang1110/main

Add hello_world binary with git lfs
This commit is contained in:
Tate, Hongliang Tian 2022-08-31 16:12:57 -07:00 committed by GitHub
commit 7e733a83eb
11 changed files with 83 additions and 46 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
src/kxos-user/hello_world/hello_world filter=lfs diff=lfs merge=lfs -text

View File

@ -34,6 +34,21 @@ While there is nothing revolutionary in KxOS, it does explore some new design po
While most code is written in Rust, the project-scope build process is governed While most code is written in Rust, the project-scope build process is governed
by Makefile. by Makefile.
Before downloading source code, install and init Git LFS since the project manage binaries with Git LFS.
```bash
# 1. install git-lfs
brew install git-lfs # for mac
apt install git-lfs # for ubuntu
# 2. init git-lfs for current user
git lfs install --skip-repo # for mac & ubuntu
```
Then, download source codes as normal.
```bash
git clone [repository url]
```
After downloading the source code, run the following command once to make sure After downloading the source code, run the following command once to make sure
all developmennt tools are installed. all developmennt tools are installed.
```bash ```bash

View File

@ -111,6 +111,7 @@ impl<'a> UserMode<'a> {
self.user_space.vm_space().activate(); self.user_space.vm_space().activate();
if !self.executed { if !self.executed {
self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip as usize; 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.executed = true; self.executed = true;
} else { } else {
if self.current.inner_exclusive_access().is_from_trap { if self.current.inner_exclusive_access().is_from_trap {
@ -137,6 +138,7 @@ impl<'a> UserMode<'a> {
} else { } else {
self.context = CpuContext::from(*self.current.syscall_frame()); self.context = CpuContext::from(*self.current.syscall_frame());
println!("[kernel] syscall id:{}",self.context.gp_regs.rax); println!("[kernel] syscall id:{}",self.context.gp_regs.rax);
println!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp);
UserEvent::Syscall UserEvent::Syscall
} }
} }

View File

@ -1,10 +1,11 @@
use core::{ops::Range, cmp::Ordering}; use core::{cmp::Ordering, ops::Range};
use alloc::vec::Vec;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec;
use kxos_frame::{ use kxos_frame::{
vm::{Vaddr, VmAllocOptions, VmFrameVec, VmIo, VmPerm, VmSpace, VmMapOptions}, config::PAGE_SIZE,
Error, config::PAGE_SIZE, vm::{Vaddr, VmAllocOptions, VmFrameVec, VmIo, VmMapOptions, VmPerm, VmSpace},
Error,
}; };
use xmas_elf::{ use xmas_elf::{
header, header,
@ -39,7 +40,7 @@ impl<'a> ElfSegment<'a> {
Ok(type_) => type_, Ok(type_) => type_,
}; };
let data = match read_segment_data(segment, elf_file) { let data = match read_segment_data(segment, elf_file) {
Err(_) => return Err(ElfError::from("")), Err(msg) => return Err(ElfError::from(msg)),
Ok(data) => data, Ok(data) => data,
}; };
let vm_perm = Self::parse_segment_perm(segment)?; let vm_perm = Self::parse_segment_perm(segment)?;
@ -58,7 +59,7 @@ impl<'a> ElfSegment<'a> {
} }
let mut vm_perm = VmPerm::R; let mut vm_perm = VmPerm::R;
if flags.is_write() { if flags.is_write() {
vm_perm |= VmPerm::W; vm_perm |= VmPerm::W;
} }
if flags.is_execute() { if flags.is_execute() {
vm_perm |= VmPerm::X; vm_perm |= VmPerm::X;
@ -188,8 +189,10 @@ impl<'a> ElfLoadInfo<'a> {
for segment in self.segments.iter() { for segment in self.segments.iter() {
let start_address = segment.start_address(); let start_address = segment.start_address();
let len = segment.data.len(); let len = segment.data.len();
let mut read_buffer = vec![0;len]; let mut read_buffer = vec![0; len];
vm_space.read_bytes(start_address, &mut read_buffer).expect("read bytes failed"); vm_space
.read_bytes(start_address, &mut read_buffer)
.expect("read bytes failed");
let res = segment.data.cmp(&read_buffer); let res = segment.data.cmp(&read_buffer);
assert_eq!(res, Ordering::Equal); assert_eq!(res, Ordering::Equal);
} }
@ -255,14 +258,17 @@ impl From<Error> for ElfError {
fn read_segment_data<'a>( fn read_segment_data<'a>(
segment: ProgramHeader<'a>, segment: ProgramHeader<'a>,
elf_file: &ElfFile<'a>, elf_file: &ElfFile<'a>,
) -> Result<&'a [u8], ()> { ) -> Result<&'a [u8], &'static str> {
match segment.get_data(&elf_file) { match segment.get_data(&elf_file) {
Err(_) => Err(()), Err(msg) => Err(msg),
Ok(data) => { Ok(data) => {
if let SegmentData::Undefined(data) = data { match data {
Ok(data) SegmentData::Note64(_, data) | SegmentData::Undefined(data) => {
} else { Ok(data)
Err(()) },
_ => {
Err("Unkonwn segment data type")
}
} }
} }
} }

View File

@ -1,7 +1,7 @@
pub mod elf; pub mod elf;
pub mod user_stack; pub mod user_stack;
pub mod vm_page; pub mod vm_page;
use kxos_frame::{vm::VmSpace, debug}; use kxos_frame::{debug, vm::VmSpace};
use self::elf::{ElfError, ElfLoadInfo}; use self::elf::{ElfError, ElfLoadInfo};

View File

@ -2,7 +2,7 @@ use core::sync::atomic::{AtomicUsize, Ordering};
use alloc::sync::Arc; use alloc::sync::Arc;
// use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace}; // use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace};
use kxos_frame::{task::Task, debug}; use kxos_frame::{debug, task::Task};
use self::task::spawn_user_task_from_elf; use self::task::spawn_user_task_from_elf;
@ -34,12 +34,19 @@ impl Process {
} }
} }
pub fn spawn_kernel_task<F>(task_fn: F) -> Self where F: Fn() + Send + Sync + 'static { pub fn spawn_kernel_task<F>(task_fn: F) -> Self
where
F: Fn() + Send + Sync + 'static,
{
let pid = new_pid(); let pid = new_pid();
debug!("pid = {}" , pid); debug!("pid = {}", pid);
let task = Task::spawn(task_fn, None::<u8>, None).expect("spawn kernel task failed"); let task = Task::spawn(task_fn, None::<u8>, None).expect("spawn kernel task failed");
let exit_code = 0; let exit_code = 0;
Self { pid, task, exit_code } Self {
pid,
task,
exit_code,
}
} }
} }

View File

@ -1,10 +1,9 @@
use alloc::sync::Arc; use alloc::sync::Arc;
use kxos_frame::{ use kxos_frame::{
cpu::CpuContext, cpu::CpuContext,
println,
task::Task, task::Task,
user::{UserEvent, UserMode, UserSpace}, user::{UserEvent, UserMode, UserSpace},
vm::VmSpace, vm::VmSpace, debug,
}; };
use crate::{memory::load_elf_to_vm_space, syscall::syscall_handler}; use crate::{memory::load_elf_to_vm_space, syscall::syscall_handler};
@ -27,6 +26,7 @@ pub fn spawn_user_task_from_elf(elf_file_content: &[u8]) -> Arc<Task> {
let mut user_mode = UserMode::new(user_space); let mut user_mode = UserMode::new(user_space);
loop { loop {
let user_event = user_mode.execute(); let user_event = user_mode.execute();
debug!("return from user mode");
let context = user_mode.context_mut(); let context = user_mode.context_mut();
if let HandlerResult::Exit = 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? // FIXME: How to set task status? How to set exit code of process?

View File

@ -1,4 +1,3 @@
use alloc::ffi::CString;
use alloc::vec; use alloc::vec;
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use kxos_frame::cpu::CpuContext; use kxos_frame::cpu::CpuContext;
@ -12,7 +11,7 @@ use crate::process::task::HandlerResult;
const SYS_WRITE: u64 = 1; const SYS_WRITE: u64 = 1;
const SYS_EXIT: u64 = 60; const SYS_EXIT: u64 = 60;
pub struct SyscallFrame { pub struct SyscallArgument {
syscall_number: u64, syscall_number: u64,
args: [u64; 6], args: [u64; 6],
} }
@ -22,7 +21,7 @@ pub enum SyscallResult {
Return(i32), Return(i32),
} }
impl SyscallFrame { impl SyscallArgument {
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;
let mut args = [0u64; 6]; let mut args = [0u64; 6];
@ -40,7 +39,7 @@ impl SyscallFrame {
} }
pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult { pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult {
let syscall_frame = SyscallFrame::new_from_context(context); 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);
match syscall_return { match syscall_return {
@ -70,7 +69,7 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> SyscallResult
let user_buffer = let user_buffer =
copy_bytes_from_user(user_space, user_buf_ptr as usize, user_buf_len as usize) copy_bytes_from_user(user_space, user_buf_ptr as usize, user_buf_len as usize)
.expect("read user buffer failed"); .expect("read user buffer failed");
let content = alloc::str::from_utf8(user_buffer.as_slice()).expect("Invalid content"); // TODO: print content let content = alloc::str::from_utf8(user_buffer.as_slice()).expect("Invalid content"); // TODO: print content
info!("Message from user mode: {:?}", content); info!("Message from user mode: {:?}", content);
SyscallResult::Return(0) SyscallResult::Return(0)
} else { } else {

View File

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

View File

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

View File

@ -1,18 +1,24 @@
global _start .global _start
section .text
.section .text
_start: _start:
mov rax, 1 ; syswrite call print_message
mov rdi, 1 ; fd call print_message
mov rsi, msg ; "Hello, world!\n", call print_message
mov rdx, msglen ; sizeof("Hello, world!\n") mov $60, %rax # syscall number of exit
syscall mov $0, %rdi # exit code
syscall
mov rax, 60 ; sys_exit print_message:
mov rdi, 0 ; exit_code mov $1, %rax # syscall number of write
syscall mov $1, %rdi # stdout
mov $message, %rsi # address of message
section .rodata mov $message, %r11
msg: db "Hello, world!", 10 mov $message_end, %r12
msglen: equ $ - msg sub %r11, %r12 # calculate message len
mov %r12, %rdx # number of bytes
syscall
ret
.section .rodata
message:
.ascii "Hello, world\n"
message_end: