1
0
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:
WangRunji 2018-11-16 18:32:45 +08:00
commit 205f90a264
72 changed files with 1278 additions and 1214 deletions

3
.gitmodules vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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> {

View File

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

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

Binary file not shown.

48
docs/2_OSLab/g5/exp2.md Normal file
View 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
View 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
View File

@ -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"

View File

@ -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]

View File

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

View File

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

View File

@ -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,

View 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`.
///

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

View File

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

View File

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

View File

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

View File

@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
View File

@ -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"
;;
*)

View File

@ -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"
;;
*)

View File

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

View File

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

View File

@ -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",