mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-21 23:56:18 +04:00
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
This commit is contained in:
commit
205f90a264
3
.gitmodules
vendored
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
|
||||
|
||||
rust: nightly-2018-09-18
|
||||
rust: nightly
|
||||
|
||||
cache:
|
||||
cargo: true
|
||||
@ -19,7 +19,7 @@ env:
|
||||
|
||||
install:
|
||||
- if [ $ARCH = riscv32 ]; then
|
||||
export FILE="riscv64-unknown-elf-gcc-2018.07.0-x86_64-linux-ubuntu14";
|
||||
export FILE="riscv64-unknown-elf-gcc-20181030-x86_64-linux-ubuntu14";
|
||||
wget https://static.dev.sifive.com/dev-tools/$FILE.tar.gz;
|
||||
tar xf $FILE.tar.gz;
|
||||
export PATH=$PATH:$PWD/$FILE/bin;
|
||||
|
@ -37,7 +37,7 @@ cargo install cargo-xbuild bootimage
|
||||
```
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wangrunji0408/RustOS.git --recursive
|
||||
git clone https://github.com/wangrunji0408/RustOS.git
|
||||
cd RustOS/kernel
|
||||
rustup override set nightly-2018-09-18
|
||||
make run arch=riscv32|x86_64
|
||||
|
@ -69,14 +69,13 @@ impl<T: PageTable> CowExt<T> {
|
||||
** @retval none
|
||||
*/
|
||||
pub fn unmap_shared(&mut self, addr: VirtAddr) {
|
||||
{
|
||||
let entry = self.page_table.get_entry(addr);
|
||||
let frame = entry.target() / PAGE_SIZE;
|
||||
if entry.readonly_shared() {
|
||||
self.rc_map.read_decrease(&frame);
|
||||
} else if entry.writable_shared() {
|
||||
self.rc_map.write_decrease(&frame);
|
||||
}
|
||||
let entry = self.page_table.get_entry(addr)
|
||||
.expect("entry not exist");
|
||||
let frame = entry.target() / PAGE_SIZE;
|
||||
if entry.readonly_shared() {
|
||||
self.rc_map.read_decrease(&frame);
|
||||
} else if entry.writable_shared() {
|
||||
self.rc_map.write_decrease(&frame);
|
||||
}
|
||||
self.page_table.unmap(addr);
|
||||
}
|
||||
@ -91,20 +90,21 @@ impl<T: PageTable> CowExt<T> {
|
||||
** @retval bool whether copy-on-write happens.
|
||||
*/
|
||||
pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool {
|
||||
// below is not being used now(no shared pages)
|
||||
{
|
||||
let entry = self.page_table.get_entry(addr);
|
||||
if !entry.readonly_shared() && !entry.writable_shared() {
|
||||
return false;
|
||||
}
|
||||
let frame = entry.target() / PAGE_SIZE;
|
||||
if self.rc_map.read_count(&frame) == 0 && self.rc_map.write_count(&frame) == 1 {
|
||||
entry.clear_shared();
|
||||
entry.set_writable(true);
|
||||
entry.update();
|
||||
self.rc_map.write_decrease(&frame);
|
||||
return true;
|
||||
}
|
||||
let entry = self.page_table.get_entry(addr);
|
||||
if entry.is_none() {
|
||||
return false;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
if !entry.readonly_shared() && !entry.writable_shared() {
|
||||
return false;
|
||||
}
|
||||
let frame = entry.target() / PAGE_SIZE;
|
||||
if self.rc_map.read_count(&frame) == 0 && self.rc_map.write_count(&frame) == 1 {
|
||||
entry.clear_shared();
|
||||
entry.set_writable(true);
|
||||
entry.update();
|
||||
self.rc_map.write_decrease(&frame);
|
||||
return true;
|
||||
}
|
||||
use core::mem::uninitialized;
|
||||
let mut temp_data: [u8; PAGE_SIZE] = unsafe { uninitialized() };
|
||||
@ -251,7 +251,7 @@ pub mod test {
|
||||
pt.write(0x1000, 2);
|
||||
assert_eq!(pt.rc_map.read_count(&frame), 1);
|
||||
assert_eq!(pt.rc_map.write_count(&frame), 1);
|
||||
assert_ne!(pt.get_entry(0x1000).target(), target);
|
||||
assert_ne!(pt.get_entry(0x1000).unwrap().target(), target);
|
||||
assert_eq!(pt.read(0x1000), 2);
|
||||
assert_eq!(pt.read(0x2000), 1);
|
||||
assert_eq!(pt.read(0x3000), 1);
|
||||
@ -264,7 +264,7 @@ pub mod test {
|
||||
pt.write(0x2000, 3);
|
||||
assert_eq!(pt.rc_map.read_count(&frame), 0);
|
||||
assert_eq!(pt.rc_map.write_count(&frame), 0);
|
||||
assert_eq!(pt.get_entry(0x2000).target(), target,
|
||||
assert_eq!(pt.get_entry(0x2000).unwrap().target(), target,
|
||||
"The last write reference should not allocate new frame.");
|
||||
assert_eq!(pt.read(0x1000), 2);
|
||||
assert_eq!(pt.read(0x2000), 3);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![no_std]
|
||||
#![feature(alloc)]
|
||||
#![feature(nll)]
|
||||
|
||||
extern crate alloc;
|
||||
#[macro_use]
|
||||
|
@ -42,7 +42,7 @@ pub trait InactivePageTable {
|
||||
** @param f: impl FnOnce() the function to be executed
|
||||
** @retval none
|
||||
*/
|
||||
unsafe fn with(&self, f: impl FnOnce());
|
||||
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T;
|
||||
/*
|
||||
** @brief get the token of the inactive page table
|
||||
** @retval usize the token of the inactive page table
|
||||
@ -61,13 +61,6 @@ pub trait InactivePageTable {
|
||||
** @retval none
|
||||
*/
|
||||
fn dealloc_frame(target: PhysAddr);
|
||||
/*
|
||||
** @brief allocate a stack space
|
||||
** @retval Stack the stack allocated
|
||||
*/
|
||||
fn alloc_stack() -> Stack;
|
||||
|
||||
unsafe fn with_retval<T>(&self, f: impl FnOnce() -> T) -> T;
|
||||
}
|
||||
|
||||
/// a continuous memory space when the same attribute
|
||||
@ -183,7 +176,7 @@ impl MemoryArea {
|
||||
let entry = pt.map(addr,0);
|
||||
self.flags.apply(entry);
|
||||
}
|
||||
let entry = pt.get_entry(addr);
|
||||
let entry = pt.get_entry(addr).unwrap();
|
||||
entry.set_present(false);
|
||||
entry.update();
|
||||
|
||||
@ -201,13 +194,13 @@ impl MemoryArea {
|
||||
for page in Page::range_of(self.start_addr, self.end_addr) {
|
||||
let addr = page.start_address();
|
||||
if self.phys_start_addr.is_none() {
|
||||
if pt.get_entry(addr).present(){
|
||||
let target = pt.get_entry(addr).target();
|
||||
if pt.get_entry(addr).unwrap().present(){
|
||||
let target = pt.get_entry(addr).unwrap().target();
|
||||
T::dealloc_frame(target);
|
||||
}
|
||||
else{
|
||||
// set valid for pt.unmap function
|
||||
pt.get_entry(addr).set_present(true);
|
||||
pt.get_entry(addr).unwrap().set_present(true);
|
||||
}
|
||||
}
|
||||
pt.unmap(addr);
|
||||
@ -290,7 +283,6 @@ impl MemoryAttr {
|
||||
pub struct MemorySet<T: InactivePageTable> {
|
||||
areas: Vec<MemoryArea>,
|
||||
page_table: T,
|
||||
kstack: Stack,
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> MemorySet<T> {
|
||||
@ -302,23 +294,12 @@ impl<T: InactivePageTable> MemorySet<T> {
|
||||
MemorySet {
|
||||
areas: Vec::<MemoryArea>::new(),
|
||||
page_table: T::new(),
|
||||
kstack: T::alloc_stack(),
|
||||
}
|
||||
}
|
||||
/*
|
||||
** @brief create a memory set from raw space
|
||||
** Used for remap_kernel() where heap alloc is unavailable
|
||||
** @param slice: &mut [u8] the initial memory for the Vec in the struct
|
||||
** @param kstack: Stack kernel stack space
|
||||
** @retval MemorySet<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>();
|
||||
pub fn new_bare() -> Self {
|
||||
MemorySet {
|
||||
areas: Vec::<MemoryArea>::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap),
|
||||
areas: Vec::<MemoryArea>::new(),
|
||||
page_table: T::new_bare(),
|
||||
kstack,
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -372,13 +353,6 @@ impl<T: InactivePageTable> MemorySet<T> {
|
||||
self.page_table.token()
|
||||
}
|
||||
/*
|
||||
** @brief get the top of the associated kernel stack
|
||||
** @retval usize the top of the associated kernel stack
|
||||
*/
|
||||
pub fn kstack_top(&self) -> usize {
|
||||
self.kstack.top
|
||||
}
|
||||
/*
|
||||
** @brief clear the memory set
|
||||
** @retval none
|
||||
*/
|
||||
@ -394,7 +368,7 @@ impl<T: InactivePageTable> MemorySet<T> {
|
||||
|
||||
/*
|
||||
** @brief get the mutable reference for the inactive page table
|
||||
** @retval: &mut T the mutable reference of the inactive page table
|
||||
** @retval: &mut T the mutable reference of the inactive page table
|
||||
*/
|
||||
pub fn get_page_table_mut(&mut self) -> &mut T{
|
||||
&mut self.page_table
|
||||
@ -414,7 +388,6 @@ impl<T: InactivePageTable> Clone for MemorySet<T> {
|
||||
MemorySet {
|
||||
areas: self.areas.clone(),
|
||||
page_table,
|
||||
kstack: T::alloc_stack(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -433,10 +406,3 @@ impl<T: InactivePageTable> Debug for MemorySet<T> {
|
||||
.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);
|
||||
entry.present = false;
|
||||
}
|
||||
fn get_entry(&mut self, addr: VirtAddr) -> &mut <Self as PageTable>::Entry {
|
||||
&mut self.entries[addr / PAGE_SIZE]
|
||||
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::Entry> {
|
||||
Some(&mut self.entries[addr / PAGE_SIZE])
|
||||
}
|
||||
fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
|
||||
self._read(addr);
|
||||
@ -175,7 +175,7 @@ impl MockPageTable {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use alloc::arc::Arc;
|
||||
use alloc::sync::Arc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
#[test]
|
||||
@ -198,34 +198,35 @@ mod test {
|
||||
fn entry() {
|
||||
let mut pt = MockPageTable::new();
|
||||
pt.map(0x0, 0x1000);
|
||||
{
|
||||
let entry = pt.get_entry(0);
|
||||
assert!(entry.present());
|
||||
assert!(entry.writable());
|
||||
assert!(!entry.accessed());
|
||||
assert!(!entry.dirty());
|
||||
assert_eq!(entry.target(), 0x1000);
|
||||
}
|
||||
|
||||
let entry = pt.get_entry(0).unwrap();
|
||||
assert!(entry.present());
|
||||
assert!(entry.writable());
|
||||
assert!(!entry.accessed());
|
||||
assert!(!entry.dirty());
|
||||
assert_eq!(entry.target(), 0x1000);
|
||||
|
||||
pt.read(0x0);
|
||||
assert!(pt.get_entry(0).accessed());
|
||||
assert!(!pt.get_entry(0).dirty());
|
||||
let entry = pt.get_entry(0).unwrap();
|
||||
assert!(entry.accessed());
|
||||
assert!(!entry.dirty());
|
||||
|
||||
pt.get_entry(0).clear_accessed();
|
||||
assert!(!pt.get_entry(0).accessed());
|
||||
entry.clear_accessed();
|
||||
assert!(!entry.accessed());
|
||||
|
||||
pt.write(0x1, 1);
|
||||
assert!(pt.get_entry(0).accessed());
|
||||
assert!(pt.get_entry(0).dirty());
|
||||
let entry = pt.get_entry(0).unwrap();
|
||||
assert!(entry.accessed());
|
||||
assert!(entry.dirty());
|
||||
|
||||
pt.get_entry(0).clear_dirty();
|
||||
assert!(!pt.get_entry(0).dirty());
|
||||
entry.clear_dirty();
|
||||
assert!(!entry.dirty());
|
||||
|
||||
pt.get_entry(0).set_writable(false);
|
||||
assert!(!pt.get_entry(0).writable());
|
||||
entry.set_writable(false);
|
||||
assert!(!entry.writable());
|
||||
|
||||
pt.get_entry(0).set_present(false);
|
||||
assert!(!pt.get_entry(0).present());
|
||||
entry.set_present(false);
|
||||
assert!(!entry.present());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -31,8 +31,7 @@ pub trait PageTable {
|
||||
** @param addr: VirtAddr the virual address
|
||||
** @retval Entry the page table entry of the virual address
|
||||
*/
|
||||
fn get_entry(&mut self, addr: VirtAddr) -> &mut Self::Entry;
|
||||
|
||||
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::Entry>;
|
||||
// For testing with mock
|
||||
/*
|
||||
** @brief used for testing with mock
|
||||
|
@ -40,7 +40,7 @@ impl SwapManager for EnhancedClockSwapManager {
|
||||
// The reason may be `get_page_slice_mut()` contains unsafe operation,
|
||||
// which lead the compiler to do a wrong optimization.
|
||||
// let slice = page_table.get_page_slice_mut(addr);
|
||||
let entry = page_table.get_entry(addr);
|
||||
let entry = page_table.get_entry(addr).unwrap();
|
||||
// println!("{:#x} , {}, {}", addr, entry.accessed(), entry.dirty());
|
||||
|
||||
match (entry.accessed(), entry.dirty()) {
|
||||
|
@ -117,7 +117,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
|
||||
targetpt.token()
|
||||
};
|
||||
targetpt.with(||{
|
||||
let entry = page_table.get_entry(addr);
|
||||
let entry = page_table.get_entry(addr).unwrap();
|
||||
if entry.present() {
|
||||
let frame = Frame::new(pt as usize, addr, pttoken);
|
||||
swap_manager.push(frame);
|
||||
@ -149,7 +149,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
|
||||
info!("try to change pagetable");
|
||||
targetpt.with(||{
|
||||
let token = {
|
||||
let entry = page_table.get_entry(addr);
|
||||
let entry = page_table.get_entry(addr).unwrap();
|
||||
if !entry.swapped() {
|
||||
if entry.present(){
|
||||
// if the addr isn't indicating a swapped page, panic occured here
|
||||
@ -214,11 +214,12 @@ impl<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 ret = unsafe{
|
||||
let pt = &mut *(frame.get_page_table() as *mut T2);
|
||||
pt.with_retval(||{
|
||||
pt.with(|| {
|
||||
//use core::slice;
|
||||
//let data = unsafe { slice::from_raw_parts_mut((frame.virtaddr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) };
|
||||
let data = page_table.get_page_slice_mut(frame.get_virtaddr());
|
||||
let entry = page_table.get_entry(frame.get_virtaddr());
|
||||
let entry = page_table.get_entry(frame.get_virtaddr())
|
||||
.ok_or(SwapError::NotMapped)?;
|
||||
if entry.swapped() {
|
||||
return Err(SwapError::AlreadySwapped);
|
||||
}
|
||||
@ -245,18 +246,16 @@ impl<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> {
|
||||
info!("come in to swap in");
|
||||
let token = {
|
||||
let entry = self.page_table.get_entry(addr);
|
||||
if !entry.swapped() {
|
||||
return Err(SwapError::NotSwapped);
|
||||
}
|
||||
let token = entry.target() / PAGE_SIZE;
|
||||
entry.set_target(target);
|
||||
entry.set_swapped(false);
|
||||
entry.set_present(true);
|
||||
entry.update();
|
||||
token
|
||||
};
|
||||
let entry = self.page_table.get_entry(addr)
|
||||
.ok_or(SwapError::NotMapped)?;
|
||||
if !entry.swapped() {
|
||||
return Err(SwapError::NotSwapped);
|
||||
}
|
||||
let token = entry.target() / PAGE_SIZE;
|
||||
entry.set_target(target);
|
||||
entry.set_swapped(false);
|
||||
entry.set_present(true);
|
||||
entry.update();
|
||||
let data = self.page_table.get_page_slice_mut(addr);
|
||||
self.swapper.swap_in(token, data).map_err(|_| SwapError::IOError)?;
|
||||
let pttoken = unsafe{
|
||||
@ -272,7 +271,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
|
||||
** This function must be called whenever PageFault happens.
|
||||
** @param pt: *mut T2 the raw pointer for the target page's inactive page table (exactly the current page table)
|
||||
** @param addr: VirtAddr the virual address of the page fault
|
||||
** @param swapin: bool whether to set the page swappable if delayed allocate a frame for a page
|
||||
** @param swapin: bool whether to set the page swappable if delayed allocate a frame for a page
|
||||
** @param alloc_frame: impl FnOnce() -> PhysAddr
|
||||
** the page allocation function
|
||||
** that allocate a page and returns physics address
|
||||
@ -284,7 +283,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
|
||||
{
|
||||
info!("try handling delayed frame allocator");
|
||||
let need_alloc ={
|
||||
let entry = self.page_table.get_entry(addr);
|
||||
let entry = self.page_table.get_entry(addr).unwrap();
|
||||
//info!("got entry!");
|
||||
!entry.present() && !entry.swapped()
|
||||
};
|
||||
@ -293,7 +292,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
|
||||
info!("need_alloc!");
|
||||
let frame = alloc_frame();
|
||||
{
|
||||
let entry = self.page_table.get_entry(addr);
|
||||
let entry = self.page_table.get_entry(addr).unwrap();
|
||||
entry.set_target(frame);
|
||||
//let new_entry = self.page_table.map(addr, frame);
|
||||
entry.set_present(true);
|
||||
@ -311,8 +310,9 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
|
||||
info!("not need alloc!");
|
||||
}
|
||||
// now we didn't attach the cow so the present will be false when swapped(), to enable the cow some changes will be needed
|
||||
if !self.page_table.get_entry(addr).swapped() {
|
||||
return false;
|
||||
match self.page_table.get_entry(addr) {
|
||||
None => return false,
|
||||
Some(entry) => if !entry.swapped() { return false; },
|
||||
}
|
||||
// Allocate a frame, if failed, swap out a page
|
||||
let frame = alloc_frame();
|
||||
@ -324,6 +324,8 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
|
||||
pub enum SwapError {
|
||||
/// attempt to swap out a page that is already swapped out
|
||||
AlreadySwapped,
|
||||
///
|
||||
NotMapped,
|
||||
/// attempt to swap in a page that is already in the memory
|
||||
NotSwapped,
|
||||
/// there are no page to be swapped out
|
||||
|
@ -17,7 +17,7 @@ extern crate spin;
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
pub mod process_manager;
|
||||
mod process_manager;
|
||||
mod processor;
|
||||
pub mod scheduler;
|
||||
pub mod thread;
|
||||
|
@ -138,22 +138,20 @@ impl ProcessManager {
|
||||
/// Switch the status of a process.
|
||||
/// Insert/Remove it to/from scheduler if necessary.
|
||||
fn set_status(&self, pid: Pid, status: Status) {
|
||||
let mut scheduler = self.scheduler.lock();
|
||||
let mut proc_lock = self.procs[pid].lock();
|
||||
let mut proc = proc_lock.as_mut().expect("process not exist");
|
||||
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
|
||||
{ // limit the lifetime of scheduler
|
||||
let mut scheduler = self.scheduler.lock();
|
||||
match (&proc.status, &status) {
|
||||
(Status::Ready, Status::Ready) => return,
|
||||
(Status::Ready, _) => scheduler.remove(pid),
|
||||
(Status::Running(_), _) => {},
|
||||
(Status::Exited(_), _) => panic!("can not set status for a exited process"),
|
||||
(Status::Waiting(target), Status::Exited(_)) =>
|
||||
self.wait_queue[*target].lock().retain(|&i| i != pid),
|
||||
(Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)),
|
||||
(_, Status::Ready) => scheduler.insert(pid),
|
||||
_ => {}
|
||||
}
|
||||
match (&proc.status, &status) {
|
||||
(Status::Ready, Status::Ready) => return,
|
||||
(Status::Ready, _) => scheduler.remove(pid),
|
||||
(Status::Running(_), _) => {},
|
||||
(Status::Exited(_), _) => panic!("can not set status for a exited process"),
|
||||
(Status::Waiting(target), Status::Exited(_)) =>
|
||||
self.wait_queue[*target].lock().retain(|&i| i != pid),
|
||||
(Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)),
|
||||
(_, Status::Ready) => scheduler.insert(pid),
|
||||
_ => {}
|
||||
}
|
||||
match proc.status {
|
||||
Status::Running(_) => proc.status_after_stop = status,
|
||||
@ -238,8 +236,9 @@ impl ProcessManager {
|
||||
(self.exit_handler)(pid);
|
||||
}
|
||||
}
|
||||
fn new_vec_default<T: Default>(size: usize) -> Vec<T> {
|
||||
|
||||
fn new_vec_default<T: Default>(size: usize) -> Vec<T> {
|
||||
let mut vec = Vec::new();
|
||||
vec.resize_default(size);
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
@ -59,9 +59,9 @@ impl Processor {
|
||||
trace!("CPU{} begin running process {}", inner.id, proc.0);
|
||||
inner.proc = Some(proc);
|
||||
unsafe {
|
||||
inner.loop_context.switch_to(&mut *inner.proc.as_mut().expect("context should not be None").1);
|
||||
inner.loop_context.switch_to(&mut *inner.proc.as_mut().unwrap().1);
|
||||
}
|
||||
let (pid, context) = inner.proc.take().expect("proc should not be None");
|
||||
let (pid, context) = inner.proc.take().unwrap();
|
||||
trace!("CPU{} stop running process {}", inner.id, pid);
|
||||
inner.manager.stop(pid, context);
|
||||
}
|
||||
@ -70,7 +70,6 @@ impl Processor {
|
||||
/// Called by process running on this Processor.
|
||||
/// Yield and reschedule.
|
||||
pub fn yield_now(&self) {
|
||||
trace!("yield start");
|
||||
let inner = self.inner();
|
||||
unsafe {
|
||||
let flags = interrupt::disable_and_store();
|
||||
@ -80,10 +79,7 @@ impl Processor {
|
||||
}
|
||||
|
||||
pub fn pid(&self) -> Pid {
|
||||
if self.inner().proc.is_none() {
|
||||
return 0;
|
||||
}
|
||||
self.inner().proc.as_ref().expect("pid should not be None").0
|
||||
self.inner().proc.as_ref().unwrap().0
|
||||
}
|
||||
|
||||
pub fn context(&self) -> &Context {
|
||||
@ -101,4 +97,3 @@ impl Processor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
pub fn current() -> Thread {
|
||||
Thread {
|
||||
pid: processor().pid(),
|
||||
}
|
||||
Thread { pid: processor().pid() }
|
||||
}
|
||||
|
||||
/// Puts the current thread to sleep for the specified amount of time.
|
||||
@ -164,6 +162,13 @@ impl<T> JoinHandle<T> {
|
||||
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> {
|
||||
|
@ -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
|
72
docs/2_OSLab/g3/catfish-proposal.md
Normal file
72
docs/2_OSLab/g3/catfish-proposal.md
Normal file
@ -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周后)
|
||||
|
||||
以上均基于只有本人一人工作的前提,若有其他人协助/加入则根据实际情况而定。
|
BIN
docs/2_OSLab/g3/catfish-proposal.pptx
Normal file
BIN
docs/2_OSLab/g3/catfish-proposal.pptx
Normal file
Binary file not shown.
48
docs/2_OSLab/g5/exp2.md
Normal file
48
docs/2_OSLab/g5/exp2.md
Normal file
@ -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):文件系统相关
|
||||
|
106
docs/2_OSLab/g5/exp3.md
Normal file
106
docs/2_OSLab/g5/exp3.md
Normal file
@ -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的用户程序,方便进行性能对比
|
||||
|
||||
|
||||
|
177
kernel/Cargo.lock
generated
177
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]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bbl"
|
||||
@ -31,12 +52,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.3.4"
|
||||
source = "git+https://github.com/wangrunji0408/bootloader#dd5723c3d7d50856073a5003e0a355ea0fc3d46c"
|
||||
dependencies = [
|
||||
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
|
||||
"fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -47,7 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -82,11 +104,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -99,17 +120,22 @@ name = "linked_list_allocator"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "once"
|
||||
version = "0.3.3"
|
||||
@ -135,7 +161,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -148,24 +184,47 @@ name = "remove_dir_all"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "riscv"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/riscv-and-rust-and-decaf/riscv#f358204af01f2374ab6ed6ea059f724cd5f2fe6f"
|
||||
dependencies = [
|
||||
"bare-metal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "simple-filesystem"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/wangrunji0408/SimpleFileSystem-Rust#ca10d11264c85932e95e6c7c29e8b10c91ae0720"
|
||||
source = "git+https://github.com/wangrunji0408/SimpleFileSystem-Rust?branch=multi-thread#24a51faff266744d83c1ef60328b28906d2b525c"
|
||||
dependencies = [
|
||||
"bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)",
|
||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -180,7 +239,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.4.9"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -203,32 +262,34 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucore"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
|
||||
"bbl 0.1.0",
|
||||
"bit-allocator 0.1.0",
|
||||
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)",
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"riscv 0.3.0",
|
||||
"simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)",
|
||||
"spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)",
|
||||
"simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust?branch=multi-thread)",
|
||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ucore-memory 0.1.0",
|
||||
"ucore-process 0.1.0",
|
||||
"volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -236,15 +297,15 @@ dependencies = [
|
||||
name = "ucore-memory"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucore-process"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -262,11 +323,6 @@ name = "ux"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.1.0"
|
||||
@ -274,7 +330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.5"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -292,10 +348,32 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "x86_64"
|
||||
version = "0.2.11"
|
||||
name = "x86"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x86_64"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x86_64"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -317,41 +395,50 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum bare-metal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bdcf9294ed648c7cd29b11db06ea244005aeef50ae8f605b1a3af2940bf8f92"
|
||||
"checksum apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)" = "<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_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1721ced9efc102309bc218c7934d642f60567858faf8d5dd90c0cc6722d97b9"
|
||||
"checksum bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)" = "<none>"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
|
||||
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
||||
"checksum linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "655d57c71827fe0891ce72231b6aa5e14033dae3f604609e6a6f807267c1678d"
|
||||
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73"
|
||||
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
|
||||
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d"
|
||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)" = "<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 spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4"
|
||||
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
|
||||
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
|
||||
"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41"
|
||||
"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
|
||||
"checksum volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37c5d76c0f40ba4f8ac10ec4717d4e98ce3e58c5607eea36e9464226fc5e0a95"
|
||||
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "466c2002e38edde7ebbaae6656793d4f71596634971c7e8cbf7afa4827968445"
|
||||
"checksum x86 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "841e1ca5a87068718a2a26f2473c6f93cf3b8119f9778fa0ae4b39b664d9e66a"
|
||||
"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4"
|
||||
"checksum x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b14609bad1c2c6a41113a1054f94394154e99bcb4b24cd7051109113c656c5a9"
|
||||
"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58"
|
||||
"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5"
|
||||
|
@ -4,13 +4,11 @@ version = "0.1.0"
|
||||
authors = ["Runji Wang <wangrunji0408@163.com>"]
|
||||
|
||||
[features]
|
||||
use_apic = []
|
||||
link_user_program = []
|
||||
no_bbl = []
|
||||
|
||||
[profile.dev]
|
||||
# MUST >= 1 : Enable RVO to avoid stack overflow
|
||||
# MUST <= 1 : Avoid double fault at -O2 T_T
|
||||
opt-level = 1
|
||||
|
||||
[profile.release]
|
||||
@ -18,27 +16,31 @@ debug = true
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
spin = "0.4.9"
|
||||
once = "0.3.3"
|
||||
spin = "0.4"
|
||||
once = "0.3"
|
||||
xmas-elf = "0.6"
|
||||
bitflags = "1.0"
|
||||
bit_field = "0.9.0"
|
||||
volatile = "0.1.0"
|
||||
bit_field = "0.9"
|
||||
volatile = "0.1"
|
||||
linked_list_allocator = "0.6"
|
||||
lazy_static = { version = "1.0.0", features = ["spin_no_std"] }
|
||||
lazy_static = { version = "1.2", features = ["spin_no_std"] }
|
||||
bit-allocator = { path = "../crate/bit-allocator" }
|
||||
ucore-memory = { path = "../crate/memory" }
|
||||
ucore-process = { path = "../crate/process" }
|
||||
simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" }
|
||||
simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust", branch = "multi-thread" }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
bootloader = "0.3"
|
||||
x86_64 = "0.2.11"
|
||||
bootloader = { git = "https://github.com/wangrunji0408/bootloader" }
|
||||
apic = { git = "https://github.com/wangrunji0408/APIC-Rust" }
|
||||
#bootloader = { path = "../crate/bootloader" }
|
||||
#apic = { path = "../crate/apic" }
|
||||
x86_64 = "0.3"
|
||||
raw-cpuid = "6.0"
|
||||
redox_syscall = "0.1"
|
||||
uart_16550 = "0.1"
|
||||
|
||||
[target.'cfg(target_arch = "riscv32")'.dependencies]
|
||||
riscv = { path = "../crate/riscv" }
|
||||
riscv = { git = "https://github.com/riscv-and-rust-and-decaf/riscv" }
|
||||
bbl = { path = "../crate/bbl" }
|
||||
|
||||
[package.metadata.bootimage]
|
||||
|
@ -12,11 +12,13 @@
|
||||
# d = int | in_asm | ... QEMU debug info
|
||||
# mode = debug | release
|
||||
# LOG = off | error | warn | info | debug | trace
|
||||
# smp SMP core number
|
||||
# board Only available on riscv32, build without bbl, run on board
|
||||
|
||||
arch ?= riscv32
|
||||
mode ?= debug
|
||||
LOG ?= debug
|
||||
smp ?= 4
|
||||
|
||||
target := $(arch)-blog_os
|
||||
kernel := target/$(target)/$(mode)/ucore
|
||||
@ -31,12 +33,16 @@ ifeq ($(arch), x86_64)
|
||||
qemu_opts := \
|
||||
-drive format=raw,file=$(bootimage) \
|
||||
-drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \
|
||||
-smp 4 \
|
||||
-smp cores=$(smp) \
|
||||
-serial mon:stdio \
|
||||
-device isa-debug-exit
|
||||
endif
|
||||
ifeq ($(arch), riscv32)
|
||||
qemu_opts := -machine virt -kernel $(bin) -nographic
|
||||
qemu_opts := \
|
||||
-machine virt \
|
||||
-kernel $(bin) \
|
||||
-nographic \
|
||||
-smp cores=$(smp)
|
||||
endif
|
||||
|
||||
ifdef board
|
||||
@ -83,6 +89,7 @@ all: $(kernel)
|
||||
|
||||
clean:
|
||||
@cargo clean
|
||||
@rm -rf ../riscv-pk/build
|
||||
|
||||
doc:
|
||||
@cargo rustdoc -- --document-private-items
|
||||
@ -104,9 +111,12 @@ endif
|
||||
asm:
|
||||
@$(objdump) -dS $(kernel) | less
|
||||
|
||||
elf-h:
|
||||
header:
|
||||
@$(objdump) -h $(kernel)
|
||||
|
||||
sym:
|
||||
@$(objdump) -t $(kernel) | less
|
||||
|
||||
$(bin): kernel
|
||||
ifdef board
|
||||
@cp $(kernel) $@
|
||||
@ -128,7 +138,10 @@ kernel:
|
||||
ifeq ($(arch), x86_64)
|
||||
@bootimage build $(build_args)
|
||||
else
|
||||
@cargo xbuild $(build_args)
|
||||
@-patch -p0 -N -b \
|
||||
$(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \
|
||||
src/arch/riscv32/atomic.patch
|
||||
@CC=$(cc) cargo xbuild $(build_args)
|
||||
endif
|
||||
|
||||
# make user.o from binary files
|
||||
|
@ -12,6 +12,13 @@ fn main() {
|
||||
// .compile("cobj");
|
||||
gen_vector_asm().unwrap();
|
||||
}
|
||||
if std::env::var("TARGET").unwrap().find("riscv32").is_some() {
|
||||
cc::Build::new()
|
||||
.file("src/arch/riscv32/compiler_rt.c")
|
||||
.flag("-march=rv32ia")
|
||||
.flag("-mabi=ilp32")
|
||||
.compile("atomic_rt");
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_vector_asm() -> Result<()> {
|
||||
|
@ -9,12 +9,11 @@
|
||||
"cpu": "generic-rv32",
|
||||
"features": "",
|
||||
"max-atomic-width": "32",
|
||||
"linker": "riscv64-unknown-elf-ld",
|
||||
"linker-flavor": "ld",
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld",
|
||||
"pre-link-args": {
|
||||
"ld": [
|
||||
"-Tsrc/arch/riscv32/boot/linker.ld",
|
||||
"-melf32lriscv"
|
||||
"ld.lld": [
|
||||
"-Tsrc/arch/riscv32/boot/linker.ld"
|
||||
]
|
||||
},
|
||||
"executables": true,
|
||||
|
57
kernel/src/arch/riscv32/atomic.patch
Normal file
57
kernel/src/arch/riscv32/atomic.patch
Normal file
@ -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`.
|
||||
///
|
38
kernel/src/arch/riscv32/compiler_rt.c
Normal file
38
kernel/src/arch/riscv32/compiler_rt.c
Normal file
@ -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() {
|
||||
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 KERNEL_OFFSET: usize = 0;
|
||||
pub const KERNEL_P2_INDEX: usize = 0x8000_0000 >> 22;
|
||||
pub const KERNEL_HEAP_OFFSET: usize = 0x8020_0000; //deprecated now
|
||||
//pub const KERNEL_HEAP_SIZE: usize = 0x0020_0000;
|
||||
pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000;
|
||||
pub const MEMORY_OFFSET: usize = 0x8000_0000;
|
||||
//pub const MEMORY_END: usize = 0x8080_0000; //for thinpad not enough now
|
||||
|
@ -26,7 +26,7 @@ impl TrapFrame {
|
||||
use core::mem::zeroed;
|
||||
let mut tf: Self = unsafe { zeroed() };
|
||||
tf.x[10] = arg; // a0
|
||||
tf.x[2] = sp;
|
||||
tf.x[2] = sp;
|
||||
tf.sepc = entry as usize;
|
||||
tf.sstatus = sstatus::read();
|
||||
// Supervisor Previous Interrupt Enable
|
||||
@ -58,10 +58,6 @@ impl TrapFrame {
|
||||
tf.sstatus.set_spp(sstatus::SPP::User);
|
||||
tf
|
||||
}
|
||||
|
||||
pub fn is_user(&self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
use core::fmt::{Debug, Formatter, Error};
|
||||
@ -87,7 +83,8 @@ impl Debug for TrapFrame {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
/// kernel stack contents for a new thread
|
||||
|
||||
/// kernel stack contents for a new thread
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct InitStack {
|
||||
@ -125,7 +122,7 @@ struct ContextData {
|
||||
|
||||
impl ContextData {
|
||||
fn new(satp: usize) -> Self {
|
||||
// satp(asid) just like cr3, save the physical address for Page directory?
|
||||
// satp(asid) just like cr3, save the physical address for Page directory?
|
||||
ContextData { ra: __trapret as usize, satp, ..ContextData::default() }
|
||||
}
|
||||
}
|
||||
@ -242,9 +239,9 @@ impl Context {
|
||||
* TrapFrame: the trapframe of the forked process(thread)
|
||||
* kstack_top: kernel stack top
|
||||
* cr3: cr3 register, save the physical address of Page directory
|
||||
* @brief:
|
||||
* @brief:
|
||||
* fork and generate a new process(thread) Context according to the TrapFrame and save it's address at kernel stack top - 1
|
||||
* @retval:
|
||||
* @retval:
|
||||
* a Context struct with the pointer to the kernel stack top - 1 as its only element
|
||||
*/
|
||||
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self {
|
||||
@ -258,4 +255,9 @@ impl Context {
|
||||
},
|
||||
}.push_at(kstack_top)
|
||||
}
|
||||
/// Called at a new user context
|
||||
/// To get the init TrapFrame in sys_exec
|
||||
pub unsafe fn get_init_tf(&self) -> TrapFrame {
|
||||
(*(self.0 as *const InitStack)).tf.clone()
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ use memory::MemorySet;
|
||||
mod context;
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* initialize the interrupt status
|
||||
*/
|
||||
pub fn init() {
|
||||
@ -29,7 +29,7 @@ pub fn init() {
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* enable interrupt
|
||||
*/
|
||||
#[inline(always)]
|
||||
@ -38,7 +38,7 @@ pub unsafe fn enable() {
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* store and disable interrupt
|
||||
* @retbal:
|
||||
* a usize value store the origin sie
|
||||
@ -53,7 +53,7 @@ pub unsafe fn disable_and_store() -> usize {
|
||||
/*
|
||||
* @param:
|
||||
* flags: input flag
|
||||
* @brief:
|
||||
* @brief:
|
||||
* enable interrupt if flags != 0
|
||||
*/
|
||||
#[inline(always)]
|
||||
@ -66,15 +66,16 @@ pub unsafe fn restore(flags: usize) {
|
||||
/*
|
||||
* @param:
|
||||
* TrapFrame: the trapFrame of the Interrupt/Exception/Trap to be processed
|
||||
* @brief:
|
||||
* @brief:
|
||||
* process the Interrupt/Exception/Trap
|
||||
*/
|
||||
#[no_mangle]
|
||||
pub extern fn rust_trap(tf: &mut TrapFrame) {
|
||||
use super::riscv::register::scause::{Trap, Interrupt as I, Exception as E};
|
||||
trace!("Interrupt: {:?}", tf.scause.cause());
|
||||
trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause());
|
||||
match tf.scause.cause() {
|
||||
Trap::Interrupt(I::SupervisorExternal) => serial(),
|
||||
Trap::Interrupt(I::SupervisorSoft) => ipi(),
|
||||
Trap::Interrupt(I::SupervisorTimer) => timer(),
|
||||
Trap::Exception(E::IllegalInstruction) => illegal_inst(tf),
|
||||
Trap::Exception(E::UserEnvCall) => syscall(tf),
|
||||
@ -94,8 +95,9 @@ fn ipi() {
|
||||
debug!("IPI");
|
||||
super::bbl::sbi::clear_ipi();
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* process timer interrupt
|
||||
*/
|
||||
fn timer() {
|
||||
@ -106,7 +108,7 @@ fn timer() {
|
||||
/*
|
||||
* @param:
|
||||
* TrapFrame: the Trapframe for the syscall
|
||||
* @brief:
|
||||
* @brief:
|
||||
* process syscall
|
||||
*/
|
||||
fn syscall(tf: &mut TrapFrame) {
|
||||
@ -118,7 +120,7 @@ fn syscall(tf: &mut TrapFrame) {
|
||||
/*
|
||||
* @param:
|
||||
* TrapFrame: the Trapframe for the illegal inst exception
|
||||
* @brief:
|
||||
* @brief:
|
||||
* process IllegalInstruction exception
|
||||
*/
|
||||
fn illegal_inst(tf: &mut TrapFrame) {
|
||||
@ -128,9 +130,9 @@ fn illegal_inst(tf: &mut TrapFrame) {
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* TrapFrame: the Trapframe for the page fault exception
|
||||
* @brief:
|
||||
* @brief:
|
||||
* process page fault exception
|
||||
*/
|
||||
fn page_fault(tf: &mut TrapFrame) {
|
||||
@ -149,9 +151,9 @@ fn page_fault(tf: &mut TrapFrame) {
|
||||
/*
|
||||
* @param:
|
||||
* TrapFrame: the Trapframe for the illegal inst exception
|
||||
* @brief:
|
||||
* @brief:
|
||||
* emulate the multiply and divide operation (if not this kind of operation return false)
|
||||
* @retval:
|
||||
* @retval:
|
||||
* a bool indicates whether emulate the multiply and divide operation successfully
|
||||
*/
|
||||
fn emulate_mul_div(tf: &mut TrapFrame) -> bool {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use core::slice;
|
||||
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack};
|
||||
use core::{slice, mem};
|
||||
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet};
|
||||
use super::riscv::{addr::*, register::sstatus};
|
||||
use ucore_memory::PAGE_SIZE;
|
||||
|
||||
@ -13,17 +13,24 @@ pub fn init() {
|
||||
static PAGE_TABLE_ROOT: PageData = PageData([0; PAGE_SIZE]);
|
||||
|
||||
unsafe { sstatus::set_sum(); } // Allow user memory access
|
||||
let frame = Frame::of_addr(PhysAddr::new(&PAGE_TABLE_ROOT as *const _ as u32));
|
||||
let frame = Frame::of_addr(PhysAddr::new(&PAGE_TABLE_ROOT as *const _ as u32));
|
||||
super::paging::setup_page_table(frame); // set up page table
|
||||
// initialize heap and Frame allocator
|
||||
init_frame_allocator();
|
||||
init_heap();
|
||||
// remap the kernel use 4K page
|
||||
remap_the_kernel();
|
||||
init_heap();
|
||||
}
|
||||
|
||||
pub fn init_other() {
|
||||
unsafe {
|
||||
sstatus::set_sum(); // Allow user memory access
|
||||
asm!("csrw 0x180, $0; sfence.vma" :: "r"(SATP) :: "volatile");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* Init frame allocator, here use a BitAlloc implemented by segment tree.
|
||||
*/
|
||||
fn init_frame_allocator() {
|
||||
@ -32,18 +39,14 @@ fn init_frame_allocator() {
|
||||
use consts::{MEMORY_OFFSET, MEMORY_END};
|
||||
|
||||
let mut ba = FRAME_ALLOCATOR.lock();
|
||||
//use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
|
||||
// keep memory for the kernel heap and set other physical memory available in BitAlloc
|
||||
//ba.insert(to_range(KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MEMORY_END));
|
||||
// end here is the end entry of the kernel
|
||||
ba.insert(to_range(end as usize + PAGE_SIZE, MEMORY_END));
|
||||
info!("FrameAllocator init end");
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* start: start address
|
||||
* start: start address
|
||||
* end: end address
|
||||
* @brief:
|
||||
* @brief:
|
||||
* transform the memory address to the page number
|
||||
* @retval:
|
||||
* the page number range from start address to end address
|
||||
@ -56,29 +59,27 @@ fn init_frame_allocator() {
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* remmap the kernel memory address with 4K page recorded in p1 page table
|
||||
*/
|
||||
fn remap_the_kernel() {
|
||||
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
|
||||
// set up kernel stack
|
||||
let kstack = Stack {
|
||||
top: bootstacktop as usize,
|
||||
bottom: bootstack as usize + PAGE_SIZE,
|
||||
};
|
||||
static mut SPACE: [u8; 0x1000] = [0; 0x1000];
|
||||
let mut ms = unsafe { MemorySet::new_from_raw_space(&mut SPACE, kstack) };
|
||||
let mut ms = MemorySet::new_bare();
|
||||
#[cfg(feature = "no_bbl")]
|
||||
ms.push(MemoryArea::new_identity(0x10000000, 0x10000008, MemoryAttr::default(), "serial"));
|
||||
ms.push(MemoryArea::new_identity(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), "text"));
|
||||
ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data"));
|
||||
ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata"));
|
||||
ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss"));
|
||||
unsafe { ms.activate(); }
|
||||
use core::mem::forget;
|
||||
forget(ms);
|
||||
unsafe { SATP = ms.token(); }
|
||||
mem::forget(ms);
|
||||
info!("kernel remap end");
|
||||
}
|
||||
|
||||
// First core stores its SATP here.
|
||||
// Other cores load it later.
|
||||
static mut SATP: usize = 0;
|
||||
|
||||
// Symbols provided by linker script
|
||||
extern {
|
||||
fn stext();
|
||||
|
@ -27,7 +27,7 @@ pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
|
||||
timer::init();
|
||||
|
||||
::process::init();
|
||||
::thread::spawn(::fs::shell);
|
||||
::thread::spawn(::shell::run_user_shell);
|
||||
|
||||
unsafe { cpu::start_others(hart_mask); }
|
||||
::kmain();
|
||||
@ -35,6 +35,7 @@ pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
|
||||
|
||||
fn others_main() -> ! {
|
||||
interrupt::init();
|
||||
memory::init_other();
|
||||
timer::init();
|
||||
::kmain();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use consts::{KERNEL_P2_INDEX, RECURSIVE_INDEX};
|
||||
// Depends on kernel
|
||||
use memory::{active_table, alloc_frame, alloc_stack, dealloc_frame};
|
||||
use memory::{active_table, alloc_frame, dealloc_frame};
|
||||
use super::riscv::addr::*;
|
||||
use super::riscv::asm::{sfence_vma, sfence_vma_all};
|
||||
use super::riscv::paging::{Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable};
|
||||
@ -14,7 +14,7 @@ use ucore_memory::paging::*;
|
||||
* @param:
|
||||
* Frame: page table root frame
|
||||
* @brief:
|
||||
* setup page table in the frame
|
||||
* setup page table in the frame
|
||||
*/
|
||||
// need 1 page
|
||||
pub fn setup_page_table(frame: Frame) {
|
||||
@ -25,7 +25,7 @@ pub fn setup_page_table(frame: Frame) {
|
||||
// Set kernel identity map
|
||||
// 0x10000000 ~ 1K area
|
||||
p2.map_identity(0x40, EF::VALID | EF::READABLE | EF::WRITABLE);
|
||||
// 0x80000000 ~ 12M area for
|
||||
// 0x80000000 ~ 12M area for
|
||||
p2.map_identity(KERNEL_P2_INDEX, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE);
|
||||
p2.map_identity(KERNEL_P2_INDEX + 1, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE);
|
||||
p2.map_identity(KERNEL_P2_INDEX + 2, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE);
|
||||
@ -44,12 +44,12 @@ impl PageTable for ActivePageTable {
|
||||
type Entry = PageEntry;
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* addr: the virtual addr to be matched
|
||||
* target: the physical addr to be matched with addr
|
||||
* @brief:
|
||||
* @brief:
|
||||
* map the virtual address 'addr' to the physical address 'target' in pagetable.
|
||||
* @retval:
|
||||
* @retval:
|
||||
* the matched PageEntry
|
||||
*/
|
||||
fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry {
|
||||
@ -62,13 +62,13 @@ impl PageTable for ActivePageTable {
|
||||
// we may need frame allocator to alloc frame for new page table(first/second)
|
||||
self.0.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
|
||||
.unwrap().flush();
|
||||
self.get_entry(addr)
|
||||
self.get_entry(addr).unwrap()
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* addr: virtual address of which the mapped physical frame should be unmapped
|
||||
* @bridf:
|
||||
* @bridf:
|
||||
^ unmap the virtual addresses' mapped physical frame
|
||||
*/
|
||||
fn unmap(&mut self, addr: usize) {
|
||||
@ -78,28 +78,31 @@ impl PageTable for ActivePageTable {
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* addr:input virtual address
|
||||
* @brief:
|
||||
* @brief:
|
||||
* get the pageEntry of 'addr'
|
||||
* @retval:
|
||||
* @retval:
|
||||
* a mutable PageEntry reference of 'addr'
|
||||
*/
|
||||
fn get_entry(&mut self, addr: usize) -> &mut PageEntry {
|
||||
fn get_entry(&mut self, addr: usize) -> Option<&mut PageEntry> {
|
||||
if unsafe { !(*ROOT_PAGE_TABLE)[addr >> 22].flags().contains(EF::VALID) } {
|
||||
return None;
|
||||
}
|
||||
let page = Page::of_addr(VirtAddr::new(addr));
|
||||
// ???
|
||||
let _ = self.0.translate_page(page);
|
||||
let entry_addr = ((addr >> 10) & ((1 << 22) - 4)) | (RECURSIVE_INDEX << 22);
|
||||
unsafe { &mut *(entry_addr as *mut PageEntry) }
|
||||
unsafe { Some(&mut *(entry_addr as *mut PageEntry)) }
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* addr:the input (virutal) address
|
||||
* @brief:
|
||||
* get the addr's memory page slice
|
||||
* @retval:
|
||||
* a mutable reference slice of 'addr' 's page
|
||||
* @brief:
|
||||
* get the addr's memory page slice
|
||||
* @retval:
|
||||
* a mutable reference slice of 'addr' 's page
|
||||
*/
|
||||
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: usize) -> &'b mut [u8] {
|
||||
use core::slice;
|
||||
@ -107,11 +110,11 @@ impl PageTable for ActivePageTable {
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* addr: virtual address
|
||||
* @brief:
|
||||
* @brief:
|
||||
* get the address's content
|
||||
* @retval:
|
||||
* @retval:
|
||||
* the content(u8) of 'addr'
|
||||
*/
|
||||
fn read(&mut self, addr: usize) -> u8 {
|
||||
@ -119,9 +122,9 @@ impl PageTable for ActivePageTable {
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* addr: virtual address
|
||||
* @brief:
|
||||
* @brief:
|
||||
* write the address's content
|
||||
*/
|
||||
fn write(&mut self, addr: usize, data: u8) {
|
||||
@ -142,7 +145,7 @@ impl ActivePageTable {
|
||||
* @param:
|
||||
* frame: the target physical frame which will be temporarily mapped
|
||||
* f: the function you would like to apply for once
|
||||
* @brief:
|
||||
* @brief:
|
||||
* do something on the target physical frame?
|
||||
*/
|
||||
fn with_temporary_map(&mut self, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut RvPageTable)) {
|
||||
@ -213,9 +216,9 @@ impl InactivePageTable for InactivePageTable0 {
|
||||
type Active = ActivePageTable;
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* get a new pagetable (for a new process or thread)
|
||||
* @retbal:
|
||||
* @retbal:
|
||||
* the new pagetable
|
||||
*/
|
||||
fn new() -> Self {
|
||||
@ -225,9 +228,9 @@ impl InactivePageTable for InactivePageTable0 {
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* allocate a new frame and then self-mapping it and regard it as the inactivepagetale
|
||||
* retval:
|
||||
* retval:
|
||||
* the inactive page table
|
||||
*/
|
||||
fn new_bare() -> Self {
|
||||
@ -241,10 +244,10 @@ impl InactivePageTable for InactivePageTable0 {
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* f: a function to do something with the temporary modified activate page table
|
||||
* @brief:
|
||||
* temporarily map the inactive pagetable as an active p2page and apply f on the temporary modified active page table
|
||||
* @brief:
|
||||
* temporarily map the inactive pagetable as an active p2page and apply f on the temporary modified active page table
|
||||
*/
|
||||
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) {
|
||||
active_table().with_temporary_map(&satp::read().frame(), |active_table, p2_table: &mut RvPageTable| {
|
||||
@ -277,28 +280,6 @@ impl InactivePageTable for InactivePageTable0 {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* f: the function to run when temporarily activate self as current page table
|
||||
* @brief:
|
||||
* Temporarily activate self and run the process
|
||||
*/
|
||||
unsafe fn with(&self, f: impl FnOnce()) {
|
||||
let old_frame = satp::read().frame();
|
||||
let new_frame = self.p2_frame.clone();
|
||||
debug!("switch table {:x?} -> {:x?}", old_frame, new_frame);
|
||||
if old_frame != new_frame {
|
||||
satp::set(satp::Mode::Sv32, 0, new_frame);
|
||||
sfence_vma_all();
|
||||
}
|
||||
f();
|
||||
debug!("switch table {:x?} -> {:x?}", new_frame, old_frame);
|
||||
if old_frame != new_frame {
|
||||
satp::set(satp::Mode::Sv32, 0, old_frame);
|
||||
sfence_vma_all();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* f: the function to run when temporarily activate self as current page table
|
||||
@ -307,7 +288,7 @@ impl InactivePageTable for InactivePageTable0 {
|
||||
* @retval:
|
||||
* the return value of f
|
||||
*/
|
||||
unsafe fn with_retval<T>(&self, f: impl FnOnce() -> T) -> T{
|
||||
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
|
||||
let old_frame = satp::read().frame();
|
||||
let new_frame = self.p2_frame.clone();
|
||||
debug!("switch table {:x?} -> {:x?}", old_frame, new_frame);
|
||||
@ -341,16 +322,12 @@ impl InactivePageTable for InactivePageTable0 {
|
||||
fn dealloc_frame(target: usize) {
|
||||
dealloc_frame(target)
|
||||
}
|
||||
|
||||
fn alloc_stack() -> Stack {
|
||||
alloc_stack()
|
||||
}
|
||||
}
|
||||
|
||||
impl InactivePageTable0 {
|
||||
/*
|
||||
* @brief:
|
||||
* map the kernel code memory address (p2 page table) in the new inactive page table according the current active page table
|
||||
* @brief:
|
||||
* map the kernel code memory address (p2 page table) in the new inactive page table according the current active page table
|
||||
*/
|
||||
fn map_kernel(&mut self) {
|
||||
let table = unsafe { &mut *ROOT_PAGE_TABLE };
|
||||
|
@ -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!
|
||||
//! Port from ucore C code.
|
||||
use spin::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DISK0: LockedIde = LockedIde(Mutex::new(IDE::new(0)));
|
||||
pub static ref DISK1: LockedIde = LockedIde(Mutex::new(IDE::new(1)));
|
||||
}
|
||||
pub const BLOCK_SIZE: usize = 512;
|
||||
|
||||
pub struct LockedIde(pub Mutex<IDE>);
|
||||
|
||||
pub struct IDE {
|
||||
num: u8,
|
||||
/// I/O Base
|
||||
|
@ -29,7 +29,6 @@ impl SerialRead for SerialPort {
|
||||
let ports = self as *mut _ as *mut [Pio<u8>; 6];
|
||||
let line_sts = &(*ports)[5];
|
||||
let data = &(*ports)[0];
|
||||
while line_sts.read() & 1 != 1 {}
|
||||
data.read()
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
|
||||
T_PGFLT => page_fault(tf),
|
||||
T_IRQ0...63 => {
|
||||
let irq = tf.trap_num as u8 - T_IRQ0;
|
||||
super::ack(irq); // must ack before switching
|
||||
match irq {
|
||||
IRQ_TIMER => ::trap::timer(),
|
||||
IRQ_KBD => keyboard(),
|
||||
@ -88,7 +89,6 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
|
||||
IRQ_IDE => ide(),
|
||||
_ => panic!("Invalid IRQ number: {}", irq),
|
||||
}
|
||||
super::ack(irq);
|
||||
}
|
||||
T_SWITCH_TOK => to_kernel(tf),
|
||||
T_SWITCH_TOU => to_user(tf),
|
||||
@ -131,6 +131,7 @@ fn keyboard() {
|
||||
fn com1() {
|
||||
use arch::driver::serial::*;
|
||||
trace!("\nInterupt: COM1");
|
||||
::trap::serial(COM1.lock().receive() as char);
|
||||
}
|
||||
|
||||
fn com2() {
|
||||
|
@ -183,4 +183,9 @@ impl Context {
|
||||
},
|
||||
}.push_at(kstack_top)
|
||||
}
|
||||
/// Called at a new user context
|
||||
/// To get the init TrapFrame in sys_exec
|
||||
pub unsafe fn get_init_tf(&self) -> TrapFrame {
|
||||
(*(self.0 as *const InitStack)).tf.clone()
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
|
||||
driver::init();
|
||||
|
||||
::process::init();
|
||||
::thread::spawn(::fs::shell);
|
||||
::thread::spawn(::shell::run_user_shell);
|
||||
|
||||
AP_CAN_INIT.store(true, Ordering::Relaxed);
|
||||
|
||||
|
@ -95,6 +95,9 @@ impl ActivePageTable {
|
||||
// Unmap the page
|
||||
self.unmap(0xcafebabe);
|
||||
}
|
||||
pub fn token() -> usize {
|
||||
Cr3::read().0.start_address().as_u64() as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl Entry for PageEntry {
|
||||
@ -206,18 +209,19 @@ impl InactivePageTable for InactivePageTable0 {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn with(&self, f: impl FnOnce()) {
|
||||
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
|
||||
let old_frame = Cr3::read().0;
|
||||
let new_frame = self.p4_frame.clone();
|
||||
debug!("switch table {:?} -> {:?}", old_frame, new_frame);
|
||||
if old_frame != new_frame {
|
||||
Cr3::write(new_frame, Cr3Flags::empty());
|
||||
}
|
||||
f();
|
||||
let ret = f();
|
||||
debug!("switch table {:?} -> {:?}", new_frame, old_frame);
|
||||
if old_frame != new_frame {
|
||||
Cr3::write(old_frame, Cr3Flags::empty());
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn token(&self) -> usize {
|
||||
|
@ -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 const MAX_CPU_NUM: usize = 8;
|
||||
pub const MAX_PROCESS_NUM: usize = 48;
|
||||
pub const MAX_PROCESS_NUM: usize = 128;
|
||||
|
173
kernel/src/fs.rs
173
kernel/src/fs.rs
@ -1,8 +1,11 @@
|
||||
use simple_filesystem::*;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::{boxed::Box, sync::Arc, string::String, collections::VecDeque, vec::Vec};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::driver::ide;
|
||||
use spin::Mutex;
|
||||
use sync::Condvar;
|
||||
use sync::SpinNoIrqLock as Mutex;
|
||||
use core::any::Any;
|
||||
use core::slice;
|
||||
|
||||
use ::memory::{InactivePageTable0, memory_set_record};
|
||||
use memory::MemorySet;
|
||||
@ -13,69 +16,29 @@ use process::context::memory_set_map_swappable;
|
||||
global_asm!(r#"
|
||||
.section .rodata
|
||||
.align 12
|
||||
_binary_user_riscv_img_start:
|
||||
.global _user_img_start
|
||||
.global _user_img_end
|
||||
_user_img_start:
|
||||
.incbin "../user/user-riscv.img"
|
||||
_binary_user_riscv_img_end:
|
||||
_user_img_end:
|
||||
"#);
|
||||
|
||||
pub fn shell() {
|
||||
// load riscv32/x86_64 user program
|
||||
use sync;
|
||||
/// below are test for sync, uncomment them if need
|
||||
//sync::test::philosopher_using_mutex();
|
||||
//sync::test::philosopher_using_monitor();
|
||||
lazy_static! {
|
||||
pub static ref ROOT_INODE: Arc<INode> = {
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
let device = {
|
||||
extern {
|
||||
fn _user_img_start();
|
||||
fn _user_img_end();
|
||||
}
|
||||
Box::new(unsafe { MemBuf::new(_user_img_start, _user_img_end) })
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let device = Box::new(ide::IDE::new(1));
|
||||
|
||||
|
||||
info!("come into shell!");
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
let device = {
|
||||
extern {
|
||||
fn _binary_user_riscv_img_start();
|
||||
fn _binary_user_riscv_img_end();
|
||||
}
|
||||
Box::new(unsafe { MemBuf::new(_binary_user_riscv_img_start, _binary_user_riscv_img_end) })
|
||||
let sfs = SimpleFileSystem::open(device).expect("failed to open SFS");
|
||||
sfs.root_inode()
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let device = Box::new(&ide::DISK1);
|
||||
let sfs = SimpleFileSystem::open(device).expect("failed to open SFS");
|
||||
let root = sfs.root_inode();
|
||||
let files = root.borrow().list().unwrap();
|
||||
println!("Available programs: {:?}", files);
|
||||
|
||||
// Avoid stack overflow in release mode
|
||||
// Equal to: `buf = Box::new([0; 64 << 12])`
|
||||
use alloc::alloc::{alloc, dealloc, Layout};
|
||||
const BUF_SIZE: usize = 0x40000;
|
||||
let layout = Layout::from_size_align(BUF_SIZE, 0x1000).unwrap();
|
||||
let buf = unsafe{ slice::from_raw_parts_mut(alloc(layout), BUF_SIZE) };
|
||||
// start interaction
|
||||
loop {
|
||||
print!(">> ");
|
||||
|
||||
use console::get_line;
|
||||
let name = get_line();
|
||||
//use alloc::prelude::ToString;
|
||||
//let name = "waitkill".to_string();
|
||||
|
||||
if name == "" {
|
||||
continue;
|
||||
}
|
||||
if let Ok(file) = root.borrow().lookup(name.as_str()) {
|
||||
use process::*;
|
||||
let len = file.borrow().read_at(0, &mut *buf).unwrap();
|
||||
let context = ContextImpl::new_user(&buf[..len]);
|
||||
//memory_set_map_swappable(context.get_memory_set_mut());
|
||||
let pid = processor().manager().add(context);
|
||||
//memory_set_map_swappable(processor().get_context_mut(pid).get_memory_set_mut());
|
||||
processor().manager().wait(thread::current().id(), pid);
|
||||
processor().yield_now();
|
||||
processor().manager().wait_done(thread::current().id(), pid);
|
||||
} else {
|
||||
println!("Program not exist");
|
||||
}
|
||||
//break;
|
||||
}
|
||||
unsafe { dealloc(buf.as_mut_ptr(), layout) };
|
||||
}
|
||||
|
||||
struct MemBuf(&'static [u8]);
|
||||
@ -99,19 +62,99 @@ impl Device for MemBuf {
|
||||
}
|
||||
}
|
||||
|
||||
use core::slice;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
impl BlockedDevice for &'static ide::DISK1 {
|
||||
impl BlockedDevice for ide::IDE {
|
||||
const BLOCK_SIZE_LOG2: u8 = 9;
|
||||
fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool {
|
||||
assert!(buf.len() >= ide::BLOCK_SIZE);
|
||||
let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
|
||||
self.0.lock().read(block_id as u64, 1, buf).is_ok()
|
||||
self.read(block_id as u64, 1, buf).is_ok()
|
||||
}
|
||||
fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool {
|
||||
assert!(buf.len() >= ide::BLOCK_SIZE);
|
||||
let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
|
||||
self.0.lock().write(block_id as u64, 1, buf).is_ok()
|
||||
self.write(block_id as u64, 1, buf).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Stdin {
|
||||
buf: Mutex<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::alloc::Layout;
|
||||
|
@ -51,7 +51,7 @@ mod syscall;
|
||||
mod fs;
|
||||
mod sync;
|
||||
mod trap;
|
||||
mod console;
|
||||
mod shell;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@ -63,10 +63,6 @@ pub mod arch;
|
||||
pub mod arch;
|
||||
|
||||
pub fn kmain() -> ! {
|
||||
info!("Come into kmain");
|
||||
// sync::test::philosopher_using_mutex();
|
||||
// sync::test::philosopher_using_monitor();
|
||||
// sync::mpsc::test::test_all();
|
||||
process::processor().run();
|
||||
|
||||
// thread::test::local_key();
|
||||
|
@ -1,5 +1,10 @@
|
||||
use core::fmt;
|
||||
use log::{self, Level, LevelFilter, Log, Metadata, Record};
|
||||
use spin::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
static ref log_mutex: Mutex<()> = Mutex::new(());
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
static LOGGER: SimpleLogger = SimpleLogger;
|
||||
@ -38,11 +43,13 @@ macro_rules! with_color {
|
||||
|
||||
fn print_in_color(args: fmt::Arguments, color: Color) {
|
||||
use arch::io;
|
||||
let mutex = log_mutex.lock();
|
||||
io::putfmt(with_color!(args, color));
|
||||
}
|
||||
|
||||
pub fn print(args: fmt::Arguments) {
|
||||
use arch::io;
|
||||
let mutex = log_mutex.lock();
|
||||
io::putfmt(args);
|
||||
}
|
||||
|
||||
@ -71,7 +78,7 @@ impl From<Level> for Color {
|
||||
Level::Error => Color::Red,
|
||||
Level::Warn => Color::Yellow,
|
||||
Level::Info => Color::Blue,
|
||||
Level::Debug => Color::LightRed,
|
||||
Level::Debug => Color::Green,
|
||||
Level::Trace => Color::DarkGray,
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use consts::MEMORY_OFFSET;
|
||||
use super::HEAP_ALLOCATOR;
|
||||
use ucore_memory::{*, paging::PageTable};
|
||||
use ucore_memory::cow::CowExt;
|
||||
pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySet_, Stack, InactivePageTable};
|
||||
pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySet_, InactivePageTable};
|
||||
use ucore_memory::swap::*;
|
||||
//use process::{processor, PROCESSOR};
|
||||
use process::{process};
|
||||
@ -26,7 +26,7 @@ pub type FrameAlloc = BitAlloc4K;
|
||||
lazy_static! {
|
||||
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = SpinNoIrqLock::new(FrameAlloc::default());
|
||||
}
|
||||
// record the user memory set for pagefault function (swap in/out and frame delayed allocate) temporarily when page fault in new_user() or fork() function
|
||||
// record the user memory set for pagefault function (swap in/out and frame delayed allocate) temporarily when page fault in new_user() or fork() function
|
||||
// after the process is set we can use use processor() to get the inactive page table
|
||||
lazy_static! {
|
||||
pub static ref MEMORY_SET_RECORD: SpinNoIrqLock<VecDeque<usize>> = SpinNoIrqLock::new(VecDeque::default());
|
||||
@ -49,7 +49,7 @@ pub fn active_table() -> MutexGuard<'static, CowExt<ActivePageTable>, SpinNoIrq>
|
||||
|
||||
// Page table for swap in and out
|
||||
lazy_static!{
|
||||
static ref ACTIVE_TABLE_SWAP: SpinNoIrqLock<SwapExt<ActivePageTable, fifo::FifoSwapManager, mock_swapper::MockSwapper>> =
|
||||
static ref ACTIVE_TABLE_SWAP: SpinNoIrqLock<SwapExt<ActivePageTable, fifo::FifoSwapManager, mock_swapper::MockSwapper>> =
|
||||
SpinNoIrqLock::new(unsafe{SwapExt::new(ActivePageTable::new(), fifo::FifoSwapManager::default(), mock_swapper::MockSwapper::default())});
|
||||
}
|
||||
|
||||
@ -58,9 +58,9 @@ pub fn active_table_swap() -> MutexGuard<'static, SwapExt<ActivePageTable, fifo:
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief:
|
||||
* @brief:
|
||||
* allocate a free physical frame, if no free frame, then swap out one page and reture mapped frame as the free one
|
||||
* @retval:
|
||||
* @retval:
|
||||
* the physical address for the allocated frame
|
||||
*/
|
||||
pub fn alloc_frame() -> Option<usize> {
|
||||
@ -76,15 +76,6 @@ pub fn dealloc_frame(target: usize) {
|
||||
FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
|
||||
}
|
||||
|
||||
// alloc from heap
|
||||
pub fn alloc_stack() -> Stack {
|
||||
use alloc::alloc::{alloc, Layout};
|
||||
const STACK_SIZE: usize = 0x8000;
|
||||
let bottom = unsafe{ alloc(Layout::from_size_align(STACK_SIZE, 0x8000).unwrap()) } as usize;
|
||||
let top = bottom + STACK_SIZE;
|
||||
Stack { top, bottom }
|
||||
}
|
||||
|
||||
pub struct KernelStack(usize);
|
||||
const STACK_SIZE: usize = 0x8000;
|
||||
|
||||
@ -107,13 +98,13 @@ impl Drop for KernelStack {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* @param:
|
||||
* addr: the virtual address of the page fault
|
||||
* @brief:
|
||||
* @brief:
|
||||
* handle page fault
|
||||
* @retval:
|
||||
* Return true to continue, false to halt
|
||||
* @retval:
|
||||
* Return true to continue, false to halt
|
||||
*/
|
||||
pub fn page_fault_handler(addr: usize) -> bool {
|
||||
info!("start handling swap in/out page fault");
|
||||
@ -131,7 +122,7 @@ pub fn page_fault_handler(addr: usize) -> bool {
|
||||
info!("get id from memroy set recorder.");
|
||||
let mmset_ptr = mmsets.get(targetid);
|
||||
// get current mmset
|
||||
|
||||
|
||||
let current_mmset = unsafe{&mut *(mmset_ptr.unwrap().clone() as *mut MemorySet)};
|
||||
//check whether the vma is legal
|
||||
if(current_mmset.find_area(addr).is_none()){
|
||||
@ -158,8 +149,8 @@ pub fn page_fault_handler(addr: usize) -> bool {
|
||||
},
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
// Handle copy on write (not being used now)
|
||||
unsafe { ACTIVE_TABLE.force_unlock(); }
|
||||
if active_table().page_fault_handler(addr, || alloc_frame().unwrap()){
|
||||
|
@ -3,15 +3,21 @@ use memory::{MemoryArea, MemoryAttr, MemorySet, KernelStack, active_table_swap,
|
||||
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}};
|
||||
use core::fmt::{Debug, Error, Formatter};
|
||||
use ucore_process::Context;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::{boxed::Box, collections::BTreeMap, vec::Vec, sync::Arc, string::String};
|
||||
use ucore_memory::{Page};
|
||||
use ::memory::{InactivePageTable0, memory_set_record};
|
||||
use ucore_memory::memory_set::*;
|
||||
use simple_filesystem::file::File;
|
||||
use spin::Mutex;
|
||||
|
||||
|
||||
// TODO: avoid pub
|
||||
pub struct ContextImpl {
|
||||
arch: ArchContext,
|
||||
memory_set: MemorySet,
|
||||
kstack: KernelStack,
|
||||
pub arch: ArchContext,
|
||||
pub memory_set: MemorySet,
|
||||
pub kstack: KernelStack,
|
||||
pub files: BTreeMap<usize, Arc<Mutex<File>>>,
|
||||
pub cwd: String,
|
||||
}
|
||||
|
||||
impl Context for ContextImpl {
|
||||
@ -28,6 +34,8 @@ impl ContextImpl {
|
||||
arch: ArchContext::null(),
|
||||
memory_set: MemorySet::new(),
|
||||
kstack: KernelStack::new(),
|
||||
files: BTreeMap::default(),
|
||||
cwd: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -38,19 +46,23 @@ impl ContextImpl {
|
||||
arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) },
|
||||
memory_set,
|
||||
kstack,
|
||||
files: BTreeMap::default(),
|
||||
cwd: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Make a new user thread from ELF data
|
||||
/*
|
||||
* @param:
|
||||
* data: the ELF data stream
|
||||
* @brief:
|
||||
* @param:
|
||||
* data: the ELF data stream
|
||||
* @brief:
|
||||
* make a new thread from ELF data
|
||||
* @retval:
|
||||
* @retval:
|
||||
* the new user thread Context
|
||||
*/
|
||||
pub fn new_user(data: &[u8]) -> Box<Context> {
|
||||
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<ContextImpl>
|
||||
where Iter: Iterator<Item=&'a str>
|
||||
{
|
||||
// Parse elf
|
||||
let elf = ElfFile::new(data).expect("failed to read elf");
|
||||
let is32 = match elf.header.pt2 {
|
||||
@ -61,7 +73,7 @@ impl ContextImpl {
|
||||
|
||||
// User stack
|
||||
use consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET};
|
||||
let (user_stack_buttom, user_stack_top) = match is32 {
|
||||
let (ustack_buttom, mut ustack_top) = match is32 {
|
||||
true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE),
|
||||
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
|
||||
};
|
||||
@ -75,7 +87,7 @@ impl ContextImpl {
|
||||
//let id = memory_set_record().iter()
|
||||
// .position(|x| unsafe { info!("current memory set record include {:x?}, {:x?}", x, (*(x.clone() as *mut MemorySet)).get_page_table_mut().token()); false });
|
||||
|
||||
memory_set.push(MemoryArea::new(user_stack_buttom, user_stack_top, MemoryAttr::default().user(), "user_stack"));
|
||||
memory_set.push(MemoryArea::new(ustack_buttom, ustack_top, MemoryAttr::default().user(), "user_stack"));
|
||||
trace!("{:#x?}", memory_set);
|
||||
|
||||
let entry_addr = elf.header.pt2.entry_point() as usize;
|
||||
@ -87,20 +99,15 @@ impl ContextImpl {
|
||||
let virt_addr = ph.virtual_addr() as usize;
|
||||
let offset = ph.offset() as usize;
|
||||
let file_size = ph.file_size() as usize;
|
||||
if file_size == 0 {
|
||||
return;
|
||||
}
|
||||
use core::slice;
|
||||
let target = unsafe { slice::from_raw_parts_mut(virt_addr as *mut u8, file_size) };
|
||||
target.copy_from_slice(&data[offset..offset + file_size]);
|
||||
}
|
||||
if is32 {
|
||||
unsafe {
|
||||
// TODO: full argc & argv
|
||||
*(user_stack_top as *mut u32).offset(-1) = 0; // argv
|
||||
*(user_stack_top as *mut u32).offset(-2) = 0; // argc
|
||||
let mem_size = ph.mem_size() as usize;
|
||||
|
||||
let target = unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) };
|
||||
if file_size != 0 {
|
||||
target[..file_size].copy_from_slice(&data[offset..offset + file_size]);
|
||||
}
|
||||
target[file_size..].iter_mut().for_each(|x| *x = 0);
|
||||
}
|
||||
ustack_top = push_args_at_stack(args, ustack_top);
|
||||
});
|
||||
}
|
||||
|
||||
@ -113,10 +120,12 @@ impl ContextImpl {
|
||||
let mut ret = Box::new(ContextImpl {
|
||||
arch: unsafe {
|
||||
ArchContext::new_user_thread(
|
||||
entry_addr, user_stack_top - 8, kstack.top(), is32, memory_set.token())
|
||||
entry_addr, ustack_top, kstack.top(), is32, memory_set.token())
|
||||
},
|
||||
memory_set,
|
||||
kstack,
|
||||
files: BTreeMap::default(),
|
||||
cwd: String::new(),
|
||||
});
|
||||
//set the user Memory pages in the memory set swappable
|
||||
memory_set_map_swappable(ret.get_memory_set_mut());
|
||||
@ -133,7 +142,7 @@ impl ContextImpl {
|
||||
info!("fork! new page table token: {:x?}", memory_set.token());
|
||||
let mmset_ptr = ((&mut memory_set) as * mut MemorySet) as usize;
|
||||
memory_set_record().push_back(mmset_ptr);
|
||||
|
||||
|
||||
info!("before copy data to temp space");
|
||||
// Copy data to temp space
|
||||
use alloc::vec::Vec;
|
||||
@ -147,7 +156,7 @@ impl ContextImpl {
|
||||
unsafe {
|
||||
memory_set.with(|| {
|
||||
for (area, data) in memory_set.iter().zip(datas.iter()) {
|
||||
unsafe { area.as_slice_mut() }.copy_from_slice(data.as_slice())
|
||||
area.as_slice_mut().copy_from_slice(data.as_slice())
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -155,15 +164,17 @@ impl ContextImpl {
|
||||
info!("temporary copy data!");
|
||||
let kstack = KernelStack::new();
|
||||
|
||||
// remove the raw pointer for the memory set since it will
|
||||
// remove the raw pointer for the memory set since it will
|
||||
let id = memory_set_record().iter()
|
||||
.position(|x| x.clone() == mmset_ptr).unwrap();
|
||||
memory_set_record().remove(id);
|
||||
|
||||
|
||||
let mut ret = Box::new(ContextImpl {
|
||||
arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) },
|
||||
memory_set,
|
||||
kstack,
|
||||
files: BTreeMap::default(),
|
||||
cwd: String::new(),
|
||||
});
|
||||
|
||||
memory_set_map_swappable(ret.get_memory_set_mut());
|
||||
@ -191,7 +202,7 @@ impl Drop for ContextImpl{
|
||||
*/
|
||||
|
||||
//set the user Memory pages in the memory set unswappable
|
||||
let Self {ref mut arch, ref mut memory_set, ref mut kstack} = self;
|
||||
let Self {ref mut arch, ref mut memory_set, ref mut kstack, ..} = self;
|
||||
let pt = {
|
||||
memory_set.get_page_table_mut() as *mut InactivePageTable0
|
||||
};
|
||||
@ -213,12 +224,39 @@ impl Debug for ContextImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/// Push a slice at the stack. Return the new sp.
|
||||
unsafe fn push_slice<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
|
||||
* @brief:
|
||||
* @brief:
|
||||
* generate a memory set according to the elf file
|
||||
* @retval:
|
||||
* @retval:
|
||||
* the new memory set
|
||||
*/
|
||||
fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> MemorySet {
|
||||
@ -246,7 +284,7 @@ fn memory_attr_from(elf_flags: Flags) -> MemoryAttr {
|
||||
}
|
||||
|
||||
/*
|
||||
* @param:
|
||||
* @param:
|
||||
* memory_set: the target MemorySet to set swappable
|
||||
* @brief:
|
||||
* map the memory area in the memory_set swappalbe, specially for the user process
|
||||
|
@ -8,7 +8,6 @@ use sync::Condvar;
|
||||
use core::sync::atomic::*;
|
||||
|
||||
pub mod context;
|
||||
|
||||
pub fn init() {
|
||||
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass
|
||||
let scheduler = Box::new(scheduler::RRScheduler::new(5));
|
||||
|
60
kernel/src/shell.rs
Normal file
60
kernel/src/shell.rs
Normal file
@ -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>
|
||||
{
|
||||
fn obtain_lock(&self) {
|
||||
while true {
|
||||
match self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) {
|
||||
Ok(X) => break,
|
||||
Err(X) => {
|
||||
// Wait until the lock looks unlocked before retrying
|
||||
while self.lock.load(Ordering::Relaxed) {
|
||||
self.support.cpu_relax();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false {
|
||||
// Wait until the lock looks unlocked before retrying
|
||||
while self.lock.load(Ordering::Relaxed) {
|
||||
self.support.cpu_relax();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,13 +144,13 @@ impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
|
||||
/// a guard within Some.
|
||||
pub fn try_lock(&self) -> Option<MutexGuard<T, S>> {
|
||||
let support_guard = S::before_lock();
|
||||
match self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) {
|
||||
Ok(X) =>
|
||||
Some(MutexGuard {
|
||||
mutex: self,
|
||||
support_guard,
|
||||
}),
|
||||
Err(X) => None,
|
||||
if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false {
|
||||
Some(MutexGuard {
|
||||
mutex: self,
|
||||
support_guard,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,12 +174,12 @@ impl<T: ?Sized + Default, S: MutexSupport> Default for Mutex<T, S> {
|
||||
impl<'a, T: ?Sized, S: MutexSupport> Deref for MutexGuard<'a, T, S>
|
||||
{
|
||||
type Target = T;
|
||||
fn deref<'b>(&'b self) -> &'b T { unsafe { &*self.mutex.data.get() } }
|
||||
fn deref(&self) -> &T { unsafe { &*self.mutex.data.get() } }
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized, S: MutexSupport> DerefMut for MutexGuard<'a, T, S>
|
||||
{
|
||||
fn deref_mut<'b>(&'b mut self) -> &'b mut T { unsafe { &mut *self.mutex.data.get() } }
|
||||
fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.mutex.data.get() } }
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized, S: MutexSupport> Drop for MutexGuard<'a, T, S>
|
||||
|
@ -1,86 +1,166 @@
|
||||
//! 系统调用解析执行模块
|
||||
|
||||
#![allow(unused)]
|
||||
//! System call
|
||||
|
||||
use arch::interrupt::TrapFrame;
|
||||
use process::*;
|
||||
use thread;
|
||||
use util;
|
||||
use simple_filesystem::{INode, file::File, FileInfo, FileType};
|
||||
use core::{slice, str};
|
||||
use alloc::sync::Arc;
|
||||
use spin::Mutex;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::string::String;
|
||||
|
||||
use process::context::memory_set_map_swappable;
|
||||
use alloc::boxed::Box;
|
||||
use process::context::*;
|
||||
/// System call dispatcher
|
||||
pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> i32 {
|
||||
let ret = match id {
|
||||
// file
|
||||
100 => sys_open(args[0] as *const u8, args[1]),
|
||||
101 => sys_close(args[0]),
|
||||
102 => sys_read(args[0], args[1] as *mut u8, args[2]),
|
||||
103 => sys_write(args[0], args[1] as *const u8, args[2]),
|
||||
030 => sys_putc(args[0] as u8 as char),
|
||||
// 104 => sys_seek(),
|
||||
110 => sys_fstat(args[0], args[1] as *mut Stat),
|
||||
// 111 => sys_fsync(),
|
||||
// 121 => sys_getcwd(),
|
||||
128 => sys_getdirentry(args[0], args[1] as *mut DirEntry),
|
||||
130 => sys_dup(args[0], args[1]),
|
||||
|
||||
// process
|
||||
001 => sys_exit(args[0] as i32),
|
||||
002 => sys_fork(tf),
|
||||
003 => sys_wait(args[0], args[1] as *mut i32),
|
||||
004 => sys_exec(args[0] as *const u8, args[1] as usize, args[2] as *const *const u8, tf),
|
||||
// 005 => sys_clone(),
|
||||
010 => sys_yield(),
|
||||
011 => sys_sleep(args[0]),
|
||||
012 => sys_kill(args[0]),
|
||||
017 => sys_get_time(),
|
||||
018 => sys_getpid(),
|
||||
255 => sys_lab6_set_priority(args[0]),
|
||||
|
||||
// memory
|
||||
// 020 => sys_mmap(),
|
||||
// 021 => sys_munmap(),
|
||||
// 022 => sys_shmem(),
|
||||
// 031 => sys_pgdir(),
|
||||
|
||||
/// 系统调用入口点
|
||||
///
|
||||
/// 当发生系统调用中断时,中断服务例程将控制权转移到这里。
|
||||
pub fn syscall(id: usize, args: [usize; 6], tf: &TrapFrame) -> i32 {
|
||||
match id {
|
||||
SYS_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
|
||||
SYS_OPEN => sys_open(args[0] as *const u8, args[1]),
|
||||
SYS_CLOSE => sys_close(args[0]),
|
||||
SYS_WAIT => sys_wait(args[0], args[1] as *mut i32),
|
||||
SYS_FORK => sys_fork(tf),
|
||||
SYS_KILL => sys_kill(args[0]),
|
||||
SYS_EXIT => sys_exit(args[0]),
|
||||
SYS_YIELD => sys_yield(),
|
||||
SYS_GETPID => sys_getpid(),
|
||||
SYS_SLEEP => sys_sleep(args[0]),
|
||||
SYS_GETTIME => sys_get_time(),
|
||||
SYS_LAB6_SET_PRIORITY => sys_lab6_set_priority(args[0]),
|
||||
SYS_PUTC => sys_putc(args[0] as u8 as char),
|
||||
_ => {
|
||||
error!("unknown syscall id: {:#x?}, args: {:x?}", id, args);
|
||||
::trap::error(tf);
|
||||
}
|
||||
};
|
||||
match ret {
|
||||
Ok(code) => code,
|
||||
Err(_) => -1,
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_write(fd: usize, base: *const u8, len: usize) -> i32 {
|
||||
fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult {
|
||||
// TODO: check ptr
|
||||
info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
|
||||
let slice = unsafe { slice::from_raw_parts_mut(base, len) };
|
||||
let len = get_file(fd)?.lock().read(slice)?;
|
||||
Ok(len as i32)
|
||||
}
|
||||
|
||||
fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult {
|
||||
// TODO: check ptr
|
||||
info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
|
||||
use core::slice;
|
||||
use core::str;
|
||||
let slice = unsafe { slice::from_raw_parts(base, len) };
|
||||
print!("{}", str::from_utf8(slice).unwrap());
|
||||
0
|
||||
let len = get_file(fd)?.lock().write(slice)?;
|
||||
Ok(len as i32)
|
||||
}
|
||||
|
||||
fn sys_open(path: *const u8, flags: usize) -> i32 {
|
||||
fn sys_open(path: *const u8, flags: usize) -> SysResult {
|
||||
// TODO: check ptr
|
||||
let path = unsafe { util::from_cstr(path) };
|
||||
let flags = VfsFlags::from_ucore_flags(flags);
|
||||
info!("open: path: {:?}, flags: {:?}", path, flags);
|
||||
match path {
|
||||
"stdin:" => 0,
|
||||
"stdout:" => 1,
|
||||
_ => -1,
|
||||
let (fd, inode) = match path {
|
||||
"stdin:" => (0, ::fs::STDIN.clone() as Arc<INode>),
|
||||
"stdout:" => (1, ::fs::STDOUT.clone() as Arc<INode>),
|
||||
_ => {
|
||||
let fd = (3..).find(|i| !process().files.contains_key(i)).unwrap();
|
||||
let inode = ::fs::ROOT_INODE.lookup(path)?;
|
||||
(fd, inode)
|
||||
}
|
||||
};
|
||||
let file = File::new(inode, flags.contains(VfsFlags::READABLE), flags.contains(VfsFlags::WRITABLE));
|
||||
process().files.insert(fd, Arc::new(Mutex::new(file)));
|
||||
Ok(fd as i32)
|
||||
}
|
||||
|
||||
fn sys_close(fd: usize) -> SysResult {
|
||||
info!("close: fd: {:?}", fd);
|
||||
match process().files.remove(&fd) {
|
||||
Some(_) => Ok(0),
|
||||
None => Err(SysError::InvalidFile),
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_close(fd: usize) -> i32 {
|
||||
info!("close: fd: {:?}", fd);
|
||||
0
|
||||
fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
|
||||
// TODO: check ptr
|
||||
info!("fstat: {}", fd);
|
||||
let file = get_file(fd)?;
|
||||
let stat = Stat::from(file.lock().info()?);
|
||||
unsafe { stat_ptr.write(stat); }
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// entry_id = dentry.offset / 256
|
||||
/// dentry.name = entry_name
|
||||
/// dentry.offset += 256
|
||||
fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult {
|
||||
// TODO: check ptr
|
||||
info!("getdirentry: {}", fd);
|
||||
let file = get_file(fd)?;
|
||||
let dentry = unsafe { &mut *dentry_ptr };
|
||||
if !dentry.check() {
|
||||
return Err(SysError::InvalidArgument);
|
||||
}
|
||||
let info = file.lock().info()?;
|
||||
if info.type_ != FileType::Dir || info.size <= dentry.entry_id() {
|
||||
return Err(SysError::InvalidArgument);
|
||||
}
|
||||
let name = file.lock().get_entry(dentry.entry_id())?;
|
||||
dentry.set_name(name.as_str());
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn sys_dup(fd1: usize, fd2: usize) -> SysResult {
|
||||
info!("dup: {} {}", fd1, fd2);
|
||||
let file = get_file(fd1)?;
|
||||
if process().files.contains_key(&fd2) {
|
||||
return Err(SysError::InvalidFile);
|
||||
}
|
||||
process().files.insert(fd2, file.clone());
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// Fork the current process. Return the child's PID.
|
||||
fn sys_fork(tf: &TrapFrame) -> i32 {
|
||||
fn sys_fork(tf: &TrapFrame) -> SysResult {
|
||||
let mut context = process().fork(tf);
|
||||
//memory_set_map_swappable(context.get_memory_set_mut());
|
||||
let pid = processor().manager().add(context);
|
||||
processor().manager().set_parent(thread::current().id(), pid);
|
||||
//memory_set_map_swappable(processor.get_context_mut(pid).get_memory_set_mut());
|
||||
info!("fork: {} -> {}", thread::current().id(), pid);
|
||||
pid as i32
|
||||
Ok(pid as i32)
|
||||
}
|
||||
|
||||
/// Wait the process exit.
|
||||
/// Return the PID. Store exit code to `code` if it's not null.
|
||||
fn sys_wait(pid: usize, code: *mut i32) -> i32 {
|
||||
fn sys_wait(pid: usize, code: *mut i32) -> SysResult {
|
||||
// TODO: check ptr
|
||||
loop {
|
||||
let wait_procs = match pid {
|
||||
0 => processor().manager().get_children(thread::current().id()),
|
||||
_ => vec![pid],
|
||||
};
|
||||
if wait_procs.is_empty() {
|
||||
return -1;
|
||||
return Ok(-1);
|
||||
}
|
||||
for pid in wait_procs {
|
||||
match processor().manager().get_status(pid) {
|
||||
@ -90,12 +170,13 @@ fn sys_wait(pid: usize, code: *mut i32) -> i32 {
|
||||
}
|
||||
processor().manager().wait_done(thread::current().id(), pid);
|
||||
info!("wait: {} -> {}", thread::current().id(), pid);
|
||||
return 0;
|
||||
return Ok(0);
|
||||
}
|
||||
None => return -1,
|
||||
None => return Ok(-1),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
info!("wait: {} -> {}, sleep", thread::current().id(), pid);
|
||||
if pid == 0 {
|
||||
processor().manager().wait_child(thread::current().id());
|
||||
processor().yield_now();
|
||||
@ -106,79 +187,193 @@ fn sys_wait(pid: usize, code: *mut i32) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn sys_yield() -> i32 {
|
||||
fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapFrame) -> SysResult {
|
||||
// TODO: check ptr
|
||||
let name = if name.is_null() { "" } else { unsafe { util::from_cstr(name) } };
|
||||
info!("exec: {:?}, argc: {}, argv: {:?}", name, argc, argv);
|
||||
// Copy args to kernel
|
||||
let args: Vec<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();
|
||||
0
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// Kill the process
|
||||
fn sys_kill(pid: usize) -> i32 {
|
||||
fn sys_kill(pid: usize) -> SysResult {
|
||||
info!("{} killed: {}", thread::current().id(), pid);
|
||||
processor().manager().exit(pid, 0x100);
|
||||
if pid == thread::current().id() {
|
||||
processor().yield_now();
|
||||
}
|
||||
0
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// Get the current process id
|
||||
fn sys_getpid() -> i32 {
|
||||
thread::current().id() as i32
|
||||
fn sys_getpid() -> SysResult {
|
||||
Ok(thread::current().id() as i32)
|
||||
}
|
||||
|
||||
/// Exit the current process
|
||||
fn sys_exit(exit_code: usize) -> i32 {
|
||||
fn sys_exit(exit_code: i32) -> SysResult {
|
||||
let pid = thread::current().id();
|
||||
info!("exit: {}", pid);
|
||||
processor().manager().exit(pid, exit_code);
|
||||
info!("exit: {}, code: {}", pid, exit_code);
|
||||
processor().manager().exit(pid, exit_code as usize);
|
||||
processor().yield_now();
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
fn sys_sleep(time: usize) -> i32 {
|
||||
fn sys_sleep(time: usize) -> SysResult {
|
||||
use core::time::Duration;
|
||||
thread::sleep(Duration::from_millis(time as u64 * 10));
|
||||
0
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn sys_get_time() -> i32 {
|
||||
unsafe { ::trap::TICK as i32 }
|
||||
fn sys_get_time() -> SysResult {
|
||||
unsafe { Ok(::trap::TICK as i32) }
|
||||
}
|
||||
|
||||
fn sys_lab6_set_priority(priority: usize) -> i32 {
|
||||
fn sys_lab6_set_priority(priority: usize) -> SysResult {
|
||||
let pid = thread::current().id();
|
||||
processor().manager().set_priority(pid, priority as u8);
|
||||
0
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn sys_putc(c: char) -> i32 {
|
||||
fn sys_putc(c: char) -> SysResult {
|
||||
print!("{}", c);
|
||||
0
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
const SYS_EXIT: usize = 1;
|
||||
const SYS_FORK: usize = 2;
|
||||
const SYS_WAIT: usize = 3;
|
||||
const SYS_EXEC: usize = 4;
|
||||
const SYS_CLONE: usize = 5;
|
||||
const SYS_YIELD: usize = 10;
|
||||
const SYS_SLEEP: usize = 11;
|
||||
const SYS_KILL: usize = 12;
|
||||
const SYS_GETTIME: usize = 17;
|
||||
const SYS_GETPID: usize = 18;
|
||||
const SYS_MMAP: usize = 20;
|
||||
const SYS_MUNMAP: usize = 21;
|
||||
const SYS_SHMEM: usize = 22;
|
||||
const SYS_PUTC: usize = 30;
|
||||
const SYS_PGDIR: usize = 31;
|
||||
const SYS_OPEN: usize = 100;
|
||||
const SYS_CLOSE: usize = 101;
|
||||
const SYS_READ: usize = 102;
|
||||
const SYS_WRITE: usize = 103;
|
||||
const SYS_SEEK: usize = 104;
|
||||
const SYS_FSTAT: usize = 110;
|
||||
const SYS_FSYNC: usize = 111;
|
||||
const SYS_GETCWD: usize = 121;
|
||||
const SYS_GETDIRENTRY: usize = 128;
|
||||
const SYS_DUP: usize = 130;
|
||||
const SYS_LAB6_SET_PRIORITY: usize = 255;
|
||||
fn get_file(fd: usize) -> Result<&'static Arc<Mutex<File>>, SysError> {
|
||||
process().files.get(&fd).ok_or(SysError::InvalidFile)
|
||||
}
|
||||
|
||||
pub type SysResult = Result<i32, SysError>;
|
||||
|
||||
#[repr(i32)]
|
||||
pub enum SysError {
|
||||
VfsError,
|
||||
InvalidFile,
|
||||
InvalidArgument,
|
||||
}
|
||||
|
||||
impl From<()> for SysError {
|
||||
fn from(_: ()) -> Self {
|
||||
SysError::VfsError
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
struct VfsFlags: usize {
|
||||
// WARNING: different from origin uCore
|
||||
const READABLE = 1 << 0;
|
||||
const WRITABLE = 1 << 1;
|
||||
/// create file if it does not exist
|
||||
const CREATE = 1 << 2;
|
||||
/// error if O_CREAT and the file exists
|
||||
const EXCLUSIVE = 1 << 3;
|
||||
/// truncate file upon open
|
||||
const TRUNCATE = 1 << 4;
|
||||
/// append on each write
|
||||
const APPEND = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
impl VfsFlags {
|
||||
fn from_ucore_flags(f: usize) -> Self {
|
||||
assert_ne!(f & 0b11, 0b11);
|
||||
Self::from_bits_truncate(f + 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct DirEntry {
|
||||
offset: u32,
|
||||
name: [u8; 256],
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
fn check(&self) -> bool {
|
||||
self.offset % 256 == 0
|
||||
}
|
||||
fn entry_id(&self) -> usize {
|
||||
(self.offset / 256) as usize
|
||||
}
|
||||
fn set_name(&mut self, name: &str) {
|
||||
self.name[..name.len()].copy_from_slice(name.as_bytes());
|
||||
self.name[name.len()] = 0;
|
||||
self.offset += 256;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Stat {
|
||||
/// protection mode and file type
|
||||
mode: StatMode,
|
||||
/// number of hard links
|
||||
nlinks: u32,
|
||||
/// number of blocks file is using
|
||||
blocks: u32,
|
||||
/// file size (bytes)
|
||||
size: u32,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
struct StatMode: u32 {
|
||||
const NULL = 0;
|
||||
/// ordinary regular file
|
||||
const FILE = 0o10000;
|
||||
/// directory
|
||||
const DIR = 0o20000;
|
||||
/// symbolic link
|
||||
const LINK = 0o30000;
|
||||
/// character device
|
||||
const CHAR = 0o40000;
|
||||
/// block device
|
||||
const BLOCK = 0o50000;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<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; }
|
||||
}
|
||||
processor().tick();
|
||||
//info!("finish before return!");
|
||||
}
|
||||
|
||||
pub fn error(tf: &TrapFrame) -> ! {
|
||||
@ -23,5 +22,5 @@ pub fn error(tf: &TrapFrame) -> ! {
|
||||
}
|
||||
|
||||
pub fn serial(c: char) {
|
||||
::console::CONSOLE_INPUT.push(c);
|
||||
}
|
||||
::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)
|
||||
|
4
riscv-pk/configure
vendored
4
riscv-pk/configure
vendored
@ -4084,8 +4084,8 @@ fi
|
||||
case "${BUILD_32BIT}" in
|
||||
yes|default)
|
||||
echo "Building 32-bit pk"
|
||||
CFLAGS="$default_CFLAGS -march=rv32i -mabi=ilp32"
|
||||
LDFLAGS="-march=rv32i -mabi=ilp32"
|
||||
CFLAGS="$default_CFLAGS -march=rv32iac -mabi=ilp32"
|
||||
LDFLAGS="-march=rv32iac -mabi=ilp32"
|
||||
install_subdir="riscv32-unknown-elf"
|
||||
;;
|
||||
*)
|
||||
|
@ -88,8 +88,8 @@ AC_ARG_ENABLE([32bit],
|
||||
case "${BUILD_32BIT}" in
|
||||
yes|default)
|
||||
echo "Building 32-bit pk"
|
||||
CFLAGS="$default_CFLAGS -march=rv32i -mabi=ilp32"
|
||||
LDFLAGS="-march=rv32i -mabi=ilp32"
|
||||
CFLAGS="$default_CFLAGS -march=rv32iac -mabi=ilp32"
|
||||
LDFLAGS="-march=rv32iac -mabi=ilp32"
|
||||
install_subdir="riscv32-unknown-elf"
|
||||
;;
|
||||
*)
|
||||
|
@ -172,7 +172,7 @@ void init_other_hart(uintptr_t hartid, uintptr_t dtb)
|
||||
boot_other_hart(dtb);
|
||||
}
|
||||
|
||||
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1)
|
||||
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1, uintptr_t arg2)
|
||||
{
|
||||
// Set up a PMP to permit access to all of memory.
|
||||
// Ignore the illegal-instruction trap if PMPs aren't supported.
|
||||
@ -194,6 +194,7 @@ void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1
|
||||
|
||||
register uintptr_t a0 asm ("a0") = arg0;
|
||||
register uintptr_t a1 asm ("a1") = arg1;
|
||||
asm volatile ("mret" : : "r" (a0), "r" (a1));
|
||||
register uintptr_t a2 asm ("a2") = arg2;
|
||||
asm volatile ("mret" : : "r" (a0), "r" (a1), "r" (a2));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ void putstring(const char* s);
|
||||
#define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); })
|
||||
#define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(-1); })
|
||||
|
||||
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1)
|
||||
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1, uintptr_t arg2)
|
||||
__attribute__((noreturn));
|
||||
void boot_loader(uintptr_t dtb);
|
||||
void boot_other_hart(uintptr_t dtb);
|
||||
|
@ -9,13 +9,8 @@
|
||||
"cpu": "generic-rv32",
|
||||
"features": "",
|
||||
"max-atomic-width": "32",
|
||||
"linker": "riscv64-unknown-elf-ld",
|
||||
"linker-flavor": "ld",
|
||||
"pre-link-args": {
|
||||
"ld": [
|
||||
"-melf32lriscv"
|
||||
]
|
||||
},
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld",
|
||||
"executables": true,
|
||||
"panic-strategy": "abort",
|
||||
"relocation-model": "static",
|
||||
|
Loading…
Reference in New Issue
Block a user