Merge branch 'dev' into g4-merge

# Conflicts:
#	crate/memory/src/cow.rs
#	crate/memory/src/memory_set.rs
#	crate/memory/src/paging/mod.rs
#	crate/memory/src/swap/mod.rs
#	crate/process/src/lib.rs
#	crate/process/src/process_manager.rs
#	crate/process/src/processor.rs
#	crate/process/src/thread.rs
#	crate/riscv
#	kernel/Cargo.lock
#	kernel/src/arch/riscv32/compiler_rt.rs
#	kernel/src/arch/riscv32/consts.rs
#	kernel/src/arch/riscv32/context.rs
#	kernel/src/arch/riscv32/interrupt.rs
#	kernel/src/arch/riscv32/memory.rs
#	kernel/src/arch/riscv32/mod.rs
#	kernel/src/arch/riscv32/paging.rs
#	kernel/src/arch/x86_64/driver/ide.rs
#	kernel/src/arch/x86_64/interrupt/handler.rs
#	kernel/src/arch/x86_64/mod.rs
#	kernel/src/console.rs
#	kernel/src/consts.rs
#	kernel/src/fs.rs
#	kernel/src/lib.rs
#	kernel/src/memory.rs
#	kernel/src/process/context.rs
#	kernel/src/process/mod.rs
#	kernel/src/syscall.rs
#	kernel/src/trap.rs
master
WangRunji 6 years ago
commit 205f90a264

3
.gitmodules vendored

@ -1,3 +0,0 @@
[submodule "crate/riscv"]
path = crate/riscv
url = https://github.com/riscv-and-rust-and-decaf/riscv.git

@ -2,7 +2,7 @@ sudo: required
language: rust language: rust
rust: nightly-2018-09-18 rust: nightly
cache: cache:
cargo: true cargo: true
@ -19,7 +19,7 @@ env:
install: install:
- if [ $ARCH = riscv32 ]; then - 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; wget https://static.dev.sifive.com/dev-tools/$FILE.tar.gz;
tar xf $FILE.tar.gz; tar xf $FILE.tar.gz;
export PATH=$PATH:$PWD/$FILE/bin; export PATH=$PATH:$PWD/$FILE/bin;

@ -37,7 +37,7 @@ cargo install cargo-xbuild bootimage
``` ```
```bash ```bash
git clone https://github.com/wangrunji0408/RustOS.git --recursive git clone https://github.com/wangrunji0408/RustOS.git
cd RustOS/kernel cd RustOS/kernel
rustup override set nightly-2018-09-18 rustup override set nightly-2018-09-18
make run arch=riscv32|x86_64 make run arch=riscv32|x86_64

@ -69,15 +69,14 @@ impl<T: PageTable> CowExt<T> {
** @retval none ** @retval none
*/ */
pub fn unmap_shared(&mut self, addr: VirtAddr) { pub fn unmap_shared(&mut self, addr: VirtAddr) {
{ let entry = self.page_table.get_entry(addr)
let entry = self.page_table.get_entry(addr); .expect("entry not exist");
let frame = entry.target() / PAGE_SIZE; let frame = entry.target() / PAGE_SIZE;
if entry.readonly_shared() { if entry.readonly_shared() {
self.rc_map.read_decrease(&frame); self.rc_map.read_decrease(&frame);
} else if entry.writable_shared() { } else if entry.writable_shared() {
self.rc_map.write_decrease(&frame); self.rc_map.write_decrease(&frame);
} }
}
self.page_table.unmap(addr); self.page_table.unmap(addr);
} }
/* /*
@ -91,9 +90,11 @@ impl<T: PageTable> CowExt<T> {
** @retval bool whether copy-on-write happens. ** @retval bool whether copy-on-write happens.
*/ */
pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool { 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); 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() { if !entry.readonly_shared() && !entry.writable_shared() {
return false; return false;
} }
@ -105,7 +106,6 @@ impl<T: PageTable> CowExt<T> {
self.rc_map.write_decrease(&frame); self.rc_map.write_decrease(&frame);
return true; return true;
} }
}
use core::mem::uninitialized; use core::mem::uninitialized;
let mut temp_data: [u8; PAGE_SIZE] = unsafe { uninitialized() }; let mut temp_data: [u8; PAGE_SIZE] = unsafe { uninitialized() };
temp_data[..].copy_from_slice(self.get_page_slice_mut(addr)); temp_data[..].copy_from_slice(self.get_page_slice_mut(addr));
@ -251,7 +251,7 @@ pub mod test {
pt.write(0x1000, 2); pt.write(0x1000, 2);
assert_eq!(pt.rc_map.read_count(&frame), 1); assert_eq!(pt.rc_map.read_count(&frame), 1);
assert_eq!(pt.rc_map.write_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(0x1000), 2);
assert_eq!(pt.read(0x2000), 1); assert_eq!(pt.read(0x2000), 1);
assert_eq!(pt.read(0x3000), 1); assert_eq!(pt.read(0x3000), 1);
@ -264,7 +264,7 @@ pub mod test {
pt.write(0x2000, 3); pt.write(0x2000, 3);
assert_eq!(pt.rc_map.read_count(&frame), 0); assert_eq!(pt.rc_map.read_count(&frame), 0);
assert_eq!(pt.rc_map.write_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."); "The last write reference should not allocate new frame.");
assert_eq!(pt.read(0x1000), 2); assert_eq!(pt.read(0x1000), 2);
assert_eq!(pt.read(0x2000), 3); assert_eq!(pt.read(0x2000), 3);

@ -1,5 +1,6 @@
#![no_std] #![no_std]
#![feature(alloc)] #![feature(alloc)]
#![feature(nll)]
extern crate alloc; extern crate alloc;
#[macro_use] #[macro_use]

@ -42,7 +42,7 @@ pub trait InactivePageTable {
** @param f: impl FnOnce() the function to be executed ** @param f: impl FnOnce() the function to be executed
** @retval none ** @retval none
*/ */
unsafe fn with(&self, f: impl FnOnce()); unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T;
/* /*
** @brief get the token of the inactive page table ** @brief get the token of the inactive page table
** @retval usize 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 ** @retval none
*/ */
fn dealloc_frame(target: PhysAddr); fn dealloc_frame(target: PhysAddr);
/*
** @brief allocate a stack space
** @retval Stack the stack allocated
*/
fn alloc_stack() -> Stack;
unsafe fn with_retval<T>(&self, f: impl FnOnce() -> T) -> T;
} }
/// a continuous memory space when the same attribute /// a continuous memory space when the same attribute
@ -183,7 +176,7 @@ impl MemoryArea {
let entry = pt.map(addr,0); let entry = pt.map(addr,0);
self.flags.apply(entry); self.flags.apply(entry);
} }
let entry = pt.get_entry(addr); let entry = pt.get_entry(addr).unwrap();
entry.set_present(false); entry.set_present(false);
entry.update(); entry.update();
@ -201,13 +194,13 @@ impl MemoryArea {
for page in Page::range_of(self.start_addr, self.end_addr) { for page in Page::range_of(self.start_addr, self.end_addr) {
let addr = page.start_address(); let addr = page.start_address();
if self.phys_start_addr.is_none() { if self.phys_start_addr.is_none() {
if pt.get_entry(addr).present(){ if pt.get_entry(addr).unwrap().present(){
let target = pt.get_entry(addr).target(); let target = pt.get_entry(addr).unwrap().target();
T::dealloc_frame(target); T::dealloc_frame(target);
} }
else{ else{
// set valid for pt.unmap function // set valid for pt.unmap function
pt.get_entry(addr).set_present(true); pt.get_entry(addr).unwrap().set_present(true);
} }
} }
pt.unmap(addr); pt.unmap(addr);
@ -290,7 +283,6 @@ impl MemoryAttr {
pub struct MemorySet<T: InactivePageTable> { pub struct MemorySet<T: InactivePageTable> {
areas: Vec<MemoryArea>, areas: Vec<MemoryArea>,
page_table: T, page_table: T,
kstack: Stack,
} }
impl<T: InactivePageTable> MemorySet<T> { impl<T: InactivePageTable> MemorySet<T> {
@ -302,23 +294,12 @@ impl<T: InactivePageTable> MemorySet<T> {
MemorySet { MemorySet {
areas: Vec::<MemoryArea>::new(), areas: Vec::<MemoryArea>::new(),
page_table: T::new(), page_table: T::new(),
kstack: T::alloc_stack(),
} }
} }
/* pub fn new_bare() -> Self {
** @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<T> 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::<MemoryArea>();
MemorySet { MemorySet {
areas: Vec::<MemoryArea>::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap), areas: Vec::<MemoryArea>::new(),
page_table: T::new_bare(), page_table: T::new_bare(),
kstack,
} }
} }
/* /*
@ -372,13 +353,6 @@ impl<T: InactivePageTable> MemorySet<T> {
self.page_table.token() 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 ** @brief clear the memory set
** @retval none ** @retval none
*/ */
@ -414,7 +388,6 @@ impl<T: InactivePageTable> Clone for MemorySet<T> {
MemorySet { MemorySet {
areas: self.areas.clone(), areas: self.areas.clone(),
page_table, page_table,
kstack: T::alloc_stack(),
} }
} }
} }
@ -433,10 +406,3 @@ impl<T: InactivePageTable> Debug for MemorySet<T> {
.finish() .finish()
} }
} }
/// the stack structure
#[derive(Debug)]
pub struct Stack {
pub top: usize,
pub bottom: usize,
}

@ -77,8 +77,8 @@ impl PageTable for MockPageTable {
assert!(entry.present); assert!(entry.present);
entry.present = false; entry.present = false;
} }
fn get_entry(&mut self, addr: VirtAddr) -> &mut <Self as PageTable>::Entry { fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::Entry> {
&mut self.entries[addr / PAGE_SIZE] Some(&mut self.entries[addr / PAGE_SIZE])
} }
fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] { fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
self._read(addr); self._read(addr);
@ -175,7 +175,7 @@ impl MockPageTable {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use alloc::arc::Arc; use alloc::sync::Arc;
use core::cell::RefCell; use core::cell::RefCell;
#[test] #[test]
@ -198,34 +198,35 @@ mod test {
fn entry() { fn entry() {
let mut pt = MockPageTable::new(); let mut pt = MockPageTable::new();
pt.map(0x0, 0x1000); pt.map(0x0, 0x1000);
{
let entry = pt.get_entry(0); let entry = pt.get_entry(0).unwrap();
assert!(entry.present()); assert!(entry.present());
assert!(entry.writable()); assert!(entry.writable());
assert!(!entry.accessed()); assert!(!entry.accessed());
assert!(!entry.dirty()); assert!(!entry.dirty());
assert_eq!(entry.target(), 0x1000); assert_eq!(entry.target(), 0x1000);
}
pt.read(0x0); pt.read(0x0);
assert!(pt.get_entry(0).accessed()); let entry = pt.get_entry(0).unwrap();
assert!(!pt.get_entry(0).dirty()); assert!(entry.accessed());
assert!(!entry.dirty());
pt.get_entry(0).clear_accessed(); entry.clear_accessed();
assert!(!pt.get_entry(0).accessed()); assert!(!entry.accessed());
pt.write(0x1, 1); pt.write(0x1, 1);
assert!(pt.get_entry(0).accessed()); let entry = pt.get_entry(0).unwrap();
assert!(pt.get_entry(0).dirty()); assert!(entry.accessed());
assert!(entry.dirty());
pt.get_entry(0).clear_dirty(); entry.clear_dirty();
assert!(!pt.get_entry(0).dirty()); assert!(!entry.dirty());
pt.get_entry(0).set_writable(false); entry.set_writable(false);
assert!(!pt.get_entry(0).writable()); assert!(!entry.writable());
pt.get_entry(0).set_present(false); entry.set_present(false);
assert!(!pt.get_entry(0).present()); assert!(!entry.present());
} }
#[test] #[test]

@ -31,8 +31,7 @@ pub trait PageTable {
** @param addr: VirtAddr the virual address ** @param addr: VirtAddr the virual address
** @retval Entry the page table entry of 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 // For testing with mock
/* /*
** @brief used for testing with mock ** @brief used for testing with mock

@ -40,7 +40,7 @@ impl SwapManager for EnhancedClockSwapManager {
// The reason may be `get_page_slice_mut()` contains unsafe operation, // The reason may be `get_page_slice_mut()` contains unsafe operation,
// which lead the compiler to do a wrong optimization. // which lead the compiler to do a wrong optimization.
// let slice = page_table.get_page_slice_mut(addr); // 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()); // println!("{:#x} , {}, {}", addr, entry.accessed(), entry.dirty());
match (entry.accessed(), entry.dirty()) { match (entry.accessed(), entry.dirty()) {

@ -117,7 +117,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
targetpt.token() targetpt.token()
}; };
targetpt.with(||{ targetpt.with(||{
let entry = page_table.get_entry(addr); let entry = page_table.get_entry(addr).unwrap();
if entry.present() { if entry.present() {
let frame = Frame::new(pt as usize, addr, pttoken); let frame = Frame::new(pt as usize, addr, pttoken);
swap_manager.push(frame); swap_manager.push(frame);
@ -149,7 +149,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
info!("try to change pagetable"); info!("try to change pagetable");
targetpt.with(||{ targetpt.with(||{
let token = { let token = {
let entry = page_table.get_entry(addr); let entry = page_table.get_entry(addr).unwrap();
if !entry.swapped() { if !entry.swapped() {
if entry.present(){ if entry.present(){
// if the addr isn't indicating a swapped page, panic occured here // if the addr isn't indicating a swapped page, panic occured here
@ -214,11 +214,12 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self; let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self;
let ret = unsafe{ let ret = unsafe{
let pt = &mut *(frame.get_page_table() as *mut T2); let pt = &mut *(frame.get_page_table() as *mut T2);
pt.with_retval(||{ pt.with(|| {
//use core::slice; //use core::slice;
//let data = unsafe { slice::from_raw_parts_mut((frame.virtaddr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) }; //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 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() { if entry.swapped() {
return Err(SwapError::AlreadySwapped); return Err(SwapError::AlreadySwapped);
} }
@ -245,8 +246,8 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
*/ */
fn swap_in<T2: InactivePageTable>(&mut self, pt: *mut T2, addr: VirtAddr, target: PhysAddr) -> Result<(), SwapError> { fn swap_in<T2: InactivePageTable>(&mut self, pt: *mut T2, addr: VirtAddr, target: PhysAddr) -> Result<(), SwapError> {
info!("come in to swap in"); info!("come in to swap in");
let token = { let entry = self.page_table.get_entry(addr)
let entry = self.page_table.get_entry(addr); .ok_or(SwapError::NotMapped)?;
if !entry.swapped() { if !entry.swapped() {
return Err(SwapError::NotSwapped); return Err(SwapError::NotSwapped);
} }
@ -255,8 +256,6 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
entry.set_swapped(false); entry.set_swapped(false);
entry.set_present(true); entry.set_present(true);
entry.update(); entry.update();
token
};
let data = self.page_table.get_page_slice_mut(addr); let data = self.page_table.get_page_slice_mut(addr);
self.swapper.swap_in(token, data).map_err(|_| SwapError::IOError)?; self.swapper.swap_in(token, data).map_err(|_| SwapError::IOError)?;
let pttoken = unsafe{ let pttoken = unsafe{
@ -284,7 +283,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
{ {
info!("try handling delayed frame allocator"); info!("try handling delayed frame allocator");
let need_alloc ={ let need_alloc ={
let entry = self.page_table.get_entry(addr); let entry = self.page_table.get_entry(addr).unwrap();
//info!("got entry!"); //info!("got entry!");
!entry.present() && !entry.swapped() !entry.present() && !entry.swapped()
}; };
@ -293,7 +292,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
info!("need_alloc!"); info!("need_alloc!");
let frame = alloc_frame(); 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); entry.set_target(frame);
//let new_entry = self.page_table.map(addr, frame); //let new_entry = self.page_table.map(addr, frame);
entry.set_present(true); entry.set_present(true);
@ -311,8 +310,9 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
info!("not need alloc!"); 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 // 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() { match self.page_table.get_entry(addr) {
return false; None => return false,
Some(entry) => if !entry.swapped() { return false; },
} }
// Allocate a frame, if failed, swap out a page // Allocate a frame, if failed, swap out a page
let frame = alloc_frame(); let frame = alloc_frame();
@ -324,6 +324,8 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
pub enum SwapError { pub enum SwapError {
/// attempt to swap out a page that is already swapped out /// attempt to swap out a page that is already swapped out
AlreadySwapped, AlreadySwapped,
///
NotMapped,
/// attempt to swap in a page that is already in the memory /// attempt to swap in a page that is already in the memory
NotSwapped, NotSwapped,
/// there are no page to be swapped out /// there are no page to be swapped out

@ -17,7 +17,7 @@ extern crate spin;
#[macro_use] #[macro_use]
extern crate std; extern crate std;
pub mod process_manager; mod process_manager;
mod processor; mod processor;
pub mod scheduler; pub mod scheduler;
pub mod thread; pub mod thread;

@ -138,11 +138,10 @@ impl ProcessManager {
/// Switch the status of a process. /// Switch the status of a process.
/// Insert/Remove it to/from scheduler if necessary. /// Insert/Remove it to/from scheduler if necessary.
fn set_status(&self, pid: Pid, status: Status) { 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_lock = self.procs[pid].lock();
let mut proc = proc_lock.as_mut().expect("process not exist"); let mut proc = proc_lock.as_mut().expect("process not exist");
trace!("process {} {:?} -> {:?}", pid, proc.status, status); trace!("process {} {:?} -> {:?}", pid, proc.status, status);
{ // limit the lifetime of scheduler
let mut scheduler = self.scheduler.lock();
match (&proc.status, &status) { match (&proc.status, &status) {
(Status::Ready, Status::Ready) => return, (Status::Ready, Status::Ready) => return,
(Status::Ready, _) => scheduler.remove(pid), (Status::Ready, _) => scheduler.remove(pid),
@ -154,7 +153,6 @@ impl ProcessManager {
(_, Status::Ready) => scheduler.insert(pid), (_, Status::Ready) => scheduler.insert(pid),
_ => {} _ => {}
} }
}
match proc.status { match proc.status {
Status::Running(_) => proc.status_after_stop = status, Status::Running(_) => proc.status_after_stop = status,
_ => proc.status = status, _ => proc.status = status,
@ -238,7 +236,8 @@ impl ProcessManager {
(self.exit_handler)(pid); (self.exit_handler)(pid);
} }
} }
fn new_vec_default<T: Default>(size: usize) -> Vec<T> {
fn new_vec_default<T: Default>(size: usize) -> Vec<T> {
let mut vec = Vec::new(); let mut vec = Vec::new();
vec.resize_default(size); vec.resize_default(size);
vec vec

@ -59,9 +59,9 @@ impl Processor {
trace!("CPU{} begin running process {}", inner.id, proc.0); trace!("CPU{} begin running process {}", inner.id, proc.0);
inner.proc = Some(proc); inner.proc = Some(proc);
unsafe { 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); trace!("CPU{} stop running process {}", inner.id, pid);
inner.manager.stop(pid, context); inner.manager.stop(pid, context);
} }
@ -70,7 +70,6 @@ impl Processor {
/// Called by process running on this Processor. /// Called by process running on this Processor.
/// Yield and reschedule. /// Yield and reschedule.
pub fn yield_now(&self) { pub fn yield_now(&self) {
trace!("yield start");
let inner = self.inner(); let inner = self.inner();
unsafe { unsafe {
let flags = interrupt::disable_and_store(); let flags = interrupt::disable_and_store();
@ -80,10 +79,7 @@ impl Processor {
} }
pub fn pid(&self) -> Pid { pub fn pid(&self) -> Pid {
if self.inner().proc.is_none() { self.inner().proc.as_ref().unwrap().0
return 0;
}
self.inner().proc.as_ref().expect("pid should not be None").0
} }
pub fn context(&self) -> &Context { pub fn context(&self) -> &Context {
@ -101,4 +97,3 @@ impl Processor {
} }
} }
} }

@ -32,9 +32,7 @@ fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box<Context>
/// Gets a handle to the thread that invokes it. /// Gets a handle to the thread that invokes it.
pub fn current() -> Thread { pub fn current() -> Thread {
Thread { Thread { pid: processor().pid() }
pid: processor().pid(),
}
} }
/// Puts the current thread to sleep for the specified amount of time. /// Puts the current thread to sleep for the specified amount of time.
@ -164,6 +162,13 @@ impl<T> JoinHandle<T> {
processor().yield_now(); processor().yield_now();
} }
} }
/// Force construct a JoinHandle struct
pub unsafe fn _of(pid: Pid) -> JoinHandle<T> {
JoinHandle {
thread: Thread { pid },
mark: PhantomData,
}
}
} }
//pub struct LocalKey<T: 'static> { //pub struct LocalKey<T: 'static> {

@ -1,15 +0,0 @@
use core::fmt::Debug;
/// Get values by 2 diff keys at the same time
pub trait GetMut2<Idx: Debug + Eq> {
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)
}
}

@ -1 +0,0 @@
Subproject commit a37a65fa13a00c5aa0068c3f2b5d55af6a37dd93

@ -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周后
以上均基于只有本人一人工作的前提,若有其他人协助/加入则根据实际情况而定。

@ -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):文件系统相关

@ -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的用户程序方便进行性能对比

175
kernel/Cargo.lock generated

@ -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]] [[package]]
name = "bare-metal" name = "bare-metal"
version = "0.2.3" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "bbl" name = "bbl"
@ -31,12 +52,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "bootloader" name = "bootloader"
version = "0.3.1" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/wangrunji0408/bootloader#dd5723c3d7d50856073a5003e0a355ea0fc3d46c"
dependencies = [ 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)", "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)", "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)", "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]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.5" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -82,11 +104,10 @@ dependencies = [
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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)",
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -99,17 +120,22 @@ name = "linked_list_allocator"
version = "0.6.3" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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]] [[package]]
name = "log" name = "log"
version = "0.4.5" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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]] [[package]]
name = "once" name = "once"
version = "0.3.3" version = "0.3.3"
@ -135,7 +161,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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]] [[package]]
@ -148,24 +184,47 @@ name = "remove_dir_all"
version = "0.5.1" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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]] [[package]]
name = "riscv" name = "riscv"
version = "0.3.0" version = "0.3.0"
source = "git+https://github.com/riscv-and-rust-and-decaf/riscv#f358204af01f2374ab6ed6ea059f724cd5f2fe6f"
dependencies = [ 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)", "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)", "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]] [[package]]
name = "simple-filesystem" name = "simple-filesystem"
version = "0.0.1" 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 = [ dependencies = [
"bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)", "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)", "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -180,7 +239,7 @@ dependencies = [
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.4.9" version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -203,32 +262,34 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "ucore" name = "ucore"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
"bbl 0.1.0", "bbl 0.1.0",
"bit-allocator 0.1.0", "bit-allocator 0.1.0",
"bit_field 0.9.0 (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)", "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)", "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)", "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)", "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)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"riscv 0.3.0", "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)", "simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust?branch=multi-thread)",
"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)",
"uart_16550 0.1.0 (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-memory 0.1.0",
"ucore-process 0.1.0", "ucore-process 0.1.0",
"volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -236,15 +297,15 @@ dependencies = [
name = "ucore-memory" name = "ucore-memory"
version = "0.1.0" version = "0.1.0"
dependencies = [ 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]] [[package]]
name = "ucore-process" name = "ucore-process"
version = "0.1.0" version = "0.1.0"
dependencies = [ 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)",
"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]] [[package]]
@ -262,11 +323,6 @@ name = "ux"
version = "0.1.2" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "volatile" name = "volatile"
version = "0.1.0" version = "0.1.0"
@ -274,7 +330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.5" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -291,11 +347,33 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
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]] [[package]]
name = "x86_64" name = "x86_64"
version = "0.2.11" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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)", "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)", "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)", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [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)" = "<none>"
"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)" = "<none>" "checksum bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)" = "<none>"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "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 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)" = "<none>"
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "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 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 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 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 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 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 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 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 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 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 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 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 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)" = "<none>" "checksum riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)" = "<none>"
"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)" = "<none>"
"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" "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 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 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 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 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 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 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 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-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 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 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" "checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5"

@ -4,13 +4,11 @@ version = "0.1.0"
authors = ["Runji Wang <wangrunji0408@163.com>"] authors = ["Runji Wang <wangrunji0408@163.com>"]
[features] [features]
use_apic = []
link_user_program = [] link_user_program = []
no_bbl = [] no_bbl = []
[profile.dev] [profile.dev]
# MUST >= 1 : Enable RVO to avoid stack overflow # MUST >= 1 : Enable RVO to avoid stack overflow
# MUST <= 1 : Avoid double fault at -O2 T_T
opt-level = 1 opt-level = 1
[profile.release] [profile.release]
@ -18,27 +16,31 @@ debug = true
[dependencies] [dependencies]
log = "0.4" log = "0.4"
spin = "0.4.9" spin = "0.4"
once = "0.3.3" once = "0.3"
xmas-elf = "0.6" xmas-elf = "0.6"
bitflags = "1.0" bitflags = "1.0"
bit_field = "0.9.0" bit_field = "0.9"
volatile = "0.1.0" volatile = "0.1"
linked_list_allocator = "0.6" 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" } bit-allocator = { path = "../crate/bit-allocator" }
ucore-memory = { path = "../crate/memory" } ucore-memory = { path = "../crate/memory" }
ucore-process = { path = "../crate/process" } 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] [target.'cfg(target_arch = "x86_64")'.dependencies]
bootloader = "0.3" bootloader = { git = "https://github.com/wangrunji0408/bootloader" }
x86_64 = "0.2.11" 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" redox_syscall = "0.1"
uart_16550 = "0.1" uart_16550 = "0.1"
[target.'cfg(target_arch = "riscv32")'.dependencies] [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" } bbl = { path = "../crate/bbl" }
[package.metadata.bootimage] [package.metadata.bootimage]

@ -12,11 +12,13 @@
# d = int | in_asm | ... QEMU debug info # d = int | in_asm | ... QEMU debug info
# mode = debug | release # mode = debug | release
# LOG = off | error | warn | info | debug | trace # LOG = off | error | warn | info | debug | trace
# smp SMP core number
# board Only available on riscv32, build without bbl, run on board # board Only available on riscv32, build without bbl, run on board
arch ?= riscv32 arch ?= riscv32
mode ?= debug mode ?= debug
LOG ?= debug LOG ?= debug
smp ?= 4
target := $(arch)-blog_os target := $(arch)-blog_os
kernel := target/$(target)/$(mode)/ucore kernel := target/$(target)/$(mode)/ucore
@ -31,12 +33,16 @@ ifeq ($(arch), x86_64)
qemu_opts := \ qemu_opts := \
-drive format=raw,file=$(bootimage) \ -drive format=raw,file=$(bootimage) \
-drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \ -drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \
-smp 4 \ -smp cores=$(smp) \
-serial mon:stdio \ -serial mon:stdio \
-device isa-debug-exit -device isa-debug-exit
endif endif
ifeq ($(arch), riscv32) ifeq ($(arch), riscv32)
qemu_opts := -machine virt -kernel $(bin) -nographic qemu_opts := \
-machine virt \
-kernel $(bin) \
-nographic \
-smp cores=$(smp)
endif endif
ifdef board ifdef board
@ -83,6 +89,7 @@ all: $(kernel)
clean: clean:
@cargo clean @cargo clean
@rm -rf ../riscv-pk/build
doc: doc:
@cargo rustdoc -- --document-private-items @cargo rustdoc -- --document-private-items
@ -104,9 +111,12 @@ endif
asm: asm:
@$(objdump) -dS $(kernel) | less @$(objdump) -dS $(kernel) | less
elf-h: header:
@$(objdump) -h $(kernel) @$(objdump) -h $(kernel)
sym:
@$(objdump) -t $(kernel) | less
$(bin): kernel $(bin): kernel
ifdef board ifdef board
@cp $(kernel) $@ @cp $(kernel) $@
@ -128,7 +138,10 @@ kernel:
ifeq ($(arch), x86_64) ifeq ($(arch), x86_64)
@bootimage build $(build_args) @bootimage build $(build_args)
else 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 endif
# make user.o from binary files # make user.o from binary files

@ -12,6 +12,13 @@ fn main() {
// .compile("cobj"); // .compile("cobj");
gen_vector_asm().unwrap(); 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<()> { fn gen_vector_asm() -> Result<()> {

@ -9,12 +9,11 @@
"cpu": "generic-rv32", "cpu": "generic-rv32",
"features": "", "features": "",
"max-atomic-width": "32", "max-atomic-width": "32",
"linker": "riscv64-unknown-elf-ld", "linker": "rust-lld",
"linker-flavor": "ld", "linker-flavor": "ld.lld",
"pre-link-args": { "pre-link-args": {
"ld": [ "ld.lld": [
"-Tsrc/arch/riscv32/boot/linker.ld", "-Tsrc/arch/riscv32/boot/linker.ld"
"-melf32lriscv"
] ]
}, },
"executables": true, "executables": true,

@ -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<u32>,
+ #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
v: UnsafeCell<u8>,
}
@@ -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`.
///

@ -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;
}

@ -23,79 +23,3 @@ pub extern fn __mulsi3(mut a: u32, mut b: u32) -> u32 {
pub extern fn abort() { pub extern fn abort() {
loop {} 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<T: PartialEq>(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
}

@ -5,8 +5,6 @@ const P2_MASK: usize = 0x3ff << 22;
pub const RECURSIVE_INDEX: usize = 0x3fe; pub const RECURSIVE_INDEX: usize = 0x3fe;
pub const KERNEL_OFFSET: usize = 0; pub const KERNEL_OFFSET: usize = 0;
pub const KERNEL_P2_INDEX: usize = 0x8000_0000 >> 22; 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 KERNEL_HEAP_SIZE: usize = 0x00a0_0000;
pub const MEMORY_OFFSET: usize = 0x8000_0000; pub const MEMORY_OFFSET: usize = 0x8000_0000;
//pub const MEMORY_END: usize = 0x8080_0000; //for thinpad not enough now //pub const MEMORY_END: usize = 0x8080_0000; //for thinpad not enough now

@ -58,10 +58,6 @@ impl TrapFrame {
tf.sstatus.set_spp(sstatus::SPP::User); tf.sstatus.set_spp(sstatus::SPP::User);
tf tf
} }
pub fn is_user(&self) -> bool {
unimplemented!()
}
} }
use core::fmt::{Debug, Formatter, Error}; use core::fmt::{Debug, Formatter, Error};
@ -87,6 +83,7 @@ impl Debug for TrapFrame {
.finish() .finish()
} }
} }
/// kernel stack contents for a new thread /// kernel stack contents for a new thread
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
@ -258,4 +255,9 @@ impl Context {
}, },
}.push_at(kstack_top) }.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()
}
} }

@ -72,9 +72,10 @@ pub unsafe fn restore(flags: usize) {
#[no_mangle] #[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) { pub extern fn rust_trap(tf: &mut TrapFrame) {
use super::riscv::register::scause::{Trap, Interrupt as I, Exception as E}; 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() { match tf.scause.cause() {
Trap::Interrupt(I::SupervisorExternal) => serial(), Trap::Interrupt(I::SupervisorExternal) => serial(),
Trap::Interrupt(I::SupervisorSoft) => ipi(),
Trap::Interrupt(I::SupervisorTimer) => timer(), Trap::Interrupt(I::SupervisorTimer) => timer(),
Trap::Exception(E::IllegalInstruction) => illegal_inst(tf), Trap::Exception(E::IllegalInstruction) => illegal_inst(tf),
Trap::Exception(E::UserEnvCall) => syscall(tf), Trap::Exception(E::UserEnvCall) => syscall(tf),
@ -94,6 +95,7 @@ fn ipi() {
debug!("IPI"); debug!("IPI");
super::bbl::sbi::clear_ipi(); super::bbl::sbi::clear_ipi();
} }
/* /*
* @brief: * @brief:
* process timer interrupt * process timer interrupt

@ -1,5 +1,5 @@
use core::slice; use core::{slice, mem};
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack}; use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet};
use super::riscv::{addr::*, register::sstatus}; use super::riscv::{addr::*, register::sstatus};
use ucore_memory::PAGE_SIZE; use ucore_memory::PAGE_SIZE;
@ -17,9 +17,16 @@ pub fn init() {
super::paging::setup_page_table(frame); // set up page table super::paging::setup_page_table(frame); // set up page table
// initialize heap and Frame allocator // initialize heap and Frame allocator
init_frame_allocator(); init_frame_allocator();
init_heap();
// remap the kernel use 4K page // remap the kernel use 4K page
remap_the_kernel(); 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");
}
} }
/* /*
@ -32,10 +39,6 @@ fn init_frame_allocator() {
use consts::{MEMORY_OFFSET, MEMORY_END}; use consts::{MEMORY_OFFSET, MEMORY_END};
let mut ba = FRAME_ALLOCATOR.lock(); 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)); ba.insert(to_range(end as usize + PAGE_SIZE, MEMORY_END));
info!("FrameAllocator init end"); info!("FrameAllocator init end");
@ -60,25 +63,23 @@ fn init_frame_allocator() {
* remmap the kernel memory address with 4K page recorded in p1 page table * remmap the kernel memory address with 4K page recorded in p1 page table
*/ */
fn remap_the_kernel() { fn remap_the_kernel() {
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; let mut ms = MemorySet::new_bare();
// set up kernel stack #[cfg(feature = "no_bbl")]
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) };
ms.push(MemoryArea::new_identity(0x10000000, 0x10000008, MemoryAttr::default(), "serial")); 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(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(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(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata"));
ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss")); ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss"));
unsafe { ms.activate(); } unsafe { ms.activate(); }
use core::mem::forget; unsafe { SATP = ms.token(); }
forget(ms); mem::forget(ms);
info!("kernel remap end"); 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 // Symbols provided by linker script
extern { extern {
fn stext(); fn stext();

@ -27,7 +27,7 @@ pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
timer::init(); timer::init();
::process::init(); ::process::init();
::thread::spawn(::fs::shell); ::thread::spawn(::shell::run_user_shell);
unsafe { cpu::start_others(hart_mask); } unsafe { cpu::start_others(hart_mask); }
::kmain(); ::kmain();
@ -35,6 +35,7 @@ pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
fn others_main() -> ! { fn others_main() -> ! {
interrupt::init(); interrupt::init();
memory::init_other();
timer::init(); timer::init();
::kmain(); ::kmain();
} }

@ -1,6 +1,6 @@
use consts::{KERNEL_P2_INDEX, RECURSIVE_INDEX}; use consts::{KERNEL_P2_INDEX, RECURSIVE_INDEX};
// Depends on kernel // 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::addr::*;
use super::riscv::asm::{sfence_vma, sfence_vma_all}; use super::riscv::asm::{sfence_vma, sfence_vma_all};
use super::riscv::paging::{Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable}; use super::riscv::paging::{Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable};
@ -62,7 +62,7 @@ impl PageTable for ActivePageTable {
// we may need frame allocator to alloc frame for new page table(first/second) // we may need frame allocator to alloc frame for new page table(first/second)
self.0.map_to(page, frame, flags, &mut FrameAllocatorForRiscv) self.0.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
.unwrap().flush(); .unwrap().flush();
self.get_entry(addr) self.get_entry(addr).unwrap()
} }
/* /*
@ -85,12 +85,15 @@ impl PageTable for ActivePageTable {
* @retval: * @retval:
* a mutable PageEntry reference of 'addr' * 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 page = Page::of_addr(VirtAddr::new(addr));
// ??? // ???
let _ = self.0.translate_page(page); let _ = self.0.translate_page(page);
let entry_addr = ((addr >> 10) & ((1 << 22) - 4)) | (RECURSIVE_INDEX << 22); 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)) }
} }
/* /*
@ -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: * @param:
* f: the function to run when temporarily activate self as current page table * f: the function to run when temporarily activate self as current page table
@ -307,7 +288,7 @@ impl InactivePageTable for InactivePageTable0 {
* @retval: * @retval:
* the return value of f * the return value of f
*/ */
unsafe fn with_retval<T>(&self, f: impl FnOnce() -> T) -> T{ unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
let old_frame = satp::read().frame(); let old_frame = satp::read().frame();
let new_frame = self.p2_frame.clone(); let new_frame = self.p2_frame.clone();
debug!("switch table {:x?} -> {:x?}", old_frame, new_frame); debug!("switch table {:x?} -> {:x?}", old_frame, new_frame);
@ -341,10 +322,6 @@ impl InactivePageTable for InactivePageTable0 {
fn dealloc_frame(target: usize) { fn dealloc_frame(target: usize) {
dealloc_frame(target) dealloc_frame(target)
} }
fn alloc_stack() -> Stack {
alloc_stack()
}
} }
impl InactivePageTable0 { impl InactivePageTable0 {

@ -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<IoApic> = Mutex::new(unsafe{IoApic::new()});
}
// IO APIC MMIO structure: write reg, then read or write data.
#[repr(C)]
struct IoApicMmio {
reg: Mmio<u32>,
pad: [Mmio<u32>; 3],
data: Mmio<u32>,
}
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
}
}

@ -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);
}
}

@ -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
// }
}

@ -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);
}
}
}

@ -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();
}

@ -2,16 +2,9 @@
//! //!
//! Borrow from Rucore project. Thanks GWord! //! Borrow from Rucore project. Thanks GWord!
//! Port from ucore C code. //! 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 const BLOCK_SIZE: usize = 512;
pub struct LockedIde(pub Mutex<IDE>);
pub struct IDE { pub struct IDE {
num: u8, num: u8,
/// I/O Base /// I/O Base

@ -29,7 +29,6 @@ impl SerialRead for SerialPort {
let ports = self as *mut _ as *mut [Pio<u8>; 6]; let ports = self as *mut _ as *mut [Pio<u8>; 6];
let line_sts = &(*ports)[5]; let line_sts = &(*ports)[5];
let data = &(*ports)[0]; let data = &(*ports)[0];
while line_sts.read() & 1 != 1 {}
data.read() data.read()
} }
} }

@ -80,6 +80,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
T_PGFLT => page_fault(tf), T_PGFLT => page_fault(tf),
T_IRQ0...63 => { T_IRQ0...63 => {
let irq = tf.trap_num as u8 - T_IRQ0; let irq = tf.trap_num as u8 - T_IRQ0;
super::ack(irq); // must ack before switching
match irq { match irq {
IRQ_TIMER => ::trap::timer(), IRQ_TIMER => ::trap::timer(),
IRQ_KBD => keyboard(), IRQ_KBD => keyboard(),
@ -88,7 +89,6 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
IRQ_IDE => ide(), IRQ_IDE => ide(),
_ => panic!("Invalid IRQ number: {}", irq), _ => panic!("Invalid IRQ number: {}", irq),
} }
super::ack(irq);
} }
T_SWITCH_TOK => to_kernel(tf), T_SWITCH_TOK => to_kernel(tf),
T_SWITCH_TOU => to_user(tf), T_SWITCH_TOU => to_user(tf),
@ -131,6 +131,7 @@ fn keyboard() {
fn com1() { fn com1() {
use arch::driver::serial::*; use arch::driver::serial::*;
trace!("\nInterupt: COM1"); trace!("\nInterupt: COM1");
::trap::serial(COM1.lock().receive() as char);
} }
fn com2() { fn com2() {

@ -183,4 +183,9 @@ impl Context {
}, },
}.push_at(kstack_top) }.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()
}
} }

@ -48,7 +48,7 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
driver::init(); driver::init();
::process::init(); ::process::init();
::thread::spawn(::fs::shell); ::thread::spawn(::shell::run_user_shell);
AP_CAN_INIT.store(true, Ordering::Relaxed); AP_CAN_INIT.store(true, Ordering::Relaxed);

@ -95,6 +95,9 @@ impl ActivePageTable {
// Unmap the page // Unmap the page
self.unmap(0xcafebabe); self.unmap(0xcafebabe);
} }
pub fn token() -> usize {
Cr3::read().0.start_address().as_u64() as usize
}
} }
impl Entry for PageEntry { impl Entry for PageEntry {
@ -206,18 +209,19 @@ impl InactivePageTable for InactivePageTable0 {
} }
} }
unsafe fn with(&self, f: impl FnOnce()) { unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
let old_frame = Cr3::read().0; let old_frame = Cr3::read().0;
let new_frame = self.p4_frame.clone(); let new_frame = self.p4_frame.clone();
debug!("switch table {:?} -> {:?}", old_frame, new_frame); debug!("switch table {:?} -> {:?}", old_frame, new_frame);
if old_frame != new_frame { if old_frame != new_frame {
Cr3::write(new_frame, Cr3Flags::empty()); Cr3::write(new_frame, Cr3Flags::empty());
} }
f(); let ret = f();
debug!("switch table {:?} -> {:?}", new_frame, old_frame); debug!("switch table {:?} -> {:?}", new_frame, old_frame);
if old_frame != new_frame { if old_frame != new_frame {
Cr3::write(old_frame, Cr3Flags::empty()); Cr3::write(old_frame, Cr3Flags::empty());
} }
ret
} }
fn token(&self) -> usize { fn token(&self) -> usize {

@ -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<MemorySet> = 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
}

@ -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<VecDeque<char>>,
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()
}

@ -3,4 +3,4 @@
pub use arch::consts::*; pub use arch::consts::*;
pub const MAX_CPU_NUM: usize = 8; pub const MAX_CPU_NUM: usize = 8;
pub const MAX_PROCESS_NUM: usize = 48; pub const MAX_PROCESS_NUM: usize = 128;

@ -1,8 +1,11 @@
use simple_filesystem::*; use simple_filesystem::*;
use alloc::boxed::Box; use alloc::{boxed::Box, sync::Arc, string::String, collections::VecDeque, vec::Vec};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use arch::driver::ide; 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::{InactivePageTable0, memory_set_record};
use memory::MemorySet; use memory::MemorySet;
@ -13,69 +16,29 @@ use process::context::memory_set_map_swappable;
global_asm!(r#" global_asm!(r#"
.section .rodata .section .rodata
.align 12 .align 12
_binary_user_riscv_img_start: .global _user_img_start
.global _user_img_end
_user_img_start:
.incbin "../user/user-riscv.img" .incbin "../user/user-riscv.img"
_binary_user_riscv_img_end: _user_img_end:
"#); "#);
pub fn shell() { lazy_static! {
// load riscv32/x86_64 user program pub static ref ROOT_INODE: Arc<INode> = {
use sync;
/// below are test for sync, uncomment them if need
//sync::test::philosopher_using_mutex();
//sync::test::philosopher_using_monitor();
info!("come into shell!");
#[cfg(target_arch = "riscv32")] #[cfg(target_arch = "riscv32")]
let device = { let device = {
extern { extern {
fn _binary_user_riscv_img_start(); fn _user_img_start();
fn _binary_user_riscv_img_end(); fn _user_img_end();
} }
Box::new(unsafe { MemBuf::new(_binary_user_riscv_img_start, _binary_user_riscv_img_end) }) Box::new(unsafe { MemBuf::new(_user_img_start, _user_img_end) })
}; };
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
let device = Box::new(&ide::DISK1); let device = Box::new(ide::IDE::new(1));
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 sfs = SimpleFileSystem::open(device).expect("failed to open SFS");
let name = get_line(); sfs.root_inode()
//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]); struct MemBuf(&'static [u8]);
@ -99,19 +62,99 @@ impl Device for MemBuf {
} }
} }
use core::slice;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
impl BlockedDevice for &'static ide::DISK1 { impl BlockedDevice for ide::IDE {
const BLOCK_SIZE_LOG2: u8 = 9; const BLOCK_SIZE_LOG2: u8 = 9;
fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool { fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool {
assert!(buf.len() >= ide::BLOCK_SIZE); assert!(buf.len() >= ide::BLOCK_SIZE);
let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; 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 { fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool {
assert!(buf.len() >= ide::BLOCK_SIZE); assert!(buf.len() >= ide::BLOCK_SIZE);
let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; 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<VecDeque<char>>,
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<Stdin> = Arc::new(Stdin::default());
pub static ref STDOUT: Arc<Stdout> = Arc::new(Stdout::default());
}
// TODO: better way to provide default impl?
macro_rules! impl_inode {
() => {
fn info(&self) -> Result<FileInfo> { unimplemented!() }
fn sync(&self) -> Result<()> { unimplemented!() }
fn resize(&self, len: usize) -> Result<()> { unimplemented!() }
fn create(&self, name: &str, type_: FileType) -> Result<Arc<INode>> { unimplemented!() }
fn unlink(&self, name: &str) -> Result<()> { unimplemented!() }
fn link(&self, name: &str, other: &Arc<INode>) -> Result<()> { unimplemented!() }
fn rename(&self, old_name: &str, new_name: &str) -> Result<()> { unimplemented!() }
fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> Result<()> { unimplemented!() }
fn find(&self, name: &str) -> Result<Arc<INode>> { unimplemented!() }
fn get_entry(&self, id: usize) -> Result<String> { unimplemented!() }
fn fs(&self) -> Arc<FileSystem> { unimplemented!() }
fn as_any_ref(&self) -> &Any { self }
};
}
impl INode for Stdin {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
buf[0] = self.pop() as u8;
Ok(1)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> { unimplemented!() }
impl_inode!();
}
impl INode for Stdout {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> { unimplemented!() }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
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<Vec<u8>>;
}
impl INodeExt for INode {
fn read_as_vec(&self) -> Result<Vec<u8>> {
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)
} }
} }

@ -1,4 +1,4 @@
// Rust language features implementions // Rust language features implementations
use core::panic::PanicInfo; use core::panic::PanicInfo;
use core::alloc::Layout; use core::alloc::Layout;

@ -51,7 +51,7 @@ mod syscall;
mod fs; mod fs;
mod sync; mod sync;
mod trap; mod trap;
mod console; mod shell;
#[allow(dead_code)] #[allow(dead_code)]
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -63,10 +63,6 @@ pub mod arch;
pub mod arch; pub mod arch;
pub fn kmain() -> ! { 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(); process::processor().run();
// thread::test::local_key(); // thread::test::local_key();

@ -1,5 +1,10 @@
use core::fmt; use core::fmt;
use log::{self, Level, LevelFilter, Log, Metadata, Record}; use log::{self, Level, LevelFilter, Log, Metadata, Record};
use spin::Mutex;
lazy_static! {
static ref log_mutex: Mutex<()> = Mutex::new(());
}
pub fn init() { pub fn init() {
static LOGGER: SimpleLogger = SimpleLogger; static LOGGER: SimpleLogger = SimpleLogger;
@ -38,11 +43,13 @@ macro_rules! with_color {
fn print_in_color(args: fmt::Arguments, color: Color) { fn print_in_color(args: fmt::Arguments, color: Color) {
use arch::io; use arch::io;
let mutex = log_mutex.lock();
io::putfmt(with_color!(args, color)); io::putfmt(with_color!(args, color));
} }
pub fn print(args: fmt::Arguments) { pub fn print(args: fmt::Arguments) {
use arch::io; use arch::io;
let mutex = log_mutex.lock();
io::putfmt(args); io::putfmt(args);
} }
@ -71,7 +78,7 @@ impl From<Level> for Color {
Level::Error => Color::Red, Level::Error => Color::Red,
Level::Warn => Color::Yellow, Level::Warn => Color::Yellow,
Level::Info => Color::Blue, Level::Info => Color::Blue,
Level::Debug => Color::LightRed, Level::Debug => Color::Green,
Level::Trace => Color::DarkGray, Level::Trace => Color::DarkGray,
} }
} }

@ -5,7 +5,7 @@ use consts::MEMORY_OFFSET;
use super::HEAP_ALLOCATOR; use super::HEAP_ALLOCATOR;
use ucore_memory::{*, paging::PageTable}; use ucore_memory::{*, paging::PageTable};
use ucore_memory::cow::CowExt; 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 ucore_memory::swap::*;
//use process::{processor, PROCESSOR}; //use process::{processor, PROCESSOR};
use process::{process}; use process::{process};
@ -76,15 +76,6 @@ pub fn dealloc_frame(target: usize) {
FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE); 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); pub struct KernelStack(usize);
const STACK_SIZE: usize = 0x8000; const STACK_SIZE: usize = 0x8000;

@ -3,15 +3,21 @@ use memory::{MemoryArea, MemoryAttr, MemorySet, KernelStack, active_table_swap,
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}}; use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}};
use core::fmt::{Debug, Error, Formatter}; use core::fmt::{Debug, Error, Formatter};
use ucore_process::Context; 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 ucore_memory::{Page};
use ::memory::{InactivePageTable0, memory_set_record}; use ::memory::{InactivePageTable0, memory_set_record};
use ucore_memory::memory_set::*; use ucore_memory::memory_set::*;
use simple_filesystem::file::File;
use spin::Mutex;
// TODO: avoid pub
pub struct ContextImpl { pub struct ContextImpl {
arch: ArchContext, pub arch: ArchContext,
memory_set: MemorySet, pub memory_set: MemorySet,
kstack: KernelStack, pub kstack: KernelStack,
pub files: BTreeMap<usize, Arc<Mutex<File>>>,
pub cwd: String,
} }
impl Context for ContextImpl { impl Context for ContextImpl {
@ -28,6 +34,8 @@ impl ContextImpl {
arch: ArchContext::null(), arch: ArchContext::null(),
memory_set: MemorySet::new(), memory_set: MemorySet::new(),
kstack: KernelStack::new(), kstack: KernelStack::new(),
files: BTreeMap::default(),
cwd: String::new(),
}) })
} }
@ -38,6 +46,8 @@ impl ContextImpl {
arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) }, arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) },
memory_set, memory_set,
kstack, kstack,
files: BTreeMap::default(),
cwd: String::new(),
}) })
} }
@ -50,7 +60,9 @@ impl ContextImpl {
* @retval: * @retval:
* the new user thread Context * the new user thread Context
*/ */
pub fn new_user(data: &[u8]) -> Box<Context> { pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<ContextImpl>
where Iter: Iterator<Item=&'a str>
{
// Parse elf // Parse elf
let elf = ElfFile::new(data).expect("failed to read elf"); let elf = ElfFile::new(data).expect("failed to read elf");
let is32 = match elf.header.pt2 { let is32 = match elf.header.pt2 {
@ -61,7 +73,7 @@ impl ContextImpl {
// User stack // User stack
use consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET}; 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), true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE),
false => (USER_STACK_OFFSET, USER_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() //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 }); // .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); trace!("{:#x?}", memory_set);
let entry_addr = elf.header.pt2.entry_point() as usize; 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 virt_addr = ph.virtual_addr() as usize;
let offset = ph.offset() as usize; let offset = ph.offset() as usize;
let file_size = ph.file_size() as usize; let file_size = ph.file_size() as usize;
if file_size == 0 { let mem_size = ph.mem_size() as usize;
return;
} let target = unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) };
use core::slice; if file_size != 0 {
let target = unsafe { slice::from_raw_parts_mut(virt_addr as *mut u8, file_size) }; target[..file_size].copy_from_slice(&data[offset..offset + 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
} }
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 { let mut ret = Box::new(ContextImpl {
arch: unsafe { arch: unsafe {
ArchContext::new_user_thread( 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, memory_set,
kstack, kstack,
files: BTreeMap::default(),
cwd: String::new(),
}); });
//set the user Memory pages in the memory set swappable //set the user Memory pages in the memory set swappable
memory_set_map_swappable(ret.get_memory_set_mut()); memory_set_map_swappable(ret.get_memory_set_mut());
@ -147,7 +156,7 @@ impl ContextImpl {
unsafe { unsafe {
memory_set.with(|| { memory_set.with(|| {
for (area, data) in memory_set.iter().zip(datas.iter()) { 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())
} }
}); });
} }
@ -164,6 +173,8 @@ impl ContextImpl {
arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) }, arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) },
memory_set, memory_set,
kstack, kstack,
files: BTreeMap::default(),
cwd: String::new(),
}); });
memory_set_map_swappable(ret.get_memory_set_mut()); 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 //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 = { let pt = {
memory_set.get_page_table_mut() as *mut InactivePageTable0 memory_set.get_page_table_mut() as *mut InactivePageTable0
}; };
@ -213,6 +224,33 @@ impl Debug for ContextImpl {
} }
} }
/// Push a slice at the stack. Return the new sp.
unsafe fn push_slice<T: Copy>(mut sp: usize, vs: &[T]) -> usize {
use core::{mem::{size_of, align_of}, slice};
sp -= vs.len() * size_of::<T>();
sp -= sp % align_of::<T>();
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<Item=&'a str>
{
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 * elf: the source ELF file

@ -8,7 +8,6 @@ use sync::Condvar;
use core::sync::atomic::*; use core::sync::atomic::*;
pub mod context; pub mod context;
pub fn init() { pub fn init() {
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass // NOTE: max_time_slice <= 5 to ensure 'priority' test pass
let scheduler = Box::new(scheduler::RRScheduler::new(5)); let scheduler = Box::new(scheduler::RRScheduler::new(5));

@ -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()
}

@ -96,17 +96,11 @@ impl<T, S: MutexSupport> Mutex<T, S>
impl<T: ?Sized, S: MutexSupport> Mutex<T, S> impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
{ {
fn obtain_lock(&self) { fn obtain_lock(&self) {
while true { while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false {
match self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) {
Ok(X) => break,
Err(X) => {
// Wait until the lock looks unlocked before retrying // Wait until the lock looks unlocked before retrying
while self.lock.load(Ordering::Relaxed) { while self.lock.load(Ordering::Relaxed) {
self.support.cpu_relax(); self.support.cpu_relax();
} }
},
};
} }
} }
@ -150,13 +144,13 @@ impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
/// a guard within Some. /// a guard within Some.
pub fn try_lock(&self) -> Option<MutexGuard<T, S>> { pub fn try_lock(&self) -> Option<MutexGuard<T, S>> {
let support_guard = S::before_lock(); let support_guard = S::before_lock();
match self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) { if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false {
Ok(X) =>
Some(MutexGuard { Some(MutexGuard {
mutex: self, mutex: self,
support_guard, support_guard,
}), })
Err(X) => None, } else {
None
} }
} }
} }
@ -180,12 +174,12 @@ impl<T: ?Sized + Default, S: MutexSupport> Default for Mutex<T, S> {
impl<'a, T: ?Sized, S: MutexSupport> Deref for MutexGuard<'a, T, S> impl<'a, T: ?Sized, S: MutexSupport> Deref for MutexGuard<'a, T, S>
{ {
type Target = T; 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> 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> impl<'a, T: ?Sized, S: MutexSupport> Drop for MutexGuard<'a, T, S>

@ -1,86 +1,166 @@
//! 系统调用解析执行模块 //! System call
#![allow(unused)]
use arch::interrupt::TrapFrame; use arch::interrupt::TrapFrame;
use process::*; use process::*;
use thread; use thread;
use util; 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;
/// 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(),
use process::context::memory_set_map_swappable;
use alloc::boxed::Box;
use process::context::*;
/// 系统调用入口点
///
/// 当发生系统调用中断时,中断服务例程将控制权转移到这里。
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); error!("unknown syscall id: {:#x?}, args: {:x?}", id, args);
::trap::error(tf); ::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); info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
use core::slice;
use core::str;
let slice = unsafe { slice::from_raw_parts(base, len) }; let slice = unsafe { slice::from_raw_parts(base, len) };
print!("{}", str::from_utf8(slice).unwrap()); let len = get_file(fd)?.lock().write(slice)?;
0 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 path = unsafe { util::from_cstr(path) };
let flags = VfsFlags::from_ucore_flags(flags);
info!("open: path: {:?}, flags: {:?}", path, flags); info!("open: path: {:?}, flags: {:?}", path, flags);
match path { let (fd, inode) = match path {
"stdin:" => 0, "stdin:" => (0, ::fs::STDIN.clone() as Arc<INode>),
"stdout:" => 1, "stdout:" => (1, ::fs::STDOUT.clone() as Arc<INode>),
_ => -1, _ => {
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) -> i32 { fn sys_close(fd: usize) -> SysResult {
info!("close: fd: {:?}", fd); info!("close: fd: {:?}", fd);
0 match process().files.remove(&fd) {
Some(_) => Ok(0),
None => Err(SysError::InvalidFile),
}
}
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. /// 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); let mut context = process().fork(tf);
//memory_set_map_swappable(context.get_memory_set_mut()); //memory_set_map_swappable(context.get_memory_set_mut());
let pid = processor().manager().add(context); let pid = processor().manager().add(context);
processor().manager().set_parent(thread::current().id(), pid); processor().manager().set_parent(thread::current().id(), pid);
//memory_set_map_swappable(processor.get_context_mut(pid).get_memory_set_mut()); //memory_set_map_swappable(processor.get_context_mut(pid).get_memory_set_mut());
info!("fork: {} -> {}", thread::current().id(), pid); info!("fork: {} -> {}", thread::current().id(), pid);
pid as i32 Ok(pid as i32)
} }
/// Wait the process exit. /// Wait the process exit.
/// Return the PID. Store exit code to `code` if it's not null. /// 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 { loop {
let wait_procs = match pid { let wait_procs = match pid {
0 => processor().manager().get_children(thread::current().id()), 0 => processor().manager().get_children(thread::current().id()),
_ => vec![pid], _ => vec![pid],
}; };
if wait_procs.is_empty() { if wait_procs.is_empty() {
return -1; return Ok(-1);
} }
for pid in wait_procs { for pid in wait_procs {
match processor().manager().get_status(pid) { 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); processor().manager().wait_done(thread::current().id(), pid);
info!("wait: {} -> {}", 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 { if pid == 0 {
processor().manager().wait_child(thread::current().id()); processor().manager().wait_child(thread::current().id());
processor().yield_now(); 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<String> = 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(); thread::yield_now();
0 Ok(0)
} }
/// Kill the process /// Kill the process
fn sys_kill(pid: usize) -> i32 { fn sys_kill(pid: usize) -> SysResult {
info!("{} killed: {}", thread::current().id(), pid); info!("{} killed: {}", thread::current().id(), pid);
processor().manager().exit(pid, 0x100); processor().manager().exit(pid, 0x100);
if pid == thread::current().id() { if pid == thread::current().id() {
processor().yield_now(); processor().yield_now();
} }
0 Ok(0)
} }
/// Get the current process id /// Get the current process id
fn sys_getpid() -> i32 { fn sys_getpid() -> SysResult {
thread::current().id() as i32 Ok(thread::current().id() as i32)
} }
/// Exit the current process /// Exit the current process
fn sys_exit(exit_code: usize) -> i32 { fn sys_exit(exit_code: i32) -> SysResult {
let pid = thread::current().id(); let pid = thread::current().id();
info!("exit: {}", pid); info!("exit: {}, code: {}", pid, exit_code);
processor().manager().exit(pid, exit_code); processor().manager().exit(pid, exit_code as usize);
processor().yield_now(); processor().yield_now();
unreachable!(); unreachable!();
} }
fn sys_sleep(time: usize) -> i32 { fn sys_sleep(time: usize) -> SysResult {
use core::time::Duration; use core::time::Duration;
thread::sleep(Duration::from_millis(time as u64 * 10)); thread::sleep(Duration::from_millis(time as u64 * 10));
0 Ok(0)
} }
fn sys_get_time() -> i32 { fn sys_get_time() -> SysResult {
unsafe { ::trap::TICK as i32 } 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(); let pid = thread::current().id();
processor().manager().set_priority(pid, priority as u8); 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); print!("{}", c);
0 Ok(0)
} }
const SYS_EXIT: usize = 1; fn get_file(fd: usize) -> Result<&'static Arc<Mutex<File>>, SysError> {
const SYS_FORK: usize = 2; process().files.get(&fd).ok_or(SysError::InvalidFile)
const SYS_WAIT: usize = 3; }
const SYS_EXEC: usize = 4;
const SYS_CLONE: usize = 5; pub type SysResult = Result<i32, SysError>;
const SYS_YIELD: usize = 10;
const SYS_SLEEP: usize = 11; #[repr(i32)]
const SYS_KILL: usize = 12; pub enum SysError {
const SYS_GETTIME: usize = 17; VfsError,
const SYS_GETPID: usize = 18; InvalidFile,
const SYS_MMAP: usize = 20; InvalidArgument,
const SYS_MUNMAP: usize = 21; }
const SYS_SHMEM: usize = 22;
const SYS_PUTC: usize = 30; impl From<()> for SysError {
const SYS_PGDIR: usize = 31; fn from(_: ()) -> Self {
const SYS_OPEN: usize = 100; SysError::VfsError
const SYS_CLOSE: usize = 101; }
const SYS_READ: usize = 102; }
const SYS_WRITE: usize = 103;
const SYS_SEEK: usize = 104; bitflags! {
const SYS_FSTAT: usize = 110; struct VfsFlags: usize {
const SYS_FSYNC: usize = 111; // WARNING: different from origin uCore
const SYS_GETCWD: usize = 121; const READABLE = 1 << 0;
const SYS_GETDIRENTRY: usize = 128; const WRITABLE = 1 << 1;
const SYS_DUP: usize = 130; /// create file if it does not exist
const SYS_LAB6_SET_PRIORITY: usize = 255; 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<FileInfo> 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,
}
}
}

@ -9,7 +9,6 @@ pub fn timer() {
unsafe { TICK += 1; } unsafe { TICK += 1; }
} }
processor().tick(); processor().tick();
//info!("finish before return!");
} }
pub fn error(tf: &TrapFrame) -> ! { pub fn error(tf: &TrapFrame) -> ! {
@ -23,5 +22,5 @@ pub fn error(tf: &TrapFrame) -> ! {
} }
pub fn serial(c: char) { pub fn serial(c: char) {
::console::CONSOLE_INPUT.push(c); ::fs::STDIN.push(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) void boot_loader(uintptr_t dtb)

@ -4084,8 +4084,8 @@ fi
case "${BUILD_32BIT}" in case "${BUILD_32BIT}" in
yes|default) yes|default)
echo "Building 32-bit pk" echo "Building 32-bit pk"
CFLAGS="$default_CFLAGS -march=rv32i -mabi=ilp32" CFLAGS="$default_CFLAGS -march=rv32iac -mabi=ilp32"
LDFLAGS="-march=rv32i -mabi=ilp32" LDFLAGS="-march=rv32iac -mabi=ilp32"
install_subdir="riscv32-unknown-elf" install_subdir="riscv32-unknown-elf"
;; ;;
*) *)

@ -88,8 +88,8 @@ AC_ARG_ENABLE([32bit],
case "${BUILD_32BIT}" in case "${BUILD_32BIT}" in
yes|default) yes|default)
echo "Building 32-bit pk" echo "Building 32-bit pk"
CFLAGS="$default_CFLAGS -march=rv32i -mabi=ilp32" CFLAGS="$default_CFLAGS -march=rv32iac -mabi=ilp32"
LDFLAGS="-march=rv32i -mabi=ilp32" LDFLAGS="-march=rv32iac -mabi=ilp32"
install_subdir="riscv32-unknown-elf" install_subdir="riscv32-unknown-elf"
;; ;;
*) *)

@ -172,7 +172,7 @@ void init_other_hart(uintptr_t hartid, uintptr_t dtb)
boot_other_hart(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. // Set up a PMP to permit access to all of memory.
// Ignore the illegal-instruction trap if PMPs aren't supported. // 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 a0 asm ("a0") = arg0;
register uintptr_t a1 asm ("a1") = arg1; 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(); __builtin_unreachable();
} }

@ -63,7 +63,7 @@ void putstring(const char* s);
#define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); }) #define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); })
#define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(-1); }) #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)); __attribute__((noreturn));
void boot_loader(uintptr_t dtb); void boot_loader(uintptr_t dtb);
void boot_other_hart(uintptr_t dtb); void boot_other_hart(uintptr_t dtb);

@ -9,13 +9,8 @@
"cpu": "generic-rv32", "cpu": "generic-rv32",
"features": "", "features": "",
"max-atomic-width": "32", "max-atomic-width": "32",
"linker": "riscv64-unknown-elf-ld", "linker": "rust-lld",
"linker-flavor": "ld", "linker-flavor": "ld.lld",
"pre-link-args": {
"ld": [
"-melf32lriscv"
]
},
"executables": true, "executables": true,
"panic-strategy": "abort", "panic-strategy": "abort",
"relocation-model": "static", "relocation-model": "static",

Loading…
Cancel
Save