reformat code using `cargo fmt`

master
WangRunji 6 years ago
parent fe88f4f77f
commit b836b11792

@ -80,8 +80,16 @@ impl<T: BitAlloc> BitAllocCascade16<T> {
assert!(start <= end);
assert!(end <= Self::CAP);
for i in start / T::CAP..=(end - 1) / T::CAP {
let begin = if start / T::CAP == i { start % T::CAP } else { 0 };
let end = if end / T::CAP == i { end % T::CAP } else { T::CAP };
let begin = if start / T::CAP == i {
start % T::CAP
} else {
0
};
let end = if end / T::CAP == i {
end % T::CAP
} else {
T::CAP
};
f(&mut self.sub[i], begin..end);
self.bitset.set_bit(i, self.sub[i].any());
}

@ -12,27 +12,29 @@ pub struct Page {
impl Page {
/*
** @brief get the virtual address of beginning of the page
** @retval VirtAddr the virtual address of beginning of the page
*/
** @brief get the virtual address of beginning of the page
** @retval VirtAddr the virtual address of beginning of the page
*/
pub fn start_address(&self) -> VirtAddr {
self.number * PAGE_SIZE
}
/*
** @brief get the page of a given virtual address
** @param addr: VirtAddr the given virtual address
** @retval Page the page of the given virtual address
*/
** @brief get the page of a given virtual address
** @param addr: VirtAddr the given virtual address
** @retval Page the page of the given virtual address
*/
pub fn of_addr(addr: VirtAddr) -> Self {
Page { number: addr / PAGE_SIZE }
Page {
number: addr / PAGE_SIZE,
}
}
/*
** @brief get a pageRange between two virtual address
** @param begin: VirtAddr the virtual address of the beginning
** @param end: VirtAddr the virtual address of the end
** @retval PageRange the page of the given virtual address
*/
** @brief get a pageRange between two virtual address
** @param begin: VirtAddr the virtual address of the beginning
** @param end: VirtAddr the virtual address of the end
** @retval PageRange the page of the given virtual address
*/
pub fn range_of(begin: VirtAddr, end: VirtAddr) -> PageRange {
PageRange {
start: Page::of_addr(begin),
@ -44,7 +46,9 @@ impl Page {
impl Add<usize> for Page {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Page { number: self.number + rhs }
Page {
number: self.number + rhs,
}
}
}
@ -116,4 +120,4 @@ impl PartialEq for Frame {
}
}
impl Eq for Frame {}
impl Eq for Frame {}

@ -33,10 +33,10 @@ pub struct CowExt<T: PageTable> {
impl<T: PageTable> CowExt<T> {
/*
** @brief create a COW extension
** @param page_table: T the inner page table
** @retval CowExt the COW extension created
*/
** @brief create a COW extension
** @param page_table: T the inner page table
** @retval CowExt the COW extension created
*/
pub fn new(page_table: T) -> Self {
CowExt {
page_table,
@ -44,13 +44,13 @@ impl<T: PageTable> CowExt<T> {
}
}
/*
** @brief map the virtual address to a target physics address as shared
** @param addr: VirtAddr the virual address to map
** @param target: VirtAddr the target physics address
** @param writable: bool if it is true, set the page as writable and shared
** else set the page as readonly and shared
** @retval none
*/
** @brief map the virtual address to a target physics address as shared
** @param addr: VirtAddr the virual address to map
** @param target: VirtAddr the target physics address
** @param writable: bool if it is true, set the page as writable and shared
** else set the page as readonly and shared
** @retval none
*/
pub fn map_to_shared(&mut self, addr: VirtAddr, target: PhysAddr, writable: bool) {
let entry = self.page_table.map(addr, target);
entry.set_writable(false);
@ -63,14 +63,13 @@ impl<T: PageTable> CowExt<T> {
}
}
/*
** @brief unmap a virual address from physics address
** with apecial additional process for shared page
** @param addr: VirtAddr the virual address to unmap
** @retval none
*/
** @brief unmap a virual address from physics address
** with apecial additional process for shared page
** @param addr: VirtAddr the virual address to unmap
** @retval none
*/
pub fn unmap_shared(&mut self, addr: VirtAddr) {
let entry = self.page_table.get_entry(addr)
.expect("entry not exist");
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);
@ -80,16 +79,20 @@ impl<T: PageTable> CowExt<T> {
self.page_table.unmap(addr);
}
/*
** @brief execute the COW process for page fault
** This function must be called whenever PageFault happens.
** @param addr: VirtAddr the virual address of the page fault
** @param alloc_frame: impl FnOnce() -> PhysAddr
** the page allocation function
** that allocate a page and returns physics address
** of beginning of the page
** @retval bool whether copy-on-write happens.
*/
pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool {
** @brief execute the COW process for page fault
** This function must be called whenever PageFault happens.
** @param addr: VirtAddr the virual address of the page fault
** @param alloc_frame: impl FnOnce() -> PhysAddr
** the page allocation function
** that allocate a page and returns physics address
** of beginning of the page
** @retval bool whether copy-on-write happens.
*/
pub fn page_fault_handler(
&mut self,
addr: VirtAddr,
alloc_frame: impl FnOnce() -> PhysAddr,
) -> bool {
let entry = self.page_table.get_entry(addr);
if entry.is_none() {
return false;
@ -113,7 +116,8 @@ impl<T: PageTable> CowExt<T> {
self.unmap_shared(addr);
self.map(addr, alloc_frame());
self.get_page_slice_mut(addr).copy_from_slice(&temp_data[..]);
self.get_page_slice_mut(addr)
.copy_from_slice(&temp_data[..]);
true
}
}
@ -142,60 +146,60 @@ type Frame = usize;
impl FrameRcMap {
/*
** @brief get the read reference count of the frame
** @param frame: &Frame the frame to get the read reference count
** @retval u16 the read reference count
*/
** @brief get the read reference count of the frame
** @param frame: &Frame the frame to get the read reference count
** @retval u16 the read reference count
*/
fn read_count(&mut self, frame: &Frame) -> u16 {
self.map().get(frame).unwrap_or(&(0, 0)).0
}
/*
** @brief get the write reference count of the frame
** @param frame: &Frame the frame to get the write reference count
** @retval u16 the write reference count
*/
** @brief get the write reference count of the frame
** @param frame: &Frame the frame to get the write reference count
** @retval u16 the write reference count
*/
fn write_count(&mut self, frame: &Frame) -> u16 {
self.map().get(frame).unwrap_or(&(0, 0)).1
}
/*
** @brief increase the read reference count of the frame
** @param frame: &Frame the frame to increase the read reference count
** @retval none
*/
** @brief increase the read reference count of the frame
** @param frame: &Frame the frame to increase the read reference count
** @retval none
*/
fn read_increase(&mut self, frame: &Frame) {
let (r, w) = self.map().get(&frame).unwrap_or(&(0, 0)).clone();
self.map().insert(frame.clone(), (r + 1, w));
}
/*
** @brief decrease the read reference count of the frame
** @param frame: &Frame the frame to decrease the read reference count
** @retval none
*/
** @brief decrease the read reference count of the frame
** @param frame: &Frame the frame to decrease the read reference count
** @retval none
*/
fn read_decrease(&mut self, frame: &Frame) {
self.map().get_mut(frame).unwrap().0 -= 1;
}
/*
** @brief increase the write reference count of the frame
** @param frame: &Frame the frame to increase the write reference count
** @retval none
*/
** @brief increase the write reference count of the frame
** @param frame: &Frame the frame to increase the write reference count
** @retval none
*/
fn write_increase(&mut self, frame: &Frame) {
let (r, w) = self.map().get(&frame).unwrap_or(&(0, 0)).clone();
self.map().insert(frame.clone(), (r, w + 1));
}
/*
** @brief decrease the write reference count of the frame
** @param frame: &Frame the frame to decrease the write reference count
** @retval none
*/
** @brief decrease the write reference count of the frame
** @param frame: &Frame the frame to decrease the write reference count
** @retval none
*/
fn write_decrease(&mut self, frame: &Frame) {
self.map().get_mut(frame).unwrap().1 -= 1;
}
/*
** @brief get the internal btree map, lazily initialize the btree map if it is not present
** @retval &mut BTreeMap<Frame, (u16, u16)>
** the internal btree map
*/
** @brief get the internal btree map, lazily initialize the btree map if it is not present
** @retval &mut BTreeMap<Frame, (u16, u16)>
** the internal btree map
*/
fn map(&mut self) -> &mut BTreeMap<Frame, (u16, u16)> {
if self.0.is_none() {
self.0 = Some(BTreeMap::new());
@ -222,9 +226,10 @@ pub mod test {
}
let mut alloc = FrameAlloc(4);
pt.page_table.set_handler(Box::new(move |_, addr: VirtAddr| {
pt0.page_fault_handler(addr, || alloc.alloc());
}));
pt.page_table
.set_handler(Box::new(move |_, addr: VirtAddr| {
pt0.page_fault_handler(addr, || alloc.alloc());
}));
test_with(&mut pt);
}
@ -263,9 +268,12 @@ 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).unwrap().target(), target,
"The last write reference should not allocate new frame.");
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);
}
}
}

@ -6,17 +6,17 @@
use log::*;
extern crate alloc;
pub mod paging;
mod addr;
pub mod cow;
pub mod swap;
pub mod memory_set;
mod addr;
pub mod no_mmu;
pub mod paging;
pub mod swap;
pub use crate::addr::*;
pub enum VMError {
InvalidPtr
InvalidPtr,
}
pub type VMResult<T> = Result<T, VMError>;
pub type VMResult<T> = Result<T, VMError>;

@ -31,4 +31,4 @@ impl<T: FrameAllocator> ByFrame<T> {
pub fn new(allocator: T) -> Self {
ByFrame { allocator }
}
}
}

@ -29,4 +29,4 @@ impl Linear {
pub fn new(offset: isize) -> Self {
Linear { offset }
}
}
}

@ -7,7 +7,7 @@ pub trait MemoryHandler: Debug + 'static {
/// Map `addr` in the page table
/// Should set page flags here instead of in page_fault_handler
fn map(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr);
/// Map `addr` in the page table eagerly (i.e. no delay allocation)
/// Should set page flags here instead of in page_fault_handler
fn map_eager(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr) {
@ -34,11 +34,11 @@ pub trait FrameAllocator: Debug + Clone + 'static {
fn dealloc(&self, target: PhysAddr);
}
mod linear;
mod byframe;
mod delay;
mod linear;
//mod swap;
pub use self::linear::Linear;
pub use self::byframe::ByFrame;
pub use self::delay::Delay;
pub use self::linear::Linear;

@ -1,7 +1,7 @@
//! memory set, area
//! and the inactive page table
use alloc::{boxed::Box, vec::Vec, string::String};
use alloc::{boxed::Box, string::String, vec::Vec};
use core::fmt::{Debug, Error, Formatter};
use crate::paging::*;
@ -23,35 +23,40 @@ pub struct MemoryArea {
name: &'static str,
}
unsafe impl Send for MemoryArea { }
unsafe impl Send for MemoryArea {}
impl MemoryArea {
/*
** @brief get slice of the content in the memory area
** @retval &[u8] the slice of the content in the memory area
*/
** @brief get slice of the content in the memory area
** @retval &[u8] the slice of the content in the memory area
*/
pub unsafe fn as_slice(&self) -> &[u8] {
::core::slice::from_raw_parts(self.start_addr as *const u8, self.end_addr - self.start_addr)
::core::slice::from_raw_parts(
self.start_addr as *const u8,
self.end_addr - self.start_addr,
)
}
/*
** @brief get mutable slice of the content in the memory area
** @retval &mut[u8] the mutable slice of the content in the memory area
*/
** @brief get mutable slice of the content in the memory area
** @retval &mut[u8] the mutable slice of the content in the memory area
*/
pub unsafe fn as_slice_mut(&self) -> &mut [u8] {
::core::slice::from_raw_parts_mut(self.start_addr as *mut u8, self.end_addr - self.start_addr)
::core::slice::from_raw_parts_mut(
self.start_addr as *mut u8,
self.end_addr - self.start_addr,
)
}
/*
** @brief test whether a virtual address is in the memory area
** @param addr: VirtAddr the virtual address to test
** @retval bool whether the virtual address is in the memory area
*/
** @brief test whether a virtual address is in the memory area
** @param addr: VirtAddr the virtual address to test
** @retval bool whether the virtual address is in the memory area
*/
pub fn contains(&self, addr: VirtAddr) -> bool {
addr >= self.start_addr && addr < self.end_addr
}
/// Check the array is within the readable memory
fn check_read_array<S>(&self, ptr: *const S, count: usize) -> bool {
ptr as usize >= self.start_addr &&
unsafe { ptr.add(count) as usize } <= self.end_addr
ptr as usize >= self.start_addr && unsafe { ptr.add(count) as usize } <= self.end_addr
}
/// Check the array is within the writable memory
fn check_write_array<S>(&self, ptr: *mut S, count: usize) -> bool {
@ -80,30 +85,30 @@ impl MemoryArea {
!(p1 <= p2 || p0 >= p3)
}
/*
** @brief map the memory area to the physice address in a page table
** @param pt: &mut T::Active the page table to use
** @retval none
*/
** @brief map the memory area to the physice address in a page table
** @param pt: &mut T::Active the page table to use
** @retval none
*/
fn map(&self, pt: &mut PageTable) {
for page in Page::range_of(self.start_addr, self.end_addr) {
self.handler.map(pt, page.start_address(), &self.attr);
}
}
/*
** @brief map the memory area to the physice address in a page table eagerly
** @param pt: &mut T::Active the page table to use
** @retval none
*/
** @brief map the memory area to the physice address in a page table eagerly
** @param pt: &mut T::Active the page table to use
** @retval none
*/
fn map_eager(&self, pt: &mut PageTable) {
for page in Page::range_of(self.start_addr, self.end_addr) {
self.handler.map_eager(pt, page.start_address(), &self.attr);
}
}
/*
** @brief unmap the memory area from the physice address in a page table
** @param pt: &mut T::Active the page table to use
** @retval none
*/
** @brief unmap the memory area from the physice address in a page table
** @param pt: &mut T::Active the page table to use
** @retval none
*/
fn unmap(&self, pt: &mut PageTable) {
for page in Page::range_of(self.start_addr, self.end_addr) {
self.handler.unmap(pt, page.start_address());
@ -122,41 +127,41 @@ pub struct MemoryAttr {
impl MemoryAttr {
/*
** @brief set the memory attribute's user bit
** @retval MemoryAttr the memory attribute itself
*/
** @brief set the memory attribute's user bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn user(mut self) -> Self {
self.user = true;
self
}
/*
** @brief set the memory attribute's readonly bit
** @retval MemoryAttr the memory attribute itself
*/
** @brief set the memory attribute's readonly bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn readonly(mut self) -> Self {
self.readonly = true;
self
}
/*
** @brief unset the memory attribute's readonly bit
** @retval MemoryAttr the memory attribute itself
*/
** @brief unset the memory attribute's readonly bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn writable(mut self) -> Self {
self.readonly = false;
self
}
/*
** @brief set the memory attribute's execute bit
** @retval MemoryAttr the memory attribute itself
*/
** @brief set the memory attribute's execute bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn execute(mut self) -> Self {
self.execute = true;
self
}
/*
** @brief set the MMIO type
** @retval MemoryAttr the memory attribute itself
*/
** @brief set the MMIO type
** @retval MemoryAttr the memory attribute itself
*/
pub fn mmio(mut self, value: u8) -> Self {
self.mmio = value;
self
@ -181,9 +186,9 @@ pub struct MemorySet<T: InactivePageTable> {
impl<T: InactivePageTable> MemorySet<T> {
/*
** @brief create a memory set
** @retval MemorySet<T> the memory set created
*/
** @brief create a memory set
** @retval MemorySet<T> the memory set created
*/
pub fn new() -> Self {
MemorySet {
areas: Vec::new(),
@ -206,24 +211,30 @@ impl<T: InactivePageTable> MemorySet<T> {
}
/// Check the array is within the readable memory
pub fn check_read_array<S>(&self, ptr: *const S, count: usize) -> VMResult<()> {
self.areas.iter()
self.areas
.iter()
.find(|area| area.check_read_array(ptr, count))
.map(|_|()).ok_or(VMError::InvalidPtr)
.map(|_| ())
.ok_or(VMError::InvalidPtr)
}
/// Check the array is within the writable memory
pub fn check_write_array<S>(&self, ptr: *mut S, count: usize) -> VMResult<()> {
self.areas.iter()
self.areas
.iter()
.find(|area| area.check_write_array(ptr, count))
.map(|_|()).ok_or(VMError::InvalidPtr)
.map(|_| ())
.ok_or(VMError::InvalidPtr)
}
/// Check the null-end C string is within the readable memory, and is valid.
/// If so, clone it to a String.
///
/// Unsafe: the page table must be active.
pub unsafe fn check_and_clone_cstr(&self, ptr: *const u8) -> VMResult<String> {
self.areas.iter()
self.areas
.iter()
.filter_map(|area| area.check_and_clone_cstr(ptr))
.next().ok_or(VMError::InvalidPtr)
.next()
.ok_or(VMError::InvalidPtr)
}
/// Find a free area with hint address `addr_hint` and length `len`.
/// Return the start address of found free area.
@ -239,28 +250,45 @@ impl<T: InactivePageTable> MemorySet<T> {
}
/// Test if [`start_addr`, `end_addr`) is a free area
fn test_free_area(&self, start_addr: usize, end_addr: usize) -> bool {
self.areas.iter()
self.areas
.iter()
.find(|area| area.is_overlap_with(start_addr, end_addr))
.is_none()
}
/*
** @brief add the memory area to the memory set
** @param area: MemoryArea the memory area to add
** @retval none
*/
pub fn push(&mut self, start_addr: VirtAddr, end_addr: VirtAddr, attr: MemoryAttr, handler: impl MemoryHandler, name: &'static str) {
** @brief add the memory area to the memory set
** @param area: MemoryArea the memory area to add
** @retval none
*/
pub fn push(
&mut self,
start_addr: VirtAddr,
end_addr: VirtAddr,
attr: MemoryAttr,
handler: impl MemoryHandler,
name: &'static str,
) {
assert!(start_addr <= end_addr, "invalid memory area");
assert!(self.test_free_area(start_addr, end_addr), "memory area overlap");
let area = MemoryArea { start_addr, end_addr, attr, handler: Box::new(handler), name };
assert!(
self.test_free_area(start_addr, end_addr),
"memory area overlap"
);
let area = MemoryArea {
start_addr,
end_addr,
attr,
handler: Box::new(handler),
name,
};
self.page_table.edit(|pt| area.map(pt));
self.areas.push(area);
}
/*
** @brief remove the memory area from the memory set
** @param area: MemoryArea the memory area to remove
** @retval none
*/
** @brief remove the memory area from the memory set
** @param area: MemoryArea the memory area to remove
** @retval none
*/
pub fn pop(&mut self, start_addr: VirtAddr, end_addr: VirtAddr) {
assert!(start_addr <= end_addr, "invalid memory area");
for i in 0..self.areas.len() {
@ -274,10 +302,10 @@ impl<T: InactivePageTable> MemorySet<T> {
}
/*
** @brief remove the memory area from the memory set and split existed ones when necessary
** @param area: MemoryArea the memory area to remove
** @retval none
*/
** @brief remove the memory area from the memory set and split existed ones when necessary
** @param area: MemoryArea the memory area to remove
** @retval none
*/
pub fn pop_with_split(&mut self, start_addr: VirtAddr, end_addr: VirtAddr) {
assert!(start_addr <= end_addr, "invalid memory area");
let mut i = 0;
@ -288,28 +316,73 @@ impl<T: InactivePageTable> MemorySet<T> {
let area = self.areas.remove(i);
self.page_table.edit(|pt| area.unmap(pt));
i -= 1;
} else if self.areas[i].start_addr >= start_addr && self.areas[i].start_addr < end_addr {
} else if self.areas[i].start_addr >= start_addr
&& self.areas[i].start_addr < end_addr
{
// prefix
let area = self.areas.remove(i);
let dead_area = MemoryArea { start_addr: area.start_addr, end_addr, attr: area.attr, handler: area.handler.box_clone(), name: area.name };
let dead_area = MemoryArea {
start_addr: area.start_addr,
end_addr,
attr: area.attr,
handler: area.handler.box_clone(),
name: area.name,
};
self.page_table.edit(|pt| dead_area.unmap(pt));
let new_area = MemoryArea { start_addr: end_addr, end_addr: area.end_addr, attr: area.attr, handler: area.handler, name: area.name };
let new_area = MemoryArea {
start_addr: end_addr,
end_addr: area.end_addr,
attr: area.attr,
handler: area.handler,
name: area.name,
};
self.areas.insert(i, new_area);
} else if self.areas[i].end_addr <= end_addr && self.areas[i].end_addr > start_addr {
} else if self.areas[i].end_addr <= end_addr && self.areas[i].end_addr > start_addr
{
// postfix
let area = self.areas.remove(i);
let dead_area = MemoryArea { start_addr: start_addr, end_addr: area.end_addr, attr: area.attr, handler: area.handler.box_clone(), name: area.name };
let dead_area = MemoryArea {
start_addr: start_addr,
end_addr: area.end_addr,
attr: area.attr,
handler: area.handler.box_clone(),
name: area.name,
};
self.page_table.edit(|pt| dead_area.unmap(pt));
let new_area = MemoryArea { start_addr: area.start_addr, end_addr: start_addr, attr: area.attr, handler: area.handler, name: area.name };
let new_area = MemoryArea {
start_addr: area.start_addr,
end_addr: start_addr,
attr: area.attr,
handler: area.handler,
name: area.name,
};
self.areas.insert(i, new_area);
} else {
// superset
let area = self.areas.remove(i);
let dead_area = MemoryArea { start_addr: start_addr, end_addr: end_addr, attr: area.attr, handler: area.handler.box_clone(), name: area.name };
let dead_area = MemoryArea {
start_addr: start_addr,
end_addr: end_addr,
attr: area.attr,
handler: area.handler.box_clone(),
name: area.name,
};
self.page_table.edit(|pt| dead_area.unmap(pt));
let new_area_left = MemoryArea { start_addr: area.start_addr, end_addr: start_addr, attr: area.attr, handler: area.handler.box_clone(), name: area.name };
let new_area_left = MemoryArea {
start_addr: area.start_addr,
end_addr: start_addr,
attr: area.attr,
handler: area.handler.box_clone(),
name: area.name,
};
self.areas.insert(i, new_area_left);
let new_area_right = MemoryArea { start_addr: end_addr, end_addr: area.end_addr, attr: area.attr, handler: area.handler, name: area.name };
let new_area_right = MemoryArea {
start_addr: end_addr,
end_addr: area.end_addr,
attr: area.attr,
handler: area.handler,
name: area.name,
};
self.areas.insert(i + 1, new_area_right);
i += 1;
}
@ -319,44 +392,48 @@ impl<T: InactivePageTable> MemorySet<T> {
}
/*
** @brief get iterator of the memory area
** @retval impl Iterator<Item=&MemoryArea>
** the memory area iterator
*/
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
** @brief get iterator of the memory area
** @retval impl Iterator<Item=&MemoryArea>
** the memory area iterator
*/
pub fn iter(&self) -> impl Iterator<Item = &MemoryArea> {
self.areas.iter()
}
pub fn edit(&mut self, f: impl FnOnce(&mut T::Active)) {
self.page_table.edit(f);
}
/*
** @brief execute function with the associated page table
** @param f: impl FnOnce() the function to be executed
** @retval none
*/
** @brief execute function with the associated page table
** @param f: impl FnOnce() the function to be executed
** @retval none
*/
pub unsafe fn with(&self, f: impl FnOnce()) {
self.page_table.with(f);
}
/*
** @brief activate the associated page table
** @retval none
*/
** @brief activate the associated page table
** @retval none
*/
pub unsafe fn activate(&self) {
self.page_table.activate();
}
/*
** @brief get the token of the associated page table
** @retval usize the token of the inactive page table
*/
** @brief get the token of the associated page table
** @retval usize the token of the inactive page table
*/
pub fn token(&self) -> usize {
self.page_table.token()
}
/*
** @brief clear the memory set
** @retval none
*/
** @brief clear the memory set
** @retval none
*/
pub fn clear(&mut self) {
let Self { ref mut page_table, ref mut areas, .. } = self;
let Self {
ref mut page_table,
ref mut areas,
..
} = self;
page_table.edit(|pt| {
for area in areas.iter() {
area.unmap(pt);
@ -379,17 +456,19 @@ 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
*/
pub fn get_page_table_mut(&mut self) -> &mut T{
** @brief get the mutable reference for 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
}
pub fn handle_page_fault(&mut self, addr: VirtAddr) -> bool {
let area = self.areas.iter().find(|area| area.contains(addr));
match area {
Some(area) => self.page_table.edit(|pt| area.handler.handle_page_fault(pt, addr)),
Some(area) => self
.page_table
.edit(|pt| area.handler.handle_page_fault(pt, addr)),
None => false,
}
}
@ -419,8 +498,6 @@ impl<T: InactivePageTable> Drop for MemorySet<T> {
impl<T: InactivePageTable> Debug for MemorySet<T> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
f.debug_list()
.entries(self.areas.iter())
.finish()
f.debug_list().entries(self.areas.iter()).finish()
}
}

@ -1,5 +1,5 @@
use alloc::alloc::{GlobalAlloc, Layout};
use alloc::vec::Vec;
use alloc::alloc::{Layout, GlobalAlloc};
use core::marker::PhantomData;
pub trait NoMMUSupport {
@ -28,8 +28,12 @@ impl<S: NoMMUSupport> MemorySet<S> {
slice
}
// empty impls
pub fn with<T>(&self, f: impl FnOnce() -> T) -> T { f() }
pub fn token(&self) -> usize { 0 }
pub fn with<T>(&self, f: impl FnOnce() -> T) -> T {
f()
}
pub fn token(&self) -> usize {
0
}
pub unsafe fn activate(&self) {}
}
@ -44,7 +48,11 @@ impl<S: NoMMUSupport> MemoryArea<S> {
fn new(size: usize) -> Self {
let layout = Layout::from_size_align(size, 1).unwrap();
let ptr = unsafe { S::allocator().alloc(layout) } as usize;
MemoryArea { ptr, layout, support: PhantomData }
MemoryArea {
ptr,
layout,
support: PhantomData,
}
}
unsafe fn as_buf(&self) -> &'static mut [u8] {
core::slice::from_raw_parts_mut(self.ptr as *mut u8, self.layout.size())
@ -63,4 +71,4 @@ impl<S: NoMMUSupport> Drop for MemoryArea<S> {
fn drop(&mut self) {
unsafe { S::allocator().dealloc(self.ptr as *mut u8, self.layout) }
}
}
}

@ -8,11 +8,16 @@ pub trait PageTableExt: PageTable {
// So this should be really high in kernel space when necessary.
const TEMP_PAGE_ADDR: VirtAddr = 0xcafeb000;
fn with_temporary_map<T, D>(&mut self, target: PhysAddr, f: impl FnOnce(&mut Self, &mut D) -> T) -> T {
fn with_temporary_map<T, D>(
&mut self,
target: PhysAddr,
f: impl FnOnce(&mut Self, &mut D) -> T,
) -> T {
self.map(Self::TEMP_PAGE_ADDR, target);
let data = unsafe { &mut *(self.get_page_slice_mut(Self::TEMP_PAGE_ADDR).as_ptr() as *mut D) };
let data =
unsafe { &mut *(self.get_page_slice_mut(Self::TEMP_PAGE_ADDR).as_ptr() as *mut D) };
let ret = f(self, data);
self.unmap(Self::TEMP_PAGE_ADDR);
ret
}
}
}

@ -3,8 +3,8 @@
//! An mock implementation for the PageTable.
//! Used to test page table operation.
use alloc::boxed::Box;
use super::*;
use alloc::boxed::Box;
const PAGE_COUNT: usize = 16;
const PAGE_SIZE: usize = 4096;
@ -31,18 +31,42 @@ pub struct MockEntry {
impl Entry for MockEntry {
fn update(&mut self) {}
fn accessed(&self) -> bool { self.accessed }
fn dirty(&self) -> bool { self.dirty }
fn writable(&self) -> bool { self.writable }
fn present(&self) -> bool { self.present }
fn clear_accessed(&mut self) { self.accessed = false; }
fn clear_dirty(&mut self) { self.dirty = false; }
fn set_writable(&mut self, value: bool) { self.writable = value; }
fn set_present(&mut self, value: bool) { self.present = value; }
fn target(&self) -> usize { self.target }
fn set_target(&mut self, target: usize) { self.target = target; }
fn writable_shared(&self) -> bool { self.writable_shared }
fn readonly_shared(&self) -> bool { self.readonly_shared }
fn accessed(&self) -> bool {
self.accessed
}
fn dirty(&self) -> bool {
self.dirty
}
fn writable(&self) -> bool {
self.writable
}
fn present(&self) -> bool {
self.present
}
fn clear_accessed(&mut self) {
self.accessed = false;
}
fn clear_dirty(&mut self) {
self.dirty = false;
}
fn set_writable(&mut self, value: bool) {
self.writable = value;
}
fn set_present(&mut self, value: bool) {
self.present = value;
}
fn target(&self) -> usize {
self.target
}
fn set_target(&mut self, target: usize) {
self.target = target;
}
fn writable_shared(&self) -> bool {
self.writable_shared
}
fn readonly_shared(&self) -> bool {
self.readonly_shared
}
fn set_shared(&mut self, writable: bool) {
self.writable_shared = writable;
self.readonly_shared = !writable;
@ -51,20 +75,36 @@ impl Entry for MockEntry {
self.writable_shared = false;
self.readonly_shared = false;
}
fn swapped(&self) -> bool { self.swapped }
fn set_swapped(&mut self, value: bool) { self.swapped = value; }
fn user(&self) -> bool { unimplemented!() }
fn set_user(&mut self, _value: bool) { unimplemented!() }
fn execute(&self) -> bool { unimplemented!() }
fn set_execute(&mut self, _value: bool) { unimplemented!() }
fn mmio(&self) -> u8 { unimplemented!() }
fn set_mmio(&mut self, _value: u8) { unimplemented!() }
fn swapped(&self) -> bool {
self.swapped
}
fn set_swapped(&mut self, value: bool) {
self.swapped = value;
}
fn user(&self) -> bool {
unimplemented!()
}
fn set_user(&mut self, _value: bool) {
unimplemented!()
}
fn execute(&self) -> bool {
unimplemented!()
}
fn set_execute(&mut self, _value: bool) {
unimplemented!()
}
fn mmio(&self) -> u8 {
unimplemented!()
}
fn set_mmio(&mut self, _value: u8) {
unimplemented!()
}
}
type PageFaultHandler = Box<FnMut(&mut MockPageTable, VirtAddr)>;
impl PageTable for MockPageTable {
// type Entry = MockEntry;
// type Entry = MockEntry;
fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Entry {
let entry = &mut self.entries[addr / PAGE_SIZE];
@ -82,10 +122,10 @@ impl PageTable for MockPageTable {
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Entry> {
Some(&mut self.entries[addr / PAGE_SIZE])
}
fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
self._read(addr);
let pa = self.translate(addr) & !(PAGE_SIZE - 1);
let data = unsafe{ &mut *(&mut self.data as *mut [u8; PAGE_SIZE * PAGE_COUNT])};
let data = unsafe { &mut *(&mut self.data as *mut [u8; PAGE_SIZE * PAGE_COUNT]) };
&mut data[pa..pa + PAGE_SIZE]
}
fn read(&mut self, addr: usize) -> u8 {
@ -100,9 +140,9 @@ impl PageTable for MockPageTable {
impl MockPageTable {
/*
** @brief create a new MockPageTable
** @retval MockPageTable the mock page table created
*/
** @brief create a new MockPageTable
** @retval MockPageTable the mock page table created
*/
pub fn new() -> Self {
use core::mem::uninitialized;
MockPageTable {
@ -112,21 +152,21 @@ impl MockPageTable {
}
}
/*
** @brief set the page fault handler
** used for mock the page fault feature
** @param page_fault_handler: PageFaultHandler
** the page fault handler
** @retval none
*/
** @brief set the page fault handler
** used for mock the page fault feature
** @param page_fault_handler: PageFaultHandler
** the page fault handler
** @retval none
*/
pub fn set_handler(&mut self, page_fault_handler: PageFaultHandler) {
self.page_fault_handler = Some(page_fault_handler);
}
/*
** @brief trigger page fault
** used for mock the page fault feature
** @param addr: VirtAddr the virtual address used to trigger the page fault
** @retval none
*/
** @brief trigger page fault
** used for mock the page fault feature
** @param addr: VirtAddr the virtual address used to trigger the page fault
** @retval none
*/
fn trigger_page_fault(&mut self, addr: VirtAddr) {
// In order to call the handler with &mut self as an argument
// We have to first take the handler out of self, finally put it back
@ -135,11 +175,11 @@ impl MockPageTable {
self.page_fault_handler = Some(handler);
}
/*
** @brief translate virtual address to physics address
** used for mock address translation feature
** @param addr: VirtAddr the virtual address to translation
** @retval PhysAddr the translation result
*/
** @brief translate virtual address to physics address
** used for mock address translation feature
** @param addr: VirtAddr the virtual address to translation
** @retval PhysAddr the translation result
*/
fn translate(&self, addr: VirtAddr) -> PhysAddr {
let entry = &self.entries[addr / PAGE_SIZE];
assert!(entry.present);
@ -148,11 +188,11 @@ impl MockPageTable {
pa
}
/*
** @brief attempt to read the virtual address
** trigger page fault when failed
** @param addr: VirtAddr the virual address of data to read
** @retval none
*/
** @brief attempt to read the virtual address
** trigger page fault when failed
** @param addr: VirtAddr the virual address of data to read
** @retval none
*/
fn _read(&mut self, addr: VirtAddr) {
while !self.entries[addr / PAGE_SIZE].present {
self.trigger_page_fault(addr);
@ -160,11 +200,11 @@ impl MockPageTable {
self.entries[addr / PAGE_SIZE].accessed = true;
}
/*
** @brief attempt to write the virtual address
** trigger page fault when failed
** @param addr: VirtAddr the virual address of data to write
** @retval none
*/
** @brief attempt to write the virtual address
** trigger page fault when failed
** @param addr: VirtAddr the virual address of data to write
** @retval none
*/
fn _write(&mut self, addr: VirtAddr) {
while !(self.entries[addr / PAGE_SIZE].present && self.entries[addr / PAGE_SIZE].writable) {
self.trigger_page_fault(addr);
@ -255,4 +295,4 @@ mod test {
pt.read(0);
assert_eq!(*page_fault_count.borrow(), 2);
}
}
}

@ -2,18 +2,17 @@
//!
//! Implemented for every architecture, used by OS.
use super::*;
pub use self::ext::*;
#[cfg(test)]
pub use self::mock_page_table::MockPageTable;
pub use self::ext::*;
use super::*;
mod ext;
#[cfg(test)]
mod mock_page_table;
mod ext;
pub trait PageTable {
// type Entry: Entry;
// type Entry: Entry;
/// Map a page of virual address `addr` to the frame of physics address `target`
/// Return the page table entry of the mapped virual address

@ -1,11 +1,10 @@
//! Implememnt the swap manager with the FIFO page replacement algorithm
use alloc::collections::VecDeque;
use super::*;
use alloc::collections::VecDeque;
#[derive(Default)]
pub struct FifoSwapManager {
pub struct FifoSwapManager {
deque: VecDeque<Frame>,
}
@ -13,22 +12,29 @@ impl SwapManager for FifoSwapManager {
fn tick(&mut self) {}
fn push(&mut self, frame: Frame) {
info!("SwapManager push token: {:x?} vaddr: {:x?}", frame.get_token(), frame.get_virtaddr());
info!(
"SwapManager push token: {:x?} vaddr: {:x?}",
frame.get_token(),
frame.get_virtaddr()
);
self.deque.push_back(frame);
}
fn remove(&mut self, token: usize, addr: VirtAddr) {
info!("SwapManager remove token: {:x?} vaddr: {:x?}", token, addr);
let id = self.deque.iter()
let id = self
.deque
.iter()
.position(|ref x| x.get_virtaddr() == addr && x.get_token() == token)
.expect("address not found");
self.deque.remove(id);
//info!("SwapManager remove token finished: {:x?} vaddr: {:x?}", token, addr);
}
fn pop<T, S>(&mut self, _: &mut T, _: &mut S) -> Option<Frame>
where T: PageTable, S: Swapper
where
T: PageTable,
S: Swapper,
{
self.deque.pop_front()
}
@ -56,4 +62,4 @@ mod test {
test_manager(FifoSwapManager::default(), &ops, &pgfault_count);
}
}
*/
*/

@ -17,7 +17,7 @@ pub struct MockSwapper {
impl Swapper for MockSwapper {
fn swap_out(&mut self, data: &[u8]) -> Result<usize, ()> {
let id = self.alloc_id();
let mut slice: [u8; PAGE_SIZE] = unsafe{ uninitialized() };
let mut slice: [u8; PAGE_SIZE] = unsafe { uninitialized() };
slice.copy_from_slice(data);
self.map.insert(id, slice);
Ok(id)
@ -27,7 +27,7 @@ impl Swapper for MockSwapper {
if !self.map.contains_key(&token) {
return Err(());
}
let mut slice: [u8; PAGE_SIZE] = unsafe{ uninitialized() };
let mut slice: [u8; PAGE_SIZE] = unsafe { uninitialized() };
slice.copy_from_slice(data);
self.map.insert(token, slice);
Ok(())
@ -43,11 +43,11 @@ impl Swapper for MockSwapper {
impl MockSwapper {
/*
** @brief allocate an unused id for location on the mock device
** @retval usize the allocated location id
*/
** @brief allocate an unused id for location on the mock device
** @retval usize the allocated location id
*/
fn alloc_id(&self) -> usize {
(0 .. 100usize).find(|i| !self.map.contains_key(i)).unwrap()
(0..100usize).find(|i| !self.map.contains_key(i)).unwrap()
}
}
@ -64,8 +64,8 @@ mod test {
#[test]
fn swap_out_in() {
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
let data1: [u8; 4096] = unsafe{ uninitialized() };
let mut data: [u8; 4096] = unsafe { uninitialized() };
let data1: [u8; 4096] = unsafe { uninitialized() };
let token = swapper.swap_out(&data1).unwrap();
swapper.swap_in(token, &mut data).unwrap();
assert_data_eq(&data, &data1);
@ -74,9 +74,9 @@ mod test {
#[test]
fn swap_update() {
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
let data1: [u8; 4096] = unsafe{ uninitialized() };
let data2: [u8; 4096] = unsafe{ uninitialized() };
let mut data: [u8; 4096] = unsafe { uninitialized() };
let data1: [u8; 4096] = unsafe { uninitialized() };
let data2: [u8; 4096] = unsafe { uninitialized() };
let token = swapper.swap_out(&data1).unwrap();
swapper.swap_update(token, &data2).unwrap();
swapper.swap_in(token, &mut data).unwrap();
@ -86,7 +86,7 @@ mod test {
#[test]
fn invalid_token() {
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
let mut data: [u8; 4096] = unsafe { uninitialized() };
assert_eq!(swapper.swap_in(0, &mut data), Err(()));
}
}
}

@ -6,9 +6,9 @@
//! Invoke page_fault_handler() on the SwapExt to run the swap process
//! If the method above returns true, a page is swapped in, else do your own things.
use super::*;
use super::paging::*;
use super::addr::Frame;
use super::paging::*;
use super::*;
use core::ops::{Deref, DerefMut};
//pub use self::fifo::FifoSwapManager;
@ -24,58 +24,60 @@ pub mod mock_swapper;
pub trait SwapManager {
//type Inactive: InactivePageTable;
/*
** @brief update intarnal state pre tick
** Called when tick interrupt occured
** @retval none
*/
** @brief update intarnal state pre tick
** Called when tick interrupt occured
** @retval none
*/
fn tick(&mut self);
/*
** @brief update intarnal state when page is pushed into memory
** Called when map a swappable page into the memory
** @param frame: Frame the Frame recording the swappable frame info
** @retval none
*/
** @brief update intarnal state when page is pushed into memory
** Called when map a swappable page into the memory
** @param frame: Frame the Frame recording the swappable frame info
** @retval none
*/
fn push(&mut self, frame: Frame);
/*
** @brief update intarnal state when page is removed from memory
** Called to delete the addr entry from the swap manager
** @param token: usize the inactive page table token for the virtual address
** @param addr: VirtAddr the virual address of the page removed from memory
** @retval none
*/
** @brief update intarnal state when page is removed from memory
** Called to delete the addr entry from the swap manager
** @param token: usize the inactive page table token for the virtual address
** @param addr: VirtAddr the virual address of the page removed from memory
** @retval none
*/
fn remove(&mut self, token: usize, addr: VirtAddr);
/*
** @brief select swap out victim when there is need to swap out a page
** (The params is only used by `EnhancedClockSwapManager` currently)
** @param page_table: &mut T the current page table
** @param swapper: &mut S the swapper used
** @retval Option<Frame> the Frame of the victim page, if present
*/
** @brief select swap out victim when there is need to swap out a page
** (The params is only used by `EnhancedClockSwapManager` currently)
** @param page_table: &mut T the current page table
** @param swapper: &mut S the swapper used
** @retval Option<Frame> the Frame of the victim page, if present
*/
fn pop<T, S>(&mut self, page_table: &mut T, swapper: &mut S) -> Option<Frame>
where T: PageTable, S: Swapper;
where
T: PageTable,
S: Swapper;
}
/// Implement swap in & out execution
pub trait Swapper {
/*
** @brief Allocate space on device and write data to it
** @param data: &[u8] the data to write to the device
** @retval Result<usize, ()> the execute result, and a token indicating the location on the device if success
*/
** @brief Allocate space on device and write data to it
** @param data: &[u8] the data to write to the device
** @retval Result<usize, ()> the execute result, and a token indicating the location on the device if success
*/
fn swap_out(&mut self, data: &[u8]) -> Result<usize, ()>;
/*
** @brief Update data on device.
** @param token: usize the token indicating the location on the device
** @param data: &[u8] the data to overwrite on the device
** @retval Result<(), ()> the execute result
*/
** @brief Update data on device.
** @param token: usize the token indicating the location on the device
** @param data: &[u8] the data to overwrite on the device
** @retval Result<(), ()> the execute result
*/
fn swap_update(&mut self, token: usize, data: &[u8]) -> Result<(), ()>;
/*
** @brief Recover data from device and deallocate the space.
** @param token: usize the token indicating the location on the device
** @param data: &mut [u8] the reference to data in the space in memory
** @retval Result<(), ()> the execute result
*/
** @brief Recover data from device and deallocate the space.
** @param token: usize the token indicating the location on the device
** @param data: &mut [u8] the reference to data in the space in memory
** @retval Result<(), ()> the execute result
*/
fn swap_in(&mut self, token: usize, data: &mut [u8]) -> Result<(), ()>;
}
@ -88,12 +90,12 @@ pub struct SwapExt<T: PageTable, M: SwapManager, S: Swapper> {
impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
/*
** @brief create a swap extension
** @param page_table: T the inner page table
** @param swap_manager: M the SwapManager used
** @param swapper: S the Swapper used
** @retval SwapExt the swap extension created
*/
** @brief create a swap extension
** @param page_table: T the inner page table
** @param swap_manager: M the SwapManager used
** @param swapper: S the Swapper used
** @retval SwapExt the swap extension created
*/
pub fn new(page_table: T, swap_manager: M, swapper: S) -> Self {
SwapExt {
page_table,
@ -103,19 +105,29 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
}
/*
** @brief set a page swappable
** @param pt: *mut T2 the raw pointer for the target page's inactive page table
** @param addr: VirtAddr the target page's virtual address
*/
pub unsafe fn set_swappable<T2: InactivePageTable>(&mut self, pt: *mut T2, addr: VirtAddr){
let Self {ref mut page_table, ref mut swap_manager, ..} = self;
** @brief set a page swappable
** @param pt: *mut T2 the raw pointer for the target page's inactive page table
** @param addr: VirtAddr the target page's virtual address
*/
pub unsafe fn set_swappable<T2: InactivePageTable>(&mut self, pt: *mut T2, addr: VirtAddr) {
let Self {
ref mut page_table,
ref mut swap_manager,
..
} = self;
let targetpt = &mut *(pt);
let pttoken = {
info!("SET_SWAPPABLE: the target page table token is {:x?}, addr is {:x?}", targetpt.token(), addr);
info!(
"SET_SWAPPABLE: the target page table token is {:x?}, addr is {:x?}",
targetpt.token(),
addr
);
targetpt.token()
};
targetpt.with(||{
let entry = page_table.get_entry(addr).expect("failed to get page entry when set swappable");
targetpt.with(|| {
let entry = page_table
.get_entry(addr)
.expect("failed to get page entry when set swappable");
if entry.present() {
let frame = Frame::new(pt as usize, addr, pttoken);
swap_manager.push(frame);
@ -131,25 +143,38 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
}
/*
** @brief remove a page (given virtual address) from swappable pages, if the page is swapped, swap in at first
** @param pt: *mut T2 the raw pointer for the target page's inactive page table
** @param addr: VirtAddr the target page's virtual address
** @param alloc_frame: the function to alloc a free physical frame for once
*/
pub unsafe fn remove_from_swappable<T2: InactivePageTable>(&mut self, pt: *mut T2, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr){
** @brief remove a page (given virtual address) from swappable pages, if the page is swapped, swap in at first
** @param pt: *mut T2 the raw pointer for the target page's inactive page table
** @param addr: VirtAddr the target page's virtual address
** @param alloc_frame: the function to alloc a free physical frame for once
*/
pub unsafe fn remove_from_swappable<T2: InactivePageTable>(
&mut self,
pt: *mut T2,
addr: VirtAddr,
alloc_frame: impl FnOnce() -> PhysAddr,
) {
//info!("come into remove_from swappable");
let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self;
let Self {
ref mut page_table,
ref mut swap_manager,
ref mut swapper,
} = self;
let targetpt = &mut *(pt);
let pttoken = {
info!("SET_UNSWAPPABLE: the target page table token is {:x?}, addr is {:x?}", targetpt.token(), addr);
info!(
"SET_UNSWAPPABLE: the target page table token is {:x?}, addr is {:x?}",
targetpt.token(),
addr
);
targetpt.token()
};
//info!("try to change pagetable");
targetpt.with(||{
targetpt.with(|| {
let token = {
let entry = page_table.get_entry(addr).unwrap();
if !entry.swapped() {
if entry.present(){
if entry.present() {
// if the addr isn't indicating a swapped page, panic occured here
swap_manager.remove(pttoken, addr);
}
@ -171,11 +196,11 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
}
/*
** @brief map the virtual address to a target physics address as swappable
** @param addr: VirtAddr the virual address to map
** @param target: VirtAddr the target physics address
** @retval none
*/
** @brief map the virtual address to a target physics address as swappable
** @param addr: VirtAddr the virual address to map
** @param target: VirtAddr the target physics address
** @retval none
*/
/*
pub fn map_to_swappable(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut T::Entry {
self.swap_manager.push(addr);
@ -183,15 +208,19 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
}*/
/*
** @brief Swap out any one of the swapped pages
** @retval Result<PhysAddr, SwapError>
** the physics address of released frame if success,
** the error if failed
*/
** @brief Swap out any one of the swapped pages
** @retval Result<PhysAddr, SwapError>
** the physics address of released frame if success,
** the error if failed
*/
pub fn swap_out_any<T2: InactivePageTable>(&mut self) -> Result<PhysAddr, SwapError> {
info!("COME in to swap_out_any");
let victim: Option<Frame> = {
let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self;
let Self {
ref mut page_table,
ref mut swap_manager,
ref mut swapper,
} = self;
swap_manager.pop(page_table, swapper)
};
info!("swap out page {}", victim.unwrap().get_virtaddr());
@ -202,21 +231,26 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
}
/*
** @brief Swap out page
** @param frame: Frame the Frame of page recording the page info
** @retval Result<PhysAddr, SwapError>
** the physics address of the original map target frame if success,
** the error if failed
*/
** @brief Swap out page
** @param frame: Frame the Frame of page recording the page info
** @retval Result<PhysAddr, SwapError>
** the physics address of the original map target frame if success,
** the error if failed
*/
fn swap_out<T2: InactivePageTable>(&mut self, frame: &Frame) -> Result<PhysAddr, SwapError> {
let Self {ref mut page_table, ref mut swapper, ..} = self;
let ret = unsafe{
let Self {
ref mut page_table,
ref mut swapper,
..
} = self;
let ret = unsafe {
let pt = &mut *(frame.get_page_table() as *mut T2);
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);
@ -235,16 +269,23 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
ret
}
/*
** @brief map the virtual address to a target physics address and then swap in page data, noted that the page should be in the current page table
** @param pt: *mut T2 the raw pointer for the swapping page's inactive page table
** @param addr: VirtAddr the virual address of beginning of page
** @param target: PhysAddr the target physics address
** @retval Result<()), SwapError>
** the execute result, and the error if failed
*/
fn swap_in<T2: InactivePageTable>(&mut self, pt: *mut T2, addr: VirtAddr, target: PhysAddr) -> Result<(), SwapError> {
** @brief map the virtual address to a target physics address and then swap in page data, noted that the page should be in the current page table
** @param pt: *mut T2 the raw pointer for the swapping page's inactive page table
** @param addr: VirtAddr the virual address of beginning of page
** @param target: PhysAddr the target physics address
** @retval Result<()), SwapError>
** the execute result, and the error if failed
*/
fn swap_in<T2: InactivePageTable>(
&mut self,
pt: *mut T2,
addr: VirtAddr,
target: PhysAddr,
) -> Result<(), SwapError> {
info!("come in to swap in");
let entry = self.page_table.get_entry(addr)
let entry = self
.page_table
.get_entry(addr)
.ok_or(SwapError::NotMapped)?;
if !entry.swapped() {
return Err(SwapError::NotSwapped);
@ -255,32 +296,38 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
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{
(*pt).token()
};
self.swapper
.swap_in(token, data)
.map_err(|_| SwapError::IOError)?;
let pttoken = unsafe { (*pt).token() };
let frame = Frame::new(pt as usize, addr, pttoken);
;
self.swap_manager.push(frame);
Ok(())
}
/*
** @brief execute the frame delayed allocate and swap process for page fault
** 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 alloc_frame: impl FnOnce() -> PhysAddr
** the page allocation function
** that allocate a page and returns physics address
** of beginning of the page
** @retval bool whether swap in happens.
*/
pub fn page_fault_handler<T2: InactivePageTable>(&mut self, pt: *mut T2, addr: VirtAddr, swapin: bool, alloc_frame: impl FnOnce() -> PhysAddr) -> bool {
** @brief execute the frame delayed allocate and swap process for page fault
** 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 alloc_frame: impl FnOnce() -> PhysAddr
** the page allocation function
** that allocate a page and returns physics address
** of beginning of the page
** @retval bool whether swap in happens.
*/
pub fn page_fault_handler<T2: InactivePageTable>(
&mut self,
pt: *mut T2,
addr: VirtAddr,
swapin: bool,
alloc_frame: impl FnOnce() -> PhysAddr,
) -> bool {
// handle page delayed allocating
{
info!("try handling delayed frame allocator");
let need_alloc ={
let need_alloc = {
let entry = self.page_table.get_entry(addr).expect("fail to get entry");
//info!("got entry!");
!entry.present() && !entry.swapped()
@ -311,7 +358,11 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
match self.page_table.get_entry(addr) {
// infact the get_entry(addr) should not be None here
None => return false,
Some(entry) => if !entry.swapped() { return false; },
Some(entry) => {
if !entry.swapped() {
return false;
}
}
}
// Allocate a frame, if failed, swap out a page
let frame = alloc_frame();
@ -411,4 +462,4 @@ mod test {
}
}
}
*/
*/

@ -1,9 +1,9 @@
//! entrance to test the communication in processes with solving five philosophers problem
mod mutex;
mod monitor;
mod mutex;
fn main() {
// mutex::main();
// mutex::main();
monitor::main();
}
}

@ -1,7 +1,7 @@
//! solve the five philosophers problem with monitor
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use std::sync::{Mutex, Condvar, Arc};
use std::time::Duration;
struct Philosopher {
@ -57,7 +57,13 @@ struct Table {
pub fn main() {
let table = Arc::new(Table {
fork_status: Mutex::new(vec![false; 5]),
fork_condvar: vec![Condvar::new(), Condvar::new(), Condvar::new(), Condvar::new(), Condvar::new()],
fork_condvar: vec![
Condvar::new(),
Condvar::new(),
Condvar::new(),
Condvar::new(),
Condvar::new(),
],
});
let philosophers = vec![
@ -68,18 +74,21 @@ pub fn main() {
Philosopher::new("5", 0, 4),
];
let handles: Vec<_> = philosophers.into_iter().map(|p| {
let table = table.clone();
let handles: Vec<_> = philosophers
.into_iter()
.map(|p| {
let table = table.clone();
thread::spawn(move || {
for _ in 0..5 {
p.think();
p.eat(&table);
}
thread::spawn(move || {
for _ in 0..5 {
p.think();
p.eat(&table);
}
})
})
}).collect();
.collect();
for h in handles {
h.join().unwrap();
}
}
}

@ -1,7 +1,7 @@
//! solve the five philosophers problem with mutex
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::{Mutex, Arc};
use std::time::Duration;
struct Philosopher {
@ -46,7 +46,7 @@ pub fn main() {
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
]
],
});
let philosophers = vec![
@ -57,18 +57,21 @@ pub fn main() {
Philosopher::new("5", 0, 4),
];
let handles: Vec<_> = philosophers.into_iter().map(|p| {
let table = table.clone();
let handles: Vec<_> = philosophers
.into_iter()
.map(|p| {
let table = table.clone();
thread::spawn(move || {
for _ in 0..5 {
p.think();
p.eat(&table);
}
thread::spawn(move || {
for _ in 0..5 {
p.think();
p.eat(&table);
}
})
})
}).collect();
.collect();
for h in handles {
h.join().unwrap();
}
}
}

@ -1,2 +1 @@
fn main() {
}
fn main() {}

@ -8,12 +8,12 @@
extern crate alloc;
mod thread_pool;
mod interrupt;
mod processor;
pub mod scheduler;
pub mod std_thread;
mod thread_pool;
mod timer;
mod interrupt;
pub use crate::thread_pool::*;
pub use crate::processor::Processor;
pub use crate::thread_pool::*;

@ -1,9 +1,9 @@
use crate::interrupt;
use crate::thread_pool::*;
use alloc::boxed::Box;
use alloc::sync::Arc;
use log::*;
use core::cell::UnsafeCell;
use crate::thread_pool::*;
use crate::interrupt;
use log::*;
/// Thread executor
///
@ -25,7 +25,9 @@ struct ProcessorInner {
impl Processor {
pub const fn new() -> Self {
Processor { inner: UnsafeCell::new(None) }
Processor {
inner: UnsafeCell::new(None),
}
}
pub unsafe fn init(&self, id: usize, context: Box<Context>, manager: Arc<ThreadPool>) {
@ -38,7 +40,8 @@ impl Processor {
}
fn inner(&self) -> &mut ProcessorInner {
unsafe { &mut *self.inner.get() }.as_mut()
unsafe { &mut *self.inner.get() }
.as_mut()
.expect("Processor is not initialized")
}
@ -51,22 +54,30 @@ impl Processor {
/// via switch back to the scheduler.
pub fn run(&self) -> ! {
let inner = self.inner();
unsafe { interrupt::disable_and_store(); }
unsafe {
interrupt::disable_and_store();
}
loop {
if let Some(proc) = inner.manager.run(inner.id) {
trace!("CPU{} begin running thread {}", inner.id, proc.0);
inner.proc = Some(proc);
unsafe {
inner.loop_context.switch_to(&mut *inner.proc.as_mut().unwrap().1);
inner
.loop_context
.switch_to(&mut *inner.proc.as_mut().unwrap().1);
}
let (tid, context) = inner.proc.take().unwrap();
trace!("CPU{} stop running thread {}", inner.id, tid);
inner.manager.stop(tid, context);
} else {
trace!("CPU{} idle", inner.id);
unsafe { interrupt::enable_and_wfi(); }
unsafe {
interrupt::enable_and_wfi();
}
// wait for a timer interrupt
unsafe { interrupt::disable_and_store(); }
unsafe {
interrupt::disable_and_store();
}
}
}
}
@ -79,7 +90,12 @@ impl Processor {
let inner = self.inner();
unsafe {
let flags = interrupt::disable_and_store();
inner.proc.as_mut().unwrap().1.switch_to(&mut *inner.loop_context);
inner
.proc
.as_mut()
.unwrap()
.1
.switch_to(&mut *inner.loop_context);
interrupt::restore(flags);
}
}

@ -36,7 +36,9 @@ impl RRScheduler {
max_time_slice,
infos: Vec::default(),
};
RRScheduler { inner: Mutex::new(inner) }
RRScheduler {
inner: Mutex::new(inner),
}
}
}
@ -63,7 +65,7 @@ impl RRSchedulerInner {
self.infos[tid].present = false;
self._list_remove(tid);
Some(tid - 1)
},
}
};
trace!("rr pop {:?}", ret);
ret

@ -1,5 +1,5 @@
//! Stride scheduler
//!
//!
//! Each task is assigned a priority. Each task has a running stride.
//! The task with least stride is selected to run.
//! When a task is rescheduled, its stride is added to proportional to 1 / priority.
@ -62,7 +62,9 @@ impl StrideScheduler {
infos: Vec::default(),
queue: BinaryHeap::default(),
};
StrideScheduler { inner: Mutex::new(inner) }
StrideScheduler {
inner: Mutex::new(inner),
}
}
}

@ -6,12 +6,12 @@
//! - `processor`: Get a reference of the current `Processor`
//! - `new_kernel_context`: Construct a `Context` of the new kernel thread
use crate::processor::*;
use crate::thread_pool::*;
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::time::Duration;
use log::*;
use crate::processor::*;
use crate::thread_pool::*;
#[linkage = "weak"]
#[no_mangle]
@ -23,14 +23,15 @@ fn processor() -> &'static Processor {
#[linkage = "weak"]
#[no_mangle]
/// Construct a `Context` of the new kernel thread
fn new_kernel_context(_entry: extern fn(usize) -> !, _arg: usize) -> Box<Context> {
fn new_kernel_context(_entry: extern "C" fn(usize) -> !, _arg: usize) -> Box<Context> {
unimplemented!("thread: Please implement and export `new_kernel_context`")
}
/// Gets a handle to the thread that invokes it.
pub fn current() -> Thread {
Thread { tid: processor().tid() }
Thread {
tid: processor().tid(),
}
}
/// Puts the current thread to sleep for the specified amount of time.
@ -50,9 +51,9 @@ pub fn sleep(dur: Duration) {
/// `F`: Type of the function `f`
/// `T`: Type of the return value of `f`
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
{
trace!("spawn:");
@ -69,10 +70,10 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
//
// 注意到它具有泛型参数因此对每一次spawn调用
// 由于F类型是独特的因此都会生成一个新的kernel_thread_entry
extern fn kernel_thread_entry<F, T>(f: usize) -> !
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
extern "C" fn kernel_thread_entry<F, T>(f: usize) -> !
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
{
// 在静态函数内部:
// 根据传进来的指针恢复f

@ -1,9 +1,9 @@
use crate::scheduler::Scheduler;
use crate::timer::Timer;
use alloc::boxed::Box;
use alloc::vec::Vec;
use spin::{Mutex, MutexGuard};
use log::*;
use crate::scheduler::Scheduler;
use crate::timer::Timer;
use spin::{Mutex, MutexGuard};
struct Thread {
status: Status,
@ -105,13 +105,12 @@ impl ThreadPool {
/// The manager first mark it `Running`,
/// then take out and return its Context.
pub(crate) fn run(&self, cpu_id: usize) -> Option<(Tid, Box<Context>)> {
self.scheduler.pop(cpu_id)
.map(|tid| {
let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("thread not exist");
proc.status = Status::Running(cpu_id);
(tid, proc.context.take().expect("context not exist"))
})
self.scheduler.pop(cpu_id).map(|tid| {
let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("thread not exist");
proc.status = Status::Running(cpu_id);
(tid, proc.context.take().expect("context not exist"))
})
}
/// Called by Processor to finish running a thread
@ -150,7 +149,7 @@ impl ThreadPool {
(Status::Ready, _) => panic!("can not remove a thread from ready queue"),
(Status::Exited(_), _) => panic!("can not set status for a exited thread"),
(Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)),
(Status::Running(_), Status::Ready) => {} // thread will be added to scheduler in stop()
(Status::Running(_), Status::Ready) => {} // thread will be added to scheduler in stop()
(_, Status::Ready) => self.scheduler.push(tid),
_ => {}
}
@ -175,7 +174,7 @@ impl ThreadPool {
// release the tid
*proc_lock = None;
Some(code)
},
}
_ => None,
}
}

@ -45,7 +45,7 @@ impl<T: PartialEq> Timer<T> {
let time = self.tick + time_after;
let event = Event { time, data };
let mut it = self.timers.iter();
let mut i : usize = 0;
let mut i: usize = 0;
loop {
match it.next() {
None => break,
@ -62,4 +62,4 @@ impl<T: PartialEq> Timer<T> {
self.timers.remove(i);
}
}
}
}

@ -4,46 +4,43 @@ use std::fs::File;
use std::io::{Result, Write};
fn main() {
println!("cargo:rerun-if-env-changed=LOG");
println!("cargo:rerun-if-env-changed=BOARD");
println!("cargo:rerun-if-env-changed=SFSIMG");
println!("cargo:rerun-if-env-changed=LOG");
println!("cargo:rerun-if-env-changed=BOARD");
println!("cargo:rerun-if-env-changed=SFSIMG");
let arch: String = std::env::var("ARCH").unwrap();
let board: String = std::env::var("BOARD").unwrap();
match arch.as_str() {
"x86_64" => {
gen_vector_asm().unwrap();
}
"riscv32" => {
}
"riscv64" => {
}
"aarch64" => {
}
_ => panic!("Unknown arch {}", arch),
}
let arch: String = std::env::var("ARCH").unwrap();
let board: String = std::env::var("BOARD").unwrap();
match arch.as_str() {
"x86_64" => {
gen_vector_asm().unwrap();
}
"riscv32" => {}
"riscv64" => {}
"aarch64" => {}
_ => panic!("Unknown arch {}", arch),
}
}
fn gen_vector_asm() -> Result<()> {
let mut f = File::create("src/arch/x86_64/interrupt/vector.asm").unwrap();
let mut f = File::create("src/arch/x86_64/interrupt/vector.asm").unwrap();
writeln!(f, "# generated by build.rs - do not edit")?;
writeln!(f, ".section .text")?;
writeln!(f, ".intel_syntax noprefix")?;
for i in 0..256 {
writeln!(f, "vector{}:", i)?;
if !(i == 8 || (i >= 10 && i <= 14) || i == 17) {
writeln!(f, "\tpush 0")?;
}
writeln!(f, "\tpush {}", i)?;
writeln!(f, "\tjmp __alltraps")?;
}
writeln!(f, "# generated by build.rs - do not edit")?;
writeln!(f, ".section .text")?;
writeln!(f, ".intel_syntax noprefix")?;
for i in 0..256 {
writeln!(f, "vector{}:", i)?;
if !(i == 8 || (i >= 10 && i <= 14) || i == 17) {
writeln!(f, "\tpush 0")?;
}
writeln!(f, "\tpush {}", i)?;
writeln!(f, "\tjmp __alltraps")?;
}
writeln!(f, "\n.section .rodata")?;
writeln!(f, ".global __vectors")?;
writeln!(f, "__vectors:")?;
for i in 0..256 {
writeln!(f, "\t.quad vector{}", i)?;
}
Ok(())
writeln!(f, "\n.section .rodata")?;
writeln!(f, ".global __vectors")?;
writeln!(f, "__vectors:")?;
for i in 0..256 {
writeln!(f, "\t.quad vector{}", i)?;
}
Ok(())
}

@ -57,16 +57,10 @@ impl ColorBuffer {
unsafe {
match color_depth {
ColorDepth16 => ColorBuffer {
buf16: core::slice::from_raw_parts_mut(
base_addr as *mut u16,
size / 2,
),
buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2),
},
ColorDepth32 => ColorBuffer {
buf32: core::slice::from_raw_parts_mut(
base_addr as *mut u32,
size / 4,
),
buf32: core::slice::from_raw_parts_mut(base_addr as *mut u32, size / 4),
},
}
}

@ -3,12 +3,12 @@
//! (ref: https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface)
use super::fb::FramebufferInfo;
use bcm2837::mailbox::{Mailbox, MailboxChannel};
use lazy_static::lazy_static;
use aarch64::asm;
use alloc::string::String;
use bcm2837::mailbox::{Mailbox, MailboxChannel};
use core::mem;
use lazy_static::lazy_static;
use spin::Mutex;
use aarch64::asm;
lazy_static! {
static ref MAILBOX: Mutex<Mailbox> = Mutex::new(Mailbox::new());
@ -33,7 +33,7 @@ impl From<PropertyMailboxError> for String {
enum PropertyMailboxStatus {
RPI_FIRMWARE_STATUS_REQUEST = 0,
RPI_FIRMWARE_STATUS_SUCCESS = 0x80000000,
RPI_FIRMWARE_STATUS_ERROR = 0x80000001,
RPI_FIRMWARE_STATUS_ERROR = 0x80000001,
}
use self::PropertyMailboxStatus::*;
@ -44,104 +44,104 @@ use self::PropertyMailboxStatus::*;
#[derive(Copy, Clone, Debug)]
#[allow(non_camel_case_types)]
enum PropertyMailboxTagId {
RPI_FIRMWARE_PROPERTY_END = 0,
RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
RPI_FIRMWARE_PROPERTY_END = 0,
RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
RPI_FIRMWARE_GET_BOARD_MODEL = 0x00010001,
RPI_FIRMWARE_GET_BOARD_REVISION = 0x00010002,
RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 0x00010003,
RPI_FIRMWARE_GET_BOARD_SERIAL = 0x00010004,
RPI_FIRMWARE_GET_ARM_MEMORY = 0x00010005,
RPI_FIRMWARE_GET_VC_MEMORY = 0x00010006,
RPI_FIRMWARE_GET_CLOCKS = 0x00010007,
RPI_FIRMWARE_GET_POWER_STATE = 0x00020001,
RPI_FIRMWARE_GET_TIMING = 0x00020002,
RPI_FIRMWARE_SET_POWER_STATE = 0x00028001,
RPI_FIRMWARE_GET_CLOCK_STATE = 0x00030001,
RPI_FIRMWARE_GET_CLOCK_RATE = 0x00030002,
RPI_FIRMWARE_GET_VOLTAGE = 0x00030003,
RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 0x00030004,
RPI_FIRMWARE_GET_MAX_VOLTAGE = 0x00030005,
RPI_FIRMWARE_GET_TEMPERATURE = 0x00030006,
RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 0x00030007,
RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
RPI_FIRMWARE_GET_TURBO = 0x00030009,
RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
RPI_FIRMWARE_GET_STC = 0x0003000b,
RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
RPI_FIRMWARE_RELEASE_MEMORY = 0x0003000f,
RPI_FIRMWARE_EXECUTE_CODE = 0x00030010,
RPI_FIRMWARE_EXECUTE_QPU = 0x00030011,
RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
RPI_FIRMWARE_SET_TURBO = 0x00038009,
RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021,
RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030,
RPI_FIRMWARE_GET_GPIO_STATE = 0x00030041,
RPI_FIRMWARE_SET_GPIO_STATE = 0x00038041,
RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042,
RPI_FIRMWARE_GET_GPIO_CONFIG = 0x00030043,
RPI_FIRMWARE_SET_GPIO_CONFIG = 0x00038043,
RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045,
RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
RPI_FIRMWARE_GET_BOARD_MODEL = 0x00010001,
RPI_FIRMWARE_GET_BOARD_REVISION = 0x00010002,
RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 0x00010003,
RPI_FIRMWARE_GET_BOARD_SERIAL = 0x00010004,
RPI_FIRMWARE_GET_ARM_MEMORY = 0x00010005,
RPI_FIRMWARE_GET_VC_MEMORY = 0x00010006,
RPI_FIRMWARE_GET_CLOCKS = 0x00010007,
RPI_FIRMWARE_GET_POWER_STATE = 0x00020001,
RPI_FIRMWARE_GET_TIMING = 0x00020002,
RPI_FIRMWARE_SET_POWER_STATE = 0x00028001,
RPI_FIRMWARE_GET_CLOCK_STATE = 0x00030001,
RPI_FIRMWARE_GET_CLOCK_RATE = 0x00030002,
RPI_FIRMWARE_GET_VOLTAGE = 0x00030003,
RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 0x00030004,
RPI_FIRMWARE_GET_MAX_VOLTAGE = 0x00030005,
RPI_FIRMWARE_GET_TEMPERATURE = 0x00030006,
RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 0x00030007,
RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
RPI_FIRMWARE_GET_TURBO = 0x00030009,
RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
RPI_FIRMWARE_GET_STC = 0x0003000b,
RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
RPI_FIRMWARE_RELEASE_MEMORY = 0x0003000f,
RPI_FIRMWARE_EXECUTE_CODE = 0x00030010,
RPI_FIRMWARE_EXECUTE_QPU = 0x00030011,
RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
RPI_FIRMWARE_SET_TURBO = 0x00038009,
RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021,
RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030,
RPI_FIRMWARE_GET_GPIO_STATE = 0x00030041,
RPI_FIRMWARE_SET_GPIO_STATE = 0x00038041,
RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042,
RPI_FIRMWARE_GET_GPIO_CONFIG = 0x00030043,
RPI_FIRMWARE_SET_GPIO_CONFIG = 0x00038043,
RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045,
RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
/* Dispmanx TAGS */
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
RPI_FIRMWARE_FRAMEBUFFER_BLANK = 0x00040002,
RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 0x00040005,
RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006,
RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007,
RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 0x00040008,
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
RPI_FIRMWARE_FRAMEBUFFER_BLANK = 0x00040002,
RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 0x00040005,
RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006,
RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007,
RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 0x00040008,
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006,
RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006,
RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
}
use self::PropertyMailboxTagId::*;
@ -268,7 +268,10 @@ pub fn framebuffer_get_depth() -> PropertyMailboxResult<u32> {
/// Set virtual offset. Returns `(X, Y)` in pixel.
/// The response may not be the same as the request so it must be checked.
/// May be the previous offset or 0 for unsupported.
pub fn framebuffer_set_virtual_offset(xoffset: u32, yoffset: u32) -> PropertyMailboxResult<(u32, u32)> {
pub fn framebuffer_set_virtual_offset(
xoffset: u32,
yoffset: u32,
) -> PropertyMailboxResult<(u32, u32)> {
let ret = send_one_tag!(
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET,
[xoffset, yoffset]
@ -278,7 +281,11 @@ pub fn framebuffer_set_virtual_offset(xoffset: u32, yoffset: u32) -> PropertyMai
/// Allocate framebuffer on GPU and try to set width/height/depth.
/// Returns `FramebufferInfo`.
pub fn framebuffer_alloc(width: u32, height: u32, depth: u32) -> PropertyMailboxResult<FramebufferInfo> {
pub fn framebuffer_alloc(
width: u32,
height: u32,
depth: u32,
) -> PropertyMailboxResult<FramebufferInfo> {
#[repr(C, packed)]
#[derive(Debug)]
struct FramebufferAllocTag {

@ -1,13 +1,13 @@
//! Raspberry PI 3 Model B/B+
use once::*;
use bcm2837::atags::Atags;
use once::*;
pub mod fb;
pub mod irq;
pub mod timer;
pub mod serial;
pub mod mailbox;
pub mod serial;
pub mod timer;
pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE;
pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000;

@ -1,8 +1,8 @@
use bcm2837::mini_uart::{MiniUart, MiniUartInterruptId};
use lazy_static::lazy_static;
use core::fmt;
use spin::Mutex;
use lazy_static::lazy_static;
use once::*;
use spin::Mutex;
/// Struct to get a global SerialPort interface
pub struct SerialPort {

File diff suppressed because it is too large Load Diff

@ -10,7 +10,7 @@ use spin::Mutex;
use crate::util::escape_parser::{CharacterAttribute, EscapeParser};
use super::fb::{ColorDepth::*, FRAME_BUFFER, FramebufferInfo};
use super::fb::{ColorDepth::*, FramebufferInfo, FRAME_BUFFER};
use self::color::FramebufferColor;
use self::fonts::{Font, Font8x16};
@ -67,10 +67,7 @@ impl<F: Font> ConsoleBuffer<F> {
ch.attr.foreground.pack16() as u32,
ch.attr.background.pack16() as u32,
),
ColorDepth32 => (
ch.attr.foreground.pack32(),
ch.attr.background.pack32(),
),
ColorDepth32 => (ch.attr.foreground.pack32(), ch.attr.background.pack32()),
};
if ch.attr.reverse {
core::mem::swap(&mut foreground, &mut background);
@ -87,7 +84,10 @@ impl<F: Font> ConsoleBuffer<F> {
};
for y in 0..F::HEIGHT {
for x in 0..F::WIDTH {
let pixel = if y == underline_y || y == strikethrough_y || F::get(ch.ascii_char, x, y) {
let pixel = if y == underline_y
|| y == strikethrough_y
|| F::get(ch.ascii_char, x, y)
{
foreground
} else {
background

@ -1,11 +1,11 @@
//! TrapFrame and context definitions for aarch64.
use spin::Mutex;
use lazy_static::lazy_static;
use aarch64::barrier;
use aarch64::addr::PhysAddr;
use aarch64::paging::PhysFrame;
use aarch64::asm::{tlb_invalidate_all, ttbr_el1_read, ttbr_el1_write_asid};
use aarch64::barrier;
use aarch64::paging::PhysFrame;
use lazy_static::lazy_static;
use spin::Mutex;
#[repr(C)]
#[derive(Default, Debug, Copy, Clone)]
@ -23,7 +23,7 @@ pub struct TrapFrame {
/// 用于在内核栈中构造新线程的中断帧
impl TrapFrame {
fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self {
fn new_kernel_thread(entry: extern "C" fn(usize) -> !, arg: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.x0 = arg;
@ -65,7 +65,7 @@ impl InitStack {
}
}
extern {
extern "C" {
fn __trapret();
}
@ -78,7 +78,10 @@ struct ContextData {
impl ContextData {
fn new() -> Self {
ContextData { lr: __trapret as usize, ..ContextData::default() }
ContextData {
lr: __trapret as usize,
..ContextData::default()
}
}
}
@ -99,7 +102,7 @@ impl Context {
/// Pop all callee-saved registers, then return to the target.
#[naked]
#[inline(never)]
unsafe extern fn __switch(_self_stack: &mut usize, _target_stack: &mut usize) {
unsafe extern "C" fn __switch(_self_stack: &mut usize, _target_stack: &mut usize) {
asm!(
"
mov x10, #-(12 * 8)
@ -144,17 +147,30 @@ impl Context {
}
}
pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, ttbr: usize) -> Self {
pub unsafe fn new_kernel_thread(
entry: extern "C" fn(usize) -> !,
arg: usize,
kstack_top: usize,
ttbr: usize,
) -> Self {
InitStack {
context: ContextData::new(),
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}.push_at(kstack_top, ttbr)
}
.push_at(kstack_top, ttbr)
}
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, _is32: bool, ttbr: usize) -> Self {
pub unsafe fn new_user_thread(
entry_addr: usize,
ustack_top: usize,
kstack_top: usize,
_is32: bool,
ttbr: usize,
) -> Self {
InitStack {
context: ContextData::new(),
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
}.push_at(kstack_top, ttbr)
}
.push_at(kstack_top, ttbr)
}
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, ttbr: usize) -> Self {
InitStack {
@ -164,9 +180,16 @@ impl Context {
tf.x0 = 0;
tf
},
}.push_at(kstack_top, ttbr)
}
.push_at(kstack_top, ttbr)
}
pub unsafe fn new_clone(tf: &TrapFrame, ustack_top: usize, kstack_top: usize, ttbr: usize, tls: usize) -> Self {
pub unsafe fn new_clone(
tf: &TrapFrame,
ustack_top: usize,
kstack_top: usize,
ttbr: usize,
tls: usize,
) -> Self {
InitStack {
context: ContextData::new(),
tf: {
@ -176,14 +199,14 @@ impl Context {
tf.x0 = 0;
tf
},
}.push_at(kstack_top, ttbr)
}
.push_at(kstack_top, ttbr)
}
/// Called at a new user context
/// To get the init TrapFrame in sys_exec
pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.stack_top as *const InitStack)).tf.clone()
}
}
const ASID_MASK: u16 = 0xffff;
@ -199,7 +222,10 @@ struct AsidAllocator(Asid);
impl AsidAllocator {
fn new() -> Self {
AsidAllocator(Asid { value: 0, generation: 1 })
AsidAllocator(Asid {
value: 0,
generation: 1,
})
}
fn alloc(&mut self, old_asid: Asid) -> Asid {

@ -1,8 +1,8 @@
//! Trap handler
use crate::arch::board::irq::handle_irq;
use super::context::TrapFrame;
use super::syndrome::{Fault, Syndrome};
use crate::arch::board::irq::handle_irq;
use aarch64::regs::*;
use log::*;

@ -1,7 +1,7 @@
//! Interrupt and exception for aarch64.
mod handler;
mod context;
mod handler;
mod syndrome;
use aarch64::regs::*;

@ -1,7 +1,7 @@
//! Input/output for aarch64.
use super::driver::serial::*;
use super::driver::console::CONSOLE;
use super::driver::serial::*;
use core::fmt::{Arguments, Write};
pub fn getchar() -> char {

@ -1,8 +1,8 @@
//! Memory initialization for aarch64.
use crate::memory::{init_heap, Linear, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
use crate::consts::{MEMORY_OFFSET, KERNEL_OFFSET};
use super::paging::MMIOType;
use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::memory::{init_heap, Linear, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
use aarch64::regs::*;
use log::*;
use rcore_memory::PAGE_SIZE;
@ -19,7 +19,9 @@ fn init_frame_allocator() {
use bit_allocator::BitAlloc;
use core::ops::Range;
let end = super::board::probe_memory().expect("failed to find memory map").1;
let end = super::board::probe_memory()
.expect("failed to find memory map")
.1;
let start = (_end as u64 + PAGE_SIZE as u64).wrapping_sub(KERNEL_OFFSET as u64) as usize;
let mut ba = FRAME_ALLOCATOR.lock();
ba.insert(to_range(start, end));
@ -39,14 +41,50 @@ static mut KERNEL_MEMORY_SET: Option<MemorySet> = None;
fn remap_the_kernel() {
let offset = -(KERNEL_OFFSET as isize);
let mut ms = MemorySet::new_bare();
ms.push(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), Linear::new(offset), "text");
ms.push(sdata as usize, edata as usize, MemoryAttr::default(), Linear::new(offset), "data");
ms.push(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), Linear::new(offset), "rodata");
ms.push(sbss as usize, ebss as usize, MemoryAttr::default(), Linear::new(offset), "bss");
ms.push(bootstack as usize, bootstacktop as usize, MemoryAttr::default(), Linear::new(offset), "kstack");
ms.push(
stext as usize,
etext as usize,
MemoryAttr::default().execute().readonly(),
Linear::new(offset),
"text",
);
ms.push(
sdata as usize,
edata as usize,
MemoryAttr::default(),
Linear::new(offset),
"data",
);
ms.push(
srodata as usize,
erodata as usize,
MemoryAttr::default().readonly(),
Linear::new(offset),
"rodata",
);
ms.push(
sbss as usize,
ebss as usize,
MemoryAttr::default(),
Linear::new(offset),
"bss",
);
ms.push(
bootstack as usize,
bootstacktop as usize,
MemoryAttr::default(),
Linear::new(offset),
"kstack",
);
use super::board::{IO_REMAP_BASE, IO_REMAP_END};
ms.push(IO_REMAP_BASE, IO_REMAP_END, MemoryAttr::default().mmio(MMIOType::Device as u8), Linear::new(offset), "io_remap");
ms.push(
IO_REMAP_BASE,
IO_REMAP_END,
MemoryAttr::default().mmio(MMIOType::Device as u8),
Linear::new(offset),
"io_remap",
);
info!("{:#x?}", ms);
unsafe { ms.get_page_table_mut().activate_as_kernel() }
@ -58,7 +96,13 @@ pub fn ioremap(paddr: usize, len: usize, name: &'static str) -> usize {
let offset = -(KERNEL_OFFSET as isize);
let vaddr = paddr.wrapping_add(KERNEL_OFFSET);
if let Some(ms) = unsafe { KERNEL_MEMORY_SET.as_mut() } {
ms.push(vaddr, vaddr + len, MemoryAttr::default().mmio(MMIOType::NormalNonCacheable as u8), Linear::new(offset), name);
ms.push(
vaddr,
vaddr + len,
MemoryAttr::default().mmio(MMIOType::NormalNonCacheable as u8),
Linear::new(offset),
name,
);
return vaddr;
}
0

@ -1,15 +1,15 @@
//! Entrance and initialization for aarch64.
pub mod io;
pub mod paging;
pub mod memory;
pub mod interrupt;
pub mod consts;
pub mod cpu;
pub mod driver;
pub mod timer;
pub mod syscall;
pub mod interrupt;
pub mod io;
pub mod memory;
pub mod paging;
pub mod rand;
pub mod syscall;
pub mod timer;
#[cfg(feature = "board_raspi3")]
#[path = "board/raspi3/mod.rs"]

@ -1,11 +1,13 @@
//! Page table implementations for aarch64.
use rcore_memory::paging::*;
use aarch64::asm::{tlb_invalidate, tlb_invalidate_all, ttbr_el1_read, ttbr_el1_write};
use aarch64::{PhysAddr, VirtAddr};
use aarch64::paging::{Mapper, PageTable as Aarch64PageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable};
use aarch64::paging::{FrameAllocator, FrameDeallocator, Page, PhysFrame as Frame, Size4KiB};
use aarch64::paging::memory_attribute::*;
use aarch64::paging::{FrameAllocator, FrameDeallocator, Page, PhysFrame as Frame, Size4KiB};
use aarch64::paging::{
Mapper, PageTable as Aarch64PageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable,
};
use aarch64::{PhysAddr, VirtAddr};
use log::*;
use rcore_memory::paging::*;
// Depends on kernel
use crate::consts::{KERNEL_OFFSET, KERNEL_PML4, RECURSIVE_INDEX};
use crate::memory::{active_table, alloc_frame, dealloc_frame};
@ -18,8 +20,16 @@ impl PageTable for ActivePageTable {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
let flags = EF::default();
let attr = MairNormal::attr_value();
self.0.map_to(Page::of_addr(addr as u64), Frame::of_addr(target as u64), flags, attr, &mut FrameAllocatorForAarch64)
.unwrap().flush();
self.0
.map_to(
Page::of_addr(addr as u64),
Frame::of_addr(target as u64),
flags,
attr,
&mut FrameAllocatorForAarch64,
)
.unwrap()
.flush();
self.get_entry(addr).expect("fail to get entry")
}
@ -30,7 +40,8 @@ impl PageTable for ActivePageTable {
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
// get p1 entry
let entry_addr = ((vaddr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39) | (vaddr & KERNEL_OFFSET);
let entry_addr =
((vaddr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39) | (vaddr & KERNEL_OFFSET);
Some(unsafe { &mut *(entry_addr as *mut PageEntry) })
}
}
@ -39,12 +50,12 @@ impl PageTableExt for ActivePageTable {
const TEMP_PAGE_ADDR: usize = KERNEL_OFFSET | 0xcafeb000;
}
const ROOT_PAGE_TABLE: *mut Aarch64PageTable =
(KERNEL_OFFSET |
(RECURSIVE_INDEX << 39) |
(RECURSIVE_INDEX << 30) |
(RECURSIVE_INDEX << 21) |
(RECURSIVE_INDEX << 12)) as *mut Aarch64PageTable;
const ROOT_PAGE_TABLE: *mut Aarch64PageTable = (KERNEL_OFFSET
| (RECURSIVE_INDEX << 39)
| (RECURSIVE_INDEX << 30)
| (RECURSIVE_INDEX << 21)
| (RECURSIVE_INDEX << 12))
as *mut Aarch64PageTable;
impl ActivePageTable {
pub unsafe fn new() -> Self {
@ -66,38 +77,63 @@ impl Entry for PageEntry {
tlb_invalidate(addr);
}
fn present(&self) -> bool { self.0.flags().contains(EF::VALID) }
fn accessed(&self) -> bool { self.0.flags().contains(EF::AF) }
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITE) }
fn dirty(&self) -> bool { self.hw_dirty() && self.sw_dirty() }
fn present(&self) -> bool {
self.0.flags().contains(EF::VALID)
}
fn accessed(&self) -> bool {
self.0.flags().contains(EF::AF)
}
fn writable(&self) -> bool {
self.0.flags().contains(EF::WRITE)
}
fn dirty(&self) -> bool {
self.hw_dirty() && self.sw_dirty()
}
fn clear_accessed(&mut self) { self.as_flags().remove(EF::AF); }
fn clear_dirty(&mut self)
{
fn clear_accessed(&mut self) {
self.as_flags().remove(EF::AF);
}
fn clear_dirty(&mut self) {
self.as_flags().remove(EF::DIRTY);
self.as_flags().insert(EF::AP_RO);
}
fn set_writable(&mut self, value: bool)
{
fn set_writable(&mut self, value: bool) {
self.as_flags().set(EF::AP_RO, !value);
self.as_flags().set(EF::WRITE, value);
}
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::VALID, value); }
fn target(&self) -> usize { self.0.addr().as_u64() as usize }
fn set_present(&mut self, value: bool) {
self.as_flags().set(EF::VALID, value);
}
fn target(&self) -> usize {
self.0.addr().as_u64() as usize
}
fn set_target(&mut self, target: usize) {
self.0.modify_addr(PhysAddr::new(target as u64));
}
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::WRITABLE_SHARED) }
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::READONLY_SHARED) }
fn writable_shared(&self) -> bool {
self.0.flags().contains(EF::WRITABLE_SHARED)
}
fn readonly_shared(&self) -> bool {
self.0.flags().contains(EF::READONLY_SHARED)
}
fn set_shared(&mut self, writable: bool) {
let flags = self.as_flags();
flags.set(EF::WRITABLE_SHARED, writable);
flags.set(EF::READONLY_SHARED, !writable);
}
fn clear_shared(&mut self) { self.as_flags().remove(EF::WRITABLE_SHARED | EF::READONLY_SHARED); }
fn user(&self) -> bool { self.0.flags().contains(EF::AP_EL0) }
fn swapped(&self) -> bool { self.0.flags().contains(EF::SWAPPED) }
fn set_swapped(&mut self, value: bool) { self.as_flags().set(EF::SWAPPED, value); }
fn clear_shared(&mut self) {
self.as_flags()
.remove(EF::WRITABLE_SHARED | EF::READONLY_SHARED);
}
fn user(&self) -> bool {
self.0.flags().contains(EF::AP_EL0)
}
fn swapped(&self) -> bool {
self.0.flags().contains(EF::SWAPPED)
}
fn set_swapped(&mut self, value: bool) {
self.as_flags().set(EF::SWAPPED, value);
}
fn set_user(&mut self, value: bool) {
self.as_flags().set(EF::AP_EL0, value);
self.as_flags().set(EF::nG, value); // set non-global to use ASID
@ -140,9 +176,15 @@ impl Entry for PageEntry {
}
impl PageEntry {
fn read_only(&self) -> bool { self.0.flags().contains(EF::AP_RO) }
fn hw_dirty(&self) -> bool { self.writable() && !self.read_only() }
fn sw_dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) }
fn read_only(&self) -> bool {
self.0.flags().contains(EF::AP_RO)
}
fn hw_dirty(&self) -> bool {
self.writable() && !self.read_only()
}
fn sw_dirty(&self) -> bool {
self.0.flags().contains(EF::DIRTY)
}
fn as_flags(&mut self) -> &mut EF {
unsafe { &mut *(self as *mut _ as *mut EF) }
}
@ -168,7 +210,11 @@ impl InactivePageTable for InactivePageTable0 {
active_table().with_temporary_map(target, |_, table: &mut Aarch64PageTable| {
table.zero();
// set up recursive mapping for the table
table[RECURSIVE_INDEX].set_frame(frame.clone(), EF::default(), MairNormal::attr_value());
table[RECURSIVE_INDEX].set_frame(
frame.clone(),
EF::default(),
MairNormal::attr_value(),
);
});
InactivePageTable0 { p4_frame: frame }
}
@ -179,7 +225,11 @@ impl InactivePageTable for InactivePageTable0 {
assert!(!e0.is_unused());
self.edit(|_| {
table[KERNEL_PML4].set_frame(Frame::containing_address(e0.addr()), EF::default(), MairNormal::attr_value());
table[KERNEL_PML4].set_frame(
Frame::containing_address(e0.addr()),
EF::default(),
MairNormal::attr_value(),
);
});
}
@ -201,24 +251,31 @@ impl InactivePageTable for InactivePageTable0 {
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
let target = ttbr_el1_read(1).start_address().as_u64() as usize;
active_table().with_temporary_map(target, |active_table, p4_table: &mut Aarch64PageTable| {
let backup = p4_table[RECURSIVE_INDEX].clone();
let old_frame = ttbr_el1_read(0);
// overwrite recursive mapping
p4_table[RECURSIVE_INDEX].set_frame(self.p4_frame.clone(), EF::default(), MairNormal::attr_value());
ttbr_el1_write(0, self.p4_frame.clone());
tlb_invalidate_all();
// execute f in the new context
let ret = f(active_table);
// restore recursive mapping to original p4 table
p4_table[RECURSIVE_INDEX] = backup;
ttbr_el1_write(0, old_frame);
tlb_invalidate_all();
ret
})
active_table().with_temporary_map(
target,
|active_table, p4_table: &mut Aarch64PageTable| {
let backup = p4_table[RECURSIVE_INDEX].clone();
let old_frame = ttbr_el1_read(0);
// overwrite recursive mapping
p4_table[RECURSIVE_INDEX].set_frame(
self.p4_frame.clone(),
EF::default(),
MairNormal::attr_value(),
);
ttbr_el1_write(0, self.p4_frame.clone());
tlb_invalidate_all();
// execute f in the new context
let ret = f(active_table);
// restore recursive mapping to original p4 table
p4_table[RECURSIVE_INDEX] = backup;
ttbr_el1_write(0, old_frame);
tlb_invalidate_all();
ret
},
)
}
}

@ -1,3 +1,3 @@
pub fn rand() -> u64 {
return 0;
}
}

@ -1,3 +1,3 @@
pub fn read_epoch() -> u64 {
0
}
}

@ -10,9 +10,10 @@ pub unsafe fn init_external_interrupt() {
/// Claim and complete external interrupt by reading and writing to
/// PLIC Interrupt Claim/Complete Register.
pub unsafe fn handle_external_interrupt() {
const HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 = (KERNEL_OFFSET + 0x0C20_2004) as *mut u32;
const HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 =
(KERNEL_OFFSET + 0x0C20_2004) as *mut u32;
// claim
let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read();
// complete
HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.write(source);
}
}

@ -3,6 +3,6 @@
//! [atomic](http://llvm.org/docs/Atomics.html#libcalls-atomic)
#[no_mangle]
pub extern fn abort() {
pub extern "C" fn abort() {
panic!("abort");
}

@ -39,4 +39,4 @@ pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000;
pub const USER32_STACK_OFFSET: usize = 0xC0000000 - USER_STACK_SIZE;
pub const MAX_DTB_SIZE: usize = 0x2000;
pub const MAX_DTB_SIZE: usize = 0x2000;

@ -1,8 +1,4 @@
use riscv::register::{
sstatus,
sstatus::Sstatus,
scause::Scause,
};
use riscv::register::{scause::Scause, sstatus, sstatus::Sstatus};
/// Saved registers on a trap.
#[derive(Clone)]
@ -27,7 +23,7 @@ impl TrapFrame {
///
/// The new thread starts at function `entry` with an usize argument `arg`.
/// The stack pointer will be set to `sp`.
fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self {
fn new_kernel_thread(entry: extern "C" fn(usize) -> !, arg: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.x[10] = arg; // a0
@ -57,17 +53,17 @@ impl TrapFrame {
}
}
use core::fmt::{Debug, Formatter, Error};
use core::fmt::{Debug, Error, Formatter};
impl Debug for TrapFrame {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
struct Regs<'a>(&'a [usize; 32]);
impl<'a> Debug for Regs<'a> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
const REG_NAME: [&str; 32] = [
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
"s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
"t3", "t4", "t5", "t6"];
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", "a1", "a2",
"a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9",
"s10", "s11", "t3", "t4", "t5", "t6",
];
f.debug_map().entries(REG_NAME.iter().zip(self.0)).finish()
}
}
@ -98,7 +94,7 @@ impl InitStack {
}
}
extern {
extern "C" {
fn trap_return();
}
@ -116,7 +112,11 @@ struct ContextData {
impl ContextData {
fn new(satp: usize) -> Self {
ContextData { ra: trap_return as usize, satp, ..ContextData::default() }
ContextData {
ra: trap_return as usize,
satp,
..ContextData::default()
}
}
}
@ -137,25 +137,29 @@ impl Context {
/// Pop all callee-saved registers, then return to the target.
#[naked]
#[inline(never)]
pub unsafe extern fn switch(&mut self, _target: &mut Self) {
pub unsafe extern "C" fn switch(&mut self, _target: &mut Self) {
#[cfg(target_arch = "riscv32")]
asm!(r"
asm!(
r"
.equ XLENB, 4
.macro Load reg, mem
lw \reg, \mem
.endm
.macro Store reg, mem
sw \reg, \mem
.endm");
.endm"
);
#[cfg(target_arch = "riscv64")]
asm!(r"
asm!(
r"
.equ XLENB, 8
.macro Load reg, mem
ld \reg, \mem
.endm
.macro Store reg, mem
sd \reg, \mem
.endm");
.endm"
);
asm!("
// save from's registers
addi sp, sp, (-XLENB*14)
@ -210,11 +214,17 @@ impl Context {
/// The new thread starts at function `entry` with an usize argument `arg`.
/// The stack pointer will be set to `kstack_top`.
/// The SATP register will be set to `satp`.
pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, satp: usize) -> Self {
pub unsafe fn new_kernel_thread(
entry: extern "C" fn(usize) -> !,
arg: usize,
kstack_top: usize,
satp: usize,
) -> Self {
InitStack {
context: ContextData::new(satp),
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
/// Constructs Context for a new user thread.
@ -222,11 +232,18 @@ impl Context {
/// The new thread starts at `entry_addr`.
/// The stack pointer of user and kernel mode will be set to `ustack_top`, `kstack_top`.
/// The SATP register will be set to `satp`.
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, _is32: bool, satp: usize) -> Self {
pub unsafe fn new_user_thread(
entry_addr: usize,
ustack_top: usize,
kstack_top: usize,
_is32: bool,
satp: usize,
) -> Self {
InitStack {
context: ContextData::new(satp),
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
/// Fork a user process and get the new Context.
@ -243,7 +260,8 @@ impl Context {
tf.x[10] = 0; // a0
tf
},
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
/// Fork a user thread and get the new Context.
@ -253,17 +271,24 @@ impl Context {
/// The new user stack will be set to `ustack_top`.
/// The new thread pointer will be set to `tls`.
/// All the other registers are same as the original.
pub unsafe fn new_clone(tf: &TrapFrame, ustack_top: usize, kstack_top: usize, satp: usize, tls: usize) -> Self {
pub unsafe fn new_clone(
tf: &TrapFrame,
ustack_top: usize,
kstack_top: usize,
satp: usize,
tls: usize,
) -> Self {
InitStack {
context: ContextData::new(satp),
tf: {
let mut tf = tf.clone();
tf.x[2] = ustack_top; // sp
tf.x[2] = ustack_top; // sp
tf.x[4] = tls; // tp
tf.x[10] = 0; // a0
tf.x[10] = 0; // a0
tf
},
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
/// Used for getting the init TrapFrame of a new user context in `sys_exec`.

@ -9,7 +9,9 @@ pub unsafe fn set_cpu_id(cpu_id: usize) {
pub fn id() -> usize {
let cpu_id;
unsafe { asm!("mv $0, gp" : "=r"(cpu_id)); }
unsafe {
asm!("mv $0, gp" : "=r"(cpu_id));
}
cpu_id
}

@ -1,14 +1,14 @@
use riscv::register::*;
use crate::drivers::DRIVERS;
pub use self::context::*;
use crate::drivers::DRIVERS;
use log::*;
use riscv::register::*;
#[path = "context.rs"]
mod context;
/// Initialize interrupt
pub fn init() {
extern {
extern "C" {
fn trap_entry();
}
unsafe {
@ -53,9 +53,13 @@ pub unsafe fn restore(flags: usize) {
///
/// This function is called from `trap.asm`.
#[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) {
use self::scause::{Trap, Interrupt as I, Exception as E};
trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause());
pub extern "C" fn rust_trap(tf: &mut TrapFrame) {
use self::scause::{Exception as E, Interrupt as I, Trap};
trace!(
"Interrupt @ CPU{}: {:?} ",
super::cpu::id(),
tf.scause.cause()
);
match tf.scause.cause() {
Trap::Interrupt(I::SupervisorExternal) => external(),
Trap::Interrupt(I::SupervisorSoft) => ipi(),
@ -71,13 +75,15 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
fn external() {
#[cfg(feature = "board_u540")]
unsafe { super::board::handle_external_interrupt(); }
unsafe {
super::board::handle_external_interrupt();
}
// true means handled, false otherwise
let handlers = [try_process_serial, try_process_drivers];
for handler in handlers.iter() {
if handler() == true {
break
break;
}
}
}
@ -88,17 +94,17 @@ fn try_process_serial() -> bool {
crate::trap::serial(ch);
true
}
None => false
None => false,
}
}
fn try_process_drivers() -> bool {
for driver in DRIVERS.read().iter() {
if driver.try_handle_interrupt(None) == true {
return true
return true;
}
}
return false
return false;
}
fn ipi() {
@ -112,8 +118,12 @@ fn timer() {
}
fn syscall(tf: &mut TrapFrame) {
tf.sepc += 4; // Must before syscall, because of fork.
let ret = crate::syscall::syscall(tf.x[17], [tf.x[10], tf.x[11], tf.x[12], tf.x[13], tf.x[14], tf.x[15]], tf);
tf.sepc += 4; // Must before syscall, because of fork.
let ret = crate::syscall::syscall(
tf.x[17],
[tf.x[10], tf.x[11], tf.x[12], tf.x[13], tf.x[14], tf.x[15]],
tf,
);
tf.x[10] = ret as usize;
}

@ -1,5 +1,5 @@
use core::fmt::{Write, Result, Arguments};
use super::sbi;
use core::fmt::{Arguments, Result, Write};
struct SerialPort;
@ -31,7 +31,7 @@ pub fn getchar() -> char {
let c = sbi::console_getchar() as u8;
match c {
255 => '\0', // null
255 => '\0', // null
c => c as char,
}
}

@ -1,15 +1,17 @@
use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET};
use crate::memory::{init_heap, Linear, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
use core::mem;
use riscv::{addr::*, register::sstatus};
use rcore_memory::PAGE_SIZE;
use log::*;
use crate::memory::{FRAME_ALLOCATOR, init_heap, MemoryAttr, MemorySet, Linear};
use crate::consts::{MEMORY_OFFSET, MEMORY_END, KERNEL_OFFSET};
use rcore_memory::PAGE_SIZE;
use riscv::register::satp;
use riscv::{addr::*, register::sstatus};
/// Initialize the memory management module
pub fn init(dtb: usize) {
unsafe { sstatus::set_sum(); } // Allow user memory access
// initialize heap and Frame allocator
unsafe {
sstatus::set_sum();
} // Allow user memory access
// initialize heap and Frame allocator
init_frame_allocator();
init_heap();
// remap the kernel use 4K page
@ -18,7 +20,7 @@ pub fn init(dtb: usize) {
pub fn init_other() {
unsafe {
sstatus::set_sum(); // Allow user memory access
sstatus::set_sum(); // Allow user memory access
asm!("csrw satp, $0; sfence.vma" :: "r"(SATP) :: "volatile");
}
}
@ -28,7 +30,10 @@ fn init_frame_allocator() {
use core::ops::Range;
let mut ba = FRAME_ALLOCATOR.lock();
let range = to_range((end as usize) - KERNEL_OFFSET + MEMORY_OFFSET + PAGE_SIZE, MEMORY_END);
let range = to_range(
(end as usize) - KERNEL_OFFSET + MEMORY_OFFSET + PAGE_SIZE,
MEMORY_END,
);
ba.insert(range);
info!("frame allocator: init end");
@ -46,18 +51,70 @@ fn init_frame_allocator() {
fn remap_the_kernel(dtb: usize) {
let offset = -(KERNEL_OFFSET as isize - MEMORY_OFFSET as isize);
let mut ms = MemorySet::new_bare();
ms.push(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), Linear::new(offset), "text");
ms.push(sdata as usize, edata as usize, MemoryAttr::default(), Linear::new(offset), "data");
ms.push(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), Linear::new(offset), "rodata");
ms.push(bootstack as usize, bootstacktop as usize, MemoryAttr::default(), Linear::new(offset), "stack");
ms.push(sbss as usize, ebss as usize, MemoryAttr::default(), Linear::new(offset), "bss");
ms.push(dtb, dtb + super::consts::MAX_DTB_SIZE, MemoryAttr::default().readonly(), Linear::new(offset), "dts");
ms.push(
stext as usize,
etext as usize,
MemoryAttr::default().execute().readonly(),
Linear::new(offset),
"text",
);
ms.push(
sdata as usize,
edata as usize,
MemoryAttr::default(),
Linear::new(offset),
"data",
);
ms.push(
srodata as usize,
erodata as usize,
MemoryAttr::default().readonly(),
Linear::new(offset),
"rodata",
);
ms.push(
bootstack as usize,
bootstacktop as usize,
MemoryAttr::default(),
Linear::new(offset),
"stack",
);
ms.push(
sbss as usize,
ebss as usize,
MemoryAttr::default(),
Linear::new(offset),
"bss",
);
ms.push(
dtb,
dtb + super::consts::MAX_DTB_SIZE,
MemoryAttr::default().readonly(),
Linear::new(offset),
"dts",
);
// map PLIC for HiFiveU
let offset = -(KERNEL_OFFSET as isize);
ms.push(KERNEL_OFFSET + 0x0C00_2000, KERNEL_OFFSET + 0x0C00_2000 + PAGE_SIZE, MemoryAttr::default(), Linear::new(offset), "plic0");
ms.push(KERNEL_OFFSET + 0x0C20_2000, KERNEL_OFFSET + 0x0C20_2000 + PAGE_SIZE, MemoryAttr::default(), Linear::new(offset), "plic1");
unsafe { ms.activate(); }
unsafe { SATP = ms.token(); }
ms.push(
KERNEL_OFFSET + 0x0C00_2000,
KERNEL_OFFSET + 0x0C00_2000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(offset),
"plic0",
);
ms.push(
KERNEL_OFFSET + 0x0C20_2000,
KERNEL_OFFSET + 0x0C20_2000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(offset),
"plic1",
);
unsafe {
ms.activate();
}
unsafe {
SATP = ms.token();
}
mem::forget(ms);
info!("remap kernel end");
}
@ -77,7 +134,7 @@ pub unsafe fn clear_bss() {
// Symbols provided by linker script
#[allow(dead_code)]
extern {
extern "C" {
fn stext();
fn etext();
fn sdata();

@ -1,34 +1,38 @@
pub mod io;
pub mod interrupt;
pub mod timer;
pub mod paging;
pub mod memory;
#[cfg(feature = "board_u540")]
#[path = "board/u540/mod.rs"]
mod board;
pub mod compiler_rt;
pub mod consts;
pub mod cpu;
pub mod syscall;
pub mod interrupt;
pub mod io;
pub mod memory;
pub mod paging;
pub mod rand;
#[cfg(feature = "board_u540")]
#[path = "board/u540/mod.rs"]
mod board;
mod sbi;
pub mod syscall;
pub mod timer;
use log::*;
#[no_mangle]
pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
pub extern "C" fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
// An initial recursive page table has been set by BBL (shared by all cores)
unsafe { cpu::set_cpu_id(hartid); }
unsafe {
cpu::set_cpu_id(hartid);
}
if hartid != BOOT_HART_ID {
while unsafe { !cpu::has_started(hartid) } { }
while unsafe { !cpu::has_started(hartid) } {}
println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb);
others_main();
//other_main -> !
}
unsafe { memory::clear_bss(); }
unsafe {
memory::clear_bss();
}
println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb);
@ -40,10 +44,14 @@ pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
#[cfg(not(feature = "board_u540"))]
crate::drivers::init(dtb);
#[cfg(feature = "board_u540")]
unsafe { board::init_external_interrupt(); }
unsafe {
board::init_external_interrupt();
}
crate::process::init();
unsafe { cpu::start_others(hart_mask); }
unsafe {
cpu::start_others(hart_mask);
}
crate::kmain();
}
@ -61,7 +69,8 @@ const BOOT_HART_ID: usize = 1;
/// Constant & Macro for `trap.asm`
#[cfg(target_arch = "riscv32")]
global_asm!(r"
global_asm!(
r"
.equ XLENB, 4
.equ XLENb, 32
.macro LOAD a1, a2
@ -70,9 +79,11 @@ global_asm!(r"
.macro STORE a1, a2
sw \a1, \a2*XLENB(sp)
.endm
");
"
);
#[cfg(target_arch = "riscv64")]
global_asm!(r"
global_asm!(
r"
.equ XLENB, 8
.equ XLENb, 64
.macro LOAD a1, a2
@ -81,8 +92,8 @@ global_asm!(r"
.macro STORE a1, a2
sd \a1, \a2*XLENB(sp)
.endm
");
"
);
global_asm!(include_str!("boot/entry.asm"));
global_asm!(include_str!("boot/trap.asm"));

@ -1,17 +1,20 @@
use crate::consts::RECURSIVE_INDEX;
// Depends on kernel
#[cfg(target_arch = "riscv32")]
use crate::consts::KERNEL_P2_INDEX;
#[cfg(target_arch = "riscv64")]
use crate::consts::KERNEL_P4_INDEX;
use crate::memory::{active_table, alloc_frame, dealloc_frame};
use log::*;
use rcore_memory::paging::*;
use riscv::addr::*;
use riscv::asm::{sfence_vma, sfence_vma_all};
use riscv::paging::{Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable, PageTableType};
use riscv::paging::{FrameAllocator, FrameDeallocator};
use riscv::paging::{
Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF, PageTableType,
RecursivePageTable,
};
use riscv::register::satp;
use rcore_memory::paging::*;
use log::*;
#[cfg(target_arch = "riscv32")]
use crate::consts::KERNEL_P2_INDEX;
#[cfg(target_arch = "riscv64")]
use crate::consts::KERNEL_P4_INDEX;
pub struct ActivePageTable(RecursivePageTable<'static>, PageEntry);
@ -20,7 +23,6 @@ pub struct ActivePageTable(RecursivePageTable<'static>, PageEntry);
pub struct PageEntry(&'static mut PageTableEntry, Page);
impl PageTable for ActivePageTable {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
// use riscv::paging:Mapper::map_to,
// map the 4K `page` to the 4K `frame` with `flags`
@ -29,7 +31,10 @@ impl PageTable for ActivePageTable {
let frame = Frame::of_addr(PhysAddr::new(target));
// map the page to the frame using FrameAllocatorForRiscv
// 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.0
.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
.unwrap()
.flush();
self.get_entry(addr).expect("fail to get entry")
}
@ -56,29 +61,26 @@ impl PageTableExt for ActivePageTable {}
/// The virtual address of root page table
#[cfg(target_arch = "riscv32")]
const ROOT_PAGE_TABLE: *mut RvPageTable =
((RECURSIVE_INDEX << 12 << 10) |
((RECURSIVE_INDEX+1) << 12)) as *mut RvPageTable;
((RECURSIVE_INDEX << 12 << 10) | ((RECURSIVE_INDEX + 1) << 12)) as *mut RvPageTable;
#[cfg(all(target_arch = "riscv64", feature = "sv39"))]
const ROOT_PAGE_TABLE: *mut RvPageTable =
((0xFFFF_0000_0000_0000) |
(0o777 << 12 << 9 << 9 << 9) |
(RECURSIVE_INDEX << 12 << 9 << 9) |
(RECURSIVE_INDEX << 12 << 9) |
((RECURSIVE_INDEX+1) << 12)) as *mut RvPageTable;
const ROOT_PAGE_TABLE: *mut RvPageTable = ((0xFFFF_0000_0000_0000)
| (0o777 << 12 << 9 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9)
| ((RECURSIVE_INDEX + 1) << 12)) as *mut RvPageTable;
#[cfg(all(target_arch = "riscv64", not(feature = "sv39")))]
const ROOT_PAGE_TABLE: *mut RvPageTable =
((0xFFFF_0000_0000_0000) |
(RECURSIVE_INDEX << 12 << 9 << 9 << 9) |
(RECURSIVE_INDEX << 12 << 9 << 9) |
(RECURSIVE_INDEX << 12 << 9) |
((RECURSIVE_INDEX+1) << 12)) as *mut RvPageTable;
const ROOT_PAGE_TABLE: *mut RvPageTable = ((0xFFFF_0000_0000_0000)
| (RECURSIVE_INDEX << 12 << 9 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9)
| ((RECURSIVE_INDEX + 1) << 12)) as *mut RvPageTable;
impl ActivePageTable {
#[cfg(target_arch = "riscv32")]
pub unsafe fn new() -> Self {
ActivePageTable(
RecursivePageTable::new(&mut *ROOT_PAGE_TABLE).unwrap(),
::core::mem::uninitialized()
::core::mem::uninitialized(),
)
}
#[cfg(target_arch = "riscv64")]
@ -89,7 +91,7 @@ impl ActivePageTable {
let type_ = PageTableType::Sv48;
ActivePageTable(
RecursivePageTable::new(&mut *ROOT_PAGE_TABLE, type_).unwrap(),
::core::mem::uninitialized()
::core::mem::uninitialized(),
)
}
}
@ -97,38 +99,78 @@ impl ActivePageTable {
/// implementation for the Entry trait in /crate/memory/src/paging/mod.rs
impl Entry for PageEntry {
fn update(&mut self) {
unsafe { sfence_vma(0, self.1.start_address().as_usize()); }
}
fn accessed(&self) -> bool { self.0.flags().contains(EF::ACCESSED) }
fn dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) }
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITABLE) }
fn present(&self) -> bool { self.0.flags().contains(EF::VALID | EF::READABLE) }
fn clear_accessed(&mut self) { self.0.flags_mut().remove(EF::ACCESSED); }
fn clear_dirty(&mut self) { self.0.flags_mut().remove(EF::DIRTY); }
fn set_writable(&mut self, value: bool) { self.0.flags_mut().set(EF::WRITABLE, value); }
fn set_present(&mut self, value: bool) { self.0.flags_mut().set(EF::VALID | EF::READABLE, value); }
fn target(&self) -> usize { self.0.addr().as_usize() }
unsafe {
sfence_vma(0, self.1.start_address().as_usize());
}
}
fn accessed(&self) -> bool {
self.0.flags().contains(EF::ACCESSED)
}
fn dirty(&self) -> bool {
self.0.flags().contains(EF::DIRTY)
}
fn writable(&self) -> bool {
self.0.flags().contains(EF::WRITABLE)
}
fn present(&self) -> bool {
self.0.flags().contains(EF::VALID | EF::READABLE)
}
fn clear_accessed(&mut self) {
self.0.flags_mut().remove(EF::ACCESSED);
}
fn clear_dirty(&mut self) {
self.0.flags_mut().remove(EF::DIRTY);
}
fn set_writable(&mut self, value: bool) {
self.0.flags_mut().set(EF::WRITABLE, value);
}
fn set_present(&mut self, value: bool) {
self.0.flags_mut().set(EF::VALID | EF::READABLE, value);
}
fn target(&self) -> usize {
self.0.addr().as_usize()
}
fn set_target(&mut self, target: usize) {
let flags = self.0.flags();
let frame = Frame::of_addr(PhysAddr::new(target));
self.0.set(frame, flags);
}
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::RESERVED1) }
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::RESERVED2) }
fn writable_shared(&self) -> bool {
self.0.flags().contains(EF::RESERVED1)
}
fn readonly_shared(&self) -> bool {
self.0.flags().contains(EF::RESERVED2)
}
fn set_shared(&mut self, writable: bool) {
let flags = self.0.flags_mut();
flags.set(EF::RESERVED1, writable);
flags.set(EF::RESERVED2, !writable);
}
fn clear_shared(&mut self) { self.0.flags_mut().remove(EF::RESERVED1 | EF::RESERVED2); }
fn swapped(&self) -> bool { self.0.flags().contains(EF::RESERVED1) }
fn set_swapped(&mut self, value: bool) { self.0.flags_mut().set(EF::RESERVED1, value); }
fn user(&self) -> bool { self.0.flags().contains(EF::USER) }
fn set_user(&mut self, value: bool) { self.0.flags_mut().set(EF::USER, value); }
fn execute(&self) -> bool { self.0.flags().contains(EF::EXECUTABLE) }
fn set_execute(&mut self, value: bool) { self.0.flags_mut().set(EF::EXECUTABLE, value); }
fn mmio(&self) -> u8 { 0 }
fn set_mmio(&mut self, _value: u8) { }
fn clear_shared(&mut self) {
self.0.flags_mut().remove(EF::RESERVED1 | EF::RESERVED2);
}
fn swapped(&self) -> bool {
self.0.flags().contains(EF::RESERVED1)
}
fn set_swapped(&mut self, value: bool) {
self.0.flags_mut().set(EF::RESERVED1, value);
}
fn user(&self) -> bool {
self.0.flags().contains(EF::USER)
}
fn set_user(&mut self, value: bool) {
self.0.flags_mut().set(EF::USER, value);
}
fn execute(&self) -> bool {
self.0.flags().contains(EF::EXECUTABLE)
}
fn set_execute(&mut self, value: bool) {
self.0.flags_mut().set(EF::EXECUTABLE, value);
}
fn mmio(&self) -> u8 {
0
}
fn set_mmio(&mut self, _value: u8) {}
}
#[derive(Debug)]
@ -152,7 +194,7 @@ impl InactivePageTable for InactivePageTable0 {
#[cfg(target_arch = "riscv32")]
fn map_kernel(&mut self) {
let table = unsafe { &mut *ROOT_PAGE_TABLE };
extern {
extern "C" {
fn start();
fn end();
}
@ -191,7 +233,7 @@ impl InactivePageTable for InactivePageTable0 {
fn token(&self) -> usize {
use bit_field::BitField;
let mut satp = self.root_frame.number();
satp.set_bits(44..60, 0); // AS is 0
satp.set_bits(44..60, 0); // AS is 0
#[cfg(feature = "sv39")]
satp.set_bits(60..64, satp::Mode::Sv39 as usize);
#[cfg(not(feature = "sv39"))]
@ -208,7 +250,9 @@ impl InactivePageTable for InactivePageTable0 {
}
fn flush_tlb() {
unsafe { sfence_vma_all(); }
unsafe {
sfence_vma_all();
}
}
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
@ -218,14 +262,18 @@ impl InactivePageTable for InactivePageTable0 {
// overwrite recursive mapping
root_table[RECURSIVE_INDEX].set(self.root_frame.clone(), EF::VALID);
unsafe { sfence_vma_all(); }
unsafe {
sfence_vma_all();
}
// execute f in the new context
let ret = f(active_table);
// restore recursive mapping to original p2 table
root_table[RECURSIVE_INDEX] = backup;
unsafe { sfence_vma_all(); }
unsafe {
sfence_vma_all();
}
ret
})

@ -1,3 +1,3 @@
pub fn rand() -> u64 {
return 0;
}
}

@ -28,7 +28,12 @@ pub fn shutdown() -> ! {
pub fn set_timer(stime_value: u64) {
#[cfg(target_pointer_width = "32")]
sbi_call(SBI_SET_TIMER, stime_value as usize, (stime_value >> 32) as usize, 0);
sbi_call(
SBI_SET_TIMER,
stime_value as usize,
(stime_value >> 32) as usize,
0,
);
#[cfg(target_pointer_width = "64")]
sbi_call(SBI_SET_TIMER, stime_value as usize, 0, 0);
}
@ -50,7 +55,12 @@ pub fn remote_sfence_vma(hart_mask: usize, _start: usize, _size: usize) {
}
pub fn remote_sfence_vma_asid(hart_mask: usize, _start: usize, _size: usize, _asid: usize) {
sbi_call(SBI_REMOTE_SFENCE_VMA_ASID, &hart_mask as *const _ as usize, 0, 0);
sbi_call(
SBI_REMOTE_SFENCE_VMA_ASID,
&hart_mask as *const _ as usize,
0,
0,
);
}
const SBI_SET_TIMER: usize = 0;

@ -1,6 +1,6 @@
use riscv::register::*;
use super::sbi;
use log::*;
use riscv::register::*;
#[cfg(target_pointer_width = "64")]
pub fn get_cycle() -> u64 {
@ -27,7 +27,9 @@ pub fn read_epoch() -> u64 {
/// Enable timer interrupt
pub fn init() {
// Enable supervisor timer interrupt
unsafe { sie::set_stimer(); }
unsafe {
sie::set_stimer();
}
set_next();
info!("timer: init end");
}

@ -14,7 +14,10 @@ pub unsafe fn exit_in_qemu(error_code: u8) -> ! {
}
pub fn id() -> usize {
CpuId::new().get_feature_info().unwrap().initial_local_apic_id() as usize
CpuId::new()
.get_feature_info()
.unwrap()
.initial_local_apic_id() as usize
}
pub fn send_ipi(cpu_id: usize) {
@ -31,7 +34,7 @@ pub fn init() {
unsafe {
asm!("mov %cr4, $0" : "=r" (value));
// OSFXSR | OSXMMEXCPT
value |= 1 << 9 | 1 << 10 ;
value |= 1 << 9 | 1 << 10;
asm!("mov $0, %cr4" :: "r" (value) : "memory");
Cr0::update(|cr0| {
cr0.remove(Cr0Flags::EMULATE_COPROCESSOR);

@ -16,10 +16,26 @@ pub struct IDE {
impl IDE {
pub fn new(num: u8) -> Self {
let ide = match num {
0 => IDE { num: 0, base: 0x1f0, ctrl: 0x3f4 },
1 => IDE { num: 1, base: 0x1f0, ctrl: 0x3f4 },
2 => IDE { num: 2, base: 0x170, ctrl: 0x374 },
3 => IDE { num: 3, base: 0x170, ctrl: 0x374 },
0 => IDE {
num: 0,
base: 0x1f0,
ctrl: 0x3f4,
},
1 => IDE {
num: 1,
base: 0x1f0,
ctrl: 0x3f4,
},
2 => IDE {
num: 2,
base: 0x170,
ctrl: 0x374,
},
3 => IDE {
num: 3,
base: 0x170,
ctrl: 0x374,
},
_ => panic!("ide number should be 0,1,2,3"),
};
ide.init();
@ -103,14 +119,17 @@ impl IDE {
port::outb(self.base + ISA_SECTOR, (sector & 0xFF) as u8);
port::outb(self.base + ISA_CYL_LO, ((sector >> 8) & 0xFF) as u8);
port::outb(self.base + ISA_CYL_HI, ((sector >> 16) & 0xFF) as u8);
port::outb(self.base + ISA_SDH, 0xE0 | ((self.num & 1) << 4) | (((sector >> 24) & 0xF) as u8));
port::outb(
self.base + ISA_SDH,
0xE0 | ((self.num & 1) << 4) | (((sector >> 24) & 0xF) as u8),
);
}
}
}
const SECTOR_SIZE: usize = 128;
const MAX_DMA_SECTORS: usize = 0x1F_F000 / SECTOR_SIZE; // Limited by sector count (and PRDT entries)
// 512 PDRT entries, assume maximum fragmentation = 512 * 4K max = 2^21 = 2MB per transfer
const MAX_DMA_SECTORS: usize = 0x1F_F000 / SECTOR_SIZE; // Limited by sector count (and PRDT entries)
// 512 PDRT entries, assume maximum fragmentation = 512 * 4K max = 2^21 = 2MB per transfer
const ISA_DATA: u16 = 0x00;
const ISA_ERROR: u16 = 0x01;
@ -146,4 +165,4 @@ mod port {
pub unsafe fn outb(port: u16, value: u8) {
Port::new(port).write(value)
}
}
}

@ -1,20 +1,21 @@
use lazy_static::lazy_static;
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
use spin::Mutex;
use x86_64::instructions::port::Port;
use pc_keyboard::{Keyboard, ScancodeSet1, DecodedKey, layouts, HandleControl};
use lazy_static::lazy_static;
pub fn init() {
use crate::arch::interrupt::consts;
use crate::arch::interrupt::enable_irq;
enable_irq(consts::Keyboard);
enable_irq(consts::Keyboard);
}
/// Receive character from keyboard
/// Should be called on every interrupt
pub fn receive() -> Option<DecodedKey> {
lazy_static! {
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore));
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> = Mutex::new(
Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore)
);
}
let mut keyboard = KEYBOARD.lock();
@ -29,4 +30,4 @@ pub fn receive() -> Option<DecodedKey> {
}
}
None
}
}

@ -1,12 +1,12 @@
use once::*;
pub mod vga;
pub mod serial;
pub mod pic;
pub mod ide;
pub mod keyboard;
pub mod pic;
pub mod pit;
pub mod ide;
pub mod rtc_cmos;
pub mod serial;
pub mod vga;
pub fn init() {
assert_has_not_been_called!();
@ -33,4 +33,4 @@ pub fn init() {
enable_irq(consts::PIRQG);
enable_irq(consts::PIRQH);
*/
}
}

@ -1,9 +1,9 @@
// Copy from Redox
use x86_64::instructions::port::Port;
use spin::Mutex;
use once::*;
use log::*;
use once::*;
use spin::Mutex;
use x86_64::instructions::port::Port;
static MASTER: Mutex<Pic> = Mutex::new(Pic::new(0x20));
static SLAVE: Mutex<Pic> = Mutex::new(Pic::new(0xA0));
@ -19,7 +19,7 @@ pub fn disable() {
pub unsafe fn init() {
assert_has_not_been_called!("pic::init must be called only once");
let mut master = MASTER.lock();
let mut slave = SLAVE.lock();
@ -53,7 +53,7 @@ pub unsafe fn init() {
pub fn enable_irq(irq: u8) {
match irq {
_ if irq < 8 => MASTER.lock().mask_set(irq),
_ if irq < 16 => SLAVE.lock().mask_set(irq-8),
_ if irq < 16 => SLAVE.lock().mask_set(irq - 8),
_ => panic!("irq not in 0..16"),
}
}
@ -80,7 +80,9 @@ impl Pic {
}
fn ack(&mut self) {
unsafe { self.cmd.write(0x20); }
unsafe {
self.cmd.write(0x20);
}
}
fn mask_set(&mut self, irq: u8) {

@ -1,6 +1,6 @@
use x86_64::instructions::port::Port;
use log::*;
use once::*;
use x86_64::instructions::port::Port;
pub fn init() {
assert_has_not_been_called!("pit::init must be called only once");
@ -39,7 +39,7 @@ impl Pit {
}
}
const TIMER_FREQ : u32 = 1193182;
const TIMER_SEL0 : u8 = 0x00; // select counter 0
const TIMER_RATEGEN : u8 = 0x04; // mode 2, rate generator
const TIMER_16BIT : u8 = 0x30; // r/w counter 16 bits, LSB first
const TIMER_FREQ: u32 = 1193182;
const TIMER_SEL0: u8 = 0x00; // select counter 0
const TIMER_RATEGEN: u8 = 0x04; // mode 2, rate generator
const TIMER_16BIT: u8 = 0x30; // r/w counter 16 bits, LSB first

@ -61,7 +61,8 @@ pub fn read_epoch() -> u64 {
month = month - 2;
}
let result = ((((year / 4 - year / 100 + year / 400 + 367 * month / 12 + day) + year * 365
let result = ((((year / 4 - year / 100 + year / 400 + 367 * month / 12 + day)
+ year * 365
- 719499)
* 24
+ hour)

@ -51,10 +51,14 @@ pub struct ScreenChar {
}
impl ScreenChar {
pub fn new(ascii_char: u8, foreground_color: ConsoleColor, background_color: ConsoleColor) -> Self {
pub fn new(
ascii_char: u8,
foreground_color: ConsoleColor,
background_color: ConsoleColor,
) -> Self {
ScreenChar {
ascii_char,
color_code: ColorCode::new(foreground_color, background_color)
color_code: ColorCode::new(foreground_color, background_color),
}
}
}
@ -69,7 +73,7 @@ pub struct VgaBuffer {
impl VgaBuffer {
pub fn clear(&mut self) {
let blank = ScreenChar::new(b' ', ConsoleColor::White, ConsoleColor::Black);
for row in 0 .. BUFFER_HEIGHT {
for row in 0..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
self.chars[row][col].write(blank);
}
@ -95,10 +99,10 @@ impl VgaBuffer {
}
lazy_static! {
pub static ref VGA_WRITER: Mutex<VgaWriter> = Mutex::new(
// VGA virtual address is specified at bootloader
VgaWriter::new(unsafe{ &mut *((KERNEL_OFFSET + 0xf0000000) as *mut VgaBuffer) })
);
pub static ref VGA_WRITER: Mutex<VgaWriter> = Mutex::new(
// VGA virtual address is specified at bootloader
VgaWriter::new(unsafe{ &mut *((KERNEL_OFFSET + 0xf0000000) as *mut VgaBuffer) })
);
}
pub struct VgaWriter {
@ -135,7 +139,8 @@ impl BaseConsole for VgaWriter {
pos.row.bound(self.get_height());
pos.col.bound(self.get_width());
self.pos = pos;
self.buffer.set_cursor_at(pos.row.0 as usize, pos.col.0 as usize);
self.buffer
.set_cursor_at(pos.row.0 as usize, pos.col.0 as usize);
Ok(())
}
@ -180,7 +185,8 @@ impl AsciiConsole for VgaWriter {
ascii_char: ch,
color_code: self.color_code,
};
self.buffer.write(pos.row.0 as usize, pos.col.0 as usize, screen_char);
self.buffer
.write(pos.row.0 as usize, pos.col.0 as usize, screen_char);
Ok(())
}
@ -221,8 +227,7 @@ impl AsciiConsole for VgaWriter {
0x1b => Some(SpecialChar::Escape),
0x7f => Some(SpecialChar::Delete),
0x08 => Some(SpecialChar::Backspace),
_ if !(ch.is_ascii_graphic() || ch == b' ')
=> Some(SpecialChar::Delete), // ignore non-graphic ascii
_ if !(ch.is_ascii_graphic() || ch == b' ') => Some(SpecialChar::Delete), // ignore non-graphic ascii
_ => None,
},
_ => None,
@ -246,7 +251,6 @@ impl VgaWriter {
impl fmt::Write for VgaWriter {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write_string(s.as_bytes())
.map_err(|_| fmt::Error)
self.write_string(s.as_bytes()).map_err(|_| fmt::Error)
}
}

@ -1,9 +1,9 @@
use alloc::boxed::Box;
use x86_64::{PrivilegeLevel, VirtAddr};
use x86_64::registers::model_specific::Msr;
use x86_64::structures::gdt::*;
use x86_64::structures::tss::TaskStateSegment;
use x86_64::registers::model_specific::Msr;
use x86_64::{PrivilegeLevel, VirtAddr};
use crate::consts::MAX_CPU_NUM;
@ -17,8 +17,7 @@ pub fn init() {
static mut CPUS: [Option<Cpu>; MAX_CPU_NUM] = [
// TODO: More elegant ?
None, None, None, None,
None, None, None, None,
None, None, None, None, None, None, None, None,
];
pub struct Cpu {
@ -41,7 +40,7 @@ impl Cpu {
}
unsafe fn init(&'static mut self) {
use x86_64::instructions::segmentation::{set_cs, load_fs};
use x86_64::instructions::segmentation::{load_fs, set_cs};
use x86_64::instructions::tables::load_tss;
// Set the stack when DoubleFault occurs
@ -79,13 +78,13 @@ impl Cpu {
pub const DOUBLE_FAULT_IST_INDEX: usize = 0;
// Copied from xv6 x86_64
const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE
const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE
const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT
const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT
// Copied from xv6
const UCODE32: Descriptor = Descriptor::UserSegment(0x00cffa00_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
const UDATA32: Descriptor = Descriptor::UserSegment(0x00cff200_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE
const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE
const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT
const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT
// Copied from xv6
const UCODE32: Descriptor = Descriptor::UserSegment(0x00cffa00_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
const UDATA32: Descriptor = Descriptor::UserSegment(0x00cff200_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
// NOTICE: for fast syscall:
// STAR[47:32] = K_CS = K_SS - 8
@ -95,4 +94,4 @@ pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLev
pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring3);
pub const UDATA32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring0);
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring0);

@ -1,5 +1,5 @@
use x86_64::structures::idt::*;
use lazy_static::lazy_static;
use x86_64::structures::idt::*;
pub fn init() {
IDT.load();
@ -8,7 +8,7 @@ pub fn init() {
lazy_static! {
static ref IDT: InterruptDescriptorTable = {
use crate::arch::interrupt::consts::*;
use crate::arch::gdt::DOUBLE_FAULT_IST_INDEX;
use crate::arch::gdt::DOUBLE_FAULT_IST_INDEX;
use x86_64::PrivilegeLevel;
use core::mem::transmute;
@ -37,9 +37,9 @@ lazy_static! {
};
}
extern {
extern "C" {
/// 中断向量表
/// 符号定义在 [trap.asm](boot/trap.asm)
//noinspection RsStaticConstNaming
static __vectors: [extern fn(); 256];
static __vectors: [extern "C" fn(); 256];
}

@ -36,7 +36,7 @@ pub const Error: u8 = 19;
pub const Spurious: u8 = 31;
// PCI Interrupts
// See https://gist.github.com/mcastelino/4acda7c2407f1c51e68f3f994d8ffc98
// See https://gist.github.com/mcastelino/4acda7c2407f1c51e68f3f994d8ffc98
pub const PIRQA: u8 = 16;
pub const PIRQB: u8 = 17;
pub const PIRQC: u8 = 18;

@ -1,9 +1,8 @@
/// `syscall` instruction
use x86_64::registers::model_specific::*;
use core::mem::transmute;
use super::super::gdt;
use super::TrapFrame;
use core::mem::transmute;
/// `syscall` instruction
use x86_64::registers::model_specific::*;
pub fn init() {
unsafe {
@ -26,7 +25,7 @@ pub fn init() {
}
}
extern {
extern "C" {
fn syscall_entry();
}

@ -66,17 +66,21 @@
use super::consts::*;
use super::TrapFrame;
use log::*;
use bitflags::*;
use crate::drivers::DRIVERS;
use bitflags::*;
use log::*;
global_asm!(include_str!("trap.asm"));
global_asm!(include_str!("vector.asm"));
#[allow(non_upper_case_globals)]
#[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) {
trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, super::super::cpu::id());
pub extern "C" fn rust_trap(tf: &mut TrapFrame) {
trace!(
"Interrupt: {:#x} @ CPU{}",
tf.trap_num,
super::super::cpu::id()
);
// Dispatch
match tf.trap_num as u8 {
Breakpoint => breakpoint(),
@ -99,7 +103,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
}
}
warn!("unhandled external IRQ number: {}", irq);
},
}
}
}
Syscall32 => syscall32(tf),
@ -120,7 +124,9 @@ fn double_fault(tf: &TrapFrame) {
fn page_fault(tf: &mut TrapFrame) {
let addr: usize;
unsafe { asm!("mov %cr2, $0" : "=r" (addr)); }
unsafe {
asm!("mov %cr2, $0" : "=r" (addr));
}
bitflags! {
struct PageError: u8 {
@ -197,7 +203,7 @@ fn invalid_opcode(tf: &mut TrapFrame) {
let opcode = unsafe { (tf.rip as *mut u16).read() };
const SYSCALL_OPCODE: u16 = 0x05_0f;
if opcode == SYSCALL_OPCODE {
tf.rip += 2; // must before syscall
tf.rip += 2; // must before syscall
syscall(tf);
} else {
crate::trap::error(tf);
@ -209,7 +215,7 @@ fn error(tf: &TrapFrame) {
}
#[no_mangle]
pub unsafe extern fn set_return_rsp(tf: *const TrapFrame) {
pub unsafe extern "C" fn set_return_rsp(tf: *const TrapFrame) {
use crate::arch::gdt::Cpu;
Cpu::current().set_ring0_rsp(tf.add(1) as usize);
}

@ -1,12 +1,12 @@
pub mod consts;
pub mod fast_syscall;
mod handler;
mod trapframe;
pub mod fast_syscall;
pub use self::trapframe::*;
pub use self::handler::*;
use apic::*;
pub use self::trapframe::*;
use crate::consts::KERNEL_OFFSET;
use apic::*;
#[inline(always)]
pub unsafe fn enable() {
@ -47,4 +47,4 @@ pub fn enable_irq(irq: u8) {
pub fn ack(_irq: u8) {
let mut lapic = unsafe { XApic::new(KERNEL_OFFSET + LAPIC_ADDR) };
lapic.eoi();
}
}

@ -1,9 +1,9 @@
use core::fmt;
use core::default::Default;
use core::fmt;
#[derive(Clone)]
#[repr(C)]
pub struct FpState([u8; 16+512]);
pub struct FpState([u8; 16 + 512]);
impl fmt::Debug for FpState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -13,11 +13,10 @@ impl fmt::Debug for FpState {
impl Default for FpState {
fn default() -> Self {
FpState([0u8; 16+512])
FpState([0u8; 16 + 512])
}
}
#[derive(Debug, Clone, Default)]
#[repr(C)]
pub struct TrapFrame {
@ -62,7 +61,7 @@ pub struct TrapFrame {
/// 用于在内核栈中构造新线程的中断帧
impl TrapFrame {
fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, rsp: usize) -> Self {
fn new_kernel_thread(entry: extern "C" fn(usize) -> !, arg: usize, rsp: usize) -> Self {
use crate::arch::gdt;
let mut tf = TrapFrame::default();
tf.rdi = arg;
@ -77,7 +76,11 @@ impl TrapFrame {
fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
use crate::arch::gdt;
let mut tf = TrapFrame::default();
tf.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize;
tf.cs = if is32 {
gdt::UCODE32_SELECTOR.0
} else {
gdt::UCODE_SELECTOR.0
} as usize;
tf.rip = entry_addr;
tf.ss = gdt::UDATA32_SELECTOR.0 as usize;
tf.rsp = rsp;
@ -105,7 +108,11 @@ struct ContextData {
impl ContextData {
fn new(cr3: usize) -> Self {
ContextData { rip: trap_ret as usize, cr3, ..ContextData::default() }
ContextData {
rip: trap_ret as usize,
cr3,
..ContextData::default()
}
}
}
@ -125,7 +132,7 @@ impl InitStack {
}
}
extern {
extern "C" {
fn trap_ret();
}
@ -142,7 +149,7 @@ impl Context {
/// Pop all callee-saved registers, then return to the target.
#[naked]
#[inline(never)]
pub unsafe extern fn switch(&mut self, _target: &mut Self) {
pub unsafe extern "C" fn switch(&mut self, _target: &mut Self) {
asm!(
"
// push rip (by caller)
@ -180,17 +187,30 @@ impl Context {
Context(0)
}
pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, cr3: usize) -> Self {
pub unsafe fn new_kernel_thread(
entry: extern "C" fn(usize) -> !,
arg: usize,
kstack_top: usize,
cr3: usize,
) -> Self {
InitStack {
context: ContextData::new(cr3),
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize) -> Self {
pub unsafe fn new_user_thread(
entry_addr: usize,
ustack_top: usize,
kstack_top: usize,
is32: bool,
cr3: usize,
) -> Self {
InitStack {
context: ContextData::new(cr3),
tf: TrapFrame::new_user_thread(entry_addr, ustack_top, is32),
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self {
InitStack {
@ -200,9 +220,16 @@ impl Context {
tf.rax = 0;
tf
},
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
pub unsafe fn new_clone(tf: &TrapFrame, ustack_top: usize, kstack_top: usize, cr3: usize, tls: usize) -> Self {
pub unsafe fn new_clone(
tf: &TrapFrame,
ustack_top: usize,
kstack_top: usize,
cr3: usize,
tls: usize,
) -> Self {
InitStack {
context: ContextData::new(cr3),
tf: {
@ -212,7 +239,8 @@ impl Context {
tf.rax = 0;
tf
},
}.push_at(kstack_top)
}
.push_at(kstack_top)
}
/// Called at a new user context
/// To get the init TrapFrame in sys_exec

@ -3,19 +3,25 @@ use super::driver::vga::VGA_WRITER;
use core::fmt::{Arguments, Write};
pub fn getchar() -> char {
unsafe { COM1.force_unlock(); }
unsafe {
COM1.force_unlock();
}
COM1.lock().receive() as char
}
pub fn putfmt(fmt: Arguments) {
#[cfg(feature = "nographic")]
{
unsafe { COM1.force_unlock(); }
unsafe {
COM1.force_unlock();
}
COM1.lock().write_fmt(fmt).unwrap();
}
#[cfg(not(feature = "nographic"))]
{
unsafe { VGA_WRITER.force_unlock(); }
unsafe {
VGA_WRITER.force_unlock();
}
VGA_WRITER.lock().write_fmt(fmt).unwrap();
}
}
}

@ -1,11 +1,11 @@
use bit_allocator::BitAlloc;
use crate::consts::KERNEL_OFFSET;
use bit_allocator::BitAlloc;
// Depends on kernel
use crate::memory::{FRAME_ALLOCATOR, init_heap, active_table};
use super::{BootInfo, MemoryRegionType};
use rcore_memory::paging::*;
use once::*;
use crate::memory::{active_table, init_heap, FRAME_ALLOCATOR};
use log::*;
use once::*;
use rcore_memory::paging::*;
pub fn init(boot_info: &BootInfo) {
assert_has_not_been_called!("memory::init must be called only once");
@ -20,7 +20,9 @@ fn init_frame_allocator(boot_info: &BootInfo) {
let mut ba = FRAME_ALLOCATOR.lock();
for region in boot_info.memory_map.iter() {
if region.region_type == MemoryRegionType::Usable {
ba.insert(region.range.start_frame_number as usize..region.range.end_frame_number as usize);
ba.insert(
region.range.start_frame_number as usize..region.range.end_frame_number as usize,
);
}
}
}
@ -28,7 +30,11 @@ fn init_frame_allocator(boot_info: &BootInfo) {
fn init_device_vm_map() {
let mut page_table = active_table();
// IOAPIC
page_table.map(KERNEL_OFFSET + 0xfec00000, 0xfec00000).update();
page_table
.map(KERNEL_OFFSET + 0xfec00000, 0xfec00000)
.update();
// LocalAPIC
page_table.map(KERNEL_OFFSET + 0xfee00000, 0xfee00000).update();
page_table
.map(KERNEL_OFFSET + 0xfee00000, 0xfee00000)
.update();
}

@ -2,18 +2,18 @@ use bootloader::bootinfo::{BootInfo, MemoryRegionType};
use core::sync::atomic::*;
use log::*;
pub mod driver;
pub mod consts;
pub mod cpu;
pub mod interrupt;
pub mod paging;
pub mod driver;
pub mod gdt;
pub mod idt;
pub mod memory;
pub mod interrupt;
pub mod io;
pub mod consts;
pub mod timer;
pub mod syscall;
pub mod memory;
pub mod paging;
pub mod rand;
pub mod syscall;
pub mod timer;
static AP_CAN_INIT: AtomicBool = ATOMIC_BOOL_INIT;
@ -62,4 +62,4 @@ fn other_start() -> ! {
cpu::init();
interrupt::fast_syscall::init();
crate::kmain();
}
}

@ -1,18 +1,18 @@
// Depends on kernel
use crate::consts::KERNEL_OFFSET;
use crate::memory::{active_table, alloc_frame, dealloc_frame};
use log::*;
use rcore_memory::paging::*;
use x86_64::instructions::tlb;
use x86_64::PhysAddr;
use x86_64::registers::control::{Cr3, Cr3Flags};
use x86_64::structures::paging::{
page_table::{PageTable as x86PageTable, PageTableEntry, PageTableFlags as EF},
frame::PhysFrame as Frame,
mapper::{Mapper, RecursivePageTable},
page::{Page, PageRange, Size4KiB},
frame::PhysFrame as Frame,
FrameAllocator, FrameDeallocator
page_table::{PageTable as x86PageTable, PageTableEntry, PageTableFlags as EF},
FrameAllocator, FrameDeallocator,
};
use crate::consts::KERNEL_OFFSET;
use log::*;
use x86_64::PhysAddr;
pub trait PageExt {
fn of_addr(address: usize) -> Self;
@ -47,7 +47,12 @@ impl PageTable for ActivePageTable {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE;
unsafe {
if let Ok(flush) = self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, &mut FrameAllocatorForX86) {
if let Ok(flush) = self.0.map_to(
Page::of_addr(addr),
Frame::of_addr(target),
flags,
&mut FrameAllocatorForX86,
) {
flush.flush();
}
}
@ -64,7 +69,9 @@ impl PageTable for ActivePageTable {
fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> {
for level in 0..3 {
let entry = get_entry_ptr(addr, 4 - level);
if unsafe { !(*entry).present() } { return None; }
if unsafe { !(*entry).present() } {
return None;
}
}
unsafe { Some(&mut *(get_entry_ptr(addr, 1))) }
}
@ -82,34 +89,64 @@ impl ActivePageTable {
impl Entry for PageEntry {
fn update(&mut self) {
use x86_64::{VirtAddr, instructions::tlb::flush};
use x86_64::{instructions::tlb::flush, VirtAddr};
let addr = VirtAddr::new_unchecked((self as *const _ as u64) << 9);
flush(addr);
}
fn accessed(&self) -> bool { self.0.flags().contains(EF::ACCESSED) }
fn dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) }
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITABLE) }
fn present(&self) -> bool { self.0.flags().contains(EF::PRESENT) }
fn clear_accessed(&mut self) { self.as_flags().remove(EF::ACCESSED); }
fn clear_dirty(&mut self) { self.as_flags().remove(EF::DIRTY); }
fn set_writable(&mut self, value: bool) { self.as_flags().set(EF::WRITABLE, value); }
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::PRESENT, value); }
fn target(&self) -> usize { self.0.addr().as_u64() as usize }
fn accessed(&self) -> bool {
self.0.flags().contains(EF::ACCESSED)
}
fn dirty(&self) -> bool {
self.0.flags().contains(EF::DIRTY)
}
fn writable(&self) -> bool {
self.0.flags().contains(EF::WRITABLE)
}
fn present(&self) -> bool {
self.0.flags().contains(EF::PRESENT)
}
fn clear_accessed(&mut self) {
self.as_flags().remove(EF::ACCESSED);
}
fn clear_dirty(&mut self) {
self.as_flags().remove(EF::DIRTY);
}
fn set_writable(&mut self, value: bool) {
self.as_flags().set(EF::WRITABLE, value);
}
fn set_present(&mut self, value: bool) {
self.as_flags().set(EF::PRESENT, value);
}
fn target(&self) -> usize {
self.0.addr().as_u64() as usize
}
fn set_target(&mut self, target: usize) {
let flags = self.0.flags();
self.0.set_addr(PhysAddr::new(target as u64), flags);
}
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::BIT_10) }
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::BIT_9) }
fn writable_shared(&self) -> bool {
self.0.flags().contains(EF::BIT_10)
}
fn readonly_shared(&self) -> bool {
self.0.flags().contains(EF::BIT_9)
}
fn set_shared(&mut self, writable: bool) {
let flags = self.as_flags();
flags.set(EF::BIT_10, writable);
flags.set(EF::BIT_9, !writable);
}
fn clear_shared(&mut self) { self.as_flags().remove(EF::BIT_9 | EF::BIT_10); }
fn swapped(&self) -> bool { self.0.flags().contains(EF::BIT_11) }
fn set_swapped(&mut self, value: bool) { self.as_flags().set(EF::BIT_11, value); }
fn user(&self) -> bool { self.0.flags().contains(EF::USER_ACCESSIBLE) }
fn clear_shared(&mut self) {
self.as_flags().remove(EF::BIT_9 | EF::BIT_10);
}
fn swapped(&self) -> bool {
self.0.flags().contains(EF::BIT_11)
}
fn set_swapped(&mut self, value: bool) {
self.as_flags().set(EF::BIT_11, value);
}
fn user(&self) -> bool {
self.0.flags().contains(EF::USER_ACCESSIBLE)
}
fn set_user(&mut self, value: bool) {
self.as_flags().set(EF::USER_ACCESSIBLE, value);
if value {
@ -122,10 +159,16 @@ impl Entry for PageEntry {
}
}
}
fn execute(&self) -> bool { !self.0.flags().contains(EF::NO_EXECUTE) }
fn set_execute(&mut self, value: bool) { self.as_flags().set(EF::NO_EXECUTE, !value); }
fn mmio(&self) -> u8 { 0 }
fn set_mmio(&mut self, _value: u8) { }
fn execute(&self) -> bool {
!self.0.flags().contains(EF::NO_EXECUTE)
}
fn set_execute(&mut self, value: bool) {
self.as_flags().set(EF::NO_EXECUTE, !value);
}
fn mmio(&self) -> u8 {
0
}
fn set_mmio(&mut self, _value: u8) {}
}
fn get_entry_ptr(addr: usize, level: u8) -> *mut PageEntry {
@ -176,7 +219,10 @@ impl InactivePageTable for InactivePageTable0 {
}
unsafe fn set_token(token: usize) {
Cr3::write(Frame::containing_address(PhysAddr::new(token as u64)), Cr3Flags::empty());
Cr3::write(
Frame::containing_address(PhysAddr::new(token as u64)),
Cr3Flags::empty(),
);
}
fn active_token() -> usize {

@ -1,3 +1,3 @@
pub fn read_epoch() -> u64 {
super::driver::rtc_cmos::read_epoch()
}
}

@ -52,8 +52,16 @@ pub fn backtrace() {
let mut current_pc = lr();
let mut current_fp = fp();
let mut stack_num = 0;
while current_pc >= stext as usize && current_pc <= etext as usize && current_fp as usize != 0 {
println!("#{} {:#018X} fp {:#018X}", stack_num, current_pc - size_of::<usize>(), current_fp);
while current_pc >= stext as usize
&& current_pc <= etext as usize
&& current_fp as usize != 0
{
println!(
"#{} {:#018X} fp {:#018X}",
stack_num,
current_pc - size_of::<usize>(),
current_fp
);
stack_num = stack_num + 1;
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
{
@ -72,8 +80,9 @@ pub fn backtrace() {
// Kernel stack at 0x0000_57ac_0000_0000 (defined in bootloader crate)
// size = 512 pages
current_fp = *(current_fp as *const usize).offset(0);
if current_fp >= 0x0000_57ac_0000_0000 + 512 * PAGE_SIZE - size_of::<usize>() &&
current_fp <= 0xffff_ff00_0000_0000 {
if current_fp >= 0x0000_57ac_0000_0000 + 512 * PAGE_SIZE - size_of::<usize>()
&& current_fp <= 0xffff_ff00_0000_0000
{
break;
}
current_pc = *(current_fp as *const usize).offset(1);

@ -1,5 +1,5 @@
use core::slice;
use alloc::string::String;
use core::slice;
use device_tree::{DeviceTree, Node};

@ -90,4 +90,4 @@ pub fn init() {
lazy_static! {
// Write only once at boot
pub static ref CMDLINE: RwLock<String> = RwLock::new(String::new());
}
}

@ -1,7 +1,7 @@
//! Implement Device
use spin::RwLock;
use rcore_fs::dev::*;
use spin::RwLock;
#[cfg(target_arch = "x86_64")]
use crate::arch::driver::ide;
@ -9,9 +9,12 @@ use crate::arch::driver::ide;
pub struct MemBuf(RwLock<&'static mut [u8]>);
impl MemBuf {
pub unsafe fn new(begin: unsafe extern fn(), end: unsafe extern fn()) -> Self {
pub unsafe fn new(begin: unsafe extern "C" fn(), end: unsafe extern "C" fn()) -> Self {
use core::slice;
MemBuf(RwLock::new(slice::from_raw_parts_mut(begin as *mut u8, end as usize - begin as usize)))
MemBuf(RwLock::new(slice::from_raw_parts_mut(
begin as *mut u8,
end as usize - begin as usize,
)))
}
}
@ -36,7 +39,8 @@ impl BlockDevice for ide::IDE {
fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool {
use core::slice;
assert!(buf.len() >= ide::BLOCK_SIZE);
let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
let buf =
unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
self.read(block_id as u64, 1, buf).is_ok()
}
fn write_at(&self, block_id: usize, buf: &[u8]) -> bool {
@ -45,4 +49,4 @@ impl BlockDevice for ide::IDE {
let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
self.write(block_id as u64, 1, buf).is_ok()
}
}
}

@ -2,7 +2,7 @@
use alloc::{string::String, sync::Arc};
use rcore_fs::vfs::{Metadata, INode, Result, FsError};
use rcore_fs::vfs::{FsError, INode, Metadata, Result};
#[derive(Clone)]
pub struct FileHandle {
@ -43,7 +43,7 @@ impl FileHandle {
pub fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize> {
if !self.options.read {
return Err(FsError::InvalidParam); // FIXME: => EBADF
return Err(FsError::InvalidParam); // FIXME: => EBADF
}
let len = self.inode.read_at(offset, buf)?;
Ok(len)
@ -61,7 +61,7 @@ impl FileHandle {
pub fn write_at(&mut self, offset: usize, buf: &[u8]) -> Result<usize> {
if !self.options.write {
return Err(FsError::InvalidParam); // FIXME: => EBADF
return Err(FsError::InvalidParam); // FIXME: => EBADF
}
let len = self.inode.write_at(offset, buf)?;
Ok(len)
@ -78,7 +78,7 @@ impl FileHandle {
pub fn set_len(&mut self, len: u64) -> Result<()> {
if !self.options.write {
return Err(FsError::InvalidParam); // FIXME: => EBADF
return Err(FsError::InvalidParam); // FIXME: => EBADF
}
self.inode.resize(len as usize)?;
Ok(())
@ -102,10 +102,10 @@ impl FileHandle {
pub fn read_entry(&mut self) -> Result<String> {
if !self.options.read {
return Err(FsError::InvalidParam); // FIXME: => EBADF
return Err(FsError::InvalidParam); // FIXME: => EBADF
}
let name = self.inode.get_entry(self.offset as usize)?;
self.offset += 1;
Ok(name)
}
}
}

@ -7,24 +7,28 @@ use rcore_fs_sfs::SimpleFileSystem;
use crate::arch::driver::ide;
pub use self::file::*;
pub use self::stdio::{STDIN, STDOUT};
pub use self::pipe::Pipe;
pub use self::stdio::{STDIN, STDOUT};
mod file;
mod stdio;
mod device;
mod file;
mod pipe;
mod stdio;
/// Hard link user programs
#[cfg(feature = "link_user")]
global_asm!(concat!(r#"
global_asm!(concat!(
r#"
.section .data
.global _user_img_start
.global _user_img_end
_user_img_start:
.incbin ""#, env!("SFSIMG"), r#""
.incbin ""#,
env!("SFSIMG"),
r#""
_user_img_end:
"#));
"#
));
lazy_static! {
/// The root of file system
@ -66,7 +70,9 @@ impl INodeExt for INode {
fn read_as_vec(&self) -> Result<Vec<u8>> {
let size = self.metadata()?.size;
let mut buf = Vec::with_capacity(size);
unsafe { buf.set_len(size); }
unsafe {
buf.set_len(size);
}
self.read_at(0, buf.as_mut_slice())?;
Ok(buf)
}

@ -67,18 +67,22 @@ impl INode for Stdin {
buf[0] = self.pop() as u8;
Ok(1)
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> { unimplemented!() }
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 read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
unimplemented!()
}
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
use core::str;
//we do not care the utf-8 things, we just want to print it!
let s = unsafe{ str::from_utf8_unchecked(buf) };
let s = unsafe { str::from_utf8_unchecked(buf) };
print!("{}", s);
Ok(buf.len())
}
impl_inode!();
}
}

@ -1,19 +1,20 @@
// Rust language features implementations
use core::panic::PanicInfo;
use crate::backtrace;
use core::alloc::Layout;
use core::panic::PanicInfo;
use log::*;
use crate::backtrace;
#[lang = "eh_personality"]
extern fn eh_personality() {
}
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
error!("\n\n{}", info);
backtrace::backtrace();
loop { crate::arch::cpu::halt() }
loop {
crate::arch::cpu::halt()
}
}
#[lang = "oom"]

@ -16,25 +16,25 @@ extern crate log;
#[macro_use]
extern crate lazy_static;
pub use crate::process::{processor, new_kernel_context};
use rcore_thread::std_thread as thread;
pub use crate::process::{new_kernel_context, processor};
use buddy_system_allocator::LockedHeap;
use rcore_thread::std_thread as thread;
#[macro_use] // print!
#[macro_use] // print!
mod logging;
mod memory;
mod lang;
mod util;
mod backtrace;
mod consts;
mod process;
mod syscall;
mod drivers;
mod fs;
mod lang;
mod memory;
mod net;
mod process;
mod shell;
mod sync;
mod syscall;
mod trap;
mod shell;
mod drivers;
mod net;
mod backtrace;
mod util;
#[allow(dead_code)]
#[cfg(target_arch = "x86_64")]

@ -61,15 +61,17 @@ struct SimpleLogger;
impl Log for SimpleLogger {
fn enabled(&self, _metadata: &Metadata) -> bool {
true
true
}
fn log(&self, record: &Record) {
static DISABLED_TARGET: &[&str] = &[
];
static DISABLED_TARGET: &[&str] = &[];
if self.enabled(record.metadata()) && !DISABLED_TARGET.contains(&record.target()) {
// let target = record.target();
// let begin = target.as_bytes().iter().rposition(|&c| c == b':').map(|i| i + 1).unwrap_or(0);
print_in_color(format_args!("[{:>5}] {}\n", record.level(), record.args()), ConsoleColor::from(record.level()));
// let target = record.target();
// let begin = target.as_bytes().iter().rposition(|&c| c == b':').map(|i| i + 1).unwrap_or(0);
print_in_color(
format_args!("[{:>5}] {}\n", record.level(), record.args()),
ConsoleColor::from(record.level()),
);
}
}
fn flush(&self) {}

@ -3,4 +3,4 @@
#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))]
#[allow(unused_imports)]
use rcore;
use rcore;

@ -1,14 +1,14 @@
use super::HEAP_ALLOCATOR;
pub use crate::arch::paging::*;
use bit_allocator::BitAlloc;
use crate::consts::MEMORY_OFFSET;
use super::HEAP_ALLOCATOR;
use rcore_memory::*;
pub use rcore_memory::memory_set::{MemoryArea, MemoryAttr, handler::*};
use crate::process::process_unsafe;
use crate::sync::SpinNoIrqLock;
use bit_allocator::BitAlloc;
use buddy_system_allocator::LockedHeap;
use lazy_static::*;
use log::*;
use buddy_system_allocator::LockedHeap;
pub use rcore_memory::memory_set::{handler::*, MemoryArea, MemoryAttr};
use rcore_memory::*;
pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
@ -25,7 +25,8 @@ pub type FrameAlloc = bit_allocator::BitAlloc4K;
pub type FrameAlloc = bit_allocator::BitAlloc1M;
lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = SpinNoIrqLock::new(FrameAlloc::default());
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> =
SpinNoIrqLock::new(FrameAlloc::default());
}
/// The only way to get active page table
@ -46,21 +47,25 @@ pub fn active_table() -> ActivePageTable {
unsafe { ActivePageTable::new() }
}
#[derive(Debug, Clone, Copy)]
pub struct GlobalFrameAlloc;
impl FrameAllocator for GlobalFrameAlloc {
fn alloc(&self) -> Option<usize> {
// get the real address of the alloc frame
let ret = FRAME_ALLOCATOR.lock().alloc().map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
let ret = FRAME_ALLOCATOR
.lock()
.alloc()
.map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
trace!("Allocate frame: {:x?}", ret);
ret
// TODO: try to swap out when alloc failed
}
fn dealloc(&self, target: usize) {
trace!("Deallocate frame: {:x}", target);
FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
FRAME_ALLOCATOR
.lock()
.dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
}
}
@ -77,7 +82,8 @@ const STACK_SIZE: usize = 0x8000;
impl KernelStack {
pub fn new() -> Self {
use alloc::alloc::{alloc, Layout};
let bottom = unsafe{ alloc(Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap()) } as usize;
let bottom =
unsafe { alloc(Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap()) } as usize;
KernelStack(bottom)
}
pub fn top(&self) -> usize {
@ -88,28 +94,34 @@ impl KernelStack {
impl Drop for KernelStack {
fn drop(&mut self) {
use alloc::alloc::{dealloc, Layout};
unsafe{ dealloc(self.0 as _, Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap()); }
unsafe {
dealloc(
self.0 as _,
Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap(),
);
}
}
}
/// Handle page fault at `addr`.
/// Return true to continue, false to halt.
pub fn handle_page_fault(addr: usize) -> bool {
debug!("page fault @ {:#x}", addr);
// This is safe as long as page fault never happens in page fault handler
unsafe {
process_unsafe().vm.handle_page_fault(addr)
}
unsafe { process_unsafe().vm.handle_page_fault(addr) }
}
pub fn init_heap() {
use crate::consts::KERNEL_HEAP_SIZE;
static mut HEAP: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE];
unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, KERNEL_HEAP_SIZE); }
unsafe {
HEAP_ALLOCATOR
.lock()
.init(HEAP.as_ptr() as usize, KERNEL_HEAP_SIZE);
}
info!("heap init end");
}
/// Allocator for the rest memory space on NO-MMU case.
pub static MEMORY_ALLOCATOR: LockedHeap = LockedHeap::empty();
pub static MEMORY_ALLOCATOR: LockedHeap = LockedHeap::empty();

@ -1,8 +1,8 @@
use alloc::sync::Arc;
use crate::arch::rand;
use crate::drivers::{NET_DRIVERS, SOCKET_ACTIVITY};
use crate::sync::SpinNoIrqLock as Mutex;
use crate::syscall::*;
use alloc::sync::Arc;
use smoltcp::socket::*;
use smoltcp::wire::*;

@ -1,6 +1,6 @@
use alloc::collections::btree_map::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use alloc::collections::btree_map::BTreeMap;
use core::ptr::null;
pub struct ProcInitInfo {
@ -16,17 +16,25 @@ impl ProcInitInfo {
// program name
writer.push_str(&self.args[0]);
// environment strings
let envs: Vec<_> = self.envs.iter().map(|(key, value)| {
writer.push_str(value.as_str());
writer.push_slice(&[b"="]);
writer.push_slice(key.as_bytes());
writer.sp
}).collect();
let envs: Vec<_> = self
.envs
.iter()
.map(|(key, value)| {
writer.push_str(value.as_str());
writer.push_slice(&[b"="]);
writer.push_slice(key.as_bytes());
writer.sp
})
.collect();
// argv strings
let argv: Vec<_> = self.args.iter().map(|arg| {
writer.push_str(arg.as_str());
writer.sp
}).collect();
let argv: Vec<_> = self
.args
.iter()
.map(|arg| {
writer.push_str(arg.as_str());
writer.sp
})
.collect();
// auxiliary vector entries
writer.push_slice(&[null::<u8>(), null::<u8>()]);
for (&type_, &value) in self.auxv.iter() {
@ -50,11 +58,13 @@ struct StackWriter {
impl StackWriter {
fn push_slice<T: Copy>(&mut self, vs: &[T]) {
use core::{mem::{size_of, align_of}, slice};
use core::{
mem::{align_of, size_of},
slice,
};
self.sp -= vs.len() * size_of::<T>();
self.sp -= self.sp % align_of::<T>();
unsafe { slice::from_raw_parts_mut(self.sp as *mut T, vs.len()) }
.copy_from_slice(vs);
unsafe { slice::from_raw_parts_mut(self.sp as *mut T, vs.len()) }.copy_from_slice(vs);
}
fn push_str(&mut self, s: &str) {
self.push_slice(&[b'\0']);

@ -1,13 +1,13 @@
pub use self::structs::*;
pub use rcore_thread::*;
use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM};
use crate::arch::cpu;
use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM};
use alloc::{boxed::Box, sync::Arc};
use spin::MutexGuard;
use log::*;
pub use rcore_thread::*;
use spin::MutexGuard;
pub mod structs;
mod abi;
pub mod structs;
pub fn init() {
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass
@ -25,7 +25,16 @@ pub fn init() {
info!("process: init end");
}
static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new()];
static PROCESSORS: [Processor; MAX_CPU_NUM] = [
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
];
/// Get current process
pub fn process() -> MutexGuard<'static, Process> {
@ -45,13 +54,10 @@ pub unsafe fn process_unsafe() -> MutexGuard<'static, Process> {
/// FIXME: It's obviously unsafe to get &mut !
pub fn current_thread() -> &'static mut Thread {
use core::mem::transmute;
let (process, _): (&mut Thread, *const ()) = unsafe {
transmute(processor().context())
};
let (process, _): (&mut Thread, *const ()) = unsafe { transmute(processor().context()) };
process
}
// Implement dependencies for std::thread
#[no_mangle]
@ -60,6 +66,6 @@ pub fn processor() -> &'static Processor {
}
#[no_mangle]
pub fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
pub fn new_kernel_context(entry: extern "C" fn(usize) -> !, arg: usize) -> Box<Context> {
Thread::new_kernel(entry, arg)
}

@ -1,18 +1,22 @@
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::Vec, sync::Weak};
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, sync::Weak, vec::Vec};
use core::fmt;
use core::str;
use log::*;
use spin::{Mutex, RwLock};
use xmas_elf::{ElfFile, header, program::{Flags, Type, SegmentData}};
use rcore_memory::PAGE_SIZE;
use rcore_thread::Tid;
use core::str;
use spin::{Mutex, RwLock};
use xmas_elf::{
header,
program::{Flags, SegmentData, Type},
ElfFile,
};
use crate::arch::interrupt::{Context, TrapFrame};
use crate::fs::{FileHandle, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH};
use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet};
use crate::fs::{FileHandle, OpenOptions, INodeExt, FOLLOW_MAX_DEPTH};
use crate::sync::Condvar;
use crate::net::{SocketWrapper, SOCKETS};
use crate::sync::Condvar;
use super::abi::{self, ProcInitInfo};
@ -26,20 +30,17 @@ pub struct Thread {
pub proc: Arc<Mutex<Process>>,
}
#[derive(Clone)]
pub enum FileLike {
File(FileHandle),
Socket(SocketWrapper)
Socket(SocketWrapper),
}
impl fmt::Debug for FileLike {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FileLike::File(_) => write!(f, "File"),
FileLike::Socket(wrapper) => {
write!(f, "{:?}", wrapper)
},
FileLike::Socket(wrapper) => write!(f, "{:?}", wrapper),
}
}
}
@ -104,7 +105,8 @@ pub struct Process {
/// Records the mapping between pid and Process struct.
lazy_static! {
pub static ref PROCESSES: RwLock<BTreeMap<usize, Weak<Mutex<Process>>>> = RwLock::new(BTreeMap::new());
pub static ref PROCESSES: RwLock<BTreeMap<usize, Weak<Mutex<Process>>>> =
RwLock::new(BTreeMap::new());
}
/// Let `rcore_thread` can switch between our `Thread`
@ -128,7 +130,9 @@ impl rcore_thread::Context for Thread {
}
// add it to threads
proc.threads.push(tid);
PROCESSES.write().insert(proc.pid.get(), Arc::downgrade(&self.proc));
PROCESSES
.write()
.insert(proc.pid.get(), Arc::downgrade(&self.proc));
}
}
@ -156,7 +160,7 @@ impl Thread {
}
/// Make a new kernel thread starting from `entry` with `arg`
pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Thread> {
pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Box<Thread> {
let vm = MemorySet::new();
let kstack = KernelStack::new();
Box::new(Thread {
@ -174,14 +178,15 @@ impl Thread {
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new()
child_exit_code: BTreeMap::new(),
})),
})
}
/// Make a new user process from ELF `data`
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<Thread>
where Iter: Iterator<Item=&'a str>
where
Iter: Iterator<Item = &'a str>,
{
// Parse ELF
let elf = ElfFile::new(data).expect("failed to read elf");
@ -192,8 +197,8 @@ impl Thread {
// Check ELF type
match elf.header.pt2.type_().as_type() {
header::Type::Executable => {},
header::Type::SharedObject => {},
header::Type::Executable => {}
header::Type::SharedObject => {}
_ => panic!("ELF is not executable or shared object"),
}
@ -220,13 +225,19 @@ impl Thread {
let mut vm = elf.make_memory_set();
// User stack
use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET};
use crate::consts::{USER32_STACK_OFFSET, USER_STACK_OFFSET, USER_STACK_SIZE};
let mut ustack_top = {
let (ustack_buttom, ustack_top) = match is32 {
true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE),
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
};
vm.push(ustack_buttom, ustack_top, MemoryAttr::default().user(), ByFrame::new(GlobalFrameAlloc), "user_stack");
vm.push(
ustack_buttom,
ustack_top,
MemoryAttr::default().user(),
ByFrame::new(GlobalFrameAlloc),
"user_stack",
);
ustack_top
};
@ -246,7 +257,7 @@ impl Thread {
},
};
unsafe {
vm.with(|| { ustack_top = init_info.push_at(ustack_top) });
vm.with(|| ustack_top = init_info.push_at(ustack_top));
}
trace!("{:#x?}", vm);
@ -254,16 +265,45 @@ impl Thread {
let kstack = KernelStack::new();
let mut files = BTreeMap::new();
files.insert(0, FileLike::File(FileHandle::new(crate::fs::STDIN.clone(), OpenOptions { read: true, write: false, append: false })));
files.insert(1, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
files.insert(2, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
files.insert(
0,
FileLike::File(FileHandle::new(
crate::fs::STDIN.clone(),
OpenOptions {
read: true,
write: false,
append: false,
},
)),
);
files.insert(
1,
FileLike::File(FileHandle::new(
crate::fs::STDOUT.clone(),
OpenOptions {
read: false,
write: true,
append: false,
},
)),
);
files.insert(
2,
FileLike::File(FileHandle::new(
crate::fs::STDOUT.clone(),
OpenOptions {
read: false,
write: true,
append: false,
},
)),
);
let entry_addr = elf.header.pt2.entry_point() as usize;
Box::new(Thread {
context: unsafe {
Context::new_user_thread(
entry_addr, ustack_top, kstack.top(), is32, vm.token())
Context::new_user_thread(entry_addr, ustack_top, kstack.top(), is32, vm.token())
},
kstack,
clear_child_tid: 0,
@ -277,7 +317,7 @@ impl Thread {
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new()
child_exit_code: BTreeMap::new(),
})),
})
}
@ -297,9 +337,7 @@ impl Thread {
// NoMMU: coping data has been done in `vm.clone()`
for area in vm.iter() {
let data = Vec::<u8>::from(unsafe { area.as_slice() });
unsafe { vm.with(|| {
area.as_slice_mut().copy_from_slice(data.as_slice())
}) }
unsafe { vm.with(|| area.as_slice_mut().copy_from_slice(data.as_slice())) }
}
debug!("fork: temporary copy data!");
@ -326,13 +364,19 @@ impl Thread {
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new()
child_exit_code: BTreeMap::new(),
})),
})
}
/// Create a new thread in the same process.
pub fn clone(&self, tf: &TrapFrame, stack_top: usize, tls: usize, clear_child_tid: usize) -> Box<Thread> {
pub fn clone(
&self,
tf: &TrapFrame,
stack_top: usize,
tls: usize,
clear_child_tid: usize,
) -> Box<Thread> {
let kstack = KernelStack::new();
let token = self.proc.lock().vm.token();
Box::new(Thread {
@ -371,7 +415,9 @@ impl ToMemoryAttr for Flags {
fn to_attr(&self) -> MemoryAttr {
let mut flags = MemoryAttr::default().user();
// FIXME: handle readonly
if self.is_execute() { flags = flags.execute(); }
if self.is_execute() {
flags = flags.execute();
}
flags
}
}
@ -406,7 +452,13 @@ impl ElfExt for ElfFile<'_> {
// Get target slice
let target = {
ms.push(virt_addr, virt_addr + mem_size, ph.flags().to_attr(), ByFrame::new(GlobalFrameAlloc), "");
ms.push(
virt_addr,
virt_addr + mem_size,
ph.flags().to_attr(),
ByFrame::new(GlobalFrameAlloc),
"",
);
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
};
// Copy data
@ -423,29 +475,34 @@ impl ElfExt for ElfFile<'_> {
}
fn get_interpreter(&self) -> Result<&str, &str> {
let header = self.program_iter()
let header = self
.program_iter()
.filter(|ph| ph.get_type() == Ok(Type::Interp))
.next().ok_or("no interp header")?;
.next()
.ok_or("no interp header")?;
let mut data = match header.get_data(self)? {
SegmentData::Undefined(data) => data,
_ => unreachable!(),
};
// skip NULL
while let Some(0) = data.last() {
data = &data[..data.len()-1];
data = &data[..data.len() - 1];
}
let path = str::from_utf8(data)
.map_err(|_| "failed to convert to utf8")?;
let path = str::from_utf8(data).map_err(|_| "failed to convert to utf8")?;
Ok(path)
}
fn get_phdr_vaddr(&self) -> Option<u64> {
if let Some(phdr) = self.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Phdr)) {
if let Some(phdr) = self
.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Phdr))
{
// if phdr exists in program header, use it
Some(phdr.virtual_addr())
} else if let Some(elf_addr) = self.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) {
} else if let Some(elf_addr) = self
.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0)
{
// otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
Some(elf_addr.virtual_addr() + self.header.pt2.ph_offset())
} else {

@ -1,16 +1,18 @@
//! Kernel shell
use crate::drivers::CMDLINE;
use crate::fs::{INodeExt, ROOT_INODE};
use crate::process::*;
use alloc::string::String;
use alloc::vec::Vec;
use crate::fs::{ROOT_INODE, INodeExt};
use crate::process::*;
use crate::drivers::CMDLINE;
#[cfg(not(feature = "run_cmdline"))]
pub fn run_user_shell() {
if let Ok(inode) = ROOT_INODE.lookup("rust/sh") {
let data = inode.read_as_vec().unwrap();
processor().manager().add(Thread::new_user(data.as_slice(), "sh".split(' ')));
processor()
.manager()
.add(Thread::new_user(data.as_slice(), "sh".split(' ')));
} else {
processor().manager().add(Thread::new_kernel(shell, 0));
}
@ -21,10 +23,12 @@ pub fn run_user_shell() {
let cmdline = CMDLINE.read();
let inode = ROOT_INODE.lookup(&cmdline).unwrap();
let data = inode.read_as_vec().unwrap();
processor().manager().add(Thread::new_user(data.as_slice(), cmdline.split(' ')));
processor()
.manager()
.add(Thread::new_user(data.as_slice(), cmdline.split(' ')));
}
pub extern fn shell(_arg: usize) -> ! {
pub extern "C" fn shell(_arg: usize) -> ! {
let files = ROOT_INODE.list().unwrap();
println!("Available programs: {:?}", files);
let mut history = Vec::new();
@ -38,9 +42,11 @@ pub extern fn shell(_arg: usize) -> ! {
let name = cmd.trim().split(' ').next().unwrap();
if let Ok(file) = ROOT_INODE.lookup(name) {
let data = file.read_as_vec().unwrap();
let _pid = processor().manager().add(Thread::new_user(data.as_slice(), cmd.split(' ')));
// TODO: wait until process exits, or use user land shell completely
//unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
let _pid = processor()
.manager()
.add(Thread::new_user(data.as_slice(), cmd.split(' ')));
// TODO: wait until process exits, or use user land shell completely
//unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
} else {
println!("Program not exist");
}

@ -1,6 +1,6 @@
use alloc::collections::VecDeque;
use super::*;
use crate::thread;
use alloc::collections::VecDeque;
use alloc::sync::Arc;
use alloc::vec::Vec;
@ -47,7 +47,8 @@ impl Condvar {
}
pub fn wait<'a, T, S>(&self, guard: MutexGuard<'a, T, S>) -> MutexGuard<'a, T, S>
where S: MutexSupport
where
S: MutexSupport,
{
let mutex = guard.mutex;
drop(guard);
@ -68,7 +69,7 @@ impl Condvar {
/// Notify up to `n` waiters.
/// Return the number of waiters that were woken up.
pub fn notify_n(&self, n: usize) -> usize {
let mut count = 0;
let mut count = 0;
while count < n {
if let Some(t) = self.wait_queue.lock().pop_front() {
t.unpark();
@ -82,4 +83,4 @@ impl Condvar {
pub fn _clear(&self) {
self.wait_queue.lock().clear();
}
}
}

@ -54,8 +54,8 @@ pub use self::condvar::*;
pub use self::mutex::*;
pub use self::semaphore::*;
mod mutex;
mod condvar;
mod semaphore;
pub mod mpsc;
mod mutex;
mod semaphore;
pub mod test;

@ -1,6 +1,6 @@
use alloc::{sync::Arc, sync::Weak, collections::VecDeque};
use super::Condvar;
use super::SpinLock as Mutex;
use alloc::{collections::VecDeque, sync::Arc, sync::Weak};
struct Channel<T> {
deque: Mutex<VecDeque<T>>,
@ -26,7 +26,7 @@ pub struct Receiver<T> {
unsafe impl<T: Send> Send for Receiver<T> {}
impl<T> ! Sync for Receiver<T> {}
impl<T> !Sync for Receiver<T> {}
#[derive(Debug)]
pub struct RecvError;
@ -54,7 +54,7 @@ pub struct Sender<T> {
unsafe impl<T: Send> Send for Sender<T> {}
impl<T> ! Sync for Sender<T> {}
impl<T> !Sync for Sender<T> {}
#[derive(Debug)]
pub struct SendError<T>(pub T);
@ -78,7 +78,9 @@ impl<T> Sender<T> {
/// Creates a new asynchronous channel, returning the sender/receiver halves.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let channel = Arc::new(Channel::<T>::default());
let sender = Sender { inner: Arc::downgrade(&channel) };
let sender = Sender {
inner: Arc::downgrade(&channel),
};
let receiver = Receiver { inner: channel };
(sender, receiver)
}
@ -86,9 +88,9 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
pub mod test {
//! Copied from std::mpsc::test
use alloc::boxed::Box;
use super::*;
use crate::thread;
use alloc::boxed::Box;
fn smoke() {
let (tx, rx) = channel::<i32>();
@ -140,4 +142,4 @@ pub mod test {
smoke_port_gone();
println!("mpsc test end");
}
}
}

@ -26,19 +26,18 @@
//! `MutexSupport`提供了若干接口,它们会在操作锁的不同时间点被调用。
//! 注意这个接口实际是取了几种实现的并集,并不是很通用。
use super::Condvar;
use crate::arch::interrupt;
use core::cell::UnsafeCell;
use core::fmt;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::{AtomicBool, Ordering};
use super::Condvar;
pub type SpinLock<T> = Mutex<T, Spin>;
pub type SpinNoIrqLock<T> = Mutex<T, SpinNoIrq>;
pub type ThreadLock<T> = Mutex<T, Condvar>;
pub struct Mutex<T: ?Sized, S: MutexSupport>
{
pub struct Mutex<T: ?Sized, S: MutexSupport> {
lock: AtomicBool,
support: S,
data: UnsafeCell<T>,
@ -47,8 +46,7 @@ pub struct Mutex<T: ?Sized, S: MutexSupport>
/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct MutexGuard<'a, T: ?Sized + 'a, S: MutexSupport + 'a>
{
pub struct MutexGuard<'a, T: ?Sized + 'a, S: MutexSupport + 'a> {
pub(super) mutex: &'a Mutex<T, S>,
support_guard: S::GuardData,
}
@ -58,8 +56,7 @@ unsafe impl<T: ?Sized + Send, S: MutexSupport> Sync for Mutex<T, S> {}
unsafe impl<T: ?Sized + Send, S: MutexSupport> Send for Mutex<T, S> {}
impl<T, S: MutexSupport> Mutex<T, S>
{
impl<T, S: MutexSupport> Mutex<T, S> {
/// Creates a new spinlock wrapping the supplied data.
///
/// May be used statically:
@ -93,8 +90,7 @@ impl<T, S: MutexSupport> Mutex<T, S>
}
}
impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
{
impl<T: ?Sized, S: MutexSupport> Mutex<T, S> {
fn obtain_lock(&self) {
while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false {
// Wait until the lock looks unlocked before retrying
@ -119,8 +115,7 @@ impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
/// }
///
/// ```
pub fn lock(&self) -> MutexGuard<T, S>
{
pub fn lock(&self) -> MutexGuard<T, S> {
let support_guard = S::before_lock();
self.obtain_lock();
MutexGuard {
@ -155,11 +150,14 @@ impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
}
}
impl<T: ?Sized + fmt::Debug, S: MutexSupport + fmt::Debug> fmt::Debug for Mutex<T, S>
{
impl<T: ?Sized + fmt::Debug, S: MutexSupport + fmt::Debug> fmt::Debug for Mutex<T, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
Some(guard) => write!(f, "Mutex {{ data: {:?}, support: {:?} }}", &*guard, self.support),
Some(guard) => write!(
f,
"Mutex {{ data: {:?}, support: {:?} }}",
&*guard, self.support
),
None => write!(f, "Mutex {{ <locked>, support: {:?} }}", self.support),
}
}
@ -171,19 +169,20 @@ impl<T: ?Sized + Default, S: MutexSupport> Default for Mutex<T, S> {
}
}
impl<'a, T: ?Sized, S: MutexSupport> Deref for MutexGuard<'a, T, S>
{
impl<'a, T: ?Sized, S: MutexSupport> Deref for MutexGuard<'a, T, S> {
type Target = T;
fn deref(&self) -> &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(&mut self) -> &mut T { unsafe { &mut *self.mutex.data.get() } }
impl<'a, T: ?Sized, S: MutexSupport> DerefMut for MutexGuard<'a, T, S> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<'a, T: ?Sized, S: MutexSupport> Drop for MutexGuard<'a, T, S>
{
impl<'a, T: ?Sized, S: MutexSupport> Drop for MutexGuard<'a, T, S> {
/// The dropping of the MutexGuard will release the lock it was created from.
fn drop(&mut self) {
self.mutex.lock.store(false, Ordering::Release);
@ -210,15 +209,17 @@ pub struct Spin;
impl MutexSupport for Spin {
type GuardData = ();
fn new() -> Self { Spin }
fn new() -> Self {
Spin
}
fn cpu_relax(&self) {
unsafe {
#[cfg(target_arch = "x86_64")]
asm!("pause" :::: "volatile");
asm!("pause" :::: "volatile");
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
asm!("nop" :::: "volatile");
asm!("nop" :::: "volatile");
#[cfg(target_arch = "aarch64")]
asm!("yield" :::: "volatile");
asm!("yield" :::: "volatile");
}
}
fn before_lock() -> Self::GuardData {}
@ -252,11 +253,11 @@ impl MutexSupport for SpinNoIrq {
fn cpu_relax(&self) {
unsafe {
#[cfg(target_arch = "x86_64")]
asm!("pause" :::: "volatile");
asm!("pause" :::: "volatile");
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
asm!("nop" :::: "volatile");
asm!("nop" :::: "volatile");
#[cfg(target_arch = "aarch64")]
asm!("yield" :::: "volatile");
asm!("yield" :::: "volatile");
}
}
fn before_lock() -> Self::GuardData {

@ -67,4 +67,4 @@ impl<'a> Drop for SemaphoreGuard<'a> {
fn drop(&mut self) {
self.sem.release();
}
}
}

@ -2,12 +2,12 @@
//!
//! The code is borrowed from [RustDoc - Dining Philosophers](https://doc.rust-lang.org/1.6.0/book/dining-philosophers.html)
use alloc::{sync::Arc, vec::Vec};
use core::time::Duration;
use crate::sync::Condvar;
use crate::sync::ThreadLock as Mutex;
use crate::thread;
use alloc::vec;
use alloc::{sync::Arc, vec::Vec};
use core::time::Duration;
use log::*;
struct Philosopher {
@ -18,11 +18,7 @@ struct Philosopher {
impl Philosopher {
fn new(name: &'static str, left: usize, right: usize) -> Philosopher {
Philosopher {
name,
left,
right,
}
Philosopher { name, left, right }
}
fn eat(&self, table: &Arc<Table>) {
@ -92,18 +88,21 @@ fn philosopher(table: Arc<Table>) {
Philosopher::new("5", 0, 4),
];
let handles: Vec<_> = philosophers.into_iter().map(|p| {
let table = table.clone();
trace!("philosopher start");
thread::spawn(move || {
for i in 0..5 {
p.think();
p.eat(&table);
println!("{} iter {} end.", p.name, i);
}
let handles: Vec<_> = philosophers
.into_iter()
.map(|p| {
let table = table.clone();
trace!("philosopher start");
thread::spawn(move || {
for i in 0..5 {
p.think();
p.eat(&table);
println!("{} iter {} end.", p.name, i);
}
})
})
}).collect();
.collect();
trace!("philosopher starting finish");
for h in handles {
@ -116,7 +115,13 @@ pub fn philosopher_using_mutex() {
println!("philosophers using mutex");
let table = Arc::new(MutexTable {
forks: vec![Mutex::new(()), Mutex::new(()), Mutex::new(()), Mutex::new(()), Mutex::new(())]
forks: vec![
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
],
});
philosopher(table);
}
@ -126,7 +131,13 @@ pub fn philosopher_using_monitor() {
let table = Arc::new(MonitorTable {
fork_status: Mutex::new(vec![false; 5]),
fork_condvar: vec![Condvar::new(), Condvar::new(), Condvar::new(), Condvar::new(), Condvar::new()],
fork_condvar: vec![
Condvar::new(),
Condvar::new(),
Condvar::new(),
Condvar::new(),
Condvar::new(),
],
});
philosopher(table);
}
}

@ -1,7 +1,7 @@
//! Custom nonstandard syscalls
use super::*;
use rcore_memory::memory_set::handler::Linear;
use rcore_memory::memory_set::MemoryAttr;
use super::*;
/// Allocate this PCI device to user space
/// The kernel driver using the PCI device will be unloaded
@ -13,15 +13,13 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult {
vendor, product
);
let tag = pci::find_device(vendor as u32, product as u32)
.ok_or(SysError::ENOENT)?;
let tag = pci::find_device(vendor as u32, product as u32).ok_or(SysError::ENOENT)?;
if pci::detach_driver(&tag) {
info!("Kernel driver detached");
}
// Get BAR0 memory
let (base, len) = unsafe { tag.get_bar_mem(0) }
.ok_or(SysError::ENOENT)?;
let (base, len) = unsafe { tag.get_bar_mem(0) }.ok_or(SysError::ENOENT)?;
let mut proc = process();
let virt_addr = proc.vm.find_free_area(0, len);

@ -1,14 +1,14 @@
//! Syscalls for file system
use core::mem::size_of;
use core::cmp::min;
use core::cell::UnsafeCell;
use core::cmp::min;
use core::mem::size_of;
use rcore_fs::vfs::Timespec;
use crate::drivers::SOCKET_ACTIVITY;
use crate::fs::*;
use crate::memory::MemorySet;
use crate::sync::Condvar;
use crate::drivers::SOCKET_ACTIVITY;
use super::*;
@ -22,7 +22,7 @@ pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult {
match proc.files.get(&fd) {
Some(FileLike::File(_)) => sys_read_file(&mut proc, fd, base, len),
Some(FileLike::Socket(_)) => sys_read_socket(&mut proc, fd, base, len),
None => Err(SysError::EINVAL)
None => Err(SysError::EINVAL),
}
}
@ -37,12 +37,15 @@ pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult {
match proc.files.get(&fd) {
Some(FileLike::File(_)) => sys_write_file(&mut proc, fd, base, len),
Some(FileLike::Socket(_)) => sys_write_socket(&mut proc, fd, base, len),
None => Err(SysError::EINVAL)
None => Err(SysError::EINVAL),
}
}
pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResult {
info!("pread: fd: {}, base: {:?}, len: {}, offset: {}", fd, base, len, offset);
info!(
"pread: fd: {}, base: {:?}, len: {}, offset: {}",
fd, base, len, offset
);
let mut proc = process();
proc.vm.check_write_array(base, len)?;
@ -52,7 +55,10 @@ pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResu
}
pub fn sys_pwrite(fd: usize, base: *const u8, len: usize, offset: usize) -> SysResult {
info!("pwrite: fd: {}, base: {:?}, len: {}, offset: {}", fd, base, len, offset);
info!(
"pwrite: fd: {}, base: {:?}, len: {}, offset: {}",
fd, base, len, offset
);
let mut proc = process();
proc.vm.check_read_array(base, len)?;
@ -74,7 +80,10 @@ pub fn sys_write_file(proc: &mut Process, fd: usize, base: *const u8, len: usize
}
pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResult {
info!("poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}", ufds, nfds, timeout_msecs);
info!(
"poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}",
ufds, nfds, timeout_msecs
);
let proc = process();
proc.vm.check_write_array(ufds, nfds)?;
@ -100,7 +109,7 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
poll.revents = poll.revents | PE::IN;
events = events + 1;
}
},
}
Some(FileLike::Socket(wrapper)) => {
let (input, output, err) = poll_socket(&wrapper);
if err {
@ -143,7 +152,7 @@ const MAX_FDSET_SIZE: usize = 1024 / FD_PER_ITEM;
struct FdSet {
addr: *mut u32,
nfds: usize,
saved: [u32; MAX_FDSET_SIZE]
saved: [u32; MAX_FDSET_SIZE],
}
impl FdSet {
@ -157,7 +166,7 @@ impl FdSet {
if len > MAX_FDSET_SIZE {
return Err(SysError::EINVAL);
}
let slice = unsafe {slice::from_raw_parts_mut(addr, len)};
let slice = unsafe { slice::from_raw_parts_mut(addr, len) };
// save the fdset, and clear it
for i in 0..len {
@ -166,11 +175,7 @@ impl FdSet {
}
}
Ok(FdSet {
addr,
nfds,
saved
})
Ok(FdSet { addr, nfds, saved })
}
/// Try to set fd in `FdSet`
@ -196,8 +201,17 @@ impl FdSet {
}
}
pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, timeout: *const TimeVal) -> SysResult {
info!("select: nfds: {}, read: {:?}, write: {:?}, err: {:?}, timeout: {:?}", nfds, read, write, err, timeout);
pub fn sys_select(
nfds: usize,
read: *mut u32,
write: *mut u32,
err: *mut u32,
timeout: *const TimeVal,
) -> SysResult {
info!(
"select: nfds: {}, read: {:?}, write: {:?}, err: {:?}, timeout: {:?}",
nfds, read, write, err, timeout
);
let proc = process();
let mut read_fds = FdSet::new(&proc.vm, read, nfds)?;
@ -222,23 +236,23 @@ pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, t
FileLike::File(_) => {
// FIXME: assume it is stdin for now
if STDIN.can_read() {
if read_fds.is_set(*fd){
if read_fds.is_set(*fd) {
read_fds.set(*fd);
events = events + 1;
}
}
},
}
FileLike::Socket(wrapper) => {
let (input, output, err) = poll_socket(&wrapper);
if err && err_fds.is_set(*fd){
if err && err_fds.is_set(*fd) {
err_fds.set(*fd);
events = events + 1;
}
if input && read_fds.is_set(*fd){
if input && read_fds.is_set(*fd) {
read_fds.set(*fd);
events = events + 1;
}
if output && write_fds.is_set(*fd){
if output && write_fds.is_set(*fd) {
write_fds.set(*fd);
events = events + 1;
}
@ -268,7 +282,10 @@ pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, t
}
pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
info!("readv: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count);
info!(
"readv: fd: {}, iov: {:?}, count: {}",
fd, iov_ptr, iov_count
);
let mut proc = process();
let mut iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, true)?;
@ -282,7 +299,10 @@ pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResul
}
pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
info!("writev: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count);
info!(
"writev: fd: {}, iov: {:?}, count: {}",
fd, iov_ptr, iov_count
);
let mut proc = process();
let iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)?;
@ -292,7 +312,7 @@ pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResu
match proc.files.get(&fd) {
Some(FileLike::File(_)) => sys_write_file(&mut proc, fd, buf.as_ptr(), len),
Some(FileLike::Socket(_)) => sys_write_socket(&mut proc, fd, buf.as_ptr(), len),
None => Err(SysError::EINVAL)
None => Err(SysError::EINVAL),
}
}
@ -306,53 +326,55 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) ->
let mut proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
let flags = OpenFlags::from_bits_truncate(flags);
info!("openat: dir_fd: {}, path: {:?}, flags: {:?}, mode: {:#o}", dir_fd as isize, path, flags, mode);
let inode =
if dir_fd == AT_FDCWD {
// from process cwd
if flags.contains(OpenFlags::CREATE) {
let (dir_path, file_name) = split_path(&path);
// relative to cwd
let dir_inode = proc.lookup_inode(dir_path)?;
match dir_inode.find(file_name) {
Ok(file_inode) => {
if flags.contains(OpenFlags::EXCLUSIVE) {
return Err(SysError::EEXIST);
}
file_inode
},
Err(FsError::EntryNotFound) => {
dir_inode.create(file_name, FileType::File, mode as u32)?
}
Err(e) => return Err(SysError::from(e)),
info!(
"openat: dir_fd: {}, path: {:?}, flags: {:?}, mode: {:#o}",
dir_fd as isize, path, flags, mode
);
let inode = if dir_fd == AT_FDCWD {
// from process cwd
if flags.contains(OpenFlags::CREATE) {
let (dir_path, file_name) = split_path(&path);
// relative to cwd
let dir_inode = proc.lookup_inode(dir_path)?;
match dir_inode.find(file_name) {
Ok(file_inode) => {
if flags.contains(OpenFlags::EXCLUSIVE) {
return Err(SysError::EEXIST);
}
} else {
proc.lookup_inode(&path)?
file_inode
}
Err(FsError::EntryNotFound) => {
dir_inode.create(file_name, FileType::File, mode as u32)?
}
Err(e) => return Err(SysError::from(e)),
}
} else {
// relative to dir_fd
let dir_file = proc.get_file(dir_fd)?;
if flags.contains(OpenFlags::CREATE) {
let (dir_path, file_name) = split_path(&path);
// relative to cwd
let dir_inode = dir_file.lookup_follow(dir_path, FOLLOW_MAX_DEPTH)?;
match dir_inode.find(file_name) {
Ok(file_inode) => {
if flags.contains(OpenFlags::EXCLUSIVE) {
return Err(SysError::EEXIST);
}
file_inode
},
Err(FsError::EntryNotFound) => {
dir_inode.create(file_name, FileType::File, mode as u32)?
}
Err(e) => return Err(SysError::from(e)),
proc.lookup_inode(&path)?
}
} else {
// relative to dir_fd
let dir_file = proc.get_file(dir_fd)?;
if flags.contains(OpenFlags::CREATE) {
let (dir_path, file_name) = split_path(&path);
// relative to cwd
let dir_inode = dir_file.lookup_follow(dir_path, FOLLOW_MAX_DEPTH)?;
match dir_inode.find(file_name) {
Ok(file_inode) => {
if flags.contains(OpenFlags::EXCLUSIVE) {
return Err(SysError::EEXIST);
}
} else {
dir_file.lookup_follow(&path, FOLLOW_MAX_DEPTH)?
file_inode
}
Err(FsError::EntryNotFound) => {
dir_inode.create(file_name, FileType::File, mode as u32)?
}
Err(e) => return Err(SysError::from(e)),
}
};
} else {
dir_file.lookup_follow(&path, FOLLOW_MAX_DEPTH)?
}
};
let fd = proc.get_free_fd();
@ -390,9 +412,7 @@ pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult {
if proc.cwd.len() + 1 > len {
return Err(SysError::ERANGE);
}
unsafe {
util::write_cstr(buf, &proc.cwd)
}
unsafe { util::write_cstr(buf, &proc.cwd) }
Ok(buf as usize)
}
@ -408,7 +428,9 @@ pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
let file = proc.get_file(fd)?;
let stat = Stat::from(file.metadata()?);
// TODO: handle symlink
unsafe { stat_ptr.write(stat); }
unsafe {
stat_ptr.write(stat);
}
Ok(0)
}
@ -420,7 +442,9 @@ pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult {
let inode = proc.lookup_inode(&path)?;
let stat = Stat::from(inode.metadata()?);
unsafe { stat_ptr.write(stat); }
unsafe {
stat_ptr.write(stat);
}
Ok(0)
}
@ -483,7 +507,10 @@ pub fn sys_ftruncate(fd: usize, len: usize) -> SysResult {
}
pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> SysResult {
info!("getdents64: fd: {}, ptr: {:?}, buf_size: {}", fd, buf, buf_size);
info!(
"getdents64: fd: {}, ptr: {:?}, buf_size: {}",
fd, buf, buf_size
);
let mut proc = process();
proc.vm.check_write_array(buf as *mut u8, buf_size)?;
let file = proc.get_file(fd)?;
@ -499,7 +526,9 @@ pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> Sy
}?;
// TODO: get ino from dirent
let ok = writer.try_write(0, DirentType::from_type(&info.type_).bits(), &name);
if !ok { break; }
if !ok {
break;
}
}
Ok(writer.written_size)
}
@ -515,12 +544,12 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult {
let new_file = FileLike::File(file.clone());
proc.files.insert(fd2, new_file);
Ok(fd2)
},
}
Some(FileLike::Socket(wrapper)) => {
let new_wrapper = wrapper.clone();
sys_dup2_socket(&mut proc, new_wrapper, fd2)
},
None => Err(SysError::EINVAL)
}
None => Err(SysError::EINVAL),
}
}
@ -552,23 +581,33 @@ pub fn sys_rename(oldpath: *const u8, newpath: *const u8) -> SysResult {
sys_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath)
}
pub fn sys_renameat(olddirfd: usize, oldpath: *const u8, newdirfd: usize, newpath: *const u8) -> SysResult {
pub fn sys_renameat(
olddirfd: usize,
oldpath: *const u8,
newdirfd: usize,
newpath: *const u8,
) -> SysResult {
let mut proc = process();
let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? };
let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? };
info!("renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}", olddirfd, oldpath, newdirfd, newpath);
info!(
"renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}",
olddirfd, oldpath, newdirfd, newpath
);
let (old_dir_path, old_file_name) = split_path(&oldpath);
let (new_dir_path, new_file_name) = split_path(&newpath);
let old_dir_inode = if olddirfd == AT_FDCWD {
proc.lookup_inode(old_dir_path)?
} else {
proc.get_file(olddirfd)?.lookup_follow(old_dir_path, FOLLOW_MAX_DEPTH)?
proc.get_file(olddirfd)?
.lookup_follow(old_dir_path, FOLLOW_MAX_DEPTH)?
};
let new_dir_inode = if newdirfd == AT_FDCWD {
proc.lookup_inode(new_dir_path)?
} else {
proc.get_file(newdirfd)?.lookup_follow(new_dir_path, FOLLOW_MAX_DEPTH)?
proc.get_file(newdirfd)?
.lookup_follow(new_dir_path, FOLLOW_MAX_DEPTH)?
};
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
Ok(0)
@ -640,10 +679,30 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult {
let (read, write) = Pipe::create_pair();
let read_fd = proc.get_free_fd();
proc.files.insert(read_fd, FileLike::File(FileHandle::new(Arc::new(read), OpenOptions { read: true, write: false, append: false })));
proc.files.insert(
read_fd,
FileLike::File(FileHandle::new(
Arc::new(read),
OpenOptions {
read: true,
write: false,
append: false,
},
)),
);
let write_fd = proc.get_free_fd();
proc.files.insert(write_fd, FileLike::File(FileHandle::new(Arc::new(write), OpenOptions { read: false, write: true, append: false })));
proc.files.insert(
write_fd,
FileLike::File(FileHandle::new(
Arc::new(write),
OpenOptions {
read: false,
write: true,
append: false,
},
)),
);
unsafe {
*fds = read_fd as u32;
@ -661,12 +720,15 @@ pub fn sys_sync() -> SysResult {
}
pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usize) -> SysResult {
info!("sendfile: out: {}, in: {}, offset: {:?}, count: {}", out_fd, in_fd, offset, count);
info!(
"sendfile: out: {}, in: {}, offset: {:?}, count: {}",
out_fd, in_fd, offset, count
);
let proc = process();
// We know it's save, pacify the borrow checker
let proc_cell = UnsafeCell::new(proc);
let proc_in = unsafe {&mut *proc_cell.get()};
let proc_out = unsafe {&mut *proc_cell.get()};
let proc_in = unsafe { &mut *proc_cell.get() };
let proc_out = unsafe { &mut *proc_cell.get() };
//let in_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(in_fd)?).get() };
//let out_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(out_fd)?).get() };
let in_file = proc_in.get_file(in_fd)?;
@ -693,11 +755,9 @@ pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usiz
}
return Ok(bytes_read);
} else {
let proc_mem = unsafe {&mut *proc_cell.get()};
let proc_mem = unsafe { &mut *proc_cell.get() };
proc_mem.vm.check_read_ptr(offset)?;
let mut read_offset = unsafe {
*offset
};
let mut read_offset = unsafe { *offset };
// read from specified offset and write new offset back
let mut bytes_read = 0;
while bytes_read < count {
@ -726,16 +786,19 @@ pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usiz
impl Process {
pub fn get_file(&mut self, fd: usize) -> Result<&mut FileHandle, SysError> {
self.files.get_mut(&fd).ok_or(SysError::EBADF).and_then(|f| {
match f {
self.files
.get_mut(&fd)
.ok_or(SysError::EBADF)
.and_then(|f| match f {
FileLike::File(file) => Ok(file),
_ => Err(SysError::EBADF)
}
})
_ => Err(SysError::EBADF),
})
}
pub fn lookup_inode(&self, path: &str) -> Result<Arc<INode>, SysError> {
debug!("lookup_inode: cwd {} path {}", self.cwd, path);
Ok(ROOT_INODE.lookup(&self.cwd)?.lookup_follow(path, FOLLOW_MAX_DEPTH)?)
Ok(ROOT_INODE
.lookup(&self.cwd)?
.lookup_follow(path, FOLLOW_MAX_DEPTH)?)
}
}
@ -1058,7 +1121,7 @@ impl From<Metadata> for Stat {
atime: info.atime,
mtime: info.mtime,
ctime: info.ctime,
_pad0: 0
_pad0: 0,
}
}
@ -1079,7 +1142,7 @@ impl From<Metadata> for Stat {
mtime: info.mtime,
ctime: info.ctime,
__pad: 0,
__pad2: 0
__pad2: 0,
}
}
}
@ -1102,7 +1165,12 @@ pub struct IoVec {
struct IoVecs(Vec<&'static mut [u8]>);
impl IoVecs {
fn check_and_new(iov_ptr: *const IoVec, iov_count: usize, vm: &MemorySet, readv: bool) -> Result<Self, SysError> {
fn check_and_new(
iov_ptr: *const IoVec,
iov_count: usize,
vm: &MemorySet,
readv: bool,
) -> Result<Self, SysError> {
vm.check_read_array(iov_ptr, iov_count)?;
let iovs = unsafe { slice::from_raw_parts(iov_ptr, iov_count) }.to_vec();
// check all bufs in iov
@ -1116,7 +1184,10 @@ impl IoVecs {
}
}
}
let slices = iovs.iter().map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len as usize) }).collect();
let slices = iovs
.iter()
.map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len as usize) })
.collect();
Ok(IoVecs(slices))
}
@ -1148,7 +1219,9 @@ impl IoVecs {
let total_len = self.0.iter().map(|slice| slice.len()).sum::<usize>();
let mut buf = Vec::with_capacity(total_len);
if set_len {
unsafe { buf.set_len(total_len); }
unsafe {
buf.set_len(total_len);
}
}
buf
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save