diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index d697db22..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "crate/riscv"] - path = crate/riscv - url = https://github.com/riscv-and-rust-and-decaf/riscv.git diff --git a/.travis.yml b/.travis.yml index d7f343ef..dc787f99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ sudo: required language: rust -rust: nightly-2018-09-18 +rust: nightly cache: cargo: true @@ -19,7 +19,7 @@ env: install: - if [ $ARCH = riscv32 ]; then - export FILE="riscv64-unknown-elf-gcc-2018.07.0-x86_64-linux-ubuntu14"; + export FILE="riscv64-unknown-elf-gcc-20181030-x86_64-linux-ubuntu14"; wget https://static.dev.sifive.com/dev-tools/$FILE.tar.gz; tar xf $FILE.tar.gz; export PATH=$PATH:$PWD/$FILE/bin; diff --git a/README.md b/README.md index c919f81e..27462caf 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ cargo install cargo-xbuild bootimage ``` ```bash -git clone https://github.com/wangrunji0408/RustOS.git --recursive +git clone https://github.com/wangrunji0408/RustOS.git cd RustOS/kernel rustup override set nightly-2018-09-18 make run arch=riscv32|x86_64 diff --git a/crate/memory/src/cow.rs b/crate/memory/src/cow.rs index 074cbc55..aae8d5c9 100644 --- a/crate/memory/src/cow.rs +++ b/crate/memory/src/cow.rs @@ -69,14 +69,13 @@ impl CowExt { ** @retval none */ pub fn unmap_shared(&mut self, addr: VirtAddr) { - { - let entry = self.page_table.get_entry(addr); - let frame = entry.target() / PAGE_SIZE; - if entry.readonly_shared() { - self.rc_map.read_decrease(&frame); - } else if entry.writable_shared() { - self.rc_map.write_decrease(&frame); - } + let entry = self.page_table.get_entry(addr) + .expect("entry not exist"); + let frame = entry.target() / PAGE_SIZE; + if entry.readonly_shared() { + self.rc_map.read_decrease(&frame); + } else if entry.writable_shared() { + self.rc_map.write_decrease(&frame); } self.page_table.unmap(addr); } @@ -91,20 +90,21 @@ impl CowExt { ** @retval bool whether copy-on-write happens. */ pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool { - // below is not being used now(no shared pages) - { - let entry = self.page_table.get_entry(addr); - if !entry.readonly_shared() && !entry.writable_shared() { - return false; - } - let frame = entry.target() / PAGE_SIZE; - if self.rc_map.read_count(&frame) == 0 && self.rc_map.write_count(&frame) == 1 { - entry.clear_shared(); - entry.set_writable(true); - entry.update(); - self.rc_map.write_decrease(&frame); - return true; - } + let entry = self.page_table.get_entry(addr); + if entry.is_none() { + return false; + } + let entry = entry.unwrap(); + if !entry.readonly_shared() && !entry.writable_shared() { + return false; + } + let frame = entry.target() / PAGE_SIZE; + if self.rc_map.read_count(&frame) == 0 && self.rc_map.write_count(&frame) == 1 { + entry.clear_shared(); + entry.set_writable(true); + entry.update(); + self.rc_map.write_decrease(&frame); + return true; } use core::mem::uninitialized; let mut temp_data: [u8; PAGE_SIZE] = unsafe { uninitialized() }; @@ -251,7 +251,7 @@ pub mod test { pt.write(0x1000, 2); assert_eq!(pt.rc_map.read_count(&frame), 1); assert_eq!(pt.rc_map.write_count(&frame), 1); - assert_ne!(pt.get_entry(0x1000).target(), target); + assert_ne!(pt.get_entry(0x1000).unwrap().target(), target); assert_eq!(pt.read(0x1000), 2); assert_eq!(pt.read(0x2000), 1); assert_eq!(pt.read(0x3000), 1); @@ -264,7 +264,7 @@ pub mod test { pt.write(0x2000, 3); assert_eq!(pt.rc_map.read_count(&frame), 0); assert_eq!(pt.rc_map.write_count(&frame), 0); - assert_eq!(pt.get_entry(0x2000).target(), target, + assert_eq!(pt.get_entry(0x2000).unwrap().target(), target, "The last write reference should not allocate new frame."); assert_eq!(pt.read(0x1000), 2); assert_eq!(pt.read(0x2000), 3); diff --git a/crate/memory/src/lib.rs b/crate/memory/src/lib.rs index 248feb6d..225d6137 100644 --- a/crate/memory/src/lib.rs +++ b/crate/memory/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![feature(alloc)] +#![feature(nll)] extern crate alloc; #[macro_use] diff --git a/crate/memory/src/memory_set.rs b/crate/memory/src/memory_set.rs index 8b588927..d3cb298b 100644 --- a/crate/memory/src/memory_set.rs +++ b/crate/memory/src/memory_set.rs @@ -42,7 +42,7 @@ pub trait InactivePageTable { ** @param f: impl FnOnce() the function to be executed ** @retval none */ - unsafe fn with(&self, f: impl FnOnce()); + unsafe fn with(&self, f: impl FnOnce() -> T) -> T; /* ** @brief get the token of the inactive page table ** @retval usize the token of the inactive page table @@ -61,13 +61,6 @@ pub trait InactivePageTable { ** @retval none */ fn dealloc_frame(target: PhysAddr); - /* - ** @brief allocate a stack space - ** @retval Stack the stack allocated - */ - fn alloc_stack() -> Stack; - - unsafe fn with_retval(&self, f: impl FnOnce() -> T) -> T; } /// a continuous memory space when the same attribute @@ -183,7 +176,7 @@ impl MemoryArea { let entry = pt.map(addr,0); self.flags.apply(entry); } - let entry = pt.get_entry(addr); + let entry = pt.get_entry(addr).unwrap(); entry.set_present(false); entry.update(); @@ -201,13 +194,13 @@ impl MemoryArea { for page in Page::range_of(self.start_addr, self.end_addr) { let addr = page.start_address(); if self.phys_start_addr.is_none() { - if pt.get_entry(addr).present(){ - let target = pt.get_entry(addr).target(); + if pt.get_entry(addr).unwrap().present(){ + let target = pt.get_entry(addr).unwrap().target(); T::dealloc_frame(target); } else{ // set valid for pt.unmap function - pt.get_entry(addr).set_present(true); + pt.get_entry(addr).unwrap().set_present(true); } } pt.unmap(addr); @@ -290,7 +283,6 @@ impl MemoryAttr { pub struct MemorySet { areas: Vec, page_table: T, - kstack: Stack, } impl MemorySet { @@ -302,23 +294,12 @@ impl MemorySet { MemorySet { areas: Vec::::new(), page_table: T::new(), - kstack: T::alloc_stack(), } } - /* - ** @brief create a memory set from raw space - ** Used for remap_kernel() where heap alloc is unavailable - ** @param slice: &mut [u8] the initial memory for the Vec in the struct - ** @param kstack: Stack kernel stack space - ** @retval MemorySet the memory set created - */ - pub unsafe fn new_from_raw_space(slice: &mut [u8], kstack: Stack) -> Self { - use core::mem::size_of; - let cap = slice.len() / size_of::(); + pub fn new_bare() -> Self { MemorySet { - areas: Vec::::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap), + areas: Vec::::new(), page_table: T::new_bare(), - kstack, } } /* @@ -372,13 +353,6 @@ impl MemorySet { self.page_table.token() } /* - ** @brief get the top of the associated kernel stack - ** @retval usize the top of the associated kernel stack - */ - pub fn kstack_top(&self) -> usize { - self.kstack.top - } - /* ** @brief clear the memory set ** @retval none */ @@ -394,7 +368,7 @@ impl MemorySet { /* ** @brief get the mutable reference for the inactive page table - ** @retval: &mut T the mutable reference of the inactive page table + ** @retval: &mut T the mutable reference of the inactive page table */ pub fn get_page_table_mut(&mut self) -> &mut T{ &mut self.page_table @@ -414,7 +388,6 @@ impl Clone for MemorySet { MemorySet { areas: self.areas.clone(), page_table, - kstack: T::alloc_stack(), } } } @@ -433,10 +406,3 @@ impl Debug for MemorySet { .finish() } } - -/// the stack structure -#[derive(Debug)] -pub struct Stack { - pub top: usize, - pub bottom: usize, -} \ No newline at end of file diff --git a/crate/memory/src/paging/mock_page_table.rs b/crate/memory/src/paging/mock_page_table.rs index 5f4931ef..bb1d415f 100644 --- a/crate/memory/src/paging/mock_page_table.rs +++ b/crate/memory/src/paging/mock_page_table.rs @@ -77,8 +77,8 @@ impl PageTable for MockPageTable { assert!(entry.present); entry.present = false; } - fn get_entry(&mut self, addr: VirtAddr) -> &mut ::Entry { - &mut self.entries[addr / PAGE_SIZE] + fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::Entry> { + Some(&mut self.entries[addr / PAGE_SIZE]) } fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] { self._read(addr); @@ -175,7 +175,7 @@ impl MockPageTable { #[cfg(test)] mod test { use super::*; - use alloc::arc::Arc; + use alloc::sync::Arc; use core::cell::RefCell; #[test] @@ -198,34 +198,35 @@ mod test { fn entry() { let mut pt = MockPageTable::new(); pt.map(0x0, 0x1000); - { - let entry = pt.get_entry(0); - assert!(entry.present()); - assert!(entry.writable()); - assert!(!entry.accessed()); - assert!(!entry.dirty()); - assert_eq!(entry.target(), 0x1000); - } + + let entry = pt.get_entry(0).unwrap(); + assert!(entry.present()); + assert!(entry.writable()); + assert!(!entry.accessed()); + assert!(!entry.dirty()); + assert_eq!(entry.target(), 0x1000); pt.read(0x0); - assert!(pt.get_entry(0).accessed()); - assert!(!pt.get_entry(0).dirty()); + let entry = pt.get_entry(0).unwrap(); + assert!(entry.accessed()); + assert!(!entry.dirty()); - pt.get_entry(0).clear_accessed(); - assert!(!pt.get_entry(0).accessed()); + entry.clear_accessed(); + assert!(!entry.accessed()); pt.write(0x1, 1); - assert!(pt.get_entry(0).accessed()); - assert!(pt.get_entry(0).dirty()); + let entry = pt.get_entry(0).unwrap(); + assert!(entry.accessed()); + assert!(entry.dirty()); - pt.get_entry(0).clear_dirty(); - assert!(!pt.get_entry(0).dirty()); + entry.clear_dirty(); + assert!(!entry.dirty()); - pt.get_entry(0).set_writable(false); - assert!(!pt.get_entry(0).writable()); + entry.set_writable(false); + assert!(!entry.writable()); - pt.get_entry(0).set_present(false); - assert!(!pt.get_entry(0).present()); + entry.set_present(false); + assert!(!entry.present()); } #[test] diff --git a/crate/memory/src/paging/mod.rs b/crate/memory/src/paging/mod.rs index 8733dcae..ceda06e2 100644 --- a/crate/memory/src/paging/mod.rs +++ b/crate/memory/src/paging/mod.rs @@ -31,8 +31,7 @@ pub trait PageTable { ** @param addr: VirtAddr the virual address ** @retval Entry the page table entry of the virual address */ - fn get_entry(&mut self, addr: VirtAddr) -> &mut Self::Entry; - + fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::Entry>; // For testing with mock /* ** @brief used for testing with mock diff --git a/crate/memory/src/swap/enhanced_clock.rs b/crate/memory/src/swap/enhanced_clock.rs index 05e78eb7..5d5d0bf8 100644 --- a/crate/memory/src/swap/enhanced_clock.rs +++ b/crate/memory/src/swap/enhanced_clock.rs @@ -40,7 +40,7 @@ impl SwapManager for EnhancedClockSwapManager { // The reason may be `get_page_slice_mut()` contains unsafe operation, // which lead the compiler to do a wrong optimization. // let slice = page_table.get_page_slice_mut(addr); - let entry = page_table.get_entry(addr); + let entry = page_table.get_entry(addr).unwrap(); // println!("{:#x} , {}, {}", addr, entry.accessed(), entry.dirty()); match (entry.accessed(), entry.dirty()) { diff --git a/crate/memory/src/swap/mod.rs b/crate/memory/src/swap/mod.rs index 19c566e9..057f5ace 100644 --- a/crate/memory/src/swap/mod.rs +++ b/crate/memory/src/swap/mod.rs @@ -117,7 +117,7 @@ impl SwapExt { targetpt.token() }; targetpt.with(||{ - let entry = page_table.get_entry(addr); + let entry = page_table.get_entry(addr).unwrap(); if entry.present() { let frame = Frame::new(pt as usize, addr, pttoken); swap_manager.push(frame); @@ -149,7 +149,7 @@ impl SwapExt { info!("try to change pagetable"); targetpt.with(||{ let token = { - let entry = page_table.get_entry(addr); + let entry = page_table.get_entry(addr).unwrap(); if !entry.swapped() { if entry.present(){ // if the addr isn't indicating a swapped page, panic occured here @@ -214,11 +214,12 @@ impl SwapExt { let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self; let ret = unsafe{ let pt = &mut *(frame.get_page_table() as *mut T2); - pt.with_retval(||{ + pt.with(|| { //use core::slice; //let data = unsafe { slice::from_raw_parts_mut((frame.virtaddr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) }; let data = page_table.get_page_slice_mut(frame.get_virtaddr()); - let entry = page_table.get_entry(frame.get_virtaddr()); + let entry = page_table.get_entry(frame.get_virtaddr()) + .ok_or(SwapError::NotMapped)?; if entry.swapped() { return Err(SwapError::AlreadySwapped); } @@ -245,18 +246,16 @@ impl SwapExt { */ fn swap_in(&mut self, pt: *mut T2, addr: VirtAddr, target: PhysAddr) -> Result<(), SwapError> { info!("come in to swap in"); - let token = { - let entry = self.page_table.get_entry(addr); - if !entry.swapped() { - return Err(SwapError::NotSwapped); - } - let token = entry.target() / PAGE_SIZE; - entry.set_target(target); - entry.set_swapped(false); - entry.set_present(true); - entry.update(); - token - }; + let entry = self.page_table.get_entry(addr) + .ok_or(SwapError::NotMapped)?; + if !entry.swapped() { + return Err(SwapError::NotSwapped); + } + let token = entry.target() / PAGE_SIZE; + entry.set_target(target); + entry.set_swapped(false); + entry.set_present(true); + entry.update(); let data = self.page_table.get_page_slice_mut(addr); self.swapper.swap_in(token, data).map_err(|_| SwapError::IOError)?; let pttoken = unsafe{ @@ -272,7 +271,7 @@ impl SwapExt { ** This function must be called whenever PageFault happens. ** @param pt: *mut T2 the raw pointer for the target page's inactive page table (exactly the current page table) ** @param addr: VirtAddr the virual address of the page fault - ** @param swapin: bool whether to set the page swappable if delayed allocate a frame for a page + ** @param swapin: bool whether to set the page swappable if delayed allocate a frame for a page ** @param alloc_frame: impl FnOnce() -> PhysAddr ** the page allocation function ** that allocate a page and returns physics address @@ -284,7 +283,7 @@ impl SwapExt { { info!("try handling delayed frame allocator"); let need_alloc ={ - let entry = self.page_table.get_entry(addr); + let entry = self.page_table.get_entry(addr).unwrap(); //info!("got entry!"); !entry.present() && !entry.swapped() }; @@ -293,7 +292,7 @@ impl SwapExt { info!("need_alloc!"); let frame = alloc_frame(); { - let entry = self.page_table.get_entry(addr); + let entry = self.page_table.get_entry(addr).unwrap(); entry.set_target(frame); //let new_entry = self.page_table.map(addr, frame); entry.set_present(true); @@ -311,8 +310,9 @@ impl SwapExt { info!("not need alloc!"); } // now we didn't attach the cow so the present will be false when swapped(), to enable the cow some changes will be needed - if !self.page_table.get_entry(addr).swapped() { - return false; + match self.page_table.get_entry(addr) { + None => return false, + Some(entry) => if !entry.swapped() { return false; }, } // Allocate a frame, if failed, swap out a page let frame = alloc_frame(); @@ -324,6 +324,8 @@ impl SwapExt { pub enum SwapError { /// attempt to swap out a page that is already swapped out AlreadySwapped, + /// + NotMapped, /// attempt to swap in a page that is already in the memory NotSwapped, /// there are no page to be swapped out diff --git a/crate/process/src/lib.rs b/crate/process/src/lib.rs index d798459b..2b45ca67 100644 --- a/crate/process/src/lib.rs +++ b/crate/process/src/lib.rs @@ -17,7 +17,7 @@ extern crate spin; #[macro_use] extern crate std; -pub mod process_manager; +mod process_manager; mod processor; pub mod scheduler; pub mod thread; diff --git a/crate/process/src/process_manager.rs b/crate/process/src/process_manager.rs index a013c130..732b046e 100644 --- a/crate/process/src/process_manager.rs +++ b/crate/process/src/process_manager.rs @@ -138,22 +138,20 @@ impl ProcessManager { /// Switch the status of a process. /// Insert/Remove it to/from scheduler if necessary. fn set_status(&self, pid: Pid, status: Status) { + let mut scheduler = self.scheduler.lock(); let mut proc_lock = self.procs[pid].lock(); let mut proc = proc_lock.as_mut().expect("process not exist"); trace!("process {} {:?} -> {:?}", pid, proc.status, status); - { // limit the lifetime of scheduler - let mut scheduler = self.scheduler.lock(); - match (&proc.status, &status) { - (Status::Ready, Status::Ready) => return, - (Status::Ready, _) => scheduler.remove(pid), - (Status::Running(_), _) => {}, - (Status::Exited(_), _) => panic!("can not set status for a exited process"), - (Status::Waiting(target), Status::Exited(_)) => - self.wait_queue[*target].lock().retain(|&i| i != pid), - (Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)), - (_, Status::Ready) => scheduler.insert(pid), - _ => {} - } + match (&proc.status, &status) { + (Status::Ready, Status::Ready) => return, + (Status::Ready, _) => scheduler.remove(pid), + (Status::Running(_), _) => {}, + (Status::Exited(_), _) => panic!("can not set status for a exited process"), + (Status::Waiting(target), Status::Exited(_)) => + self.wait_queue[*target].lock().retain(|&i| i != pid), + (Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)), + (_, Status::Ready) => scheduler.insert(pid), + _ => {} } match proc.status { Status::Running(_) => proc.status_after_stop = status, @@ -238,8 +236,9 @@ impl ProcessManager { (self.exit_handler)(pid); } } - fn new_vec_default(size: usize) -> Vec { + +fn new_vec_default(size: usize) -> Vec { let mut vec = Vec::new(); vec.resize_default(size); vec -} \ No newline at end of file +} diff --git a/crate/process/src/processor.rs b/crate/process/src/processor.rs index 518dcbdf..f0b3a4e7 100644 --- a/crate/process/src/processor.rs +++ b/crate/process/src/processor.rs @@ -59,9 +59,9 @@ impl Processor { trace!("CPU{} begin running process {}", inner.id, proc.0); inner.proc = Some(proc); unsafe { - inner.loop_context.switch_to(&mut *inner.proc.as_mut().expect("context should not be None").1); + inner.loop_context.switch_to(&mut *inner.proc.as_mut().unwrap().1); } - let (pid, context) = inner.proc.take().expect("proc should not be None"); + let (pid, context) = inner.proc.take().unwrap(); trace!("CPU{} stop running process {}", inner.id, pid); inner.manager.stop(pid, context); } @@ -70,7 +70,6 @@ impl Processor { /// Called by process running on this Processor. /// Yield and reschedule. pub fn yield_now(&self) { - trace!("yield start"); let inner = self.inner(); unsafe { let flags = interrupt::disable_and_store(); @@ -80,10 +79,7 @@ impl Processor { } pub fn pid(&self) -> Pid { - if self.inner().proc.is_none() { - return 0; - } - self.inner().proc.as_ref().expect("pid should not be None").0 + self.inner().proc.as_ref().unwrap().0 } pub fn context(&self) -> &Context { @@ -101,4 +97,3 @@ impl Processor { } } } - diff --git a/crate/process/src/thread.rs b/crate/process/src/thread.rs index 4dc7e458..fc40a85a 100644 --- a/crate/process/src/thread.rs +++ b/crate/process/src/thread.rs @@ -32,9 +32,7 @@ fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box /// Gets a handle to the thread that invokes it. pub fn current() -> Thread { - Thread { - pid: processor().pid(), - } + Thread { pid: processor().pid() } } /// Puts the current thread to sleep for the specified amount of time. @@ -164,6 +162,13 @@ impl JoinHandle { processor().yield_now(); } } + /// Force construct a JoinHandle struct + pub unsafe fn _of(pid: Pid) -> JoinHandle { + JoinHandle { + thread: Thread { pid }, + mark: PhantomData, + } + } } //pub struct LocalKey { diff --git a/crate/process/src/util.rs b/crate/process/src/util.rs deleted file mode 100644 index 11a8d3c0..00000000 --- a/crate/process/src/util.rs +++ /dev/null @@ -1,15 +0,0 @@ -use core::fmt::Debug; - -/// Get values by 2 diff keys at the same time -pub trait GetMut2 { - type Output; - fn get_mut(&mut self, id: Idx) -> &mut Self::Output; - fn get_mut2(&mut self, id1: Idx, id2: Idx) -> (&mut Self::Output, &mut Self::Output) { - assert_ne!(id1, id2); - let self1 = self as *mut Self; - let self2 = self1; - let p1 = unsafe { &mut *self1 }.get_mut(id1); - let p2 = unsafe { &mut *self2 }.get_mut(id2); - (p1, p2) - } -} diff --git a/crate/riscv b/crate/riscv deleted file mode 160000 index a37a65fa..00000000 --- a/crate/riscv +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a37a65fa13a00c5aa0068c3f2b5d55af6a37dd93 diff --git a/docs/FinalPresentation.pdf b/docs/1_OS/FinalPresentation.pdf similarity index 100% rename from docs/FinalPresentation.pdf rename to docs/1_OS/FinalPresentation.pdf diff --git a/docs/FinalReport.md b/docs/1_OS/FinalReport.md similarity index 100% rename from docs/FinalReport.md rename to docs/1_OS/FinalReport.md diff --git a/docs/Log.md b/docs/1_OS/Log.md similarity index 100% rename from docs/Log.md rename to docs/1_OS/Log.md diff --git a/docs/MidPresentation.md b/docs/1_OS/MidPresentation.md similarity index 100% rename from docs/MidPresentation.md rename to docs/1_OS/MidPresentation.md diff --git a/docs/MidPresentation.pdf b/docs/1_OS/MidPresentation.pdf similarity index 100% rename from docs/MidPresentation.pdf rename to docs/1_OS/MidPresentation.pdf diff --git a/docs/MidReport.md b/docs/1_OS/MidReport.md similarity index 100% rename from docs/MidReport.md rename to docs/1_OS/MidReport.md diff --git a/docs/RISCV.md b/docs/1_OS/RISCV.md similarity index 100% rename from docs/RISCV.md rename to docs/1_OS/RISCV.md diff --git a/docs/2_OSLab/g3/catfish-proposal.md b/docs/2_OSLab/g3/catfish-proposal.md new file mode 100644 index 00000000..d738e4af --- /dev/null +++ b/docs/2_OSLab/g3/catfish-proposal.md @@ -0,0 +1,72 @@ +# Rust OS多核移植与基于PARD框架的线程级Label管理 方案设计文档 + +2015011251 王纪霆 + +## 实验目标 + ++ 完成RustOS在riscv32上的多核开启 ++ 使RustOS可在中科院计算所PARD RISCV硬件环境下运行 ++ 使RustOS能够在PARD上开启smp ++ 添加控制功能,使得RustOS可以控制/查看PARD的寄存器 + +如果以上这些要全部实现,可以预料地将无法在八周内完成。 + +## 实验背景 + +[LvNA/PARD](https://github.com/LvNA-system/labeled-RISC-V)是一个用于进行内存隔离的硬件系统。它基于[rocket-chip](https://github.com/freechipsproject/rocket-chip)实现,在通常的多核以外,在核与各存储设备间增加了寄存器和额外的模块,并且对总线访问添加了标签,两者相结合下,可以完成对总线访问的控制,即对各核能够使用的缓存大小、磁盘流量进行限制等。 + +但目前为止,这项工作还有一些问题。首先是作为控制流量的关键——control plane,并未暴露给各核,而需要通过硬件的JTAG机制与板子上的控制模块prm(内含一个linux系统)沟通,并且在prm上实现控制脚本。而prm又和各核无法直接沟通,这样,运行在各核上的OS不仅无法修改寄存器,也无法知晓自己所分配到的资源大小,与PARD系统完全隔离。 + +如此一来,这个系统仅能进行核间的隔离,而无法完成进程间的隔离。这是因为,为了区分进程、给两个进程打上不同的标签,就必须让OS可以主动修改和设置control plane。 + +解决这个问题,实现进程级的label管理就是这个项目的主要目的。 + +## 实验设计 + +实际上,本项目的两个方向,即多核移植和PARD移植,是可以独立完成的。因为也可以退而求其次,考虑在PARD上只运行单核的线程级标签管理。但最终的目的还是让RustOS接手PARD的所有核,作为一个多核OS运行,对整个系统的运行进行管理。 + +最理想的方法是让硬件把control plane映射到内存,作为各核的一个设备。但硬件非常复杂,并且中科院方也没有实现这一功能。所以还是对硬件不做修改,依旧通过prm管理control plane,而将prm用串口等和各核连接,让其作为核的一个设备,在核的控制下修改底层配置。 + +为此,需要做的具体来说是: + ++ 让RustOS可以在核上运行; ++ 在prm上写脚本(运行在完善的Linux环境,且有现成范例),控制control plane; ++ 在RustOS上写驱动,使其可以与prm交互完成控制; ++ 在RustOS中添加系统调用等,使得操作系统可以管理驱动; + +另一边,多核移植所要做的是: + ++ 开启多核,实现原子操作等,为内核中可能的竞争加锁(Rust已经帮我们做了很多); ++ 核间进程调度,load balance; + +多核这边打算做的简单一些,基本照搬uCore+ on rv64来做,因为主要的设计和优化工作应该交给wrj同学。 + +## 目前进度 + +PARD端: + ++ 完成了实现机理的调研 ++ 正在服务器上编译复现(工程太大,本地vivado编译不了) + +多核端: + ++ 完成了ucore+ smp的初步学习 ++ 学习了bbl,完成了RustOS on rv32的多核开启 + +## 暂时计划 + +如果必须前八周结束,估计是无法做完的。 + +根据能否在前八周过后继续做,有以下远近期的计划: + +### 短期 + ++ 完成rv32 on smp的移植(第5-6周) ++ 完成多核Rust OS在PARD上的运行(第7-8周) + +### 长期 + ++ 完成RustOS与PARD的交互协议构建(第9-11周) ++ 实现基于RustOS的进程级标签管理(第12周后) + +以上均基于只有本人一人工作的前提,若有其他人协助/加入则根据实际情况而定。 \ No newline at end of file diff --git a/docs/2_OSLab/g3/catfish-proposal.pptx b/docs/2_OSLab/g3/catfish-proposal.pptx new file mode 100644 index 00000000..e79c5041 Binary files /dev/null and b/docs/2_OSLab/g3/catfish-proposal.pptx differ diff --git a/docs/2_OSLab/g5/exp2.md b/docs/2_OSLab/g5/exp2.md new file mode 100644 index 00000000..d346b23e --- /dev/null +++ b/docs/2_OSLab/g5/exp2.md @@ -0,0 +1,48 @@ +# 2018操作系统专题训练 + +# 实验2:方案设计文档 + +计53 王润基 2015011279 + +## 实验目标 + +**基于RustOS,参考sv6完成多核实现和优化。** + +分为以下三个子任务: + +1. 实现x86_64和RISCV下的多核启动和通信 +2. 拓展线程管理模块,使之支持多核调度 +3. 学习sv6进行多核优化 + +## 相关工作和实验方案 + +1. 实现x86_64和RISCV下的多核启动和通信 + + x86_64下的多核启动已经完成,下面计划将其移植到Rust-OSDev项目的Bootloader中。 + + RISCV下尚未实现,这块第3组同学们有丰富经验。 + + 这部分计划与第3组合作,在第4周内完成。 + +2. 拓展线程管理模块,使之支持多核调度 + + 参照xv6 / ucore SMP实现一个可工作的版本。 + + 计划在第5周内完成。 + +3. 学习sv6进行多核优化 + + 已经完成[sv6 for RV64](https://github.com/twd2/sv6)在macOS上的复现。 + + 正在研究代码,并准备日后与twd2交流。 + + 计划在第6周移植一两个简单的实现到RustOS,并在之后视时间精力将其它部分逐渐移植过来。 + + + + 参考论文: + + * [The Scalable Commutativity Rule: Designing Scalable Software for Multicore Processors](https://pdos.csail.mit.edu/papers/commutativity:sosp13.pdf):Commuter项目论文,如何定量测试OS的并行度。鉴于时间有限,将其应用到RustOS应该无法在本学期完成。 + * [RadixVM: Scalable Address Spaces for Multithreaded Applications](http://pdos.csail.mit.edu/papers/radixvm:eurosys13.pdf):内存管理相关 + * [Scaling a file system to many cores using an operation log](http://delivery.acm.org/10.1145/3140000/3132779/p69-bhat.pdf?ip=183.172.124.170&id=3132779&acc=OA&key=BF85BBA5741FDC6E%2E587F3204F5B62A59%2E4D4702B0C3E38B35%2EEE2C838055815368&__acm__=1539103199_b0979df5a4432f0766f604f7a6e4809b):文件系统相关 + diff --git a/docs/2_OSLab/g5/exp3.md b/docs/2_OSLab/g5/exp3.md new file mode 100644 index 00000000..1b369023 --- /dev/null +++ b/docs/2_OSLab/g5/exp3.md @@ -0,0 +1,106 @@ +# 2018操作系统专题训练 + +# 实验3:实现和测试报告 + +计53 王润基 2015011279 + +2018.10.25 + +## 实验目标 + +**基于RustOS,参考sv6完成多核实现和优化。** + +分为以下三个子任务: + +1. 实现x86_64和RISCV下的多核启动和通信 +2. 拓展线程管理模块,使之支持多核调度 +3. 学习sv6进行多核优化 + +## 实验进展 + +基本完成前两项子任务,即:**实现了多核线程调度执行**。 + +具体的任务节点是: + +1. 到10月19日,我完成了x86下的多核启动和IPI。与此同时,王纪霆完成了riscv32下的多核启动,并针对编译器原子操作缺失问题给出了临时解决方案。我合并了他的成果,至此多核的底层支持实现完毕。 +2. 到10月25日,我完成了线程管理模块针对多处理机模型的重构,原来正常的用户程序都能在多核环境下正确执行。 + +## 实现方案 + +### x86的多核启动 + +实际上这部分工作已经在上学期OS课大作业中实现完毕。不过由于之后替换了x86下的bootloader,多核启动特性被暂时关闭。因此实际的任务是:**把原来Kernel中的多核启动代码,移植到新bootloader中**。 + +简单描述多核启动流程: + +* 将其它核的启动代码放置于物理地址0x8000处 + + 这个靠修改linker.ld,在链接阶段完成。物理地址必须4K对齐。 + +* 在主核初始化完毕后,调用一段操作LocalAPIC的代码(借用自xv6),向其它核发送启动IPI,让它从0x8000开始执行。主核需依次启动其它核,因为它们使用相同的栈空间,不能同时执行。 + +* 启动后,首先进行boot,在16位下设置段寄存器、页表、开启LongMode,直接进入64位,跳到Rust代码,再跳到Kernel入口点。 + +目前还未实现的特性是: + +* 应该首先读取ACPI中的LocalAPIC信息,确定核的个数。 + + 我原本计划使用RustOSDev的[ACPI库](https://github.com/rust-osdev/acpi),但它仍在开发中,功能尚不完全。 + +### x86的中断管理 + +在原来的单核环境中,系统使用PIC中断控制器和PIT时钟。 + +而在多核环境中,它们被IOAPIC和APIC Timer替代。 + +为此,我参考了xv6/sv6/Redox在这方面的实现,其中xv6实现最为简单,sv6进行了更好的对象包装,Redox提供了Rust下实现的参考。我发现这部分功能相对独立,而还没有人发布过Rust crate实现APIC功能,因此我自己实现了一个[APIC crate](https://github.com/wangrunji0408/APIC-Rust),综合参考了以上三个项目的代码。并将它用在了bootloader和kernel中。 + +### 合并RV工作 + +riscv32下的多核启动由王纪霆同学完成。我之后为它开启了IPI。 + +由于Rust编译器对riscv支持还不完全,不能生成原子指令,且核心库中的原子操作也没有为rv适配,具体体现为:rv下只有32位数据的原子操作,因此没有AtomicBool;此外即使用AtomicUsize实现的Mutex也不能正常工作,陈秋昊同学经过实验推测是Rust编译器内部实现的问题。 + +针对上述问题,王纪霆的解决方案是修改Kernel中Mutex的实现。而我在考虑直接修改核心库的实现,这样上层不用做修改,spin库也能正常使用。不过这一想法还没付诸实施。 + +### 多核线程管理 + +以上几个任务完成了平台相关的工作,接下来的任务都是平台无关的。 + +这部分主要工作是重构了process模块,使之支持多处理机模型。 + +在原来的设计中,用一个Processor类维护所有线程的状态,同时负责线程切换,对外提供exit/wait/sleep等控制接口。它是全局唯一的,用一个大锁包起来。 + +在新的设计中,线程状态和实际执行被分开。其中线程状态由[ProcessManager](http://os.cs.tsinghua.edu.cn/oscourse/ProcessManager)类管理,另外的Processor类负责线程的实际执行。前者是全局唯一的,后者是CPU核的抽象,每个核对应一个。由于它们都需要定义为全局变量,因此对外接口都是&self,内部用[SpinLock](http://os.cs.tsinghua.edu.cn/oscourse/SpinLock)或[UnsafeCell](http://os.cs.tsinghua.edu.cn/oscourse/UnsafeCell)维护可变状态。 + +参考xv6/ucore的设计,每个CPU核在初始化完毕后都进入自己的“调度线程”,无限重复以下操作: + +- 从[ProcessManager](http://os.cs.tsinghua.edu.cn/oscourse/ProcessManager)中取出一个可执行线程的上下文(委托内部的Scheduler决定选哪个) +- 执行上下文切换运行该线程 +- 线程运行时(主动地,或在时钟中断时被动地)调用yield切换回调度线程 +- 将运行完的线程上下文交还[ProcessManager](http://os.cs.tsinghua.edu.cn/oscourse/ProcessManager) + + + +上述内容实现后,就得到了一个最基础的线程执行框架: + +* 每个进程有3个状态:Ready等待执行,Running正在执行,Sleep不可执行 +* 若干处理机并发地从一个公共线程池里取出、执行、放回 + +注意这个实现不包括: + +* 维护线程间的父子关系(所有线程是平级的) +* 维护线程间的等待关系(等待和唤醒应该由等待队列完成) + +这部分工作的前期大量时间投入在构思设计上:如何界定类的指责和它们的交互关系?更具体的——哪里用锁?哪里可变?每个需求如何实现?受制于Rust类型系统和安全机制的约束,要设计一个编译通过的方案并不容易。 + +前期设计断断续续用了几天时间,而编写代码只用了一天,而其中相当一部分时间在与编译器作斗争。不过在编译通过后,仅修复了几个明显的Bug就能正常运行了!完全没有数据竞争问题!不得不承认Rust语言在处理并发问题上有很大优势。 + +## 未来计划 + +1. 在HiFive开发版上运行RustOS +2. 更深入研究sv6,移植其中的多核优化特性 +3. 完善系统调用,争取能跑起来sv6的用户程序,方便进行性能对比 + + + diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index d798497e..ca9d5a1e 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -1,7 +1,28 @@ +[[package]] +name = "apic" +version = "0.1.0" +source = "git+https://github.com/wangrunji0408/APIC-Rust#5002b7de801178bef0635e7fe399ce513f04cbf9" +dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "x86 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "array-init" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bare-metal" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "bbl" @@ -31,12 +52,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bootloader" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.3.4" +source = "git+https://github.com/wangrunji0408/bootloader#dd5723c3d7d50856073a5003e0a355ea0fc3d46c" dependencies = [ + "apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)", "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -47,7 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -82,11 +104,10 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -99,17 +120,22 @@ name = "linked_list_allocator" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "once" version = "0.3.3" @@ -135,7 +161,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "raw-cpuid" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -148,24 +184,47 @@ name = "remove_dir_all" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "riscv" version = "0.3.0" +source = "git+https://github.com/riscv-and-rust-and-decaf/riscv#f358204af01f2374ab6ed6ea059f724cd5f2fe6f" dependencies = [ - "bare-metal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "simple-filesystem" version = "0.0.1" -source = "git+https://github.com/wangrunji0408/SimpleFileSystem-Rust#ca10d11264c85932e95e6c7c29e8b10c91ae0720" +source = "git+https://github.com/wangrunji0408/SimpleFileSystem-Rust?branch=multi-thread#24a51faff266744d83c1ef60328b28906d2b525c" dependencies = [ "bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -180,7 +239,7 @@ dependencies = [ [[package]] name = "spin" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -203,32 +262,34 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ucore" version = "0.1.0" dependencies = [ + "apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)", "bbl 0.1.0", "bit-allocator 0.1.0", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)", "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "riscv 0.3.0", - "simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)", - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)", + "simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust?branch=multi-thread)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ucore-memory 0.1.0", "ucore-process 0.1.0", "volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -236,15 +297,15 @@ dependencies = [ name = "ucore-memory" version = "0.1.0" dependencies = [ - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ucore-process" version = "0.1.0" dependencies = [ - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -262,11 +323,6 @@ name = "ux" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "version_check" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "volatile" version = "0.1.0" @@ -274,7 +330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -292,10 +348,32 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "x86_64" -version = "0.2.11" +name = "x86" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -317,41 +395,50 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum bare-metal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bdcf9294ed648c7cd29b11db06ea244005aeef50ae8f605b1a3af2940bf8f92" +"checksum apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)" = "" +"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" +"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a" "checksum bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)" = "" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1721ced9efc102309bc218c7934d642f60567858faf8d5dd90c0cc6722d97b9" +"checksum bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)" = "" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" -"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" +"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" -"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" +"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" "checksum linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "655d57c71827fe0891ce72231b6aa5e14033dae3f604609e6a6f807267c1678d" -"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" +"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)" = "" +"checksum riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)" = "" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust?branch=multi-thread)" = "" "checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" -"checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4" +"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" "checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" -"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37c5d76c0f40ba4f8ac10ec4717d4e98ce3e58c5607eea36e9464226fc5e0a95" -"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "466c2002e38edde7ebbaae6656793d4f71596634971c7e8cbf7afa4827968445" +"checksum x86 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "841e1ca5a87068718a2a26f2473c6f93cf3b8119f9778fa0ae4b39b664d9e66a" +"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4" +"checksum x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b14609bad1c2c6a41113a1054f94394154e99bcb4b24cd7051109113c656c5a9" "checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" "checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 0afa030f..d37a0d15 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,13 +4,11 @@ version = "0.1.0" authors = ["Runji Wang "] [features] -use_apic = [] link_user_program = [] no_bbl = [] [profile.dev] # MUST >= 1 : Enable RVO to avoid stack overflow -# MUST <= 1 : Avoid double fault at -O2 T_T opt-level = 1 [profile.release] @@ -18,27 +16,31 @@ debug = true [dependencies] log = "0.4" -spin = "0.4.9" -once = "0.3.3" +spin = "0.4" +once = "0.3" xmas-elf = "0.6" bitflags = "1.0" -bit_field = "0.9.0" -volatile = "0.1.0" +bit_field = "0.9" +volatile = "0.1" linked_list_allocator = "0.6" -lazy_static = { version = "1.0.0", features = ["spin_no_std"] } +lazy_static = { version = "1.2", features = ["spin_no_std"] } bit-allocator = { path = "../crate/bit-allocator" } ucore-memory = { path = "../crate/memory" } ucore-process = { path = "../crate/process" } -simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } +simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust", branch = "multi-thread" } [target.'cfg(target_arch = "x86_64")'.dependencies] -bootloader = "0.3" -x86_64 = "0.2.11" +bootloader = { git = "https://github.com/wangrunji0408/bootloader" } +apic = { git = "https://github.com/wangrunji0408/APIC-Rust" } +#bootloader = { path = "../crate/bootloader" } +#apic = { path = "../crate/apic" } +x86_64 = "0.3" +raw-cpuid = "6.0" redox_syscall = "0.1" uart_16550 = "0.1" [target.'cfg(target_arch = "riscv32")'.dependencies] -riscv = { path = "../crate/riscv" } +riscv = { git = "https://github.com/riscv-and-rust-and-decaf/riscv" } bbl = { path = "../crate/bbl" } [package.metadata.bootimage] diff --git a/kernel/Makefile b/kernel/Makefile index 00531848..471585c4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -12,11 +12,13 @@ # d = int | in_asm | ... QEMU debug info # mode = debug | release # LOG = off | error | warn | info | debug | trace +# smp SMP core number # board Only available on riscv32, build without bbl, run on board arch ?= riscv32 mode ?= debug LOG ?= debug +smp ?= 4 target := $(arch)-blog_os kernel := target/$(target)/$(mode)/ucore @@ -31,12 +33,16 @@ ifeq ($(arch), x86_64) qemu_opts := \ -drive format=raw,file=$(bootimage) \ -drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \ - -smp 4 \ + -smp cores=$(smp) \ -serial mon:stdio \ -device isa-debug-exit endif ifeq ($(arch), riscv32) -qemu_opts := -machine virt -kernel $(bin) -nographic +qemu_opts := \ + -machine virt \ + -kernel $(bin) \ + -nographic \ + -smp cores=$(smp) endif ifdef board @@ -83,6 +89,7 @@ all: $(kernel) clean: @cargo clean + @rm -rf ../riscv-pk/build doc: @cargo rustdoc -- --document-private-items @@ -104,9 +111,12 @@ endif asm: @$(objdump) -dS $(kernel) | less -elf-h: +header: @$(objdump) -h $(kernel) +sym: + @$(objdump) -t $(kernel) | less + $(bin): kernel ifdef board @cp $(kernel) $@ @@ -128,7 +138,10 @@ kernel: ifeq ($(arch), x86_64) @bootimage build $(build_args) else - @cargo xbuild $(build_args) + @-patch -p0 -N -b \ + $(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ + src/arch/riscv32/atomic.patch + @CC=$(cc) cargo xbuild $(build_args) endif # make user.o from binary files diff --git a/kernel/build.rs b/kernel/build.rs index af15f66d..ec94d4eb 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -12,6 +12,13 @@ fn main() { // .compile("cobj"); gen_vector_asm().unwrap(); } + if std::env::var("TARGET").unwrap().find("riscv32").is_some() { + cc::Build::new() + .file("src/arch/riscv32/compiler_rt.c") + .flag("-march=rv32ia") + .flag("-mabi=ilp32") + .compile("atomic_rt"); + } } fn gen_vector_asm() -> Result<()> { diff --git a/kernel/riscv32-blog_os.json b/kernel/riscv32-blog_os.json index ab160b8d..33e9156e 100644 --- a/kernel/riscv32-blog_os.json +++ b/kernel/riscv32-blog_os.json @@ -9,12 +9,11 @@ "cpu": "generic-rv32", "features": "", "max-atomic-width": "32", - "linker": "riscv64-unknown-elf-ld", - "linker-flavor": "ld", + "linker": "rust-lld", + "linker-flavor": "ld.lld", "pre-link-args": { - "ld": [ - "-Tsrc/arch/riscv32/boot/linker.ld", - "-melf32lriscv" + "ld.lld": [ + "-Tsrc/arch/riscv32/boot/linker.ld" ] }, "executables": true, diff --git a/kernel/src/arch/riscv32/atomic.patch b/kernel/src/arch/riscv32/atomic.patch new file mode 100644 index 00000000..ec7ca3af --- /dev/null +++ b/kernel/src/arch/riscv32/atomic.patch @@ -0,0 +1,57 @@ +--- atomic_backup.rs 2018-10-06 19:59:14.000000000 +0800 ++++ atomic.rs 2018-10-26 14:34:31.000000000 +0800 +@@ -125,6 +125,9 @@ + #[cfg(target_has_atomic = "8")] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct AtomicBool { ++ #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] ++ v: UnsafeCell, ++ #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] + v: UnsafeCell, + } + +@@ -265,6 +268,44 @@ + pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); + + #[cfg(target_has_atomic = "8")] ++#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] ++impl AtomicBool { ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ pub const fn new(v: bool) -> AtomicBool { ++ AtomicBool { v: UnsafeCell::new(v as u32) } ++ } ++ ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ pub fn load(&self, order: Ordering) -> bool { ++ unsafe { atomic_load(self.v.get(), order) != 0 } ++ } ++ ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ pub fn store(&self, val: bool, order: Ordering) { ++ unsafe { atomic_store(self.v.get(), val as u32, order); } ++ } ++ ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ #[cfg(target_has_atomic = "cas")] ++ pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { ++ loop { ++ if let Ok(val) = unsafe { atomic_compare_exchange(self.v.get(), current as u32, new as u32, order, order) } { ++ return val != 0; ++ } ++ } ++ } ++} ++ ++#[cfg(target_has_atomic = "8")] ++#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] + impl AtomicBool { + /// Creates a new `AtomicBool`. + /// diff --git a/kernel/src/arch/riscv32/compiler_rt.c b/kernel/src/arch/riscv32/compiler_rt.c new file mode 100644 index 00000000..95c871f9 --- /dev/null +++ b/kernel/src/arch/riscv32/compiler_rt.c @@ -0,0 +1,38 @@ +// http://llvm.org/docs/Atomics.html#libcalls-atomic + +int __atomic_load_4(int *src) { + int res = 0; + __asm__ __volatile__("amoadd.w.rl %0, zero, (%1)" : "=r"(res) : "r"(src) : "memory"); + return res; +} + +int __atomic_store_4(int *dst, int val) { + __asm__ __volatile__("amoswap.w.aq zero, %0, (%1)" :: "r"(val), "r"(dst) : "memory"); +} + +char __atomic_compare_exchange_4(int* dst, int* expected, int desired) { + int val; + // val = *dst + __asm__ __volatile__("lr.w %0, (%1)" : "=r"(val) : "r"(dst) : "memory"); + if (val == *expected) { + int result; + // Try: *dst = desired. If success, result = 0, otherwise result != 0. + __asm__ __volatile__("sc.w %0, %1, (%2)" : "=r"(result) : "r"(desired), "r"(dst) : "memory"); + return result == 0; + } + // *expected should always equal to the previous value of *dst + *expected = val; + return 0; +} + +int __atomic_fetch_add_4(int* ptr, int val) { + int res; + __asm__ __volatile__("amoadd.w.rl %0, %1, (%2)" : "=r"(res) : "r"(val), "r"(ptr) : "memory"); + return res; +} + +int __atomic_fetch_sub_4(int* ptr, int val) { + int res; + __asm__ __volatile__("amoadd.w.rl %0, %1, (%2)" : "=r"(res) : "r"(-val), "r"(ptr) : "memory"); + return res; +} \ No newline at end of file diff --git a/kernel/src/arch/riscv32/compiler_rt.rs b/kernel/src/arch/riscv32/compiler_rt.rs index 63752c9a..e8fff841 100644 --- a/kernel/src/arch/riscv32/compiler_rt.rs +++ b/kernel/src/arch/riscv32/compiler_rt.rs @@ -23,79 +23,3 @@ pub extern fn __mulsi3(mut a: u32, mut b: u32) -> u32 { pub extern fn abort() { loop {} } - -use core::ptr::{read, write}; - -#[no_mangle] -pub unsafe extern fn __atomic_load_1(src: *const u8) -> u8 { - read(src) -} - -#[no_mangle] -pub unsafe extern fn __atomic_load_2(src: *const u16) -> u16 { - read(src) -} - -#[no_mangle] -pub unsafe extern fn __atomic_load_4(src: *const u32) -> u32 { - read(src) -} - -#[no_mangle] -pub unsafe extern fn __atomic_store_1(dst: *mut u8, val: u8) { - write(dst, val) -} - -#[no_mangle] -pub unsafe extern fn __atomic_store_4(dst: *mut u32, val: u32) { - write(dst, val) -} - -unsafe fn __atomic_compare_exchange(dst: *mut T, expected: *mut T, desired: T) -> bool { - use super::interrupt; - let flags = interrupt::disable_and_store(); - let val = read(dst); - let success = val == read(expected); - if success { - write(dst, desired); - write(expected, val); - } else { - write(expected, val); - } - - interrupt::restore(flags); - success -} - -#[no_mangle] -pub unsafe extern fn __atomic_compare_exchange_1(dst: *mut u8, expected: *mut u8, desired: u8) -> bool { - __atomic_compare_exchange(dst, expected, desired) -} - -#[no_mangle] -pub unsafe extern fn __atomic_compare_exchange_4(dst: *mut u32, expected: *mut u32, desired: u32) -> bool { - __atomic_compare_exchange(dst, expected, desired) -} - - -#[no_mangle] -pub unsafe extern fn __atomic_fetch_add_4(dst: *mut u32, delta: u32) -> u32 { - use super::interrupt; - let flags = interrupt::disable_and_store(); - let val = read(dst); - let new_val = val + delta; - write(dst, new_val); - interrupt::restore(flags); - val -} - -#[no_mangle] -pub unsafe extern fn __atomic_fetch_sub_4(dst: *mut u32, delta: u32) -> u32 { - use super::interrupt; - let flags = interrupt::disable_and_store(); - let val = read(dst); - let new_val = val - delta; - write(dst, new_val); - interrupt::restore(flags); - val -} \ No newline at end of file diff --git a/kernel/src/arch/riscv32/consts.rs b/kernel/src/arch/riscv32/consts.rs index 71efb2cd..40a8e6be 100644 --- a/kernel/src/arch/riscv32/consts.rs +++ b/kernel/src/arch/riscv32/consts.rs @@ -5,8 +5,6 @@ const P2_MASK: usize = 0x3ff << 22; pub const RECURSIVE_INDEX: usize = 0x3fe; pub const KERNEL_OFFSET: usize = 0; pub const KERNEL_P2_INDEX: usize = 0x8000_0000 >> 22; -pub const KERNEL_HEAP_OFFSET: usize = 0x8020_0000; //deprecated now -//pub const KERNEL_HEAP_SIZE: usize = 0x0020_0000; pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000; pub const MEMORY_OFFSET: usize = 0x8000_0000; //pub const MEMORY_END: usize = 0x8080_0000; //for thinpad not enough now diff --git a/kernel/src/arch/riscv32/context.rs b/kernel/src/arch/riscv32/context.rs index 1486e9fb..50c99ad3 100644 --- a/kernel/src/arch/riscv32/context.rs +++ b/kernel/src/arch/riscv32/context.rs @@ -26,7 +26,7 @@ impl TrapFrame { use core::mem::zeroed; let mut tf: Self = unsafe { zeroed() }; tf.x[10] = arg; // a0 - tf.x[2] = sp; + tf.x[2] = sp; tf.sepc = entry as usize; tf.sstatus = sstatus::read(); // Supervisor Previous Interrupt Enable @@ -58,10 +58,6 @@ impl TrapFrame { tf.sstatus.set_spp(sstatus::SPP::User); tf } - - pub fn is_user(&self) -> bool { - unimplemented!() - } } use core::fmt::{Debug, Formatter, Error}; @@ -87,7 +83,8 @@ impl Debug for TrapFrame { .finish() } } -/// kernel stack contents for a new thread + +/// kernel stack contents for a new thread #[derive(Debug)] #[repr(C)] pub struct InitStack { @@ -125,7 +122,7 @@ struct ContextData { impl ContextData { fn new(satp: usize) -> Self { - // satp(asid) just like cr3, save the physical address for Page directory? + // satp(asid) just like cr3, save the physical address for Page directory? ContextData { ra: __trapret as usize, satp, ..ContextData::default() } } } @@ -242,9 +239,9 @@ impl Context { * TrapFrame: the trapframe of the forked process(thread) * kstack_top: kernel stack top * cr3: cr3 register, save the physical address of Page directory - * @brief: + * @brief: * fork and generate a new process(thread) Context according to the TrapFrame and save it's address at kernel stack top - 1 - * @retval: + * @retval: * a Context struct with the pointer to the kernel stack top - 1 as its only element */ pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { @@ -258,4 +255,9 @@ impl Context { }, }.push_at(kstack_top) } + /// Called at a new user context + /// To get the init TrapFrame in sys_exec + pub unsafe fn get_init_tf(&self) -> TrapFrame { + (*(self.0 as *const InitStack)).tf.clone() + } } \ No newline at end of file diff --git a/kernel/src/arch/riscv32/interrupt.rs b/kernel/src/arch/riscv32/interrupt.rs index b1d291ec..7942938f 100644 --- a/kernel/src/arch/riscv32/interrupt.rs +++ b/kernel/src/arch/riscv32/interrupt.rs @@ -7,7 +7,7 @@ use memory::MemorySet; mod context; /* -* @brief: +* @brief: * initialize the interrupt status */ pub fn init() { @@ -29,7 +29,7 @@ pub fn init() { } /* -* @brief: +* @brief: * enable interrupt */ #[inline(always)] @@ -38,7 +38,7 @@ pub unsafe fn enable() { } /* -* @brief: +* @brief: * store and disable interrupt * @retbal: * a usize value store the origin sie @@ -53,7 +53,7 @@ pub unsafe fn disable_and_store() -> usize { /* * @param: * flags: input flag -* @brief: +* @brief: * enable interrupt if flags != 0 */ #[inline(always)] @@ -66,15 +66,16 @@ pub unsafe fn restore(flags: usize) { /* * @param: * TrapFrame: the trapFrame of the Interrupt/Exception/Trap to be processed -* @brief: +* @brief: * process the Interrupt/Exception/Trap */ #[no_mangle] pub extern fn rust_trap(tf: &mut TrapFrame) { use super::riscv::register::scause::{Trap, Interrupt as I, Exception as E}; - trace!("Interrupt: {:?}", tf.scause.cause()); + trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause()); match tf.scause.cause() { Trap::Interrupt(I::SupervisorExternal) => serial(), + Trap::Interrupt(I::SupervisorSoft) => ipi(), Trap::Interrupt(I::SupervisorTimer) => timer(), Trap::Exception(E::IllegalInstruction) => illegal_inst(tf), Trap::Exception(E::UserEnvCall) => syscall(tf), @@ -94,8 +95,9 @@ fn ipi() { debug!("IPI"); super::bbl::sbi::clear_ipi(); } + /* -* @brief: +* @brief: * process timer interrupt */ fn timer() { @@ -106,7 +108,7 @@ fn timer() { /* * @param: * TrapFrame: the Trapframe for the syscall -* @brief: +* @brief: * process syscall */ fn syscall(tf: &mut TrapFrame) { @@ -118,7 +120,7 @@ fn syscall(tf: &mut TrapFrame) { /* * @param: * TrapFrame: the Trapframe for the illegal inst exception -* @brief: +* @brief: * process IllegalInstruction exception */ fn illegal_inst(tf: &mut TrapFrame) { @@ -128,9 +130,9 @@ fn illegal_inst(tf: &mut TrapFrame) { } /* -* @param: +* @param: * TrapFrame: the Trapframe for the page fault exception -* @brief: +* @brief: * process page fault exception */ fn page_fault(tf: &mut TrapFrame) { @@ -149,9 +151,9 @@ fn page_fault(tf: &mut TrapFrame) { /* * @param: * TrapFrame: the Trapframe for the illegal inst exception -* @brief: +* @brief: * emulate the multiply and divide operation (if not this kind of operation return false) -* @retval: +* @retval: * a bool indicates whether emulate the multiply and divide operation successfully */ fn emulate_mul_div(tf: &mut TrapFrame) -> bool { diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index a87618a0..e9020506 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -1,5 +1,5 @@ -use core::slice; -use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack}; +use core::{slice, mem}; +use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet}; use super::riscv::{addr::*, register::sstatus}; use ucore_memory::PAGE_SIZE; @@ -13,17 +13,24 @@ pub fn init() { static PAGE_TABLE_ROOT: PageData = PageData([0; PAGE_SIZE]); unsafe { sstatus::set_sum(); } // Allow user memory access - let frame = Frame::of_addr(PhysAddr::new(&PAGE_TABLE_ROOT as *const _ as u32)); + let frame = Frame::of_addr(PhysAddr::new(&PAGE_TABLE_ROOT as *const _ as u32)); super::paging::setup_page_table(frame); // set up page table // initialize heap and Frame allocator init_frame_allocator(); + init_heap(); // remap the kernel use 4K page remap_the_kernel(); - init_heap(); +} + +pub fn init_other() { + unsafe { + sstatus::set_sum(); // Allow user memory access + asm!("csrw 0x180, $0; sfence.vma" :: "r"(SATP) :: "volatile"); + } } /* -* @brief: +* @brief: * Init frame allocator, here use a BitAlloc implemented by segment tree. */ fn init_frame_allocator() { @@ -32,18 +39,14 @@ fn init_frame_allocator() { use consts::{MEMORY_OFFSET, MEMORY_END}; let mut ba = FRAME_ALLOCATOR.lock(); - //use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; - // keep memory for the kernel heap and set other physical memory available in BitAlloc - //ba.insert(to_range(KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MEMORY_END)); - // end here is the end entry of the kernel ba.insert(to_range(end as usize + PAGE_SIZE, MEMORY_END)); info!("FrameAllocator init end"); /* * @param: - * start: start address + * start: start address * end: end address - * @brief: + * @brief: * transform the memory address to the page number * @retval: * the page number range from start address to end address @@ -56,29 +59,27 @@ fn init_frame_allocator() { } /* -* @brief: +* @brief: * remmap the kernel memory address with 4K page recorded in p1 page table */ fn remap_the_kernel() { - use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; - // set up kernel stack - let kstack = Stack { - top: bootstacktop as usize, - bottom: bootstack as usize + PAGE_SIZE, - }; - static mut SPACE: [u8; 0x1000] = [0; 0x1000]; - let mut ms = unsafe { MemorySet::new_from_raw_space(&mut SPACE, kstack) }; + let mut ms = MemorySet::new_bare(); + #[cfg(feature = "no_bbl")] ms.push(MemoryArea::new_identity(0x10000000, 0x10000008, MemoryAttr::default(), "serial")); ms.push(MemoryArea::new_identity(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), "text")); ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data")); ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata")); ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss")); unsafe { ms.activate(); } - use core::mem::forget; - forget(ms); + unsafe { SATP = ms.token(); } + mem::forget(ms); info!("kernel remap end"); } +// First core stores its SATP here. +// Other cores load it later. +static mut SATP: usize = 0; + // Symbols provided by linker script extern { fn stext(); diff --git a/kernel/src/arch/riscv32/mod.rs b/kernel/src/arch/riscv32/mod.rs index de43a259..ffdb0887 100644 --- a/kernel/src/arch/riscv32/mod.rs +++ b/kernel/src/arch/riscv32/mod.rs @@ -27,7 +27,7 @@ pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! { timer::init(); ::process::init(); - ::thread::spawn(::fs::shell); + ::thread::spawn(::shell::run_user_shell); unsafe { cpu::start_others(hart_mask); } ::kmain(); @@ -35,6 +35,7 @@ pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! { fn others_main() -> ! { interrupt::init(); + memory::init_other(); timer::init(); ::kmain(); } diff --git a/kernel/src/arch/riscv32/paging.rs b/kernel/src/arch/riscv32/paging.rs index e4fe5e3d..8440b703 100644 --- a/kernel/src/arch/riscv32/paging.rs +++ b/kernel/src/arch/riscv32/paging.rs @@ -1,6 +1,6 @@ use consts::{KERNEL_P2_INDEX, RECURSIVE_INDEX}; // Depends on kernel -use memory::{active_table, alloc_frame, alloc_stack, dealloc_frame}; +use memory::{active_table, alloc_frame, dealloc_frame}; use super::riscv::addr::*; use super::riscv::asm::{sfence_vma, sfence_vma_all}; use super::riscv::paging::{Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable}; @@ -14,7 +14,7 @@ use ucore_memory::paging::*; * @param: * Frame: page table root frame * @brief: -* setup page table in the frame +* setup page table in the frame */ // need 1 page pub fn setup_page_table(frame: Frame) { @@ -25,7 +25,7 @@ pub fn setup_page_table(frame: Frame) { // Set kernel identity map // 0x10000000 ~ 1K area p2.map_identity(0x40, EF::VALID | EF::READABLE | EF::WRITABLE); - // 0x80000000 ~ 12M area for + // 0x80000000 ~ 12M area for p2.map_identity(KERNEL_P2_INDEX, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE); p2.map_identity(KERNEL_P2_INDEX + 1, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE); p2.map_identity(KERNEL_P2_INDEX + 2, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE); @@ -44,12 +44,12 @@ impl PageTable for ActivePageTable { type Entry = PageEntry; /* - * @param: + * @param: * addr: the virtual addr to be matched * target: the physical addr to be matched with addr - * @brief: + * @brief: * map the virtual address 'addr' to the physical address 'target' in pagetable. - * @retval: + * @retval: * the matched PageEntry */ fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry { @@ -62,13 +62,13 @@ impl PageTable for ActivePageTable { // we may need frame allocator to alloc frame for new page table(first/second) self.0.map_to(page, frame, flags, &mut FrameAllocatorForRiscv) .unwrap().flush(); - self.get_entry(addr) + self.get_entry(addr).unwrap() } /* - * @param: + * @param: * addr: virtual address of which the mapped physical frame should be unmapped - * @bridf: + * @bridf: ^ unmap the virtual addresses' mapped physical frame */ fn unmap(&mut self, addr: usize) { @@ -78,28 +78,31 @@ impl PageTable for ActivePageTable { } /* - * @param: + * @param: * addr:input virtual address - * @brief: + * @brief: * get the pageEntry of 'addr' - * @retval: + * @retval: * a mutable PageEntry reference of 'addr' */ - fn get_entry(&mut self, addr: usize) -> &mut PageEntry { + fn get_entry(&mut self, addr: usize) -> Option<&mut PageEntry> { + if unsafe { !(*ROOT_PAGE_TABLE)[addr >> 22].flags().contains(EF::VALID) } { + return None; + } let page = Page::of_addr(VirtAddr::new(addr)); // ??? let _ = self.0.translate_page(page); let entry_addr = ((addr >> 10) & ((1 << 22) - 4)) | (RECURSIVE_INDEX << 22); - unsafe { &mut *(entry_addr as *mut PageEntry) } + unsafe { Some(&mut *(entry_addr as *mut PageEntry)) } } /* - * @param: + * @param: * addr:the input (virutal) address - * @brief: - * get the addr's memory page slice - * @retval: - * a mutable reference slice of 'addr' 's page + * @brief: + * get the addr's memory page slice + * @retval: + * a mutable reference slice of 'addr' 's page */ fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: usize) -> &'b mut [u8] { use core::slice; @@ -107,11 +110,11 @@ impl PageTable for ActivePageTable { } /* - * @param: + * @param: * addr: virtual address - * @brief: + * @brief: * get the address's content - * @retval: + * @retval: * the content(u8) of 'addr' */ fn read(&mut self, addr: usize) -> u8 { @@ -119,9 +122,9 @@ impl PageTable for ActivePageTable { } /* - * @param: + * @param: * addr: virtual address - * @brief: + * @brief: * write the address's content */ fn write(&mut self, addr: usize, data: u8) { @@ -142,7 +145,7 @@ impl ActivePageTable { * @param: * frame: the target physical frame which will be temporarily mapped * f: the function you would like to apply for once - * @brief: + * @brief: * do something on the target physical frame? */ fn with_temporary_map(&mut self, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut RvPageTable)) { @@ -213,9 +216,9 @@ impl InactivePageTable for InactivePageTable0 { type Active = ActivePageTable; /* - * @brief: + * @brief: * get a new pagetable (for a new process or thread) - * @retbal: + * @retbal: * the new pagetable */ fn new() -> Self { @@ -225,9 +228,9 @@ impl InactivePageTable for InactivePageTable0 { } /* - * @brief: + * @brief: * allocate a new frame and then self-mapping it and regard it as the inactivepagetale - * retval: + * retval: * the inactive page table */ fn new_bare() -> Self { @@ -241,10 +244,10 @@ impl InactivePageTable for InactivePageTable0 { } /* - * @param: + * @param: * f: a function to do something with the temporary modified activate page table - * @brief: - * temporarily map the inactive pagetable as an active p2page and apply f on the temporary modified active page table + * @brief: + * temporarily map the inactive pagetable as an active p2page and apply f on the temporary modified active page table */ fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) { active_table().with_temporary_map(&satp::read().frame(), |active_table, p2_table: &mut RvPageTable| { @@ -277,28 +280,6 @@ impl InactivePageTable for InactivePageTable0 { } } - /* - * @param: - * f: the function to run when temporarily activate self as current page table - * @brief: - * Temporarily activate self and run the process - */ - unsafe fn with(&self, f: impl FnOnce()) { - let old_frame = satp::read().frame(); - let new_frame = self.p2_frame.clone(); - debug!("switch table {:x?} -> {:x?}", old_frame, new_frame); - if old_frame != new_frame { - satp::set(satp::Mode::Sv32, 0, new_frame); - sfence_vma_all(); - } - f(); - debug!("switch table {:x?} -> {:x?}", new_frame, old_frame); - if old_frame != new_frame { - satp::set(satp::Mode::Sv32, 0, old_frame); - sfence_vma_all(); - } - } - /* * @param: * f: the function to run when temporarily activate self as current page table @@ -307,7 +288,7 @@ impl InactivePageTable for InactivePageTable0 { * @retval: * the return value of f */ - unsafe fn with_retval(&self, f: impl FnOnce() -> T) -> T{ + unsafe fn with(&self, f: impl FnOnce() -> T) -> T { let old_frame = satp::read().frame(); let new_frame = self.p2_frame.clone(); debug!("switch table {:x?} -> {:x?}", old_frame, new_frame); @@ -341,16 +322,12 @@ impl InactivePageTable for InactivePageTable0 { fn dealloc_frame(target: usize) { dealloc_frame(target) } - - fn alloc_stack() -> Stack { - alloc_stack() - } } impl InactivePageTable0 { /* - * @brief: - * map the kernel code memory address (p2 page table) in the new inactive page table according the current active page table + * @brief: + * map the kernel code memory address (p2 page table) in the new inactive page table according the current active page table */ fn map_kernel(&mut self) { let table = unsafe { &mut *ROOT_PAGE_TABLE }; diff --git a/kernel/src/arch/x86_64/driver/apic/ioapic.rs b/kernel/src/arch/x86_64/driver/apic/ioapic.rs deleted file mode 100644 index 48e7d357..00000000 --- a/kernel/src/arch/x86_64/driver/apic/ioapic.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Migrate from xv6 ioapic.c - -/// The I/O APIC manages hardware interrupts for an SMP system. -/// http://www.intel.com/design/chipsets/datashts/29056601.pdf -/// See also picirq.c. - -use super::super::redox_syscall::io::{Io, Mmio}; -use bit_field::BitField; -use arch::interrupt::consts::T_IRQ0; -use spin::Mutex; - -pub fn init() -{ - let mut ioapic = IOAPIC.lock(); - - // Mark all interrupts edge-triggered, active high, disabled, - // and not routed to any CPUs. - for i in 0.. ioapic.maxintr() + 1 { - ioapic.write_irq(i, RedirectionEntry::DISABLED, 0); - } - info!("ioapic: init end"); -} - -const IOAPIC_ADDRESS : u32 = 0xFEC00000; // Default physical address of IO APIC - -const REG_ID : u8 = 0x00; // Register index: ID -const REG_VER : u8 = 0x01; // Register index: version -const REG_TABLE : u8 = 0x10; // Redirection table base - -// The redirection table starts at REG_TABLE and uses -// two registers to configure each interrupt. -// The first (low) register in a pair contains configuration bits. -// The second (high) register contains a bitmask telling which -// CPUs can serve that interrupt. - -bitflags! { - struct RedirectionEntry: u32 { - const DISABLED = 0x00010000; // Interrupt disabled - const LEVEL = 0x00008000; // Level-triggered (vs edge-) - const ACTIVELOW = 0x00002000; // Active low (vs high) - const LOGICAL = 0x00000800; // Destination is CPU id (vs APIC ID) - const NONE = 0x00000000; - } -} - -lazy_static! { - pub static ref IOAPIC: Mutex = Mutex::new(unsafe{IoApic::new()}); -} - -// IO APIC MMIO structure: write reg, then read or write data. -#[repr(C)] -struct IoApicMmio { - reg: Mmio, - pad: [Mmio; 3], - data: Mmio, -} - -pub struct IoApic { - mmio: &'static mut IoApicMmio -} - -impl IoApic { - unsafe fn new() -> Self { - IoApic { mmio: &mut *(IOAPIC_ADDRESS as *mut IoApicMmio) } - } - fn read(&mut self, reg: u8) -> u32 - { - self.mmio.reg.write(reg as u32); - self.mmio.data.read() - } - fn write(&mut self, reg: u8, data: u32) - { - self.mmio.reg.write(reg as u32); - self.mmio.data.write(data); - } - fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8) - { - self.write(REG_TABLE+2*irq, (T_IRQ0 + irq) as u32 | flags.bits()); - self.write(REG_TABLE+2*irq+1, (dest as u32) << 24); - } - pub fn enable(&mut self, irq: u8, cpunum: u8) - { - info!("ioapic: enable irq {} @ cpu{}", irq, cpunum); - // Mark interrupt edge-triggered, active high, - // enabled, and routed to the given cpunum, - // which happens to be that cpu's APIC ID. - self.write_irq(irq, RedirectionEntry::NONE, cpunum); - } - fn id(&mut self) -> u8 { - self.read(REG_ID).get_bits(24..28) as u8 - } - fn version(&mut self) -> u8 { - self.read(REG_VER).get_bits(0..8) as u8 - } - fn maxintr(&mut self) -> u8 { - self.read(REG_VER).get_bits(16..24) as u8 - } -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/apic/lapic.c b/kernel/src/arch/x86_64/driver/apic/lapic.c deleted file mode 100644 index b01b1b89..00000000 --- a/kernel/src/arch/x86_64/driver/apic/lapic.c +++ /dev/null @@ -1,165 +0,0 @@ -// The local APIC manages internal (non-I/O) interrupts. -// See Chapter 8 & Appendix C of Intel processor manual volume 3. - -typedef unsigned int uint; -typedef unsigned char uchar; -typedef unsigned short ushort; - -static inline void -outb(ushort port, uchar data) -{ - asm volatile("out %0,%1" : : "a" (data), "d" (port)); -} - -#define KERNBASE 0xFFFFFF0000000000 // First kernel virtual address -#define P2V(a) (((void *) (a)) + KERNBASE) - -#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ - -#define IRQ_TIMER 0 -#define IRQ_KBD 1 -#define IRQ_COM1 4 -#define IRQ_IDE 14 -#define IRQ_ERROR 19 -#define IRQ_SPURIOUS 31 - -// Local APIC registers, divided by 4 for use as uint[] indices. -#define ID (0x0020/4) // ID -#define VER (0x0030/4) // Version -#define TPR (0x0080/4) // Task Priority -#define EOI (0x00B0/4) // EOI -#define SVR (0x00F0/4) // Spurious Interrupt Vector - #define ENABLE 0x00000100 // Unit Enable -#define ESR (0x0280/4) // Error Status -#define ICRLO (0x0300/4) // Interrupt Command - #define INIT 0x00000500 // INIT/RESET - #define STARTUP 0x00000600 // Startup IPI - #define DELIVS 0x00001000 // Delivery status - #define ASSERT 0x00004000 // Assert interrupt (vs deassert) - #define DEASSERT 0x00000000 - #define LEVEL 0x00008000 // Level triggered - #define BCAST 0x00080000 // Send to all APICs, including self. - #define BUSY 0x00001000 - #define FIXED 0x00000000 -#define ICRHI (0x0310/4) // Interrupt Command [63:32] -#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER) - #define X1 0x0000000B // divide counts by 1 - #define PERIODIC 0x00020000 // Periodic -#define PCINT (0x0340/4) // Performance Counter LVT -#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0) -#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1) -#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR) - #define MASKED 0x00010000 // Interrupt masked -#define TICR (0x0380/4) // Timer Initial Count -#define TCCR (0x0390/4) // Timer Current Count -#define TDCR (0x03E0/4) // Timer Divide Configuration - -volatile uint *lapic; // Initialized in mp.c - -static void -lapicw(int index, int value) -{ - lapic[index] = value; - lapic[ID]; // wait for write to finish, by reading -} -//PAGEBREAK! - -void -lapicinit(void) -{ - if(!lapic) - return; - - // Enable local APIC; set spurious interrupt vector. - lapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS)); - - // The timer repeatedly counts down at bus frequency - // from lapic[TICR] and then issues an interrupt. - // If xv6 cared more about precise timekeeping, - // TICR would be calibrated using an external time source. - lapicw(TDCR, X1); - lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER)); - lapicw(TICR, 10000000); - - // Disable logical interrupt lines. - lapicw(LINT0, MASKED); - lapicw(LINT1, MASKED); - - // Disable performance counter overflow interrupts - // on machines that provide that interrupt entry. - if(((lapic[VER]>>16) & 0xFF) >= 4) - lapicw(PCINT, MASKED); - - // Map error interrupt to IRQ_ERROR. - lapicw(ERROR, T_IRQ0 + IRQ_ERROR); - - // Clear error status register (requires back-to-back writes). - lapicw(ESR, 0); - lapicw(ESR, 0); - - // Ack any outstanding interrupts. - lapicw(EOI, 0); - - // Send an Init Level De-Assert to synchronise arbitration ID's. - lapicw(ICRHI, 0); - lapicw(ICRLO, BCAST | INIT | LEVEL); - while(lapic[ICRLO] & DELIVS) - ; - - // Enable interrupts on the APIC (but not on the processor). - lapicw(TPR, 0); -} - -// Acknowledge interrupt. -void -lapiceoi(void) -{ - if(lapic) - lapicw(EOI, 0); -} - -// Spin for a given number of microseconds. -// On real hardware would want to tune this dynamically. -void -microdelay(int us) -{ -} - -#define CMOS_PORT 0x70 -#define CMOS_RETURN 0x71 - -// Start additional processor running entry code at addr. -// See Appendix B of MultiProcessor Specification. -void -lapicstartap(uchar apicid, uint addr) -{ - int i; - ushort *wrv; - - // "The BSP must initialize CMOS shutdown code to 0AH - // and the warm reset vector (DWORD based at 40:67) to point at - // the AP startup code prior to the [universal startup algorithm]." - outb(CMOS_PORT, 0xF); // offset 0xF is shutdown code - outb(CMOS_PORT+1, 0x0A); - wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector - wrv[0] = 0; - wrv[1] = addr >> 4; - - // "Universal startup algorithm." - // Send INIT (level-triggered) interrupt to reset other CPU. - lapicw(ICRHI, apicid<<24); - lapicw(ICRLO, INIT | LEVEL | ASSERT); - microdelay(200); - lapicw(ICRLO, INIT | LEVEL); - microdelay(10000); - - // Send startup IPI (twice!) to enter code. - // Regular hardware is supposed to only accept a STARTUP - // when it is in the halted state due to an INIT. So the second - // should be ignored, but it is part of the official Intel algorithm. - for(i = 0; i < 2; i++){ - lapicw(ICRHI, apicid<<24); - lapicw(ICRLO, STARTUP | (addr>>12)); - microdelay(200); - } -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/apic/lapic.rs b/kernel/src/arch/x86_64/driver/apic/lapic.rs deleted file mode 100644 index b70e776e..00000000 --- a/kernel/src/arch/x86_64/driver/apic/lapic.rs +++ /dev/null @@ -1,46 +0,0 @@ -extern { - //noinspection RsStaticConstNaming - static mut lapic: *const (); - fn lapicinit(); // must set `lapic` first - fn lapiceoi(); // ack - fn lapicstartap(apicid: u8, addr: u32); -} - -pub fn set_addr(lapic_addr: usize) { - unsafe { -// lapic = lapic_addr; - } -} - -pub fn init() { - warn!("lapic::init use C lib"); - unsafe { -// lapicinit(); - } - info!("lapic: init end"); -} - -pub fn ack(_irq: u8) { - unsafe { -// lapiceoi(); - } -} - -pub fn start_ap(apicid: u8, addr: u32) { - warn!("lapic::start_ap use C lib"); - unsafe { -// lapicstartap(apicid, addr); - } -} - -pub fn lapic_id() -> u8 { - 0 -// unsafe{ -// if lapic.is_null() { -// warn!("lapic is null. return lapic id = 0"); -// return 0; -// } -// let ptr = (lapic as *const u32).offset(0x0020 / 4); -// (ptr.read_volatile() >> 24) as u8 -// } -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/apic/local_apic.rs b/kernel/src/arch/x86_64/driver/apic/local_apic.rs deleted file mode 100644 index edb228b7..00000000 --- a/kernel/src/arch/x86_64/driver/apic/local_apic.rs +++ /dev/null @@ -1,116 +0,0 @@ -use core::intrinsics::{volatile_load, volatile_store}; -use x86::cpuid::CpuId; -use x86::msr::*; - -use memory::Frame; -use paging::{ActivePageTable, PhysAddr, Page, VirtualAddress}; -use paging::entry::EntryFlags; - -pub static mut LOCAL_APIC: LocalApic = LocalApic { - address: 0, - x2: false -}; - -pub unsafe fn init(active_table: &mut ActivePageTable) { - LOCAL_APIC.init(active_table); -} - -pub unsafe fn init_ap() { - LOCAL_APIC.init_ap(); -} - -/// Local APIC -pub struct LocalApic { - pub address: usize, - pub x2: bool -} - -impl LocalApic { - unsafe fn init(&mut self, active_table: &mut ActivePageTable) { - self.address = (rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000) + ::KERNEL_OFFSET; - self.x2 = CpuId::new().get_feature_info().unwrap().has_x2apic(); - - if ! self.x2 { - let page = Page::containing_address(VirtualAddress::new(self.address)); - let frame = Frame::containing_address(PhysAddr::new(self.address - ::KERNEL_OFFSET)); - let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE); - result.flush(active_table); - } - - self.init_ap(); - } - - unsafe fn init_ap(&mut self) { - if self.x2 { - wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10); - wrmsr(IA32_X2APIC_SIVR, 0x100); - } else { - self.write(0xF0, 0x100); - } - } - - unsafe fn read(&self, reg: u32) -> u32 { - volatile_load((self.address + reg as usize) as *const u32) - } - - unsafe fn write(&mut self, reg: u32, value: u32) { - volatile_store((self.address + reg as usize) as *mut u32, value); - } - - pub fn id(&self) -> u32 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_APICID) as u32 } - } else { - unsafe { self.read(0x20) } - } - } - - pub fn version(&self) -> u32 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 } - } else { - unsafe { self.read(0x30) } - } - } - - pub fn icr(&self) -> u64 { - if self.x2 { - unsafe { rdmsr(IA32_X2APIC_ICR) } - } else { - unsafe { - (self.read(0x310) as u64) << 32 | self.read(0x300) as u64 - } - } - } - - pub fn set_icr(&mut self, value: u64) { - if self.x2 { - unsafe { wrmsr(IA32_X2APIC_ICR, value); } - } else { - unsafe { - while self.read(0x300) & 1 << 12 == 1 << 12 {} - self.write(0x310, (value >> 32) as u32); - self.write(0x300, value as u32); - while self.read(0x300) & 1 << 12 == 1 << 12 {} - } - } - } - - pub fn ipi(&mut self, apic_id: usize) { - let mut icr = 0x4040; - if self.x2 { - icr |= (apic_id as u64) << 32; - } else { - icr |= (apic_id as u64) << 56; - } - self.set_icr(icr); - } - - pub unsafe fn eoi(&mut self) { - if self.x2 { - wrmsr(IA32_X2APIC_EOI, 0); - } else { - self.write(0xB0, 0); - } - } -} diff --git a/kernel/src/arch/x86_64/driver/apic/mod.rs b/kernel/src/arch/x86_64/driver/apic/mod.rs deleted file mode 100644 index 3cf6af8b..00000000 --- a/kernel/src/arch/x86_64/driver/apic/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub use self::ioapic::IOAPIC; -pub use self::lapic::{ack, start_ap, lapic_id}; - -mod lapic; -mod ioapic; - -pub fn init() { - assert_has_not_been_called!("apic::init must be called only once"); - use consts::KERNEL_OFFSET; - self::lapic::set_addr(KERNEL_OFFSET + 0xfee00000); - self::lapic::init(); - self::ioapic::init(); -} - -pub fn other_init() { - self::lapic::init(); -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/ide.rs b/kernel/src/arch/x86_64/driver/ide.rs index 356978ef..6b26feb7 100644 --- a/kernel/src/arch/x86_64/driver/ide.rs +++ b/kernel/src/arch/x86_64/driver/ide.rs @@ -2,16 +2,9 @@ //! //! Borrow from Rucore project. Thanks GWord! //! Port from ucore C code. -use spin::Mutex; -lazy_static! { - pub static ref DISK0: LockedIde = LockedIde(Mutex::new(IDE::new(0))); - pub static ref DISK1: LockedIde = LockedIde(Mutex::new(IDE::new(1))); -} pub const BLOCK_SIZE: usize = 512; -pub struct LockedIde(pub Mutex); - pub struct IDE { num: u8, /// I/O Base diff --git a/kernel/src/arch/x86_64/driver/serial.rs b/kernel/src/arch/x86_64/driver/serial.rs index 182e7339..fb398993 100644 --- a/kernel/src/arch/x86_64/driver/serial.rs +++ b/kernel/src/arch/x86_64/driver/serial.rs @@ -29,7 +29,6 @@ impl SerialRead for SerialPort { let ports = self as *mut _ as *mut [Pio; 6]; let line_sts = &(*ports)[5]; let data = &(*ports)[0]; - while line_sts.read() & 1 != 1 {} data.read() } } diff --git a/kernel/src/arch/x86_64/interrupt/handler.rs b/kernel/src/arch/x86_64/interrupt/handler.rs index 2b8b1889..7c727d7b 100644 --- a/kernel/src/arch/x86_64/interrupt/handler.rs +++ b/kernel/src/arch/x86_64/interrupt/handler.rs @@ -80,6 +80,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) { T_PGFLT => page_fault(tf), T_IRQ0...63 => { let irq = tf.trap_num as u8 - T_IRQ0; + super::ack(irq); // must ack before switching match irq { IRQ_TIMER => ::trap::timer(), IRQ_KBD => keyboard(), @@ -88,7 +89,6 @@ pub extern fn rust_trap(tf: &mut TrapFrame) { IRQ_IDE => ide(), _ => panic!("Invalid IRQ number: {}", irq), } - super::ack(irq); } T_SWITCH_TOK => to_kernel(tf), T_SWITCH_TOU => to_user(tf), @@ -131,6 +131,7 @@ fn keyboard() { fn com1() { use arch::driver::serial::*; trace!("\nInterupt: COM1"); + ::trap::serial(COM1.lock().receive() as char); } fn com2() { diff --git a/kernel/src/arch/x86_64/interrupt/trapframe.rs b/kernel/src/arch/x86_64/interrupt/trapframe.rs index 6f143499..05001343 100644 --- a/kernel/src/arch/x86_64/interrupt/trapframe.rs +++ b/kernel/src/arch/x86_64/interrupt/trapframe.rs @@ -183,4 +183,9 @@ impl Context { }, }.push_at(kstack_top) } + /// Called at a new user context + /// To get the init TrapFrame in sys_exec + pub unsafe fn get_init_tf(&self) -> TrapFrame { + (*(self.0 as *const InitStack)).tf.clone() + } } \ No newline at end of file diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index b739925d..5d03d9ca 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -48,7 +48,7 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { driver::init(); ::process::init(); - ::thread::spawn(::fs::shell); + ::thread::spawn(::shell::run_user_shell); AP_CAN_INIT.store(true, Ordering::Relaxed); diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs index 8838dce8..0f07debd 100644 --- a/kernel/src/arch/x86_64/paging.rs +++ b/kernel/src/arch/x86_64/paging.rs @@ -95,6 +95,9 @@ impl ActivePageTable { // Unmap the page self.unmap(0xcafebabe); } + pub fn token() -> usize { + Cr3::read().0.start_address().as_u64() as usize + } } impl Entry for PageEntry { @@ -206,18 +209,19 @@ impl InactivePageTable for InactivePageTable0 { } } - unsafe fn with(&self, f: impl FnOnce()) { + unsafe fn with(&self, f: impl FnOnce() -> T) -> T { let old_frame = Cr3::read().0; let new_frame = self.p4_frame.clone(); debug!("switch table {:?} -> {:?}", old_frame, new_frame); if old_frame != new_frame { Cr3::write(new_frame, Cr3Flags::empty()); } - f(); + let ret = f(); debug!("switch table {:?} -> {:?}", new_frame, old_frame); if old_frame != new_frame { Cr3::write(old_frame, Cr3Flags::empty()); } + ret } fn token(&self) -> usize { diff --git a/kernel/src/arch/x86_64/smp.rs b/kernel/src/arch/x86_64/smp.rs deleted file mode 100644 index 1d39a7b9..00000000 --- a/kernel/src/arch/x86_64/smp.rs +++ /dev/null @@ -1,41 +0,0 @@ -use arch::driver::{acpi::AcpiResult, apic::start_ap}; -use consts::MAX_CPU_NUM; -use core::ptr::{read_volatile, write_volatile}; -use memory::*; -use x86_64::registers::control::Cr3; - -pub const ENTRYOTHER_ADDR: usize = 0x7000; - -pub fn start_other_cores(acpi: &AcpiResult) { - let args = unsafe { &mut *(0x8000 as *mut EntryArgs).offset(-1) }; - for i in 1 .. acpi.cpu_num { - let apic_id = acpi.cpu_acpi_ids[i as usize]; - let ms = MemorySet::new(); - *args = EntryArgs { - kstack: ms.kstack_top() as u64, - page_table: Cr3::read().0.start_address().as_u64() as u32, - stack: args as *const _ as u32, // just enough stack to get us to entry64mp - }; - unsafe { MS = Some(ms); } - start_ap(apic_id, ENTRYOTHER_ADDR as u32); - while unsafe { !read_volatile(&STARTED[i as usize]) } {} - } -} - -#[repr(C)] -#[derive(Debug)] -struct EntryArgs { - kstack: u64, - page_table: u32, - stack: u32, -} - -static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM]; -static mut MS: Option = None; - -pub unsafe fn notify_started(cpu_id: u8) -> MemorySet { - write_volatile(&mut STARTED[cpu_id as usize], true); - let ms = MS.take().unwrap(); - ms.activate(); - ms -} \ No newline at end of file diff --git a/kernel/src/console.rs b/kernel/src/console.rs deleted file mode 100644 index c4106f5c..00000000 --- a/kernel/src/console.rs +++ /dev/null @@ -1,56 +0,0 @@ -use core::ops::Deref; -use alloc::string::String; -use arch::io::getchar; -use alloc::collections::VecDeque; -use sync::Condvar; -use sync::SpinNoIrqLock as Mutex; - -pub fn get_line() -> String { - let mut s = String::new(); - loop { - let c = get_char(); - match c { - '\u{7f}' /* '\b' */ => { - if s.pop().is_some() { - print!("\u{7f}"); - } - } - ' '...'\u{7e}' => { - s.push(c); - print!("{}", c); - } - '\n' | '\r' => { - print!("\n"); - return s; - } - _ => {} - } - } -} - - #[derive(Default)] -pub struct InputQueue { - buf: Mutex>, - pushed: Condvar, -} - impl InputQueue { - pub fn push(&self, c: char) { - self.buf.lock().push_back(c); - self.pushed.notify_one(); - } - pub fn pop(&self) -> char { - loop { - let ret = self.buf.lock().pop_front(); - match ret { - Some(c) => return c, - None => self.pushed._wait(), - } - } - } -} - lazy_static! { - pub static ref CONSOLE_INPUT: InputQueue = InputQueue::default(); -} - pub fn get_char() -> char { - CONSOLE_INPUT.pop() -} \ No newline at end of file diff --git a/kernel/src/consts.rs b/kernel/src/consts.rs index ea22abd7..8c25dd55 100644 --- a/kernel/src/consts.rs +++ b/kernel/src/consts.rs @@ -3,4 +3,4 @@ pub use arch::consts::*; pub const MAX_CPU_NUM: usize = 8; -pub const MAX_PROCESS_NUM: usize = 48; +pub const MAX_PROCESS_NUM: usize = 128; diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index 456e4220..df70f103 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -1,8 +1,11 @@ use simple_filesystem::*; -use alloc::boxed::Box; +use alloc::{boxed::Box, sync::Arc, string::String, collections::VecDeque, vec::Vec}; #[cfg(target_arch = "x86_64")] use arch::driver::ide; -use spin::Mutex; +use sync::Condvar; +use sync::SpinNoIrqLock as Mutex; +use core::any::Any; +use core::slice; use ::memory::{InactivePageTable0, memory_set_record}; use memory::MemorySet; @@ -13,69 +16,29 @@ use process::context::memory_set_map_swappable; global_asm!(r#" .section .rodata .align 12 -_binary_user_riscv_img_start: + .global _user_img_start + .global _user_img_end +_user_img_start: .incbin "../user/user-riscv.img" -_binary_user_riscv_img_end: +_user_img_end: "#); -pub fn shell() { - // load riscv32/x86_64 user program - use sync; - /// below are test for sync, uncomment them if need - //sync::test::philosopher_using_mutex(); - //sync::test::philosopher_using_monitor(); +lazy_static! { + pub static ref ROOT_INODE: Arc = { + #[cfg(target_arch = "riscv32")] + let device = { + extern { + fn _user_img_start(); + fn _user_img_end(); + } + Box::new(unsafe { MemBuf::new(_user_img_start, _user_img_end) }) + }; + #[cfg(target_arch = "x86_64")] + let device = Box::new(ide::IDE::new(1)); - - info!("come into shell!"); - #[cfg(target_arch = "riscv32")] - let device = { - extern { - fn _binary_user_riscv_img_start(); - fn _binary_user_riscv_img_end(); - } - Box::new(unsafe { MemBuf::new(_binary_user_riscv_img_start, _binary_user_riscv_img_end) }) + let sfs = SimpleFileSystem::open(device).expect("failed to open SFS"); + sfs.root_inode() }; - #[cfg(target_arch = "x86_64")] - let device = Box::new(&ide::DISK1); - let sfs = SimpleFileSystem::open(device).expect("failed to open SFS"); - let root = sfs.root_inode(); - let files = root.borrow().list().unwrap(); - println!("Available programs: {:?}", files); - - // Avoid stack overflow in release mode - // Equal to: `buf = Box::new([0; 64 << 12])` - use alloc::alloc::{alloc, dealloc, Layout}; - const BUF_SIZE: usize = 0x40000; - let layout = Layout::from_size_align(BUF_SIZE, 0x1000).unwrap(); - let buf = unsafe{ slice::from_raw_parts_mut(alloc(layout), BUF_SIZE) }; - // start interaction - loop { - print!(">> "); - - use console::get_line; - let name = get_line(); - //use alloc::prelude::ToString; - //let name = "waitkill".to_string(); - - if name == "" { - continue; - } - if let Ok(file) = root.borrow().lookup(name.as_str()) { - use process::*; - let len = file.borrow().read_at(0, &mut *buf).unwrap(); - let context = ContextImpl::new_user(&buf[..len]); - //memory_set_map_swappable(context.get_memory_set_mut()); - let pid = processor().manager().add(context); - //memory_set_map_swappable(processor().get_context_mut(pid).get_memory_set_mut()); - processor().manager().wait(thread::current().id(), pid); - processor().yield_now(); - processor().manager().wait_done(thread::current().id(), pid); - } else { - println!("Program not exist"); - } - //break; - } - unsafe { dealloc(buf.as_mut_ptr(), layout) }; } struct MemBuf(&'static [u8]); @@ -99,19 +62,99 @@ impl Device for MemBuf { } } -use core::slice; - #[cfg(target_arch = "x86_64")] -impl BlockedDevice for &'static ide::DISK1 { +impl BlockedDevice for ide::IDE { const BLOCK_SIZE_LOG2: u8 = 9; fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool { assert!(buf.len() >= ide::BLOCK_SIZE); let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; - self.0.lock().read(block_id as u64, 1, buf).is_ok() + self.read(block_id as u64, 1, buf).is_ok() } fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool { assert!(buf.len() >= ide::BLOCK_SIZE); let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; - self.0.lock().write(block_id as u64, 1, buf).is_ok() + self.write(block_id as u64, 1, buf).is_ok() + } +} + +#[derive(Default)] +pub struct Stdin { + buf: Mutex>, + pushed: Condvar, +} + +impl Stdin { + pub fn push(&self, c: char) { + self.buf.lock().push_back(c); + self.pushed.notify_one(); + } + pub fn pop(&self) -> char { + loop { + let ret = self.buf.lock().pop_front(); + match ret { + Some(c) => return c, + None => self.pushed._wait(), + } + } + } +} + +#[derive(Default)] +pub struct Stdout; + +lazy_static! { + pub static ref STDIN: Arc = Arc::new(Stdin::default()); + pub static ref STDOUT: Arc = Arc::new(Stdout::default()); +} + +// TODO: better way to provide default impl? +macro_rules! impl_inode { + () => { + fn info(&self) -> Result { unimplemented!() } + fn sync(&self) -> Result<()> { unimplemented!() } + fn resize(&self, len: usize) -> Result<()> { unimplemented!() } + fn create(&self, name: &str, type_: FileType) -> Result> { unimplemented!() } + fn unlink(&self, name: &str) -> Result<()> { unimplemented!() } + fn link(&self, name: &str, other: &Arc) -> Result<()> { unimplemented!() } + fn rename(&self, old_name: &str, new_name: &str) -> Result<()> { unimplemented!() } + fn move_(&self, old_name: &str, target: &Arc, new_name: &str) -> Result<()> { unimplemented!() } + fn find(&self, name: &str) -> Result> { unimplemented!() } + fn get_entry(&self, id: usize) -> Result { unimplemented!() } + fn fs(&self) -> Arc { unimplemented!() } + fn as_any_ref(&self) -> &Any { self } + }; +} + +impl INode for Stdin { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + buf[0] = self.pop() as u8; + Ok(1) + } + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { unimplemented!() } + impl_inode!(); +} + +impl INode for Stdout { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { unimplemented!() } + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + use core::str; + let s = str::from_utf8(buf).map_err(|_| ())?; + print!("{}", s); + Ok(buf.len()) + } + impl_inode!(); +} + +pub trait INodeExt { + fn read_as_vec(&self) -> Result>; +} + +impl INodeExt for INode { + fn read_as_vec(&self) -> Result> { + let size = self.info()?.size; + let mut buf = Vec::with_capacity(size); + unsafe { buf.set_len(size); } + self.read_at(0, buf.as_mut_slice())?; + Ok(buf) } } \ No newline at end of file diff --git a/kernel/src/lang.rs b/kernel/src/lang.rs index 43730f0c..c4596d24 100644 --- a/kernel/src/lang.rs +++ b/kernel/src/lang.rs @@ -1,4 +1,4 @@ -// Rust language features implementions +// Rust language features implementations use core::panic::PanicInfo; use core::alloc::Layout; diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index d9598828..1c8ae2f6 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -51,7 +51,7 @@ mod syscall; mod fs; mod sync; mod trap; -mod console; +mod shell; #[allow(dead_code)] #[cfg(target_arch = "x86_64")] @@ -63,10 +63,6 @@ pub mod arch; pub mod arch; pub fn kmain() -> ! { - info!("Come into kmain"); -// sync::test::philosopher_using_mutex(); -// sync::test::philosopher_using_monitor(); -// sync::mpsc::test::test_all(); process::processor().run(); // thread::test::local_key(); diff --git a/kernel/src/logging.rs b/kernel/src/logging.rs index a007cb4b..33edd254 100644 --- a/kernel/src/logging.rs +++ b/kernel/src/logging.rs @@ -1,5 +1,10 @@ use core::fmt; use log::{self, Level, LevelFilter, Log, Metadata, Record}; +use spin::Mutex; + +lazy_static! { + static ref log_mutex: Mutex<()> = Mutex::new(()); +} pub fn init() { static LOGGER: SimpleLogger = SimpleLogger; @@ -38,11 +43,13 @@ macro_rules! with_color { fn print_in_color(args: fmt::Arguments, color: Color) { use arch::io; + let mutex = log_mutex.lock(); io::putfmt(with_color!(args, color)); } pub fn print(args: fmt::Arguments) { use arch::io; + let mutex = log_mutex.lock(); io::putfmt(args); } @@ -71,7 +78,7 @@ impl From for Color { Level::Error => Color::Red, Level::Warn => Color::Yellow, Level::Info => Color::Blue, - Level::Debug => Color::LightRed, + Level::Debug => Color::Green, Level::Trace => Color::DarkGray, } } diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index d1aca52c..93b8636d 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -5,7 +5,7 @@ use consts::MEMORY_OFFSET; use super::HEAP_ALLOCATOR; use ucore_memory::{*, paging::PageTable}; use ucore_memory::cow::CowExt; -pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySet_, Stack, InactivePageTable}; +pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySet_, InactivePageTable}; use ucore_memory::swap::*; //use process::{processor, PROCESSOR}; use process::{process}; @@ -26,7 +26,7 @@ pub type FrameAlloc = BitAlloc4K; lazy_static! { pub static ref FRAME_ALLOCATOR: SpinNoIrqLock = SpinNoIrqLock::new(FrameAlloc::default()); } -// record the user memory set for pagefault function (swap in/out and frame delayed allocate) temporarily when page fault in new_user() or fork() function +// record the user memory set for pagefault function (swap in/out and frame delayed allocate) temporarily when page fault in new_user() or fork() function // after the process is set we can use use processor() to get the inactive page table lazy_static! { pub static ref MEMORY_SET_RECORD: SpinNoIrqLock> = SpinNoIrqLock::new(VecDeque::default()); @@ -49,7 +49,7 @@ pub fn active_table() -> MutexGuard<'static, CowExt, SpinNoIrq> // Page table for swap in and out lazy_static!{ - static ref ACTIVE_TABLE_SWAP: SpinNoIrqLock> = + static ref ACTIVE_TABLE_SWAP: SpinNoIrqLock> = SpinNoIrqLock::new(unsafe{SwapExt::new(ActivePageTable::new(), fifo::FifoSwapManager::default(), mock_swapper::MockSwapper::default())}); } @@ -58,9 +58,9 @@ pub fn active_table_swap() -> MutexGuard<'static, SwapExt Option { @@ -76,15 +76,6 @@ pub fn dealloc_frame(target: usize) { FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE); } -// alloc from heap -pub fn alloc_stack() -> Stack { - use alloc::alloc::{alloc, Layout}; - const STACK_SIZE: usize = 0x8000; - let bottom = unsafe{ alloc(Layout::from_size_align(STACK_SIZE, 0x8000).unwrap()) } as usize; - let top = bottom + STACK_SIZE; - Stack { top, bottom } -} - pub struct KernelStack(usize); const STACK_SIZE: usize = 0x8000; @@ -107,13 +98,13 @@ impl Drop for KernelStack { } -/* +/* * @param: * addr: the virtual address of the page fault -* @brief: +* @brief: * handle page fault -* @retval: -* Return true to continue, false to halt +* @retval: +* Return true to continue, false to halt */ pub fn page_fault_handler(addr: usize) -> bool { info!("start handling swap in/out page fault"); @@ -131,7 +122,7 @@ pub fn page_fault_handler(addr: usize) -> bool { info!("get id from memroy set recorder."); let mmset_ptr = mmsets.get(targetid); // get current mmset - + let current_mmset = unsafe{&mut *(mmset_ptr.unwrap().clone() as *mut MemorySet)}; //check whether the vma is legal if(current_mmset.find_area(addr).is_none()){ @@ -158,8 +149,8 @@ pub fn page_fault_handler(addr: usize) -> bool { }, }; ////////////////////////////////////////////////////////////////////////////// - - + + // Handle copy on write (not being used now) unsafe { ACTIVE_TABLE.force_unlock(); } if active_table().page_fault_handler(addr, || alloc_frame().unwrap()){ diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index b80dee4b..671b9999 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -3,15 +3,21 @@ use memory::{MemoryArea, MemoryAttr, MemorySet, KernelStack, active_table_swap, use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}}; use core::fmt::{Debug, Error, Formatter}; use ucore_process::Context; -use alloc::boxed::Box; +use alloc::{boxed::Box, collections::BTreeMap, vec::Vec, sync::Arc, string::String}; use ucore_memory::{Page}; use ::memory::{InactivePageTable0, memory_set_record}; use ucore_memory::memory_set::*; +use simple_filesystem::file::File; +use spin::Mutex; + +// TODO: avoid pub pub struct ContextImpl { - arch: ArchContext, - memory_set: MemorySet, - kstack: KernelStack, + pub arch: ArchContext, + pub memory_set: MemorySet, + pub kstack: KernelStack, + pub files: BTreeMap>>, + pub cwd: String, } impl Context for ContextImpl { @@ -28,6 +34,8 @@ impl ContextImpl { arch: ArchContext::null(), memory_set: MemorySet::new(), kstack: KernelStack::new(), + files: BTreeMap::default(), + cwd: String::new(), }) } @@ -38,19 +46,23 @@ impl ContextImpl { arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) }, memory_set, kstack, + files: BTreeMap::default(), + cwd: String::new(), }) } /// Make a new user thread from ELF data /* - * @param: - * data: the ELF data stream - * @brief: + * @param: + * data: the ELF data stream + * @brief: * make a new thread from ELF data - * @retval: + * @retval: * the new user thread Context */ - pub fn new_user(data: &[u8]) -> Box { + pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box + where Iter: Iterator + { // Parse elf let elf = ElfFile::new(data).expect("failed to read elf"); let is32 = match elf.header.pt2 { @@ -61,7 +73,7 @@ impl ContextImpl { // User stack use consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET}; - let (user_stack_buttom, user_stack_top) = match is32 { + let (ustack_buttom, mut ustack_top) = match is32 { true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE), false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE), }; @@ -75,7 +87,7 @@ impl ContextImpl { //let id = memory_set_record().iter() // .position(|x| unsafe { info!("current memory set record include {:x?}, {:x?}", x, (*(x.clone() as *mut MemorySet)).get_page_table_mut().token()); false }); - memory_set.push(MemoryArea::new(user_stack_buttom, user_stack_top, MemoryAttr::default().user(), "user_stack")); + memory_set.push(MemoryArea::new(ustack_buttom, ustack_top, MemoryAttr::default().user(), "user_stack")); trace!("{:#x?}", memory_set); let entry_addr = elf.header.pt2.entry_point() as usize; @@ -87,20 +99,15 @@ impl ContextImpl { let virt_addr = ph.virtual_addr() as usize; let offset = ph.offset() as usize; let file_size = ph.file_size() as usize; - if file_size == 0 { - return; - } - use core::slice; - let target = unsafe { slice::from_raw_parts_mut(virt_addr as *mut u8, file_size) }; - target.copy_from_slice(&data[offset..offset + file_size]); - } - if is32 { - unsafe { - // TODO: full argc & argv - *(user_stack_top as *mut u32).offset(-1) = 0; // argv - *(user_stack_top as *mut u32).offset(-2) = 0; // argc + let mem_size = ph.mem_size() as usize; + + let target = unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }; + if file_size != 0 { + target[..file_size].copy_from_slice(&data[offset..offset + file_size]); } + target[file_size..].iter_mut().for_each(|x| *x = 0); } + ustack_top = push_args_at_stack(args, ustack_top); }); } @@ -113,10 +120,12 @@ impl ContextImpl { let mut ret = Box::new(ContextImpl { arch: unsafe { ArchContext::new_user_thread( - entry_addr, user_stack_top - 8, kstack.top(), is32, memory_set.token()) + entry_addr, ustack_top, kstack.top(), is32, memory_set.token()) }, memory_set, kstack, + files: BTreeMap::default(), + cwd: String::new(), }); //set the user Memory pages in the memory set swappable memory_set_map_swappable(ret.get_memory_set_mut()); @@ -133,7 +142,7 @@ impl ContextImpl { info!("fork! new page table token: {:x?}", memory_set.token()); let mmset_ptr = ((&mut memory_set) as * mut MemorySet) as usize; memory_set_record().push_back(mmset_ptr); - + info!("before copy data to temp space"); // Copy data to temp space use alloc::vec::Vec; @@ -147,7 +156,7 @@ impl ContextImpl { unsafe { memory_set.with(|| { for (area, data) in memory_set.iter().zip(datas.iter()) { - unsafe { area.as_slice_mut() }.copy_from_slice(data.as_slice()) + area.as_slice_mut().copy_from_slice(data.as_slice()) } }); } @@ -155,15 +164,17 @@ impl ContextImpl { info!("temporary copy data!"); let kstack = KernelStack::new(); - // remove the raw pointer for the memory set since it will + // remove the raw pointer for the memory set since it will let id = memory_set_record().iter() .position(|x| x.clone() == mmset_ptr).unwrap(); memory_set_record().remove(id); - + let mut ret = Box::new(ContextImpl { arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) }, memory_set, kstack, + files: BTreeMap::default(), + cwd: String::new(), }); memory_set_map_swappable(ret.get_memory_set_mut()); @@ -191,7 +202,7 @@ impl Drop for ContextImpl{ */ //set the user Memory pages in the memory set unswappable - let Self {ref mut arch, ref mut memory_set, ref mut kstack} = self; + let Self {ref mut arch, ref mut memory_set, ref mut kstack, ..} = self; let pt = { memory_set.get_page_table_mut() as *mut InactivePageTable0 }; @@ -213,12 +224,39 @@ impl Debug for ContextImpl { } } +/// Push a slice at the stack. Return the new sp. +unsafe fn push_slice(mut sp: usize, vs: &[T]) -> usize { + use core::{mem::{size_of, align_of}, slice}; + sp -= vs.len() * size_of::(); + sp -= sp % align_of::(); + slice::from_raw_parts_mut(sp as *mut T, vs.len()) + .copy_from_slice(vs); + sp +} + +unsafe fn push_args_at_stack<'a, Iter>(args: Iter, stack_top: usize) -> usize + where Iter: Iterator +{ + use core::{ptr, slice}; + let mut sp = stack_top; + let mut argv = Vec::new(); + for arg in args { + sp = push_slice(sp, &[0u8]); + sp = push_slice(sp, arg.as_bytes()); + argv.push(sp); + } + sp = push_slice(sp, argv.as_slice()); + sp = push_slice(sp, &[argv.len()]); + sp +} + + /* -* @param: +* @param: * elf: the source ELF file -* @brief: +* @brief: * generate a memory set according to the elf file -* @retval: +* @retval: * the new memory set */ fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> MemorySet { @@ -246,7 +284,7 @@ fn memory_attr_from(elf_flags: Flags) -> MemoryAttr { } /* -* @param: +* @param: * memory_set: the target MemorySet to set swappable * @brief: * map the memory area in the memory_set swappalbe, specially for the user process diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 60497cb7..65c19804 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -8,7 +8,6 @@ use sync::Condvar; use core::sync::atomic::*; pub mod context; - pub fn init() { // NOTE: max_time_slice <= 5 to ensure 'priority' test pass let scheduler = Box::new(scheduler::RRScheduler::new(5)); diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs new file mode 100644 index 00000000..4f487328 --- /dev/null +++ b/kernel/src/shell.rs @@ -0,0 +1,60 @@ +//! Kernel shell + +use alloc::string::String; +use alloc::vec::Vec; +use fs::{ROOT_INODE, INodeExt}; +use process::*; + +pub fn run_user_shell() { + let inode = ROOT_INODE.lookup("sh").unwrap(); + let data = inode.read_as_vec().unwrap(); + processor().manager().add(ContextImpl::new_user(data.as_slice(), "sh".split(' '))); +} + +pub fn shell() { + let files = ROOT_INODE.list().unwrap(); + println!("Available programs: {:?}", files); + + loop { + print!(">> "); + let cmd = get_line(); + if cmd == "" { + continue; + } + let name = cmd.split(' ').next().unwrap(); + if let Ok(file) = ROOT_INODE.lookup(name) { + let data = file.read_as_vec().unwrap(); + let pid = processor().manager().add(ContextImpl::new_user(data.as_slice(), cmd.split(' '))); + unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap(); + } else { + println!("Program not exist"); + } + } +} + +fn get_line() -> String { + let mut s = String::new(); + loop { + let c = get_char(); + match c { + '\u{7f}' /* '\b' */ => { + if s.pop().is_some() { + print!("\u{7f}"); + } + } + ' '...'\u{7e}' => { + s.push(c); + print!("{}", c); + } + '\n' | '\r' => { + print!("\n"); + return s; + } + _ => {} + } + } +} + +fn get_char() -> char { + ::fs::STDIN.pop() +} diff --git a/kernel/src/sync/mutex.rs b/kernel/src/sync/mutex.rs index 73e902b9..6cddc9cd 100644 --- a/kernel/src/sync/mutex.rs +++ b/kernel/src/sync/mutex.rs @@ -96,17 +96,11 @@ impl Mutex impl Mutex { fn obtain_lock(&self) { - while true { - match self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) { - Ok(X) => break, - Err(X) => { - // Wait until the lock looks unlocked before retrying - while self.lock.load(Ordering::Relaxed) { - self.support.cpu_relax(); - } - }, - }; - + while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false { + // Wait until the lock looks unlocked before retrying + while self.lock.load(Ordering::Relaxed) { + self.support.cpu_relax(); + } } } @@ -150,13 +144,13 @@ impl Mutex /// a guard within Some. pub fn try_lock(&self) -> Option> { let support_guard = S::before_lock(); - match self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) { - Ok(X) => - Some(MutexGuard { - mutex: self, - support_guard, - }), - Err(X) => None, + if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false { + Some(MutexGuard { + mutex: self, + support_guard, + }) + } else { + None } } } @@ -180,12 +174,12 @@ impl Default for Mutex { impl<'a, T: ?Sized, S: MutexSupport> Deref for MutexGuard<'a, T, S> { type Target = T; - fn deref<'b>(&'b self) -> &'b T { unsafe { &*self.mutex.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.mutex.data.get() } } } impl<'a, T: ?Sized, S: MutexSupport> DerefMut for MutexGuard<'a, T, S> { - fn deref_mut<'b>(&'b mut self) -> &'b mut T { unsafe { &mut *self.mutex.data.get() } } + fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.mutex.data.get() } } } impl<'a, T: ?Sized, S: MutexSupport> Drop for MutexGuard<'a, T, S> diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 0823bebf..7675d708 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -1,86 +1,166 @@ -//! 系统调用解析执行模块 - -#![allow(unused)] +//! System call use arch::interrupt::TrapFrame; use process::*; use thread; use util; +use simple_filesystem::{INode, file::File, FileInfo, FileType}; +use core::{slice, str}; +use alloc::sync::Arc; +use spin::Mutex; +use alloc::vec::Vec; +use alloc::string::String; -use process::context::memory_set_map_swappable; -use alloc::boxed::Box; -use process::context::*; +/// System call dispatcher +pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> i32 { + let ret = match id { + // file + 100 => sys_open(args[0] as *const u8, args[1]), + 101 => sys_close(args[0]), + 102 => sys_read(args[0], args[1] as *mut u8, args[2]), + 103 => sys_write(args[0], args[1] as *const u8, args[2]), + 030 => sys_putc(args[0] as u8 as char), +// 104 => sys_seek(), + 110 => sys_fstat(args[0], args[1] as *mut Stat), +// 111 => sys_fsync(), +// 121 => sys_getcwd(), + 128 => sys_getdirentry(args[0], args[1] as *mut DirEntry), + 130 => sys_dup(args[0], args[1]), + + // process + 001 => sys_exit(args[0] as i32), + 002 => sys_fork(tf), + 003 => sys_wait(args[0], args[1] as *mut i32), + 004 => sys_exec(args[0] as *const u8, args[1] as usize, args[2] as *const *const u8, tf), +// 005 => sys_clone(), + 010 => sys_yield(), + 011 => sys_sleep(args[0]), + 012 => sys_kill(args[0]), + 017 => sys_get_time(), + 018 => sys_getpid(), + 255 => sys_lab6_set_priority(args[0]), + + // memory +// 020 => sys_mmap(), +// 021 => sys_munmap(), +// 022 => sys_shmem(), +// 031 => sys_pgdir(), -/// 系统调用入口点 -/// -/// 当发生系统调用中断时,中断服务例程将控制权转移到这里。 -pub fn syscall(id: usize, args: [usize; 6], tf: &TrapFrame) -> i32 { - match id { - SYS_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), - SYS_OPEN => sys_open(args[0] as *const u8, args[1]), - SYS_CLOSE => sys_close(args[0]), - SYS_WAIT => sys_wait(args[0], args[1] as *mut i32), - SYS_FORK => sys_fork(tf), - SYS_KILL => sys_kill(args[0]), - SYS_EXIT => sys_exit(args[0]), - SYS_YIELD => sys_yield(), - SYS_GETPID => sys_getpid(), - SYS_SLEEP => sys_sleep(args[0]), - SYS_GETTIME => sys_get_time(), - SYS_LAB6_SET_PRIORITY => sys_lab6_set_priority(args[0]), - SYS_PUTC => sys_putc(args[0] as u8 as char), _ => { error!("unknown syscall id: {:#x?}, args: {:x?}", id, args); ::trap::error(tf); } + }; + match ret { + Ok(code) => code, + Err(_) => -1, } } -fn sys_write(fd: usize, base: *const u8, len: usize) -> i32 { +fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { + // TODO: check ptr + info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); + let slice = unsafe { slice::from_raw_parts_mut(base, len) }; + let len = get_file(fd)?.lock().read(slice)?; + Ok(len as i32) +} + +fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { + // TODO: check ptr info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); - use core::slice; - use core::str; let slice = unsafe { slice::from_raw_parts(base, len) }; - print!("{}", str::from_utf8(slice).unwrap()); - 0 + let len = get_file(fd)?.lock().write(slice)?; + Ok(len as i32) } -fn sys_open(path: *const u8, flags: usize) -> i32 { +fn sys_open(path: *const u8, flags: usize) -> SysResult { + // TODO: check ptr let path = unsafe { util::from_cstr(path) }; + let flags = VfsFlags::from_ucore_flags(flags); info!("open: path: {:?}, flags: {:?}", path, flags); - match path { - "stdin:" => 0, - "stdout:" => 1, - _ => -1, + let (fd, inode) = match path { + "stdin:" => (0, ::fs::STDIN.clone() as Arc), + "stdout:" => (1, ::fs::STDOUT.clone() as Arc), + _ => { + let fd = (3..).find(|i| !process().files.contains_key(i)).unwrap(); + let inode = ::fs::ROOT_INODE.lookup(path)?; + (fd, inode) + } + }; + let file = File::new(inode, flags.contains(VfsFlags::READABLE), flags.contains(VfsFlags::WRITABLE)); + process().files.insert(fd, Arc::new(Mutex::new(file))); + Ok(fd as i32) +} + +fn sys_close(fd: usize) -> SysResult { + info!("close: fd: {:?}", fd); + match process().files.remove(&fd) { + Some(_) => Ok(0), + None => Err(SysError::InvalidFile), } } -fn sys_close(fd: usize) -> i32 { - info!("close: fd: {:?}", fd); - 0 +fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult { + // TODO: check ptr + info!("fstat: {}", fd); + let file = get_file(fd)?; + let stat = Stat::from(file.lock().info()?); + unsafe { stat_ptr.write(stat); } + Ok(0) +} + +/// entry_id = dentry.offset / 256 +/// dentry.name = entry_name +/// dentry.offset += 256 +fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult { + // TODO: check ptr + info!("getdirentry: {}", fd); + let file = get_file(fd)?; + let dentry = unsafe { &mut *dentry_ptr }; + if !dentry.check() { + return Err(SysError::InvalidArgument); + } + let info = file.lock().info()?; + if info.type_ != FileType::Dir || info.size <= dentry.entry_id() { + return Err(SysError::InvalidArgument); + } + let name = file.lock().get_entry(dentry.entry_id())?; + dentry.set_name(name.as_str()); + Ok(0) +} + +fn sys_dup(fd1: usize, fd2: usize) -> SysResult { + info!("dup: {} {}", fd1, fd2); + let file = get_file(fd1)?; + if process().files.contains_key(&fd2) { + return Err(SysError::InvalidFile); + } + process().files.insert(fd2, file.clone()); + Ok(0) } /// Fork the current process. Return the child's PID. -fn sys_fork(tf: &TrapFrame) -> i32 { +fn sys_fork(tf: &TrapFrame) -> SysResult { let mut context = process().fork(tf); //memory_set_map_swappable(context.get_memory_set_mut()); let pid = processor().manager().add(context); processor().manager().set_parent(thread::current().id(), pid); //memory_set_map_swappable(processor.get_context_mut(pid).get_memory_set_mut()); info!("fork: {} -> {}", thread::current().id(), pid); - pid as i32 + Ok(pid as i32) } /// Wait the process exit. /// Return the PID. Store exit code to `code` if it's not null. -fn sys_wait(pid: usize, code: *mut i32) -> i32 { +fn sys_wait(pid: usize, code: *mut i32) -> SysResult { + // TODO: check ptr loop { let wait_procs = match pid { 0 => processor().manager().get_children(thread::current().id()), _ => vec![pid], }; if wait_procs.is_empty() { - return -1; + return Ok(-1); } for pid in wait_procs { match processor().manager().get_status(pid) { @@ -90,12 +170,13 @@ fn sys_wait(pid: usize, code: *mut i32) -> i32 { } processor().manager().wait_done(thread::current().id(), pid); info!("wait: {} -> {}", thread::current().id(), pid); - return 0; + return Ok(0); } - None => return -1, + None => return Ok(-1), _ => {} } } + info!("wait: {} -> {}, sleep", thread::current().id(), pid); if pid == 0 { processor().manager().wait_child(thread::current().id()); processor().yield_now(); @@ -106,79 +187,193 @@ fn sys_wait(pid: usize, code: *mut i32) -> i32 { } } -fn sys_yield() -> i32 { +fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapFrame) -> SysResult { + // TODO: check ptr + let name = if name.is_null() { "" } else { unsafe { util::from_cstr(name) } }; + info!("exec: {:?}, argc: {}, argv: {:?}", name, argc, argv); + // Copy args to kernel + let args: Vec = unsafe { + slice::from_raw_parts(argv, argc).iter() + .map(|&arg| String::from(util::from_cstr(arg))) + .collect() + }; + + // Read program file + let path = args[0].as_str(); + let inode = ::fs::ROOT_INODE.lookup(path)?; + let size = inode.info()?.size; + let mut buf = Vec::with_capacity(size); + unsafe { buf.set_len(size); } + inode.read_at(0, buf.as_mut_slice())?; + + // Make new Context + let iter = args.iter().map(|s| s.as_str()); + let mut context = ContextImpl::new_user(buf.as_slice(), iter); + + // Activate new page table + unsafe { context.memory_set.activate(); } + + // Modify the TrapFrame + *tf = unsafe { context.arch.get_init_tf() }; + + // Swap Context but keep KStack + ::core::mem::swap(&mut process().kstack, &mut context.kstack); + ::core::mem::swap(process(), &mut *context); + + Ok(0) +} + +fn sys_yield() -> SysResult { thread::yield_now(); - 0 + Ok(0) } /// Kill the process -fn sys_kill(pid: usize) -> i32 { +fn sys_kill(pid: usize) -> SysResult { info!("{} killed: {}", thread::current().id(), pid); processor().manager().exit(pid, 0x100); if pid == thread::current().id() { processor().yield_now(); } - 0 + Ok(0) } /// Get the current process id -fn sys_getpid() -> i32 { - thread::current().id() as i32 +fn sys_getpid() -> SysResult { + Ok(thread::current().id() as i32) } /// Exit the current process -fn sys_exit(exit_code: usize) -> i32 { +fn sys_exit(exit_code: i32) -> SysResult { let pid = thread::current().id(); - info!("exit: {}", pid); - processor().manager().exit(pid, exit_code); + info!("exit: {}, code: {}", pid, exit_code); + processor().manager().exit(pid, exit_code as usize); processor().yield_now(); unreachable!(); } -fn sys_sleep(time: usize) -> i32 { +fn sys_sleep(time: usize) -> SysResult { use core::time::Duration; thread::sleep(Duration::from_millis(time as u64 * 10)); - 0 + Ok(0) } -fn sys_get_time() -> i32 { - unsafe { ::trap::TICK as i32 } +fn sys_get_time() -> SysResult { + unsafe { Ok(::trap::TICK as i32) } } -fn sys_lab6_set_priority(priority: usize) -> i32 { +fn sys_lab6_set_priority(priority: usize) -> SysResult { let pid = thread::current().id(); processor().manager().set_priority(pid, priority as u8); - 0 + Ok(0) } -fn sys_putc(c: char) -> i32 { +fn sys_putc(c: char) -> SysResult { print!("{}", c); - 0 + Ok(0) } -const SYS_EXIT: usize = 1; -const SYS_FORK: usize = 2; -const SYS_WAIT: usize = 3; -const SYS_EXEC: usize = 4; -const SYS_CLONE: usize = 5; -const SYS_YIELD: usize = 10; -const SYS_SLEEP: usize = 11; -const SYS_KILL: usize = 12; -const SYS_GETTIME: usize = 17; -const SYS_GETPID: usize = 18; -const SYS_MMAP: usize = 20; -const SYS_MUNMAP: usize = 21; -const SYS_SHMEM: usize = 22; -const SYS_PUTC: usize = 30; -const SYS_PGDIR: usize = 31; -const SYS_OPEN: usize = 100; -const SYS_CLOSE: usize = 101; -const SYS_READ: usize = 102; -const SYS_WRITE: usize = 103; -const SYS_SEEK: usize = 104; -const SYS_FSTAT: usize = 110; -const SYS_FSYNC: usize = 111; -const SYS_GETCWD: usize = 121; -const SYS_GETDIRENTRY: usize = 128; -const SYS_DUP: usize = 130; -const SYS_LAB6_SET_PRIORITY: usize = 255; +fn get_file(fd: usize) -> Result<&'static Arc>, SysError> { + process().files.get(&fd).ok_or(SysError::InvalidFile) +} + +pub type SysResult = Result; + +#[repr(i32)] +pub enum SysError { + VfsError, + InvalidFile, + InvalidArgument, +} + +impl From<()> for SysError { + fn from(_: ()) -> Self { + SysError::VfsError + } +} + +bitflags! { + struct VfsFlags: usize { + // WARNING: different from origin uCore + const READABLE = 1 << 0; + const WRITABLE = 1 << 1; + /// create file if it does not exist + const CREATE = 1 << 2; + /// error if O_CREAT and the file exists + const EXCLUSIVE = 1 << 3; + /// truncate file upon open + const TRUNCATE = 1 << 4; + /// append on each write + const APPEND = 1 << 5; + } +} + +impl VfsFlags { + fn from_ucore_flags(f: usize) -> Self { + assert_ne!(f & 0b11, 0b11); + Self::from_bits_truncate(f + 1) + } +} + +#[repr(C)] +struct DirEntry { + offset: u32, + name: [u8; 256], +} + +impl DirEntry { + fn check(&self) -> bool { + self.offset % 256 == 0 + } + fn entry_id(&self) -> usize { + (self.offset / 256) as usize + } + fn set_name(&mut self, name: &str) { + self.name[..name.len()].copy_from_slice(name.as_bytes()); + self.name[name.len()] = 0; + self.offset += 256; + } +} + +#[repr(C)] +struct Stat { + /// protection mode and file type + mode: StatMode, + /// number of hard links + nlinks: u32, + /// number of blocks file is using + blocks: u32, + /// file size (bytes) + size: u32, +} + +bitflags! { + struct StatMode: u32 { + const NULL = 0; + /// ordinary regular file + const FILE = 0o10000; + /// directory + const DIR = 0o20000; + /// symbolic link + const LINK = 0o30000; + /// character device + const CHAR = 0o40000; + /// block device + const BLOCK = 0o50000; + } +} + +impl From for Stat { + fn from(info: FileInfo) -> Self { + Stat { + mode: match info.type_ { + FileType::File => StatMode::FILE, + FileType::Dir => StatMode::DIR, + _ => StatMode::NULL, + }, + nlinks: info.nlinks as u32, + blocks: info.blocks as u32, + size: info.size as u32, + } + } +} diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index 0e595489..99ba7b18 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -9,7 +9,6 @@ pub fn timer() { unsafe { TICK += 1; } } processor().tick(); - //info!("finish before return!"); } pub fn error(tf: &TrapFrame) -> ! { @@ -23,5 +22,5 @@ pub fn error(tf: &TrapFrame) -> ! { } pub fn serial(c: char) { - ::console::CONSOLE_INPUT.push(c); -} \ No newline at end of file + ::fs::STDIN.push(c); +} \ No newline at end of file diff --git a/riscv-pk/bbl/bbl.c b/riscv-pk/bbl/bbl.c index 1b96a9d5..dbb92778 100644 --- a/riscv-pk/bbl/bbl.c +++ b/riscv-pk/bbl/bbl.c @@ -48,7 +48,7 @@ void boot_other_hart(uintptr_t unused __attribute__((unused))) } } - enter_supervisor_mode(entry, hartid, dtb_output()); + enter_supervisor_mode(entry, hartid, dtb_output(), ~disabled_hart_mask & hart_mask); } void boot_loader(uintptr_t dtb) diff --git a/riscv-pk/configure b/riscv-pk/configure index 49dddf36..a41f9082 100755 --- a/riscv-pk/configure +++ b/riscv-pk/configure @@ -4084,8 +4084,8 @@ fi case "${BUILD_32BIT}" in yes|default) echo "Building 32-bit pk" - CFLAGS="$default_CFLAGS -march=rv32i -mabi=ilp32" - LDFLAGS="-march=rv32i -mabi=ilp32" + CFLAGS="$default_CFLAGS -march=rv32iac -mabi=ilp32" + LDFLAGS="-march=rv32iac -mabi=ilp32" install_subdir="riscv32-unknown-elf" ;; *) diff --git a/riscv-pk/configure.ac b/riscv-pk/configure.ac index 107a3f2d..20cd6d19 100644 --- a/riscv-pk/configure.ac +++ b/riscv-pk/configure.ac @@ -88,8 +88,8 @@ AC_ARG_ENABLE([32bit], case "${BUILD_32BIT}" in yes|default) echo "Building 32-bit pk" - CFLAGS="$default_CFLAGS -march=rv32i -mabi=ilp32" - LDFLAGS="-march=rv32i -mabi=ilp32" + CFLAGS="$default_CFLAGS -march=rv32iac -mabi=ilp32" + LDFLAGS="-march=rv32iac -mabi=ilp32" install_subdir="riscv32-unknown-elf" ;; *) diff --git a/riscv-pk/machine/minit.c b/riscv-pk/machine/minit.c index c3fce3d8..ca6f43b3 100644 --- a/riscv-pk/machine/minit.c +++ b/riscv-pk/machine/minit.c @@ -172,7 +172,7 @@ void init_other_hart(uintptr_t hartid, uintptr_t dtb) boot_other_hart(dtb); } -void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1) +void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1, uintptr_t arg2) { // Set up a PMP to permit access to all of memory. // Ignore the illegal-instruction trap if PMPs aren't supported. @@ -194,6 +194,7 @@ void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1 register uintptr_t a0 asm ("a0") = arg0; register uintptr_t a1 asm ("a1") = arg1; - asm volatile ("mret" : : "r" (a0), "r" (a1)); + register uintptr_t a2 asm ("a2") = arg2; + asm volatile ("mret" : : "r" (a0), "r" (a1), "r" (a2)); __builtin_unreachable(); } diff --git a/riscv-pk/machine/mtrap.h b/riscv-pk/machine/mtrap.h index eafdb14e..b4390887 100644 --- a/riscv-pk/machine/mtrap.h +++ b/riscv-pk/machine/mtrap.h @@ -63,7 +63,7 @@ void putstring(const char* s); #define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); }) #define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(-1); }) -void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1) +void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1, uintptr_t arg2) __attribute__((noreturn)); void boot_loader(uintptr_t dtb); void boot_other_hart(uintptr_t dtb); diff --git a/user/riscv32-ucore.json b/user/riscv32-ucore.json index 621b0da7..37dac6fe 100644 --- a/user/riscv32-ucore.json +++ b/user/riscv32-ucore.json @@ -9,13 +9,8 @@ "cpu": "generic-rv32", "features": "", "max-atomic-width": "32", - "linker": "riscv64-unknown-elf-ld", - "linker-flavor": "ld", - "pre-link-args": { - "ld": [ - "-melf32lriscv" - ] - }, + "linker": "rust-lld", + "linker-flavor": "ld.lld", "executables": true, "panic-strategy": "abort", "relocation-model": "static",