From b8e1bfd69bb8a1a5be9eeb3fcd5ce68811440f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E4=B8=B0=E6=BA=90?= Date: Mon, 10 Feb 2020 22:03:53 +0800 Subject: [PATCH 01/13] finish sys_fork --- os/src/context.rs | 26 ++++++++++++++++++++++++++ os/src/memory/memory_set/area.rs | 8 ++++---- os/src/memory/memory_set/handler.rs | 29 +++++++++++++++++++++++++++++ os/src/memory/memory_set/mod.rs | 21 ++++++++++++++++++++- os/src/memory/paging.rs | 9 +++++++++ os/src/process/mod.rs | 9 +++++++++ os/src/process/processor.rs | 8 ++++++-- os/src/process/structs.rs | 25 ++++++++++++++++++++++++- os/src/process/thread_pool.rs | 4 +++- os/src/syscall.rs | 13 +++++++++++-- usr/rust/src/bin/fork.rs | 21 +++++++++++++++++++++ usr/rust/src/syscall.rs | 5 +++++ 12 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 usr/rust/src/bin/fork.rs diff --git a/os/src/context.rs b/os/src/context.rs index 5ea0e44..984e265 100644 --- a/os/src/context.rs +++ b/os/src/context.rs @@ -3,6 +3,7 @@ use riscv::register::sstatus; use riscv::register::{scause::Scause, sstatus::Sstatus}; #[repr(C)] +#[derive(Clone)] pub struct TrapFrame { pub x: [usize; 32], // General registers pub sstatus: Sstatus, // Supervisor Status Register @@ -12,6 +13,7 @@ pub struct TrapFrame { } #[repr(C)] +#[derive(Clone)] pub struct Context { pub content_addr: usize, } @@ -31,6 +33,10 @@ impl Context { ContextContent::new_kernel_thread(entry, kstack_top, satp).push_at(kstack_top) } + pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Context { + ContextContent::new_fork(tf, kstack_top, satp) + } + pub unsafe fn append_initial_arguments(&self, args: [usize; 3]) { let contextContent = &mut *(self.content_addr as *mut ContextContent); contextContent.tf.x[10] = args[0]; @@ -98,6 +104,26 @@ impl ContextContent { } } + /// Fork a user process and get the new Context. + /// + /// The stack pointer in kernel mode will be set to `kstack_top`. + /// The SATP register will be set to `satp`. + /// All the other registers are same as the original. + unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Context { + ContextContent { + ra: __trapret as usize, + satp, + s: [0; 12], + tf: { + let mut tf = tf.clone(); + // fork function's ret value, the new process is 0 + tf.x[10] = 0; // a0 + tf + }, + } + .push_at(kstack_top) + } + unsafe fn push_at(self, stack_top: usize) -> Context { let ptr = (stack_top as *mut ContextContent).sub(1); *ptr = self; diff --git a/os/src/memory/memory_set/area.rs b/os/src/memory/memory_set/area.rs index b5e0e02..5b6157d 100644 --- a/os/src/memory/memory_set/area.rs +++ b/os/src/memory/memory_set/area.rs @@ -5,10 +5,10 @@ use alloc::boxed::Box; #[derive(Debug, Clone)] pub struct MemoryArea { - start: usize, - end: usize, - handler: Box, - attr: MemoryAttr, + pub start: usize, + pub end: usize, + pub handler: Box, + pub attr: MemoryAttr, } impl MemoryArea { diff --git a/os/src/memory/memory_set/handler.rs b/os/src/memory/memory_set/handler.rs index 3750f24..cf9aa8d 100644 --- a/os/src/memory/memory_set/handler.rs +++ b/os/src/memory/memory_set/handler.rs @@ -11,6 +11,13 @@ pub trait MemoryHandler: Debug + 'static { fn map(&self, pt: &mut PageTableImpl, va: usize, attr: &MemoryAttr); fn unmap(&self, pt: &mut PageTableImpl, va: usize); fn page_copy(&self, pt: &mut PageTableImpl, va: usize, src: usize, length: usize); + fn clone_map( + &self, + pt: &mut PageTableImpl, + src_pt: &mut PageTableImpl, + addr: usize, + attr: &MemoryAttr, + ); } impl Clone for Box { @@ -56,6 +63,15 @@ impl MemoryHandler for Linear { } } } + fn clone_map( + &self, + pt: &mut PageTableImpl, + _src_pt: &mut PageTableImpl, + addr: usize, + attr: &MemoryAttr, + ) { + self.map(pt, addr, attr); + } } #[derive(Debug, Clone)] @@ -79,6 +95,7 @@ impl MemoryHandler for ByFrame { fn unmap(&self, pt: &mut PageTableImpl, va: usize) { pt.unmap(va); } + fn page_copy(&self, pt: &mut PageTableImpl, va: usize, src: usize, length: usize) { let pa = pt.get_entry(va).expect("get pa error!").0.addr().as_usize(); unsafe { @@ -94,4 +111,16 @@ impl MemoryHandler for ByFrame { } } } + + fn clone_map( + &self, + pt: &mut PageTableImpl, + src_pt: &mut PageTableImpl, + addr: usize, + attr: &MemoryAttr, + ) { + self.map(pt, addr, attr); + let data = src_pt.get_page_slice_mut(addr); + pt.get_page_slice_mut(addr).copy_from_slice(data); + } } diff --git a/os/src/memory/memory_set/mod.rs b/os/src/memory/memory_set/mod.rs index 4117256..7e2ade6 100644 --- a/os/src/memory/memory_set/mod.rs +++ b/os/src/memory/memory_set/mod.rs @@ -4,11 +4,12 @@ pub mod handler; use crate::consts::*; use crate::memory::access_pa_via_va; -use crate::memory::paging::PageTableImpl; +use crate::memory::paging::{PageRange, PageTableImpl}; use alloc::{boxed::Box, vec::Vec}; use area::MemoryArea; use attr::MemoryAttr; use handler::{Linear, MemoryHandler}; +use riscv::addr::{Page, VirtAddr}; pub struct MemorySet { areas: Vec, @@ -108,4 +109,22 @@ impl MemorySet { pub fn token(&self) -> usize { self.page_table.token() } + pub fn clone(&mut self) -> Self { + let mut new_page_table = PageTableImpl::new_bare(); + let Self { + ref mut page_table, + ref areas, + .. + } = self; + for area in areas.iter() { + for page in PageRange::new(area.start, area.end) { + area.handler + .clone_map(&mut new_page_table, page_table, page, &area.attr); + } + } + MemorySet { + areas: areas.clone(), + page_table: new_page_table, + } + } } diff --git a/os/src/memory/paging.rs b/os/src/memory/paging.rs index 9ab62e8..88d963d 100644 --- a/os/src/memory/paging.rs +++ b/os/src/memory/paging.rs @@ -157,6 +157,15 @@ impl PageTableImpl { Self::flush_tlb(); } } + + pub fn get_page_slice_mut<'a>(&mut self, addr: usize) -> &'a mut [u8] { + let frame = self + .page_table + .translate_page(Page::of_addr(VirtAddr::new(addr))) + .unwrap(); + let vaddr = frame.start_address().as_usize() + PHYSICAL_MEMORY_OFFSET; + unsafe { core::slice::from_raw_parts_mut(vaddr as *mut u8, 0x1000) } + } } #[derive(Clone, Copy, PartialEq, Eq)] diff --git a/os/src/process/mod.rs b/os/src/process/mod.rs index a97ba07..882d392 100644 --- a/os/src/process/mod.rs +++ b/os/src/process/mod.rs @@ -62,6 +62,15 @@ pub fn yield_now() { pub fn wake_up(tid: Tid) { CPU.wake_up(tid); } + pub fn current_tid() -> usize { CPU.current_tid() } + +pub fn add_thread(thread: Box) -> usize { + CPU.add_thread(thread) +} + +pub fn current_thread() -> Box { + CPU.current_thread() +} diff --git a/os/src/process/processor.rs b/os/src/process/processor.rs index 10b76a8..21fd38a 100644 --- a/os/src/process/processor.rs +++ b/os/src/process/processor.rs @@ -41,8 +41,8 @@ impl Processor { .expect("Processor is not initialized!") } - pub fn add_thread(&self, thread: Box) { - self.inner().pool.add(thread); + pub fn add_thread(&self, thread: Box) -> Tid { + self.inner().pool.add(thread) } pub fn idle_main(&self) -> ! { @@ -132,4 +132,8 @@ impl Processor { pub fn current_tid(&self) -> usize { self.inner().current.as_mut().unwrap().0 as usize } + + pub fn current_thread(&self) -> Box { + self.inner().current.as_ref().unwrap().1.clone() + } } diff --git a/os/src/process/structs.rs b/os/src/process/structs.rs index fbb25aa..6c97f13 100644 --- a/os/src/process/structs.rs +++ b/os/src/process/structs.rs @@ -1,11 +1,13 @@ use super::{ExitCode, Tid}; use crate::alloc::alloc::{alloc, dealloc, Layout}; use crate::consts::*; -use crate::context::Context; +use crate::context::{Context, ContextContent, TrapFrame}; use crate::memory::memory_set::{attr::MemoryAttr, handler::ByFrame, MemorySet}; use alloc::boxed::Box; +use alloc::sync::Arc; use core::str; use riscv::register::satp; +use spin::Mutex; use xmas_elf::{ header, program::{Flags, SegmentData, Type}, @@ -20,10 +22,12 @@ pub enum Status { Exited(ExitCode), } +#[derive(Clone)] pub struct Thread { pub context: Context, pub kstack: KernelStack, pub wait: Option, + pub vm: Option>>, } impl Thread { @@ -40,6 +44,7 @@ impl Thread { context: Context::new_kernel_thread(entry, kstack_.top(), satp::read().bits()), kstack: kstack_, wait: None, + vm: None, }) } } @@ -49,6 +54,7 @@ impl Thread { context: Context::null(), kstack: KernelStack::new_empty(), wait: None, + vm: None, }) } @@ -94,11 +100,28 @@ impl Thread { context: Context::new_user_thread(entry_addr, ustack_top, kstack.top(), vm.token()), kstack: kstack, wait: wait_thread, + vm: Some(Arc::new(Mutex::new(vm))), + }) + } + + /// Fork a new process from current one + pub fn fork(&self, tf: &TrapFrame) -> Box { + let kstack = KernelStack::new(); + let vm = self.vm.as_ref().unwrap().lock().clone(); + let vm_token = vm.token(); + let context = unsafe { Context::new_fork(tf, kstack.top(), vm_token) }; + Box::new(Thread { + context, + kstack, + wait: self.wait.clone(), + vm: Some(Arc::new(Mutex::new(vm))), }) } } +#[derive(Clone)] pub struct KernelStack(usize); + impl KernelStack { pub fn new() -> Self { let bottom = unsafe { diff --git a/os/src/process/thread_pool.rs b/os/src/process/thread_pool.rs index ade6652..98513fb 100644 --- a/os/src/process/thread_pool.rs +++ b/os/src/process/thread_pool.rs @@ -24,6 +24,7 @@ impl ThreadPool { scheduler, } } + fn alloc_tid(&self) -> Tid { for (i, info) in self.threads.iter().enumerate() { if info.is_none() { @@ -33,13 +34,14 @@ impl ThreadPool { panic!("alloc tid failed!"); } - pub fn add(&mut self, _thread: Box) { + pub fn add(&mut self, _thread: Box) -> Tid { let tid = self.alloc_tid(); self.threads[tid] = Some(ThreadInfo { status: Status::Ready, thread: Some(_thread), }); self.scheduler.push(tid); + return tid; } pub fn acquire(&mut self) -> Option<(Tid, Box)> { diff --git a/os/src/syscall.rs b/os/src/syscall.rs index 97a8ac0..a4c1e35 100644 --- a/os/src/syscall.rs +++ b/os/src/syscall.rs @@ -1,13 +1,16 @@ use crate::context::TrapFrame; use crate::process; +pub const SYS_FORK: usize = 57; +pub const SYS_READ: usize = 63; pub const SYS_WRITE: usize = 64; pub const SYS_EXIT: usize = 93; -pub const SYS_READ: usize = 63; pub const SYS_EXEC: usize = 221; pub fn syscall(id: usize, args: [usize; 3], tf: &mut TrapFrame) -> isize { match id { + SYS_FORK => sys_fork(tf), + SYS_READ => sys_read(args[0], args[1] as *mut u8, args[2]), SYS_WRITE => { print!("{}", args[0] as u8 as char); 0 @@ -16,7 +19,6 @@ pub fn syscall(id: usize, args: [usize; 3], tf: &mut TrapFrame) -> isize { sys_exit(args[0]); 0 } - SYS_READ => sys_read(args[0], args[1] as *mut u8, args[2]), SYS_EXEC => sys_exec(args[0] as *const u8), _ => { panic!("unknown syscall id {}", id); @@ -24,6 +26,13 @@ pub fn syscall(id: usize, args: [usize; 3], tf: &mut TrapFrame) -> isize { } } +fn sys_fork(tf: &mut TrapFrame) -> isize { + println!("forking"); + let new_thread = process::current_thread().fork(tf); + let tid = process::add_thread(new_thread); + tid as isize +} + fn sys_exit(code: usize) { process::exit(code); } diff --git a/usr/rust/src/bin/fork.rs b/usr/rust/src/bin/fork.rs new file mode 100644 index 0000000..8882499 --- /dev/null +++ b/usr/rust/src/bin/fork.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +#[macro_use] +extern crate user; + +use user::syscall::sys_fork; + +#[no_mangle] +pub fn main() -> usize { + let tid = sys_fork(); + if tid == 0 { + println!("I am child"); + } else { + println!("I am father"); + } + println!("ret tid is: {}", tid); + 0 +} diff --git a/usr/rust/src/syscall.rs b/usr/rust/src/syscall.rs index afadc6d..6e774f9 100644 --- a/usr/rust/src/syscall.rs +++ b/usr/rust/src/syscall.rs @@ -1,4 +1,5 @@ enum SyscallId { + Fork = 57, Read = 63, Write = 64, Exit = 93, @@ -21,6 +22,10 @@ fn sys_call(syscall_id: SyscallId, arg0: usize, arg1: usize, arg2: usize, arg3: ret } +pub fn sys_fork() -> i64 { + sys_call(SyscallId::Fork, 0, 0, 0, 0) +} + pub fn sys_write(ch: u8) -> i64 { sys_call(SyscallId::Write, ch as usize, 0, 0, 0) } From 4b3d44e1602baa750370fc658d15235d9e35e33b Mon Sep 17 00:00:00 2001 From: deathwish5 Date: Tue, 11 Feb 2020 22:32:29 +0800 Subject: [PATCH 02/13] finish sys_exec --- os/src/context.rs | 35 +++++++++++++++++++++++++++++++ os/src/process/structs.rs | 11 ++++++---- os/src/syscall.rs | 38 ++++++++++++++++++++++++++++------ usr/rust/src/bin/user_shell.rs | 10 ++++++--- 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/os/src/context.rs b/os/src/context.rs index 984e265..8646109 100644 --- a/os/src/context.rs +++ b/os/src/context.rs @@ -12,6 +12,41 @@ pub struct TrapFrame { pub scause: Scause, // Scause register: record the cause of exception/interrupt/trap } +impl TrapFrame { + /// Constructs TrapFrame for a new kernel thread. + /// + /// The new thread starts at function `entry` with an usize argument `arg`. + /// The stack pointer will be set to `sp`. + fn new_kernel_thread(entry: extern "C" fn(usize) -> !, arg: usize, sp: usize) -> Self { + use core::mem::zeroed; + let mut tf: Self = unsafe { zeroed() }; + tf.x[10] = arg; // a0 + tf.x[2] = sp; + tf.sepc = entry as usize; + tf.sstatus = sstatus::read(); + tf.sstatus.set_spie(true); + tf.sstatus.set_sie(false); + tf.sstatus.set_spp(sstatus::SPP::Supervisor); + tf + } + + /// Constructs TrapFrame for a new user thread. + /// + /// The new thread starts at `entry_addr`. + /// The stack pointer will be set to `sp`. + pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + use core::mem::zeroed; + let mut tf: Self = unsafe { zeroed() }; + tf.x[2] = sp; + tf.sepc = entry_addr; + tf.sstatus = sstatus::read(); + tf.sstatus.set_spie(true); + tf.sstatus.set_sie(false); + tf.sstatus.set_spp(sstatus::SPP::User); + tf + } +} + #[repr(C)] #[derive(Clone)] pub struct Context { diff --git a/os/src/process/structs.rs b/os/src/process/structs.rs index 6c97f13..8ac4d81 100644 --- a/os/src/process/structs.rs +++ b/os/src/process/structs.rs @@ -64,13 +64,11 @@ impl Thread { } } - pub unsafe fn new_user(data: &[u8], wait_thread: Option) -> Box { + pub unsafe fn new_user_vm(data: &[u8]) -> (MemorySet, usize, usize) { let elf = ElfFile::new(data).expect("failed to analyse elf!"); match elf.header.pt2.type_().as_type() { - header::Type::Executable => { - // println!("it really a executable!"); - } + header::Type::Executable => {} header::Type::SharedObject => { panic!("shared object is not supported!"); } @@ -93,6 +91,11 @@ impl Thread { ); ustack_top }; + (vm, entry_addr, ustack_top) + } + + pub unsafe fn new_user(data: &[u8], wait_thread: Option) -> Box { + let (vm, entry_addr, ustack_top) = unsafe { Self::new_user_vm(data) }; let kstack = KernelStack::new(); diff --git a/os/src/syscall.rs b/os/src/syscall.rs index a4c1e35..0697c87 100644 --- a/os/src/syscall.rs +++ b/os/src/syscall.rs @@ -1,6 +1,9 @@ use crate::context::TrapFrame; use crate::process; +use crate::fs::{INodeExt, ROOT_INODE}; +use crate::process::structs::Thread; + pub const SYS_FORK: usize = 57; pub const SYS_READ: usize = 63; pub const SYS_WRITE: usize = 64; @@ -19,7 +22,7 @@ pub fn syscall(id: usize, args: [usize; 3], tf: &mut TrapFrame) -> isize { sys_exit(args[0]); 0 } - SYS_EXEC => sys_exec(args[0] as *const u8), + SYS_EXEC => sys_exec(args[0] as *const u8, tf), _ => { panic!("unknown syscall id {}", id); } @@ -50,10 +53,33 @@ pub unsafe fn from_cstr(s: *const u8) -> &'static str { str::from_utf8(slice::from_raw_parts(s, len)).unwrap() } -fn sys_exec(path: *const u8) -> isize { - let valid = process::execute(unsafe { from_cstr(path) }, Some(process::current_tid())); - if valid { - process::yield_now(); +// fn sys_exec(path: *const u8) -> isize { +// let valid = process::execute(unsafe { from_cstr(path) }, Some(process::current_tid())); +// if valid { +// process::yield_now(); +// } +// return 0; +// } + +fn sys_exec(path: *const u8, tf: &mut TrapFrame) -> isize { + let exec_path = unsafe { from_cstr(path) }; + let find_result = ROOT_INODE.lookup(exec_path); + match find_result { + Ok(inode) => { + let data = inode.read_as_vec().unwrap(); + let (mut vm, entry_addr, ustack_top) = unsafe { Thread::new_user_vm(data.as_slice()) }; + let proc = process::current_thread(); + core::mem::swap(&mut *proc.vm.as_ref().unwrap().lock(), &mut vm); + unsafe { + proc.vm.as_ref().unwrap().lock().activate(); + } + drop(proc); + *tf = TrapFrame::new_user_thread(entry_addr, ustack_top); + 0 + } + Err(_) => { + println!("exec error! cannot find the program {}", exec_path); + -1 + } } - return 0; } diff --git a/usr/rust/src/bin/user_shell.rs b/usr/rust/src/bin/user_shell.rs index 7c565d7..cb8c1c4 100644 --- a/usr/rust/src/bin/user_shell.rs +++ b/usr/rust/src/bin/user_shell.rs @@ -11,11 +11,11 @@ const CR: u8 = 0x0du8; use alloc::string::String; use user::io::getc; -use user::syscall::sys_exec; +use user::syscall::{sys_exec, sys_fork}; #[no_mangle] pub fn main() { - println!("Rust user shell"); + println!("Rust user shell v2.0"); let mut line: String = String::new(); print!(">> "); loop { @@ -25,7 +25,11 @@ pub fn main() { println!(""); if !line.is_empty() { println!("searching for program {}", line); - sys_exec(line.as_ptr()); + if (sys_fork() == 0) { + sys_exec(line.as_ptr()); + panic!("should not arrive here!"); + } + // sys_exec(line.as_ptr()); line.clear(); } print!(">> "); From 920445f4f0d496fc93bfc85dbefa0ae417a5ac04 Mon Sep 17 00:00:00 2001 From: deathwish5 Date: Wed, 12 Feb 2020 15:33:36 +0800 Subject: [PATCH 03/13] double fork error --- usr/rust/src/bin/exec.rs | 17 +++++++++++++++++ usr/rust/src/bin/user_shell.rs | 8 +++++--- 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 usr/rust/src/bin/exec.rs diff --git a/usr/rust/src/bin/exec.rs b/usr/rust/src/bin/exec.rs new file mode 100644 index 0000000..a3f877b --- /dev/null +++ b/usr/rust/src/bin/exec.rs @@ -0,0 +1,17 @@ + +#![no_std] +#![no_main] + +extern crate alloc; + +#[macro_use] +extern crate user; + +use user::syscall::sys_exec; + +#[no_mangle] +pub fn main() -> usize { + sys_fork(); + sys_fork(); + 0 +} \ No newline at end of file diff --git a/usr/rust/src/bin/user_shell.rs b/usr/rust/src/bin/user_shell.rs index cb8c1c4..e1a2c97 100644 --- a/usr/rust/src/bin/user_shell.rs +++ b/usr/rust/src/bin/user_shell.rs @@ -11,11 +11,11 @@ const CR: u8 = 0x0du8; use alloc::string::String; use user::io::getc; -use user::syscall::{sys_exec, sys_fork}; +use user::syscall::{sys_exec, sys_fork, sys_exit}; #[no_mangle] pub fn main() { - println!("Rust user shell v2.0"); + println!("Rust user shell v3.0"); let mut line: String = String::new(); print!(">> "); loop { @@ -26,9 +26,11 @@ pub fn main() { if !line.is_empty() { println!("searching for program {}", line); if (sys_fork() == 0) { + println!("this is child program."); sys_exec(line.as_ptr()); - panic!("should not arrive here!"); + sys_exit(0); } + println!("this is parent program"); // sys_exec(line.as_ptr()); line.clear(); } From a763d89d396ef57c3fe8c73a303ea80d678c2d48 Mon Sep 17 00:00:00 2001 From: deathwish5 Date: Wed, 12 Feb 2020 16:46:55 +0800 Subject: [PATCH 04/13] adjust Makefile to automaticly recompile usr programs --- usr/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/Makefile b/usr/Makefile index 09aac95..e54082f 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -15,7 +15,7 @@ ifeq ($(shell which rcore-fs-fuse),) @cargo install rcore-fs-fuse --git https://github.com/rcore-os/rcore-fs --rev d8d61190 endif -rust: +rust: $(rust_srcs) @cd rust && cargo build @echo targets includes $(rust_targets) @rm -rf $(out_dir)/rust && mkdir -p $(out_dir)/rust From 7d86efab44bfffc51f8c90ca6c9ef1c300818fda Mon Sep 17 00:00:00 2001 From: shinbokuow Date: Mon, 10 Feb 2020 09:16:41 +0800 Subject: [PATCH 05/13] virtio_disk found, todo: implement kvmpa --- os/Makefile | 4 +- os/src/drivers/mod.rs | 1 + os/src/drivers/virtio_disk.rs | 243 ++++++++++++++++++++++++++++++++ os/src/init.rs | 1 + os/src/lib.rs | 1 + os/src/memory/memory_set/mod.rs | 12 ++ os/src/memory/mod.rs | 25 ++-- 7 files changed, 272 insertions(+), 15 deletions(-) create mode 100644 os/src/drivers/mod.rs create mode 100644 os/src/drivers/virtio_disk.rs diff --git a/os/Makefile b/os/Makefile index aa394b0..5a17e44 100644 --- a/os/Makefile +++ b/os/Makefile @@ -34,6 +34,8 @@ qemu: build -machine virt \ -nographic \ -bios default \ - -device loader,file=$(bin),addr=0x80200000 + -device loader,file=$(bin),addr=0x80200000 \ + -drive file=../usr/build/riscv64.img,if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 run: build qemu diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs new file mode 100644 index 0000000..2fdb50b --- /dev/null +++ b/os/src/drivers/mod.rs @@ -0,0 +1 @@ +pub mod virtio_disk; diff --git a/os/src/drivers/virtio_disk.rs b/os/src/drivers/virtio_disk.rs new file mode 100644 index 0000000..33c6a62 --- /dev/null +++ b/os/src/drivers/virtio_disk.rs @@ -0,0 +1,243 @@ +use crate::memory::{ + access_pa_via_va, + get_pa_via_va +}; +use spin::Mutex; +use crate::consts::PAGE_SIZE; +const VIRTIO_MMIO_0: usize = 0x10001000; +const VIRTIO_MMIO_MAGIC_VALUE: usize = 0x000; +const VIRTIO_MMIO_VERSION: usize = 0x004; +const VIRTIO_MMIO_DEVICE_ID: usize = 0x008; +const VIRTIO_MMIO_VENDOR_ID: usize = 0x00c; +const VIRTIO_MMIO_DEVICE_FEATURES: usize = 0x010; +const VIRTIO_MMIO_DRIVER_FEATURES: usize = 0x020; +const VIRTIO_MMIO_GUEST_PAGE_SIZE: usize = 0x028; +const VIRTIO_MMIO_QUEUE_SEL: usize = 0x030; +const VIRTIO_MMIO_QUEUE_NUM_MAX: usize = 0x034; +const VIRTIO_MMIO_QUEUE_NUM: usize = 0x038; +const VIRTIO_MMIO_QUEUE_ALIGH: usize = 0x03c; +const VIRTIO_MMIO_QUEUE_PFN: usize = 0x040; +const VIRTIO_MMIO_QUEUE_READY: usize = 0x044; +const VIRTIO_MMIO_QUEUE_NOTIFY: usize = 0x050; +const VIRTIO_MMIO_INTERRUPT_STATUS: usize = 0x060; +const VIRTIO_MMIO_INTERRUPT_ACK: usize = 0x064; +const VIRTIO_MMIO_STATUS: usize = 0x070; + +const VIRTIO_MMIO_MAGIC_NUMBER: u32 = 0x74726976; +const VIRTIO_MMIO_VENDOR_NUMBER: u32 = 0x554d4551; + +// VIRTIO_MMIO_STATUS register bits +const VIRTIO_CONFIG_S_ACKNOWLEDGE: u32 = 1; +const VIRTIO_CONFIG_S_DRIVER: u32 = 1; +const VIRTIO_CONFIG_S_DRIVER_OK: u32 = 4; +const VIRTIO_CONFIG_S_FEATURES_OK: u32 = 8; + +// device feature bits +const VIRTIO_BLK_F_RO: usize = 5; +const VIRTIO_BLK_F_SCSI: usize = 7; +const VIRTIO_BLK_F_CONFIG_WCE: usize = 11; +const VIRTIO_BLK_F_MQ: usize = 12; +const VIRTIO_F_ANY_LAYOUT: usize = 27; +const VIRTIO_RING_F_INDIRECT_DESC: usize = 28; +const VIRTIO_RING_F_EVENT_IDX: usize = 29; + +const NUM: usize = 8; + +fn get_reg(offset: usize) -> *mut T { + let p = access_pa_via_va(VIRTIO_MMIO_0 + offset); + p as *mut T +} +fn reg_read(offset: usize) -> T where T: Copy{ + unsafe { + let p = get_reg::(offset); + *p + } +} +fn reg_write(offset: usize, v: T) { + unsafe { + let p = get_reg::(offset); + *p = v; + } +} + +#[repr(C)] +struct VRingDesc { + addr: u64, + len: u32, + flags: u16, + next: u16, +} +const VRING_DESC_F_NEXT: u16 = 1; +const VRING_DESC_F_WRITE: u16 = 2; + +#[repr(C)] +struct VRingUsedElem { + id: u32, + len: u32, +} + +const VIRTIO_BLK_T_IN: usize = 0; // read the disk +const VIRTIO_BLK_T_OUT: usize = 1; // write the disk + +#[repr(C)] +struct UsedArea { + flags: u16, + id: u16, + elems: [VRingUsedElem; NUM], +} + +#[repr(C)] +#[repr(align(4096))] +struct VirtioDisk { + pages: [u8; 2 * PAGE_SIZE], + free: [u8; NUM], + used_idx: u16, + init: bool, +} + +#[repr(C)] +struct Buf { + blockno: u64, + data: [u8; 512], +} + +#[repr(C)] +struct VirtioBlockOuthdr { + op: u32, + reserved: u32, + sector: u64, +} + +static DISK: Mutex = Mutex::new(VirtioDisk { + pages: [0; 2 * PAGE_SIZE], + free: [0; NUM], + used_idx: 0, + init: false, +}); + +impl VirtioDisk { + fn get_desc_array(&mut self) -> &mut [VRingDesc] { + unsafe { core::slice::from_raw_parts_mut(&mut self.pages[0] as *mut u8 as *mut VRingDesc, NUM) } + } + + fn get_avail_array(&mut self) -> &mut [u16] { + let desc = self.get_desc_array(); + let avail = &mut desc[0] as *mut VRingDesc as usize + NUM * core::mem::size_of::(); + unsafe { core::slice::from_raw_parts_mut(avail as *mut u16, NUM) } + } + + fn get_used_array(&mut self) -> &mut [UsedArea] { + unsafe { core::slice::from_raw_parts_mut(&mut self.pages[PAGE_SIZE] as *mut u8 as *mut UsedArea, NUM) } + } + + fn alloc_desc(&mut self) -> i32 { + let p = (0..NUM).filter(|i| self.free[*i] == 1).next(); + if let Some(a) = p { + self.free[a] = 0; + a as i32 + } else { + -1 + } + } + + fn free_desc(&mut self, i: usize) { + assert!(i < NUM, "free_desc intr 1"); + assert!(self.free[i] == 0, "free_desc intr 2"); + let desc_array = self.get_desc_array(); + desc_array[i].addr = 0; + self.free[i] = 1; + // wakeup? + } + + fn free_chain(&mut self, i: usize) { + //let desc_array = self.get_desc_array(); + let desc_array = unsafe { core::slice::from_raw_parts_mut(&mut self.pages[0] as *mut u8 as *mut VRingDesc, NUM) }; + let mut p: usize = i; + loop { + assert!(p < NUM, "free_chain intr 1"); + assert!(self.free[p] == 0, "free_desc intr 2"); + desc_array[p].addr = 0; + self.free[p] = 1; + if desc_array[p].flags & VRING_DESC_F_NEXT != 0 { + p = desc_array[p].next as usize; + } else { + break; + } + } + } + + fn alloc_3desc(&mut self, idx: &mut[usize; 3]) -> i32 { + for i in 0..3 { + let id = self.alloc_desc(); + if id < 0 { + for j in 0..i { + self.free_desc(idx[j]); + } + return -1; + } else { + idx[i] = id as usize; + } + } + 0 + } + + fn virtio_disk_rw(&mut self, buf: &Buf, bool write) { + u64 sector = buf.blockno; + let mut idx: [usize; 3] = [0; 3]; + assert!(self.alloc_3desc(&mut idx) == 0); // assuming desc space is sufficient + let virtio_hdr = VirtioBlockOuthdr { + op: if write { VIRTIO_BLK_T_OUT } else { VIRTIO_BLK_T_IN }, + reserved: 0, + sector, + }; + + } +} + + +pub fn init() { + assert_eq!(reg_read::(VIRTIO_MMIO_MAGIC_VALUE), VIRTIO_MMIO_MAGIC_NUMBER, "magic is wrong!"); + assert_eq!(reg_read::(VIRTIO_MMIO_VERSION), 0x1, "not legacy ver of virtio!"); + assert_eq!(reg_read::(VIRTIO_MMIO_DEVICE_ID), 0x2, "not virtio_blk device!"); + assert_eq!(reg_read::(VIRTIO_MMIO_VENDOR_ID), VIRTIO_MMIO_VENDOR_NUMBER, "vendor id is wrong!"); + println!("virtio_disk found!"); + + let mut status: u32 = 0; + + status |= VIRTIO_CONFIG_S_ACKNOWLEDGE; + reg_write::(VIRTIO_MMIO_STATUS, status); + + status |= VIRTIO_CONFIG_S_DRIVER; + reg_write::(VIRTIO_MMIO_STATUS, status); + + let mut features: u32 = reg_read::(VIRTIO_MMIO_DEVICE_FEATURES); + features ^= 1 << VIRTIO_BLK_F_RO; + features ^= 1 << VIRTIO_BLK_F_SCSI; + features ^= 1 << VIRTIO_BLK_F_CONFIG_WCE; + features ^= 1 << VIRTIO_BLK_F_MQ; + features ^= 1 << VIRTIO_F_ANY_LAYOUT; + features ^= 1 << VIRTIO_RING_F_EVENT_IDX; + features ^= 1 << VIRTIO_RING_F_INDIRECT_DESC; + reg_write::(VIRTIO_MMIO_DEVICE_FEATURES, features); + + status |= VIRTIO_CONFIG_S_FEATURES_OK; + reg_write::(VIRTIO_MMIO_STATUS, status); + + status |= VIRTIO_CONFIG_S_DRIVER_OK; + reg_write::(VIRTIO_MMIO_STATUS, status); + + reg_write::(VIRTIO_MMIO_GUEST_PAGE_SIZE, PAGE_SIZE as u32); + + let mut disk = DISK.lock(); + reg_write::(VIRTIO_MMIO_QUEUE_SEL, 0u32); + let max = reg_read::(VIRTIO_MMIO_QUEUE_NUM_MAX); + assert!(max > 0, "virtio disk has no virtqueue 0!"); + assert!(max >= NUM as u32, "virtqueue max size is too small!"); + reg_write::(VIRTIO_MMIO_QUEUE_NUM, NUM as u32); + reg_write::(VIRTIO_MMIO_QUEUE_PFN, (get_pa_via_va(&disk.pages[0] as *const u8 as usize) / PAGE_SIZE) as u32); + + for i in 0..NUM { + disk.free[i] = 1; + } + disk.init = true; +} diff --git a/os/src/init.rs b/os/src/init.rs index d94231d..9b5e22a 100644 --- a/os/src/init.rs +++ b/os/src/init.rs @@ -14,6 +14,7 @@ pub extern "C" fn rust_main() -> ! { PHYSICAL_MEMORY_END >> 12, ); crate::interrupt::init(); + crate::drivers::virtio_disk::init(); crate::fs::init(); crate::process::init(); crate::timer::init(); diff --git a/os/src/lib.rs b/os/src/lib.rs index ad61357..a124c0d 100644 --- a/os/src/lib.rs +++ b/os/src/lib.rs @@ -21,3 +21,4 @@ mod sbi; mod sync; mod syscall; mod timer; +mod drivers; diff --git a/os/src/memory/memory_set/mod.rs b/os/src/memory/memory_set/mod.rs index 7e2ade6..c12875f 100644 --- a/os/src/memory/memory_set/mod.rs +++ b/os/src/memory/memory_set/mod.rs @@ -106,6 +106,18 @@ impl MemorySet { None, ); } + pub fn push_mmio(&mut self, l: usize, r: usize) { + // check alignment + assert!(l & (PAGE_SIZE - 1) == 0); + assert!(r & (PAGE_SIZE - 1) == 0); + self.push( + access_pa_via_va(l), + access_pa_via_va(r), + MemoryAttr::new(), + Linear::new(PHYSICAL_MEMORY_OFFSET), + None, + ); + } pub fn token(&self) -> usize { self.page_table.token() } diff --git a/os/src/memory/mod.rs b/os/src/memory/mod.rs index c32246b..68187c8 100644 --- a/os/src/memory/mod.rs +++ b/os/src/memory/mod.rs @@ -39,6 +39,10 @@ fn init_heap() { pub fn access_pa_via_va(pa: usize) -> usize { pa + PHYSICAL_MEMORY_OFFSET } +// only works for pa in main memory +pub fn get_pa_via_va(va: usize) -> usize { + va - PHYSICAL_MEMORY_OFFSET +} pub fn kernel_remap() { let mut memory_set = MemorySet::new(); @@ -54,20 +58,13 @@ pub fn kernel_remap() { Linear::new(PHYSICAL_MEMORY_OFFSET), None, ); - memory_set.push( - access_pa_via_va(0x0c00_2000), - access_pa_via_va(0x0c00_3000), - MemoryAttr::new(), - Linear::new(PHYSICAL_MEMORY_OFFSET), - None, - ); - memory_set.push( - access_pa_via_va(0x1000_0000), - access_pa_via_va(0x1000_1000), - MemoryAttr::new(), - Linear::new(PHYSICAL_MEMORY_OFFSET), - None, - ); + // PLIC for RISC-V virt machine + memory_set.push_mmio(0x0c00_2000, 0x0c00_3000); + // 16550a UART for RISC-V virt machine + memory_set.push_mmio(0x1000_0000, 0x1000_1000); + // VIRTIO0 for RISC-V virt machine + memory_set.push_mmio(0x1000_1000, 0x1000_2000); + unsafe { memory_set.activate(); From 36811ba7b8462e5c4a7b12eaa82d69c6377c80ab Mon Sep 17 00:00:00 2001 From: shinbokuow Date: Tue, 11 Feb 2020 11:08:08 +0800 Subject: [PATCH 06/13] virtio-disk block I/O test passed --- os/src/drivers/virtio_disk.rs | 187 +++++++++++++++++++++++++++++----- os/src/interrupt.rs | 38 ++++++- os/src/memory/mod.rs | 2 + os/src/memory/paging.rs | 15 +++ os/src/process/mod.rs | 4 +- os/src/sync/condvar.rs | 4 + 6 files changed, 219 insertions(+), 31 deletions(-) diff --git a/os/src/drivers/virtio_disk.rs b/os/src/drivers/virtio_disk.rs index 33c6a62..a05c383 100644 --- a/os/src/drivers/virtio_disk.rs +++ b/os/src/drivers/virtio_disk.rs @@ -1,9 +1,14 @@ use crate::memory::{ access_pa_via_va, - get_pa_via_va + get_pa_via_va, + paging }; use spin::Mutex; -use crate::consts::PAGE_SIZE; +use crate::consts::{ + PAGE_SIZE, + PHYSICAL_MEMORY_OFFSET +}; +use crate::sync::condvar; const VIRTIO_MMIO_0: usize = 0x10001000; const VIRTIO_MMIO_MAGIC_VALUE: usize = 0x000; const VIRTIO_MMIO_VERSION: usize = 0x004; @@ -15,7 +20,7 @@ const VIRTIO_MMIO_GUEST_PAGE_SIZE: usize = 0x028; const VIRTIO_MMIO_QUEUE_SEL: usize = 0x030; const VIRTIO_MMIO_QUEUE_NUM_MAX: usize = 0x034; const VIRTIO_MMIO_QUEUE_NUM: usize = 0x038; -const VIRTIO_MMIO_QUEUE_ALIGH: usize = 0x03c; +const VIRTIO_MMIO_QUEUE_ALIGN: usize = 0x03c; const VIRTIO_MMIO_QUEUE_PFN: usize = 0x040; const VIRTIO_MMIO_QUEUE_READY: usize = 0x044; const VIRTIO_MMIO_QUEUE_NOTIFY: usize = 0x050; @@ -28,7 +33,7 @@ const VIRTIO_MMIO_VENDOR_NUMBER: u32 = 0x554d4551; // VIRTIO_MMIO_STATUS register bits const VIRTIO_CONFIG_S_ACKNOWLEDGE: u32 = 1; -const VIRTIO_CONFIG_S_DRIVER: u32 = 1; +const VIRTIO_CONFIG_S_DRIVER: u32 = 2; const VIRTIO_CONFIG_S_DRIVER_OK: u32 = 4; const VIRTIO_CONFIG_S_FEATURES_OK: u32 = 8; @@ -76,8 +81,8 @@ struct VRingUsedElem { len: u32, } -const VIRTIO_BLK_T_IN: usize = 0; // read the disk -const VIRTIO_BLK_T_OUT: usize = 1; // write the disk +const VIRTIO_BLK_T_IN: u32 = 0; // read the disk +const VIRTIO_BLK_T_OUT: u32 = 1; // write the disk #[repr(C)] struct UsedArea { @@ -86,6 +91,22 @@ struct UsedArea { elems: [VRingUsedElem; NUM], } +#[repr(C)] +pub struct Buf { + blockno: u64, + data: [u8; 512], + disk: u8, + // sleep_lock: condvar::Condvar, + completed: bool, +} + +#[repr(C)] +#[derive(Clone,Copy)] +struct BufInfo { + buf: usize, // va of struct Buf + status: u8, +} + #[repr(C)] #[repr(align(4096))] struct VirtioDisk { @@ -93,12 +114,7 @@ struct VirtioDisk { free: [u8; NUM], used_idx: u16, init: bool, -} - -#[repr(C)] -struct Buf { - blockno: u64, - data: [u8; 512], + buf_info: [BufInfo; NUM], } #[repr(C)] @@ -113,6 +129,7 @@ static DISK: Mutex = Mutex::new(VirtioDisk { free: [0; NUM], used_idx: 0, init: false, + buf_info: [BufInfo { buf: 0, status: 0 }; NUM], }); impl VirtioDisk { @@ -123,11 +140,12 @@ impl VirtioDisk { fn get_avail_array(&mut self) -> &mut [u16] { let desc = self.get_desc_array(); let avail = &mut desc[0] as *mut VRingDesc as usize + NUM * core::mem::size_of::(); - unsafe { core::slice::from_raw_parts_mut(avail as *mut u16, NUM) } + unsafe { core::slice::from_raw_parts_mut(avail as *mut u16, NUM + 2) } } - fn get_used_array(&mut self) -> &mut [UsedArea] { - unsafe { core::slice::from_raw_parts_mut(&mut self.pages[PAGE_SIZE] as *mut u8 as *mut UsedArea, NUM) } + fn get_used(&mut self) -> &mut UsedArea { + let slice = unsafe { core::slice::from_raw_parts_mut(&mut self.pages[PAGE_SIZE] as *mut u8 as *mut UsedArea, 1) }; + &mut slice[0] } fn alloc_desc(&mut self) -> i32 { @@ -146,7 +164,6 @@ impl VirtioDisk { let desc_array = self.get_desc_array(); desc_array[i].addr = 0; self.free[i] = 1; - // wakeup? } fn free_chain(&mut self, i: usize) { @@ -154,6 +171,7 @@ impl VirtioDisk { let desc_array = unsafe { core::slice::from_raw_parts_mut(&mut self.pages[0] as *mut u8 as *mut VRingDesc, NUM) }; let mut p: usize = i; loop { + // println!("p = {}", p); assert!(p < NUM, "free_chain intr 1"); assert!(self.free[p] == 0, "free_desc intr 2"); desc_array[p].addr = 0; @@ -164,6 +182,7 @@ impl VirtioDisk { break; } } + // println!("free_chain exited!"); } fn alloc_3desc(&mut self, idx: &mut[usize; 3]) -> i32 { @@ -181,8 +200,8 @@ impl VirtioDisk { 0 } - fn virtio_disk_rw(&mut self, buf: &Buf, bool write) { - u64 sector = buf.blockno; + fn virtio_disk_issue(&mut self, buf: &mut Buf, write: bool) -> usize { + let sector: u64 = buf.blockno; let mut idx: [usize; 3] = [0; 3]; assert!(self.alloc_3desc(&mut idx) == 0); // assuming desc space is sufficient let virtio_hdr = VirtioBlockOuthdr { @@ -191,9 +210,85 @@ impl VirtioDisk { sector, }; + self.buf_info[idx[0]].buf = buf as *const _ as usize; + self.buf_info[idx[0]].status = 0xf; + let buf_status_va = &self.buf_info[idx[0]].status as *const _ as usize; + + let desc_array = self.get_desc_array(); + desc_array[idx[0]] = VRingDesc { + addr: paging::PageTableImpl::kvmpa(&virtio_hdr as *const _ as usize) as u64, + len: core::mem::size_of::() as u32, + flags: VRING_DESC_F_NEXT, + next: idx[1] as u16 + }; + desc_array[idx[1]] = VRingDesc { + addr: paging::PageTableImpl::kvmpa(&buf.data[0] as *const _ as usize) as u64, + len: 512, + flags: if write { VRING_DESC_F_NEXT } else { VRING_DESC_F_NEXT | VRING_DESC_F_WRITE }, + next: idx[2] as u16 + }; + desc_array[idx[2]] = VRingDesc { + addr: paging::PageTableImpl::kvmpa(buf_status_va) as u64, + len: 1, + flags: VRING_DESC_F_WRITE, + next: 0 + }; + + let avail_array = self.get_avail_array(); + avail_array[2 + avail_array[1] as usize % NUM] = idx[0] as u16; + compiler_memory_barrier(); + avail_array[1] += 1; + compiler_memory_barrier(); + // assert!(avail_array[1] >= 1 && avail_array[1 + avail_array[1] as usize % NUM] == idx[0] as u16, "memory barrier issue!"); + + buf.disk = 1; + + reg_write::(VIRTIO_MMIO_QUEUE_NOTIFY, 0x0); + + idx[0] + } + + fn virtio_disk_clean(&mut self, idx: usize) { + self.buf_info[idx].buf = 0; + self.free_chain(idx); + } + + fn virtio_disk_intr(&mut self) { + // println!("into virtio_disk_intr inside!"); + let slice = unsafe { core::slice::from_raw_parts_mut(&mut self.pages[PAGE_SIZE] as *mut u8 as *mut UsedArea, 1) }; + let used = &mut slice[0]; + let num: u16 = NUM as u16; + // println!("self.used_idx = {}", self.used_idx); + // println!("used.id = {}", used.id); + while self.used_idx % num != used.id % num { + let id: usize = used.elems[self.used_idx as usize].id as usize; + // println!("used_length = {}", used.elems[self.used_idx as usize].len); + assert!(self.buf_info[id].status == 0, "virtio_disk_intr status"); + let buf = unsafe { &mut *(self.buf_info[id].buf as *mut u8 as *mut Buf) }; + buf.disk = 0; + // println!("before notify!"); + // buf.sleep_lock.notify(); + buf.completed = true; + // println!("after notify!"); + self.used_idx = (self.used_idx + 1) % num; + } + // println!("exit virtio_disk_intr inside!"); } } +pub fn virtio_disk_rw(buf: &mut Buf, write: bool) { + let idx = DISK.lock().virtio_disk_issue(buf, write); + // println!("begin waiting..."); + // buf.sleep_lock.wait(); + loop { + if buf.completed { + break; + } + } + // println!("end waiting..."); + DISK.lock() + .virtio_disk_clean(idx); +} pub fn init() { assert_eq!(reg_read::(VIRTIO_MMIO_MAGIC_VALUE), VIRTIO_MMIO_MAGIC_NUMBER, "magic is wrong!"); @@ -211,13 +306,14 @@ pub fn init() { reg_write::(VIRTIO_MMIO_STATUS, status); let mut features: u32 = reg_read::(VIRTIO_MMIO_DEVICE_FEATURES); - features ^= 1 << VIRTIO_BLK_F_RO; - features ^= 1 << VIRTIO_BLK_F_SCSI; - features ^= 1 << VIRTIO_BLK_F_CONFIG_WCE; - features ^= 1 << VIRTIO_BLK_F_MQ; - features ^= 1 << VIRTIO_F_ANY_LAYOUT; - features ^= 1 << VIRTIO_RING_F_EVENT_IDX; - features ^= 1 << VIRTIO_RING_F_INDIRECT_DESC; + // println!("features = {:#x}", features); + features &= !(1 << VIRTIO_BLK_F_RO); + features &= !(1 << VIRTIO_BLK_F_SCSI); + features &= !(1 << VIRTIO_BLK_F_CONFIG_WCE); + features &= !(1 << VIRTIO_BLK_F_MQ); + features &= !(1 << VIRTIO_F_ANY_LAYOUT); + features &= !(1 << VIRTIO_RING_F_EVENT_IDX); + features &= !(1 << VIRTIO_RING_F_INDIRECT_DESC); reg_write::(VIRTIO_MMIO_DEVICE_FEATURES, features); status |= VIRTIO_CONFIG_S_FEATURES_OK; @@ -233,6 +329,9 @@ pub fn init() { let max = reg_read::(VIRTIO_MMIO_QUEUE_NUM_MAX); assert!(max > 0, "virtio disk has no virtqueue 0!"); assert!(max >= NUM as u32, "virtqueue max size is too small!"); + // assert!(reg_read::(VIRTIO_MMIO_QUEUE_ALIGN) == 4096, "virtqueue alignment {} != 4096!"); + // println!("virtqueue alignment = {}", reg_read::(VIRTIO_MMIO_QUEUE_ALIGN)); + reg_write::(VIRTIO_MMIO_QUEUE_ALIGN, 4096); reg_write::(VIRTIO_MMIO_QUEUE_NUM, NUM as u32); reg_write::(VIRTIO_MMIO_QUEUE_PFN, (get_pa_via_va(&disk.pages[0] as *const u8 as usize) / PAGE_SIZE) as u32); @@ -241,3 +340,41 @@ pub fn init() { } disk.init = true; } + +pub fn virtio_disk_intr() { + // println!("into virtio_disk_intr!"); + DISK.lock().virtio_disk_intr(); +} + +pub fn virtio_disk_test() { + // println!("into virtio_disk_test!"); + let mut buf = Buf { + blockno: 100, + data: [0; 512], + disk: 1, + // sleep_lock: condvar::Condvar::new(), + completed: false, + }; + for i in 0..256 { + buf.data[i] = i as u8; + } + virtio_disk_rw(&mut buf, true); + let mut chk_buf = Buf { + blockno: 100, + data: [0; 512], + disk: 1, + completed: false, + }; + virtio_disk_rw(&mut chk_buf, false); + for i in 0..256 { + assert_eq!(chk_buf.data[i], i as u8); + // println!("data[{}] = {}", i, chk_buf.data[i]); + } + println!("passed the disk I/O test!"); + loop {} +} + +fn compiler_memory_barrier() { + //no re-ordering of reads and writes across this point is allowed + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); +} diff --git a/os/src/interrupt.rs b/os/src/interrupt.rs index 1edeb16..578bcd4 100644 --- a/os/src/interrupt.rs +++ b/os/src/interrupt.rs @@ -34,7 +34,8 @@ pub fn init() { pub unsafe fn init_external_interrupt() { let HART0_S_MODE_INTERRUPT_ENABLES: *mut u32 = access_pa_via_va(0x0c00_2080) as *mut u32; const SERIAL: u32 = 0xa; - HART0_S_MODE_INTERRUPT_ENABLES.write_volatile(1 << SERIAL); + const VIRTIO0: u32 = 0x1; + HART0_S_MODE_INTERRUPT_ENABLES.write_volatile(1 << SERIAL | 1 << VIRTIO0); } pub unsafe fn enable_serial_interrupt() { @@ -43,8 +44,20 @@ pub unsafe fn enable_serial_interrupt() { UART16550.add(1).write_volatile(0x01); } +pub fn plic_claim() -> i32 { + let irq = access_pa_via_va(0x0c20_1004) as *const i32; + unsafe { *irq } +} + +pub fn plic_complete(irq: i32) { + unsafe { + *(access_pa_via_va(0x0c20_1004) as *mut i32) = irq; + } +} + #[no_mangle] pub fn rust_trap(tf: &mut TrapFrame) { + // println!("scause = {:#x}", tf.scause.bits()); match tf.scause.cause() { Trap::Exception(Exception::Breakpoint) => breakpoint(&mut tf.sepc), Trap::Interrupt(Interrupt::SupervisorTimer) => super_timer(), @@ -52,7 +65,7 @@ pub fn rust_trap(tf: &mut TrapFrame) { Trap::Exception(Exception::LoadPageFault) => page_fault(tf), Trap::Exception(Exception::StorePageFault) => page_fault(tf), Trap::Exception(Exception::UserEnvCall) => syscall(tf), - Trap::Interrupt(Interrupt::SupervisorExternal) => external(), + Trap::Interrupt(Interrupt::SupervisorExternal) => external(tf), _ => panic!("undefined trap!"), } } @@ -82,8 +95,25 @@ fn syscall(tf: &mut TrapFrame) { tf.x[10] = ret as usize; } -fn external() { - let _ = try_serial(); +fn external(tf: &mut TrapFrame) { + // println!("into external"); + if tf.scause.is_interrupt() && (tf.scause.bits() & 0xff == 0x9) { + // println!("supervisorExternal!"); + let irq = plic_claim(); + // println!("irq = {}", irq); + if irq == 0x01 { + crate::drivers::virtio_disk::virtio_disk_intr(); + } else if irq == 0x0a { + panic!("irq == 0x0a, uart found!"); + } else { + // println!("irq = {}", irq); + } + if irq > 0 { + plic_complete(irq); + } + } else { + let _ = try_serial(); + } } fn try_serial() -> bool { diff --git a/os/src/memory/mod.rs b/os/src/memory/mod.rs index 68187c8..a412495 100644 --- a/os/src/memory/mod.rs +++ b/os/src/memory/mod.rs @@ -65,6 +65,8 @@ pub fn kernel_remap() { // VIRTIO0 for RISC-V virt machine memory_set.push_mmio(0x1000_1000, 0x1000_2000); + memory_set.push_mmio(0x0c20_1000, 0x0c20_2000); + unsafe { memory_set.activate(); diff --git a/os/src/memory/paging.rs b/os/src/memory/paging.rs index 88d963d..0d7c4d6 100644 --- a/os/src/memory/paging.rs +++ b/os/src/memory/paging.rs @@ -103,6 +103,21 @@ impl PageTableImpl { } } + pub fn kvmpa(va: usize) -> usize { + let root_frame_ppn = Self::active_token() & ((1 << 44) - 1); + let root_frame_pa = root_frame_ppn << 12; + let table = unsafe { &mut *(access_pa_via_va(root_frame_pa) as *mut PageTableEntryArray) }; + let mut pageTable = PageTableImpl { + page_table: Rv39PageTable::new(table, PHYSICAL_MEMORY_OFFSET), + root_frame: Frame::of_addr(PhysAddr::new(root_frame_pa)), + entry: None, + }; + if let Some(pageEntry) = pageTable.get_entry(va) { + return pageEntry.target() + (va & (PAGE_SIZE - 1)); + } + panic!("in kvmpa, given va hasn't been mapped!"); + } + pub fn map(&mut self, va: usize, pa: usize) -> &mut PageEntry { let flags = EF::VALID | EF::READABLE | EF::WRITABLE; let page = Page::of_addr(VirtAddr::new(va)); diff --git a/os/src/process/mod.rs b/os/src/process/mod.rs index 882d392..a64fcf6 100644 --- a/os/src/process/mod.rs +++ b/os/src/process/mod.rs @@ -21,8 +21,8 @@ pub fn init() { let idle = Thread::new_kernel(Processor::idle_main as usize); idle.append_initial_arguments([&CPU as *const Processor as usize, 0, 0]); CPU.init(idle, Box::new(thread_pool)); - - execute("rust/user_shell", None); + CPU.add_thread(Thread::new_kernel(crate::drivers::virtio_disk::virtio_disk_test as usize)); + //execute("rust/user_shell", None); println!("++++ setup process! ++++"); } diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs index dc25b8a..14022f0 100644 --- a/os/src/sync/condvar.rs +++ b/os/src/sync/condvar.rs @@ -13,6 +13,7 @@ impl Condvar { } pub fn wait(&self) { + println!("tid_wait = {}", current_tid()); self.wait_queue.lock().push_back(current_tid()); yield_now(); } @@ -20,7 +21,10 @@ impl Condvar { pub fn notify(&self) { let tid = self.wait_queue.lock().pop_front(); if let Some(tid) = tid { + println!("tid_to_wake_up = {}", tid); wake_up(tid); + } else { + panic!("no threads to wake up!"); } /* yield_now(); */ } From e2c1758eae5794e8469245b7f10a6f74a52451a0 Mon Sep 17 00:00:00 2001 From: shinbokuow Date: Tue, 11 Feb 2020 18:51:57 +0800 Subject: [PATCH 07/13] TODO: deadlocks & still unsolved fs issues --- os/src/drivers/virtio_disk.rs | 51 +++++++++++++++++++++++++++++++-- os/src/fs/device.rs | 42 +++++++++++++++++++++++++++ os/src/fs/mod.rs | 5 ++++ os/src/interrupt.rs | 4 +-- os/src/memory/memory_set/mod.rs | 8 ++++++ os/src/memory/mod.rs | 9 ------ os/src/process/mod.rs | 9 ++++-- os/src/sync/condvar.rs | 4 +-- os/src/syscall.rs | 1 + usr/rust/src/bin/a_plus_b.rs | 15 ++++++++++ 10 files changed, 131 insertions(+), 17 deletions(-) create mode 100644 usr/rust/src/bin/a_plus_b.rs diff --git a/os/src/drivers/virtio_disk.rs b/os/src/drivers/virtio_disk.rs index a05c383..72679f6 100644 --- a/os/src/drivers/virtio_disk.rs +++ b/os/src/drivers/virtio_disk.rs @@ -9,6 +9,11 @@ use crate::consts::{ PHYSICAL_MEMORY_OFFSET }; use crate::sync::condvar; +use riscv::register::{ + sstatus, + sie +}; + const VIRTIO_MMIO_0: usize = 0x10001000; const VIRTIO_MMIO_MAGIC_VALUE: usize = 0x000; const VIRTIO_MMIO_VERSION: usize = 0x004; @@ -52,16 +57,22 @@ fn get_reg(offset: usize) -> *mut T { let p = access_pa_via_va(VIRTIO_MMIO_0 + offset); p as *mut T } + +#[no_mangle] fn reg_read(offset: usize) -> T where T: Copy{ unsafe { let p = get_reg::(offset); *p } } + +#[no_mangle] fn reg_write(offset: usize, v: T) { unsafe { let p = get_reg::(offset); + // println!("before reg_write!"); *p = v; + // println!("after reg_write!"); } } @@ -94,12 +105,23 @@ struct UsedArea { #[repr(C)] pub struct Buf { blockno: u64, - data: [u8; 512], + pub data: [u8; 512], disk: u8, // sleep_lock: condvar::Condvar, completed: bool, } +impl Buf { + pub fn new(blockno: u64) -> Self { + Buf { + blockno, + data: [0; 512], + disk: 0, + completed: false, + } + } +} + #[repr(C)] #[derive(Clone,Copy)] struct BufInfo { @@ -277,7 +299,21 @@ impl VirtioDisk { } pub fn virtio_disk_rw(buf: &mut Buf, write: bool) { - let idx = DISK.lock().virtio_disk_issue(buf, write); + // println!("virtio_disk_rw blockno = {}, write = {}", buf.blockno, write); + /* + let timer_enabled = sie::read().stimer(); + if timer_enabled { + unsafe { sie::clear_stimer(); } + } + */ + let intr_enabled = sstatus::read().sie(); + if !intr_enabled { + unsafe { sstatus::set_sie(); } + } + + let idx = DISK.lock() + .virtio_disk_issue(buf, write); + // println!("begin waiting..."); // buf.sleep_lock.wait(); loop { @@ -285,12 +321,23 @@ pub fn virtio_disk_rw(buf: &mut Buf, write: bool) { break; } } + /* + if timer_enabled { + unsafe { sie::set_stimer(); } + } + */ + if !intr_enabled { + unsafe { sstatus::clear_sie(); } + } + // println!("end waiting..."); DISK.lock() .virtio_disk_clean(idx); + // println!("virtio_disk_rw exit!"); } pub fn init() { + assert_eq!(reg_read::(VIRTIO_MMIO_MAGIC_VALUE), VIRTIO_MMIO_MAGIC_NUMBER, "magic is wrong!"); assert_eq!(reg_read::(VIRTIO_MMIO_VERSION), 0x1, "not legacy ver of virtio!"); assert_eq!(reg_read::(VIRTIO_MMIO_DEVICE_ID), 0x2, "not virtio_blk device!"); diff --git a/os/src/fs/device.rs b/os/src/fs/device.rs index ab2c42b..e800c8c 100644 --- a/os/src/fs/device.rs +++ b/os/src/fs/device.rs @@ -1,5 +1,6 @@ use rcore_fs::dev::*; use spin::RwLock; +use crate::drivers::virtio_disk; pub struct MemBuf(RwLock<&'static mut [u8]>); @@ -30,3 +31,44 @@ impl Device for MemBuf { Ok(()) } } + +pub struct Disk; +impl Disk { + pub fn new() -> Self { + Disk {} + } +} + +impl Device for Disk { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + // println!("read_at offset = {}, buf.len = {}", offset, buf.len()); + let b_sector = offset / 512; + let e_sector = (offset + buf.len() + 511) / 512; + let mut l = offset; + for sector in b_sector..e_sector { + let mut disk_buf = virtio_disk::Buf::new(sector as u64); + virtio_disk::virtio_disk_rw(&mut disk_buf, false); + let mut r = (l / 512 + 1) * 512; + r = core::cmp::min(r, offset + buf.len()); + buf[l - offset..r - offset] + .copy_from_slice(&disk_buf.data[l & 511..{ if r % 512 == 0 { 512 } else {r % 512} }]); + l = r; + } + Ok(buf.len()) + } + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + // println!("write_at offset = {}, buf.len = {}", offset, buf.len()); + assert!(offset % 512 == 0, "offset alignment panic!"); + assert!(buf.len() % 512 == 0, "buf length alignment panic!"); + for sector in offset / 512..(offset + buf.len()) / 512 { + let mut disk_buf = virtio_disk::Buf::new(sector as u64); + disk_buf.data[0..512] + .copy_from_slice(&buf[sector * 512 - offset..(sector + 1) * 512 - offset]); + virtio_disk::virtio_disk_rw(&mut disk_buf, true); + } + Ok(buf.len()) + } + fn sync(&self) -> Result<()> { + Ok(()) + } +} diff --git a/os/src/fs/mod.rs b/os/src/fs/mod.rs index abfc57b..922cb65 100644 --- a/os/src/fs/mod.rs +++ b/os/src/fs/mod.rs @@ -8,6 +8,7 @@ use rcore_fs_sfs::SimpleFileSystem; lazy_static! { pub static ref ROOT_INODE: Arc = { + /* let device = { extern "C" { fn _user_img_start(); @@ -17,6 +18,8 @@ lazy_static! { let end = _user_img_end as usize; Arc::new(unsafe { device::MemBuf::new(start, end) }) }; + */ + let device = Arc::new(device::Disk::new()); let sfs = SimpleFileSystem::open(device).expect("failed to open SFS"); sfs.root_inode() }; @@ -29,10 +32,12 @@ pub trait INodeExt { impl INodeExt for dyn INode { fn read_as_vec(&self) -> Result> { let size = self.metadata()?.size; + // println!("size = {}", size); let mut buf = Vec::with_capacity(size); unsafe { buf.set_len(size); } + // println!("begin read_at..."); self.read_at(0, buf.as_mut_slice())?; Ok(buf) } diff --git a/os/src/interrupt.rs b/os/src/interrupt.rs index 578bcd4..131efe8 100644 --- a/os/src/interrupt.rs +++ b/os/src/interrupt.rs @@ -104,7 +104,7 @@ fn external(tf: &mut TrapFrame) { if irq == 0x01 { crate::drivers::virtio_disk::virtio_disk_intr(); } else if irq == 0x0a { - panic!("irq == 0x0a, uart found!"); + try_serial(); } else { // println!("irq = {}", irq); } @@ -112,7 +112,7 @@ fn external(tf: &mut TrapFrame) { plic_complete(irq); } } else { - let _ = try_serial(); + panic!("unhandled external!"); } } diff --git a/os/src/memory/memory_set/mod.rs b/os/src/memory/memory_set/mod.rs index c12875f..0ba2263 100644 --- a/os/src/memory/memory_set/mod.rs +++ b/os/src/memory/memory_set/mod.rs @@ -105,6 +105,14 @@ impl MemorySet { Linear::new(offset), None, ); + // PLIC for RISC-V virt machine + self.push_mmio(0x0c00_2000, 0x0c00_3000); + // 16550a UART for RISC-V virt machine + self.push_mmio(0x1000_0000, 0x1000_1000); + // VIRTIO0 for RISC-V virt machine + self.push_mmio(0x1000_1000, 0x1000_2000); + + self.push_mmio(0x0c20_1000, 0x0c20_2000); } pub fn push_mmio(&mut self, l: usize, r: usize) { // check alignment diff --git a/os/src/memory/mod.rs b/os/src/memory/mod.rs index a412495..5cdf737 100644 --- a/os/src/memory/mod.rs +++ b/os/src/memory/mod.rs @@ -58,15 +58,6 @@ pub fn kernel_remap() { Linear::new(PHYSICAL_MEMORY_OFFSET), None, ); - // PLIC for RISC-V virt machine - memory_set.push_mmio(0x0c00_2000, 0x0c00_3000); - // 16550a UART for RISC-V virt machine - memory_set.push_mmio(0x1000_0000, 0x1000_1000); - // VIRTIO0 for RISC-V virt machine - memory_set.push_mmio(0x1000_1000, 0x1000_2000); - - memory_set.push_mmio(0x0c20_1000, 0x0c20_2000); - unsafe { memory_set.activate(); diff --git a/os/src/process/mod.rs b/os/src/process/mod.rs index a64fcf6..7e4b706 100644 --- a/os/src/process/mod.rs +++ b/os/src/process/mod.rs @@ -21,19 +21,24 @@ pub fn init() { let idle = Thread::new_kernel(Processor::idle_main as usize); idle.append_initial_arguments([&CPU as *const Processor as usize, 0, 0]); CPU.init(idle, Box::new(thread_pool)); - CPU.add_thread(Thread::new_kernel(crate::drivers::virtio_disk::virtio_disk_test as usize)); - //execute("rust/user_shell", None); + // CPU.add_thread(Thread::new_kernel(crate::drivers::virtio_disk::virtio_disk_test as usize)); + execute("rust/user_shell", None); println!("++++ setup process! ++++"); } pub fn execute(path: &str, host_tid: Option) -> bool { + // println!("before lookup!"); let find_result = ROOT_INODE.lookup(path); + // println!("after loopup!"); match find_result { Ok(inode) => { + // println!("Ok(inode)!"); let data = inode.read_as_vec().unwrap(); + // println!("ok data!"); let user_thread = unsafe { Thread::new_user(data.as_slice(), host_tid) }; CPU.add_thread(user_thread); + // println!("CPU.add_thread"); true } Err(_) => { diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs index 14022f0..169a042 100644 --- a/os/src/sync/condvar.rs +++ b/os/src/sync/condvar.rs @@ -13,7 +13,7 @@ impl Condvar { } pub fn wait(&self) { - println!("tid_wait = {}", current_tid()); + // println!("tid_wait = {}", current_tid()); self.wait_queue.lock().push_back(current_tid()); yield_now(); } @@ -21,7 +21,7 @@ impl Condvar { pub fn notify(&self) { let tid = self.wait_queue.lock().pop_front(); if let Some(tid) = tid { - println!("tid_to_wake_up = {}", tid); + // println!("tid_to_wake_up = {}", tid); wake_up(tid); } else { panic!("no threads to wake up!"); diff --git a/os/src/syscall.rs b/os/src/syscall.rs index a4c1e35..404c620 100644 --- a/os/src/syscall.rs +++ b/os/src/syscall.rs @@ -51,6 +51,7 @@ pub unsafe fn from_cstr(s: *const u8) -> &'static str { } fn sys_exec(path: *const u8) -> isize { + // println!("enter sys_exec!"); let valid = process::execute(unsafe { from_cstr(path) }, Some(process::current_tid())); if valid { process::yield_now(); diff --git a/usr/rust/src/bin/a_plus_b.rs b/usr/rust/src/bin/a_plus_b.rs new file mode 100644 index 0000000..04e8cd6 --- /dev/null +++ b/usr/rust/src/bin/a_plus_b.rs @@ -0,0 +1,15 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +#[macro_use] +extern crate user; + +#[no_mangle] +pub fn main() -> usize { + let a = 1; + let b = 2; + println!("a + b = {}", a + b); + 0 +} From 02323c83e61eaa5136646b123b65e1b5613e875f Mon Sep 17 00:00:00 2001 From: shinbokuow Date: Wed, 12 Feb 2020 18:41:01 +0800 Subject: [PATCH 08/13] run user program loaded from disk --- os/Makefile | 2 ++ os/src/drivers/virtio_disk.rs | 63 +++++++++++++++++++---------------- os/src/interrupt.rs | 25 +++++++++++++- os/src/process/processor.rs | 2 ++ 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/os/Makefile b/os/Makefile index 5a17e44..6289755 100644 --- a/os/Makefile +++ b/os/Makefile @@ -23,6 +23,8 @@ $(bin): kernel asm: $(objdump) -d $(kernel) | less +assembly: + $(objdump) -d $(kernel) > target/os.asm build: $(bin) diff --git a/os/src/drivers/virtio_disk.rs b/os/src/drivers/virtio_disk.rs index 72679f6..2a70d61 100644 --- a/os/src/drivers/virtio_disk.rs +++ b/os/src/drivers/virtio_disk.rs @@ -13,6 +13,14 @@ use riscv::register::{ sstatus, sie }; +use crate::interrupt::{ + disable_and_store, + restore, + enable_and_wfi, + disable_timer_and_store, + restore_timer, + enable_and_store, +}; const VIRTIO_MMIO_0: usize = 0x10001000; const VIRTIO_MMIO_MAGIC_VALUE: usize = 0x000; @@ -222,7 +230,8 @@ impl VirtioDisk { 0 } - fn virtio_disk_issue(&mut self, buf: &mut Buf, write: bool) -> usize { + #[no_mangle] + fn virtio_disk_issue(&mut self, buf: &mut Buf, write: bool, idx0: &mut usize) { let sector: u64 = buf.blockno; let mut idx: [usize; 3] = [0; 3]; assert!(self.alloc_3desc(&mut idx) == 0); // assuming desc space is sufficient @@ -261,13 +270,14 @@ impl VirtioDisk { compiler_memory_barrier(); avail_array[1] += 1; compiler_memory_barrier(); - // assert!(avail_array[1] >= 1 && avail_array[1 + avail_array[1] as usize % NUM] == idx[0] as u16, "memory barrier issue!"); + buf.disk = 1; + *idx0 = idx[0]; reg_write::(VIRTIO_MMIO_QUEUE_NOTIFY, 0x0); - - idx[0] + // println!("after writing notify"); + // println!("issue successfully!"); } fn virtio_disk_clean(&mut self, idx: usize) { @@ -285,6 +295,7 @@ impl VirtioDisk { while self.used_idx % num != used.id % num { let id: usize = used.elems[self.used_idx as usize].id as usize; // println!("used_length = {}", used.elems[self.used_idx as usize].len); + // println!("status = {}", self.buf_info[id].status); assert!(self.buf_info[id].status == 0, "virtio_disk_intr status"); let buf = unsafe { &mut *(self.buf_info[id].buf as *mut u8 as *mut Buf) }; buf.disk = 0; @@ -298,42 +309,37 @@ impl VirtioDisk { } } +#[no_mangle] pub fn virtio_disk_rw(buf: &mut Buf, write: bool) { + let status = disable_and_store(); + let stimer = riscv::register::sie::read().stimer(); + unsafe { riscv::register::sie::clear_stimer(); } // println!("virtio_disk_rw blockno = {}, write = {}", buf.blockno, write); - /* - let timer_enabled = sie::read().stimer(); - if timer_enabled { - unsafe { sie::clear_stimer(); } - } - */ - let intr_enabled = sstatus::read().sie(); - if !intr_enabled { - unsafe { sstatus::set_sie(); } - } - let idx = DISK.lock() - .virtio_disk_issue(buf, write); + let mut idx0: usize = 0; + DISK.lock() + .virtio_disk_issue(buf, write, &mut idx0); - // println!("begin waiting..."); // buf.sleep_lock.wait(); + + enable_and_store(); + //reg_write::(VIRTIO_MMIO_QUEUE_NOTIFY, 0x0); + + // println!("start waiting..."); loop { if buf.completed { break; } } - /* - if timer_enabled { - unsafe { sie::set_stimer(); } - } - */ - if !intr_enabled { - unsafe { sstatus::clear_sie(); } - } - // println!("end waiting..."); + restore(status); + DISK.lock() - .virtio_disk_clean(idx); - // println!("virtio_disk_rw exit!"); + .virtio_disk_clean(idx0); + + if stimer { + unsafe { riscv::register::sie::set_stimer(); } + } } pub fn init() { @@ -386,6 +392,7 @@ pub fn init() { disk.free[i] = 1; } disk.init = true; + println!("++++ setup disk! ++++"); } pub fn virtio_disk_intr() { diff --git a/os/src/interrupt.rs b/os/src/interrupt.rs index 131efe8..34d6180 100644 --- a/os/src/interrupt.rs +++ b/os/src/interrupt.rs @@ -76,6 +76,7 @@ fn breakpoint(sepc: &mut usize) { } fn super_timer() { + // println!("T"); clock_set_next_event(); tick(); } @@ -129,7 +130,29 @@ fn try_serial() -> bool { None => false, } } - +#[inline(always)] +pub fn disable_timer_and_store() -> usize { + let sie: usize; + let bitmask: usize = 1 << 5; + unsafe { + asm!("csrrc $0, sie, $1" : "=r"(sie) : "r"(bitmask):: "volatile"); + } + sie +} +#[inline(always)] +pub fn restore_timer(sie: usize) { + unsafe { + asm!("csrs sie, $0" :: "r"(sie) :: "volatile"); + } +} +#[inline(always)] +pub fn enable_and_store() -> usize { + let sstatus: usize; + unsafe { + asm!("csrsi sstatus, 1 << 1" : "=r"(sstatus) ::: "volatile"); + } + sstatus +} #[inline(always)] pub fn disable_and_store() -> usize { let sstatus: usize; diff --git a/os/src/process/processor.rs b/os/src/process/processor.rs index 21fd38a..d8843e9 100644 --- a/os/src/process/processor.rs +++ b/os/src/process/processor.rs @@ -70,7 +70,9 @@ impl Processor { pub fn tick(&self) { let inner = self.inner(); if !inner.current.is_none() { + // println!("N"); if inner.pool.tick() { + // println!("P"); let flags = disable_and_store(); inner.current.as_mut().unwrap().1.switch_to(&mut inner.idle); From 5461f933839f713b35dd062aa9599c13aeec6479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E4=B8=B0=E6=BA=90?= Date: Wed, 12 Feb 2020 22:28:20 +0800 Subject: [PATCH 09/13] fix fork bug --- os/src/interrupt.rs | 1 + os/src/process/mod.rs | 2 +- os/src/process/processor.rs | 4 ++-- os/src/process/structs.rs | 1 - usr/rust/src/bin/fork.rs | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/os/src/interrupt.rs b/os/src/interrupt.rs index 1edeb16..c260e54 100644 --- a/os/src/interrupt.rs +++ b/os/src/interrupt.rs @@ -66,6 +66,7 @@ fn super_timer() { clock_set_next_event(); tick(); } + fn page_fault(tf: &mut TrapFrame) { println!( "{:?} va = {:#x} instruction = {:#x}", diff --git a/os/src/process/mod.rs b/os/src/process/mod.rs index 882d392..3e34db7 100644 --- a/os/src/process/mod.rs +++ b/os/src/process/mod.rs @@ -71,6 +71,6 @@ pub fn add_thread(thread: Box) -> usize { CPU.add_thread(thread) } -pub fn current_thread() -> Box { +pub fn current_thread() -> &'static Box { CPU.current_thread() } diff --git a/os/src/process/processor.rs b/os/src/process/processor.rs index 21fd38a..836cfe3 100644 --- a/os/src/process/processor.rs +++ b/os/src/process/processor.rs @@ -133,7 +133,7 @@ impl Processor { self.inner().current.as_mut().unwrap().0 as usize } - pub fn current_thread(&self) -> Box { - self.inner().current.as_ref().unwrap().1.clone() + pub fn current_thread(&self) -> &Box { + &self.inner().current.as_mut().unwrap().1 } } diff --git a/os/src/process/structs.rs b/os/src/process/structs.rs index 6c97f13..236a747 100644 --- a/os/src/process/structs.rs +++ b/os/src/process/structs.rs @@ -119,7 +119,6 @@ impl Thread { } } -#[derive(Clone)] pub struct KernelStack(usize); impl KernelStack { diff --git a/usr/rust/src/bin/fork.rs b/usr/rust/src/bin/fork.rs index 8882499..9735115 100644 --- a/usr/rust/src/bin/fork.rs +++ b/usr/rust/src/bin/fork.rs @@ -10,6 +10,7 @@ use user::syscall::sys_fork; #[no_mangle] pub fn main() -> usize { + let tid = sys_fork(); let tid = sys_fork(); if tid == 0 { println!("I am child"); From 01d2e36b013846bb5ae773a06f7d7a797708fb17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E4=B8=B0=E6=BA=90?= Date: Thu, 13 Feb 2020 13:00:52 +0800 Subject: [PATCH 10/13] fix bug --- os/src/process/structs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/os/src/process/structs.rs b/os/src/process/structs.rs index 236a747..61d7c2f 100644 --- a/os/src/process/structs.rs +++ b/os/src/process/structs.rs @@ -22,7 +22,6 @@ pub enum Status { Exited(ExitCode), } -#[derive(Clone)] pub struct Thread { pub context: Context, pub kstack: KernelStack, From 98b76dc90e61ca53f16a9232c53801f15be27619 Mon Sep 17 00:00:00 2001 From: deathwish5 Date: Thu, 13 Feb 2020 17:27:06 +0800 Subject: [PATCH 11/13] finish test of sys_exec, simplify some code --- os/src/process/scheduler.rs | 8 ++------ os/src/syscall.rs | 10 +--------- usr/rust/src/bin/exec.rs | 10 +++++----- usr/rust/src/bin/user_shell.rs | 9 +++------ 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/os/src/process/scheduler.rs b/os/src/process/scheduler.rs index f8c25ef..992c7d0 100644 --- a/os/src/process/scheduler.rs +++ b/os/src/process/scheduler.rs @@ -79,13 +79,9 @@ impl Scheduler for RRScheduler { let tid = self.current; if tid != 0 { self.threads[tid].time -= 1; - if self.threads[tid].time == 0 { - return true; - } else { - return false; - } + return self.threads[tid].time == 0; } - return true; + true } fn exit(&mut self, tid: Tid) { diff --git a/os/src/syscall.rs b/os/src/syscall.rs index 786a5f7..a436e8c 100644 --- a/os/src/syscall.rs +++ b/os/src/syscall.rs @@ -30,7 +30,7 @@ pub fn syscall(id: usize, args: [usize; 3], tf: &mut TrapFrame) -> isize { } fn sys_fork(tf: &mut TrapFrame) -> isize { - println!("forking"); + // println!("forking"); let new_thread = process::current_thread().fork(tf); let tid = process::add_thread(new_thread); tid as isize @@ -53,7 +53,6 @@ pub unsafe fn from_cstr(s: *const u8) -> &'static str { str::from_utf8(slice::from_raw_parts(s, len)).unwrap() } -<<<<<<< HEAD // fn sys_exec(path: *const u8) -> isize { // let valid = process::execute(unsafe { from_cstr(path) }, Some(process::current_tid())); // if valid { @@ -82,12 +81,5 @@ fn sys_exec(path: *const u8, tf: &mut TrapFrame) -> isize { println!("exec error! cannot find the program {}", exec_path); -1 } -======= -fn sys_exec(path: *const u8) -> isize { - // println!("enter sys_exec!"); - let valid = process::execute(unsafe { from_cstr(path) }, Some(process::current_tid())); - if valid { - process::yield_now(); ->>>>>>> master } } diff --git a/usr/rust/src/bin/exec.rs b/usr/rust/src/bin/exec.rs index a3f877b..8b8c538 100644 --- a/usr/rust/src/bin/exec.rs +++ b/usr/rust/src/bin/exec.rs @@ -1,4 +1,3 @@ - #![no_std] #![no_main] @@ -7,11 +6,12 @@ extern crate alloc; #[macro_use] extern crate user; -use user::syscall::sys_exec; +use alloc::string::String; +use user::syscall::{sys_exec, sys_fork}; #[no_mangle] pub fn main() -> usize { - sys_fork(); - sys_fork(); + sys_exec("/rust/hello_world".as_ptr() as *const u8); + println!("should not arrive here. exec error."); 0 -} \ No newline at end of file +} diff --git a/usr/rust/src/bin/user_shell.rs b/usr/rust/src/bin/user_shell.rs index e1a2c97..2146d07 100644 --- a/usr/rust/src/bin/user_shell.rs +++ b/usr/rust/src/bin/user_shell.rs @@ -11,11 +11,11 @@ const CR: u8 = 0x0du8; use alloc::string::String; use user::io::getc; -use user::syscall::{sys_exec, sys_fork, sys_exit}; +use user::syscall::{sys_exec, sys_exit, sys_fork}; #[no_mangle] pub fn main() { - println!("Rust user shell v3.0"); + println!("Rust user shell"); let mut line: String = String::new(); print!(">> "); loop { @@ -25,13 +25,10 @@ pub fn main() { println!(""); if !line.is_empty() { println!("searching for program {}", line); - if (sys_fork() == 0) { - println!("this is child program."); + if sys_fork() == 0 { sys_exec(line.as_ptr()); sys_exit(0); } - println!("this is parent program"); - // sys_exec(line.as_ptr()); line.clear(); } print!(">> "); From 9656fdc1041be39b8efd0cbf4e7adde0514e53fc Mon Sep 17 00:00:00 2001 From: deathwish5 Date: Fri, 14 Feb 2020 23:38:08 +0800 Subject: [PATCH 12/13] fix a bug of user_shell --- usr/rust/src/bin/exec.rs | 3 ++- usr/rust/src/bin/user_shell.rs | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/usr/rust/src/bin/exec.rs b/usr/rust/src/bin/exec.rs index 8b8c538..deac3e7 100644 --- a/usr/rust/src/bin/exec.rs +++ b/usr/rust/src/bin/exec.rs @@ -11,7 +11,8 @@ use user::syscall::{sys_exec, sys_fork}; #[no_mangle] pub fn main() -> usize { - sys_exec("/rust/hello_world".as_ptr() as *const u8); + println!("this is exec_test ^o^"); + sys_exec("/rust/hello_world".as_ptr()); println!("should not arrive here. exec error."); 0 } diff --git a/usr/rust/src/bin/user_shell.rs b/usr/rust/src/bin/user_shell.rs index 2146d07..8044afd 100644 --- a/usr/rust/src/bin/user_shell.rs +++ b/usr/rust/src/bin/user_shell.rs @@ -13,6 +13,13 @@ use alloc::string::String; use user::io::getc; use user::syscall::{sys_exec, sys_exit, sys_fork}; +unsafe fn to_cstr(s: &mut String) -> *const u8 { + let ptr = s.as_mut_ptr(); + let len = s.len(); + *ptr.add(len) = 0; + ptr +} + #[no_mangle] pub fn main() { println!("Rust user shell"); @@ -26,7 +33,7 @@ pub fn main() { if !line.is_empty() { println!("searching for program {}", line); if sys_fork() == 0 { - sys_exec(line.as_ptr()); + sys_exec(unsafe { to_cstr(&mut line) }); sys_exit(0); } line.clear(); From c555f6f80bb20ab5027e5c812ca2db6cb48e1731 Mon Sep 17 00:00:00 2001 From: deathwish5 Date: Fri, 14 Feb 2020 23:50:12 +0800 Subject: [PATCH 13/13] a simpler way to fix the bug --- usr/rust/src/bin/exec.rs | 9 ++++++++- usr/rust/src/bin/user_shell.rs | 10 ++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/usr/rust/src/bin/exec.rs b/usr/rust/src/bin/exec.rs index deac3e7..7122129 100644 --- a/usr/rust/src/bin/exec.rs +++ b/usr/rust/src/bin/exec.rs @@ -9,10 +9,17 @@ extern crate user; use alloc::string::String; use user::syscall::{sys_exec, sys_fork}; +unsafe fn to_cstr(s: &mut String) -> *const u8 { + let ptr = s.as_mut_ptr(); + let len = s.len(); + *ptr.add(len) = 0; + ptr +} + #[no_mangle] pub fn main() -> usize { println!("this is exec_test ^o^"); - sys_exec("/rust/hello_world".as_ptr()); + sys_exec("/rust/hello_world\0".as_ptr()); println!("should not arrive here. exec error."); 0 } diff --git a/usr/rust/src/bin/user_shell.rs b/usr/rust/src/bin/user_shell.rs index 8044afd..0fc3072 100644 --- a/usr/rust/src/bin/user_shell.rs +++ b/usr/rust/src/bin/user_shell.rs @@ -13,13 +13,6 @@ use alloc::string::String; use user::io::getc; use user::syscall::{sys_exec, sys_exit, sys_fork}; -unsafe fn to_cstr(s: &mut String) -> *const u8 { - let ptr = s.as_mut_ptr(); - let len = s.len(); - *ptr.add(len) = 0; - ptr -} - #[no_mangle] pub fn main() { println!("Rust user shell"); @@ -33,7 +26,8 @@ pub fn main() { if !line.is_empty() { println!("searching for program {}", line); if sys_fork() == 0 { - sys_exec(unsafe { to_cstr(&mut line) }); + line.push('\0'); + sys_exec(line.as_ptr()); sys_exit(0); } line.clear();