1
0
mirror of https://github.com/rcore-os/rCore.git synced 2025-01-18 17:07:04 +04:00

Merge remote-tracking branch 'origin/master' into mipsel

This commit is contained in:
Harry Chen 2019-04-01 23:32:30 +08:00
commit b6f1b3c926
118 changed files with 3191 additions and 2415 deletions

View File

@ -75,7 +75,7 @@ fn enable_mmu() {
TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
TCR_EL1::EPD1::EnableTTBR1Walks + TCR_EL1::EPD1::EnableTTBR1Walks +
TCR_EL1::A1::UseTTBR1ASID + TCR_EL1::A1::UseTTBR0ASID +
TCR_EL1::T1SZ.val(16) + TCR_EL1::T1SZ.val(16) +
TCR_EL1::TG0::KiB_4 + TCR_EL1::TG0::KiB_4 +

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,11 +8,16 @@ pub trait PageTableExt: PageTable {
// So this should be really high in kernel space when necessary. // So this should be really high in kernel space when necessary.
const TEMP_PAGE_ADDR: VirtAddr = 0xcafeb000; 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); 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); let ret = f(self, data);
self.unmap(Self::TEMP_PAGE_ADDR); self.unmap(Self::TEMP_PAGE_ADDR);
ret ret
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,4 +8,4 @@ edition = "2018"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
spin = "0.5" spin = "0.5"
deque = { git = "https://github.com/wangrunji0408/deque.git", branch = "no_std" } deque = { git = "https://github.com/rcore-os/deque.git", branch = "no_std" }

View File

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

View File

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

View File

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

View File

@ -36,7 +36,9 @@ impl RRScheduler {
max_time_slice, max_time_slice,
infos: Vec::default(), 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.infos[tid].present = false;
self._list_remove(tid); self._list_remove(tid);
Some(tid - 1) Some(tid - 1)
}, }
}; };
trace!("rr pop {:?}", ret); trace!("rr pop {:?}", ret);
ret ret

View File

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

View File

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

View File

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

View File

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

20
kernel/Cargo.lock generated
View File

@ -125,7 +125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "deque" name = "deque"
version = "0.3.2" version = "0.3.2"
source = "git+https://github.com/wangrunji0408/deque.git?branch=no_std#907d03935b9badde1902d9c84d138872f34c6763" source = "git+https://github.com/rcore-os/deque.git?branch=no_std#907d03935b9badde1902d9c84d138872f34c6763"
[[package]] [[package]]
name = "device_tree" name = "device_tree"
@ -318,8 +318,8 @@ dependencies = [
"once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs?branch=sefs)", "rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
"rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs?branch=sefs)", "rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
"rcore-memory 0.1.0", "rcore-memory 0.1.0",
"rcore-thread 0.1.0", "rcore-thread 0.1.0",
"riscv 0.5.0 (git+https://github.com/rcore-os/riscv)", "riscv 0.5.0 (git+https://github.com/rcore-os/riscv)",
@ -334,16 +334,16 @@ dependencies = [
[[package]] [[package]]
name = "rcore-fs" name = "rcore-fs"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs?branch=sefs#166616e5ade1a5c929f705fd1564ef0ea337ba72" source = "git+https://github.com/rcore-os/rcore-fs#c611248f800e946acf44d64b218aeb8fc6751640"
[[package]] [[package]]
name = "rcore-fs-sfs" name = "rcore-fs-sfs"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs?branch=sefs#166616e5ade1a5c929f705fd1564ef0ea337ba72" source = "git+https://github.com/rcore-os/rcore-fs#c611248f800e946acf44d64b218aeb8fc6751640"
dependencies = [ dependencies = [
"bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs?branch=sefs)", "rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -359,7 +359,7 @@ dependencies = [
name = "rcore-thread" name = "rcore-thread"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"deque 0.3.2 (git+https://github.com/wangrunji0408/deque.git?branch=no_std)", "deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -598,7 +598,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" "checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"checksum console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f711b3d1d5c3f7ae7d6428901c0f3e5d5f5c800fcfac86bf0252e96373a2cec6" "checksum console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f711b3d1d5c3f7ae7d6428901c0f3e5d5f5c800fcfac86bf0252e96373a2cec6"
"checksum deque 0.3.2 (git+https://github.com/wangrunji0408/deque.git?branch=no_std)" = "<none>" "checksum deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)" = "<none>"
"checksum device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)" = "<none>" "checksum device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)" = "<none>"
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" "checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" "checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f"
@ -623,8 +623,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d"
"checksum rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs?branch=sefs)" = "<none>" "checksum rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "<none>"
"checksum rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs?branch=sefs)" = "<none>" "checksum rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "<none>"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb" "checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"

View File

@ -30,8 +30,8 @@ link_user = []
run_cmdline = [] run_cmdline = []
[profile.dev] [profile.dev]
# MUST >= 1 : Enable RVO to avoid stack overflow # MUST >= 2 : Enable RVO to avoid stack overflow
opt-level = 1 opt-level = 2
[dependencies] [dependencies]
log = "0.4" log = "0.4"
@ -51,8 +51,8 @@ smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "l
bit-allocator = { path = "../crate/bit-allocator" } bit-allocator = { path = "../crate/bit-allocator" }
rcore-memory = { path = "../crate/memory" } rcore-memory = { path = "../crate/memory" }
rcore-thread = { path = "../crate/thread" } rcore-thread = { path = "../crate/thread" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", branch = "sefs" } rcore-fs = { git = "https://github.com/rcore-os/rcore-fs" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", branch = "sefs" } rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs" }
[target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies]
bootloader = { git = "https://github.com/rcore-os/bootloader" } bootloader = { git = "https://github.com/rcore-os/bootloader" }

View File

@ -76,6 +76,7 @@ qemu_opts += \
-drive format=raw,file=$(bootimage) \ -drive format=raw,file=$(bootimage) \
-drive format=qcow2,file=$(SFSIMG),media=disk,cache=writeback \ -drive format=qcow2,file=$(SFSIMG),media=disk,cache=writeback \
-serial mon:stdio \ -serial mon:stdio \
-m 4G \
-device isa-debug-exit -device isa-debug-exit
ifeq ($(pci_passthru), ) ifeq ($(pci_passthru), )
qemu_net_opts += \ qemu_net_opts += \
@ -340,4 +341,4 @@ endif
.PHONY: .PHONY:
addr2line: addr2line:
@python3 ../tools/addr2line.py $(prefix)addr2line $(arch) @python3 ../tools/addr2line.py $(prefix)addr2line $(arch) $(mode)

View File

@ -5,9 +5,9 @@ use std::io::{Result, Write};
use std::path::Path; use std::path::Path;
fn main() { fn main() {
println!("cargo:rerun-if-env-changed=LOG"); println!("cargo:rerun-if-env-changed=LOG");
println!("cargo:rerun-if-env-changed=BOARD"); println!("cargo:rerun-if-env-changed=BOARD");
println!("cargo:rerun-if-env-changed=SFSIMG"); println!("cargo:rerun-if-env-changed=SFSIMG");
let arch: String = std::env::var("ARCH").unwrap(); let arch: String = std::env::var("ARCH").unwrap();
let board: String = std::env::var("BOARD").unwrap(); let board: String = std::env::var("BOARD").unwrap();
@ -29,27 +29,27 @@ fn main() {
} }
fn gen_vector_asm() -> Result<()> { 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, "# generated by build.rs - do not edit")?;
writeln!(f, ".section .text")?; writeln!(f, ".section .text")?;
writeln!(f, ".intel_syntax noprefix")?; writeln!(f, ".intel_syntax noprefix")?;
for i in 0..256 { for i in 0..256 {
writeln!(f, "vector{}:", i)?; writeln!(f, "vector{}:", i)?;
if !(i == 8 || (i >= 10 && i <= 14) || i == 17) { if !(i == 8 || (i >= 10 && i <= 14) || i == 17) {
writeln!(f, "\tpush 0")?; writeln!(f, "\tpush 0")?;
} }
writeln!(f, "\tpush {}", i)?; writeln!(f, "\tpush {}", i)?;
writeln!(f, "\tjmp __alltraps")?; writeln!(f, "\tjmp __alltraps")?;
} }
writeln!(f, "\n.section .rodata")?; writeln!(f, "\n.section .rodata")?;
writeln!(f, ".global __vectors")?; writeln!(f, ".global __vectors")?;
writeln!(f, "__vectors:")?; writeln!(f, "__vectors:")?;
for i in 0..256 { for i in 0..256 {
writeln!(f, "\t.quad vector{}", i)?; writeln!(f, "\t.quad vector{}", i)?;
} }
Ok(()) Ok(())
} }

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,13 @@
//! Page table implementations for aarch64. //! 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::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::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 log::*;
use rcore_memory::paging::*;
// Depends on kernel // Depends on kernel
use crate::consts::{KERNEL_OFFSET, KERNEL_PML4, RECURSIVE_INDEX}; use crate::consts::{KERNEL_OFFSET, KERNEL_PML4, RECURSIVE_INDEX};
use crate::memory::{active_table, alloc_frame, dealloc_frame}; 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 { fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
let flags = EF::default(); let flags = EF::default();
let attr = MairNormal::attr_value(); 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) self.0
.unwrap().flush(); .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") 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> { fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
// get p1 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) }) 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 TEMP_PAGE_ADDR: usize = KERNEL_OFFSET | 0xcafeb000;
} }
const ROOT_PAGE_TABLE: *mut Aarch64PageTable = const ROOT_PAGE_TABLE: *mut Aarch64PageTable = (KERNEL_OFFSET
(KERNEL_OFFSET | | (RECURSIVE_INDEX << 39)
(RECURSIVE_INDEX << 39) | | (RECURSIVE_INDEX << 30)
(RECURSIVE_INDEX << 30) | | (RECURSIVE_INDEX << 21)
(RECURSIVE_INDEX << 21) | | (RECURSIVE_INDEX << 12))
(RECURSIVE_INDEX << 12)) as *mut Aarch64PageTable; as *mut Aarch64PageTable;
impl ActivePageTable { impl ActivePageTable {
pub unsafe fn new() -> Self { pub unsafe fn new() -> Self {
@ -66,38 +77,63 @@ impl Entry for PageEntry {
tlb_invalidate(addr); tlb_invalidate(addr);
} }
fn present(&self) -> bool { self.0.flags().contains(EF::VALID) } fn present(&self) -> bool {
fn accessed(&self) -> bool { self.0.flags().contains(EF::AF) } self.0.flags().contains(EF::VALID)
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITE) } }
fn dirty(&self) -> bool { self.hw_dirty() && self.sw_dirty() } 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_accessed(&mut self) {
fn clear_dirty(&mut self) self.as_flags().remove(EF::AF);
{ }
fn clear_dirty(&mut self) {
self.as_flags().remove(EF::DIRTY); self.as_flags().remove(EF::DIRTY);
self.as_flags().insert(EF::AP_RO); 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::AP_RO, !value);
self.as_flags().set(EF::WRITE, value); self.as_flags().set(EF::WRITE, value);
} }
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::VALID, value); } fn set_present(&mut self, value: bool) {
fn target(&self) -> usize { self.0.addr().as_u64() as usize } 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) { fn set_target(&mut self, target: usize) {
self.0.modify_addr(PhysAddr::new(target as u64)); self.0.modify_addr(PhysAddr::new(target as u64));
} }
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::WRITABLE_SHARED) } fn writable_shared(&self) -> bool {
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::READONLY_SHARED) } 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) { fn set_shared(&mut self, writable: bool) {
let flags = self.as_flags(); let flags = self.as_flags();
flags.set(EF::WRITABLE_SHARED, writable); flags.set(EF::WRITABLE_SHARED, writable);
flags.set(EF::READONLY_SHARED, !writable); flags.set(EF::READONLY_SHARED, !writable);
} }
fn clear_shared(&mut self) { self.as_flags().remove(EF::WRITABLE_SHARED | EF::READONLY_SHARED); } fn clear_shared(&mut self) {
fn user(&self) -> bool { self.0.flags().contains(EF::AP_EL0) } self.as_flags()
fn swapped(&self) -> bool { self.0.flags().contains(EF::SWAPPED) } .remove(EF::WRITABLE_SHARED | EF::READONLY_SHARED);
fn set_swapped(&mut self, value: bool) { self.as_flags().set(EF::SWAPPED, value); } }
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) { fn set_user(&mut self, value: bool) {
self.as_flags().set(EF::AP_EL0, value); self.as_flags().set(EF::AP_EL0, value);
self.as_flags().set(EF::nG, value); // set non-global to use ASID self.as_flags().set(EF::nG, value); // set non-global to use ASID
@ -140,9 +176,15 @@ impl Entry for PageEntry {
} }
impl PageEntry { impl PageEntry {
fn read_only(&self) -> bool { self.0.flags().contains(EF::AP_RO) } fn read_only(&self) -> bool {
fn hw_dirty(&self) -> bool { self.writable() && !self.read_only() } self.0.flags().contains(EF::AP_RO)
fn sw_dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) } }
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 { fn as_flags(&mut self) -> &mut EF {
unsafe { &mut *(self as *mut _ as *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| { active_table().with_temporary_map(target, |_, table: &mut Aarch64PageTable| {
table.zero(); table.zero();
// set up recursive mapping for the table // 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 } InactivePageTable0 { p4_frame: frame }
} }
@ -179,7 +225,11 @@ impl InactivePageTable for InactivePageTable0 {
assert!(!e0.is_unused()); assert!(!e0.is_unused());
self.edit(|_| { 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 { 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; let target = ttbr_el1_read(1).start_address().as_u64() as usize;
active_table().with_temporary_map(target, |active_table, p4_table: &mut Aarch64PageTable| { active_table().with_temporary_map(
let backup = p4_table[RECURSIVE_INDEX].clone(); target,
let old_frame = ttbr_el1_read(0); |active_table, p4_table: &mut Aarch64PageTable| {
let backup = p4_table[RECURSIVE_INDEX].clone();
let old_frame = ttbr_el1_read(0);
// overwrite recursive mapping // overwrite recursive mapping
p4_table[RECURSIVE_INDEX].set_frame(self.p4_frame.clone(), EF::default(), MairNormal::attr_value()); p4_table[RECURSIVE_INDEX].set_frame(
ttbr_el1_write(0, self.p4_frame.clone()); self.p4_frame.clone(),
tlb_invalidate_all(); EF::default(),
MairNormal::attr_value(),
);
ttbr_el1_write(0, self.p4_frame.clone());
tlb_invalidate_all();
// execute f in the new context // execute f in the new context
let ret = f(active_table); let ret = f(active_table);
// restore recursive mapping to original p4 table // restore recursive mapping to original p4 table
p4_table[RECURSIVE_INDEX] = backup; p4_table[RECURSIVE_INDEX] = backup;
ttbr_el1_write(0, old_frame); ttbr_el1_write(0, old_frame);
tlb_invalidate_all(); tlb_invalidate_all();
ret ret
}) },
)
} }
} }

View File

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

View File

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

View File

@ -10,9 +10,10 @@ pub unsafe fn init_external_interrupt() {
/// Claim and complete external interrupt by reading and writing to /// Claim and complete external interrupt by reading and writing to
/// PLIC Interrupt Claim/Complete Register. /// PLIC Interrupt Claim/Complete Register.
pub unsafe fn handle_external_interrupt() { 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 // claim
let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read(); let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read();
// complete // complete
HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.write(source); HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.write(source);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,34 +1,38 @@
pub mod io;
pub mod interrupt;
pub mod timer;
pub mod paging;
pub mod memory;
pub mod compiler_rt;
pub mod consts;
pub mod cpu;
pub mod syscall;
pub mod rand;
#[cfg(feature = "board_u540")] #[cfg(feature = "board_u540")]
#[path = "board/u540/mod.rs"] #[path = "board/u540/mod.rs"]
mod board; mod board;
pub mod compiler_rt;
pub mod consts;
pub mod cpu;
pub mod interrupt;
pub mod io;
pub mod memory;
pub mod paging;
pub mod rand;
mod sbi; mod sbi;
pub mod syscall;
pub mod timer;
use log::*; use log::*;
#[no_mangle] #[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) // 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 { 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); println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb);
others_main(); others_main();
//other_main -> ! //other_main -> !
} }
unsafe { memory::clear_bss(); } unsafe {
memory::clear_bss();
}
println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb); 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"))] #[cfg(not(feature = "board_u540"))]
crate::drivers::init(dtb); crate::drivers::init(dtb);
#[cfg(feature = "board_u540")] #[cfg(feature = "board_u540")]
unsafe { board::init_external_interrupt(); } unsafe {
board::init_external_interrupt();
}
crate::process::init(); crate::process::init();
unsafe { cpu::start_others(hart_mask); } unsafe {
cpu::start_others(hart_mask);
}
crate::kmain(); crate::kmain();
} }
@ -61,7 +69,8 @@ const BOOT_HART_ID: usize = 1;
/// Constant & Macro for `trap.asm` /// Constant & Macro for `trap.asm`
#[cfg(target_arch = "riscv32")] #[cfg(target_arch = "riscv32")]
global_asm!(r" global_asm!(
r"
.equ XLENB, 4 .equ XLENB, 4
.equ XLENb, 32 .equ XLENb, 32
.macro LOAD a1, a2 .macro LOAD a1, a2
@ -70,9 +79,11 @@ global_asm!(r"
.macro STORE a1, a2 .macro STORE a1, a2
sw \a1, \a2*XLENB(sp) sw \a1, \a2*XLENB(sp)
.endm .endm
"); "
);
#[cfg(target_arch = "riscv64")] #[cfg(target_arch = "riscv64")]
global_asm!(r" global_asm!(
r"
.equ XLENB, 8 .equ XLENB, 8
.equ XLENb, 64 .equ XLENb, 64
.macro LOAD a1, a2 .macro LOAD a1, a2
@ -81,8 +92,8 @@ global_asm!(r"
.macro STORE a1, a2 .macro STORE a1, a2
sd \a1, \a2*XLENB(sp) sd \a1, \a2*XLENB(sp)
.endm .endm
"); "
);
global_asm!(include_str!("boot/entry.asm")); global_asm!(include_str!("boot/entry.asm"));
global_asm!(include_str!("boot/trap.asm")); global_asm!(include_str!("boot/trap.asm"));

View File

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

View File

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

View File

@ -28,7 +28,12 @@ pub fn shutdown() -> ! {
pub fn set_timer(stime_value: u64) { pub fn set_timer(stime_value: u64) {
#[cfg(target_pointer_width = "32")] #[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")] #[cfg(target_pointer_width = "64")]
sbi_call(SBI_SET_TIMER, stime_value as usize, 0, 0); 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) { 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; const SBI_SET_TIMER: usize = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -61,7 +61,8 @@ pub fn read_epoch() -> u64 {
month = month - 2; 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) - 719499)
* 24 * 24
+ hour) + hour)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,17 +1,21 @@
use bit_allocator::BitAlloc;
use crate::consts::KERNEL_OFFSET; use crate::consts::KERNEL_OFFSET;
use bit_allocator::BitAlloc;
// Depends on kernel // Depends on kernel
use crate::memory::{FRAME_ALLOCATOR, init_heap, active_table};
use super::{BootInfo, MemoryRegionType}; use super::{BootInfo, MemoryRegionType};
use rcore_memory::paging::*; use crate::memory::{active_table, init_heap, FRAME_ALLOCATOR, alloc_frame};
use once::*; use crate::HEAP_ALLOCATOR;
use rcore_memory::PAGE_SIZE;
use alloc::vec::Vec;
use log::*; use log::*;
use once::*;
use rcore_memory::paging::*;
pub fn init(boot_info: &BootInfo) { pub fn init(boot_info: &BootInfo) {
assert_has_not_been_called!("memory::init must be called only once"); assert_has_not_been_called!("memory::init must be called only once");
init_frame_allocator(boot_info); init_frame_allocator(boot_info);
init_device_vm_map(); init_device_vm_map();
init_heap(); init_heap();
enlarge_heap();
info!("memory: init end"); info!("memory: init end");
} }
@ -20,7 +24,9 @@ fn init_frame_allocator(boot_info: &BootInfo) {
let mut ba = FRAME_ALLOCATOR.lock(); let mut ba = FRAME_ALLOCATOR.lock();
for region in boot_info.memory_map.iter() { for region in boot_info.memory_map.iter() {
if region.region_type == MemoryRegionType::Usable { 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 +34,40 @@ fn init_frame_allocator(boot_info: &BootInfo) {
fn init_device_vm_map() { fn init_device_vm_map() {
let mut page_table = active_table(); let mut page_table = active_table();
// IOAPIC // IOAPIC
page_table.map(KERNEL_OFFSET + 0xfec00000, 0xfec00000).update(); page_table
.map(KERNEL_OFFSET + 0xfec00000, 0xfec00000)
.update();
// LocalAPIC // LocalAPIC
page_table.map(KERNEL_OFFSET + 0xfee00000, 0xfee00000).update(); page_table
.map(KERNEL_OFFSET + 0xfee00000, 0xfee00000)
.update();
}
fn enlarge_heap() {
let mut page_table = active_table();
let mut addrs = Vec::new();
let va_offset = KERNEL_OFFSET + 0xe0000000;
for i in 0..16384 {
let page = alloc_frame().unwrap();
let va = KERNEL_OFFSET + 0xe0000000 + page;
if let Some((ref mut addr, ref mut len)) = addrs.last_mut() {
if *addr - PAGE_SIZE == va {
*len += PAGE_SIZE;
*addr -= PAGE_SIZE;
continue;
}
}
addrs.push((va, PAGE_SIZE));
}
for (addr, len) in addrs.into_iter() {
for va in (addr..(addr+len)).step_by(PAGE_SIZE) {
page_table.map(va, va - va_offset).update();
}
info!("Adding {:#X} {:#X} to heap", addr, len);
unsafe {
HEAP_ALLOCATOR
.lock()
.init(addr, len);
}
}
} }

View File

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

View File

@ -1,18 +1,18 @@
// Depends on kernel // Depends on kernel
use crate::consts::KERNEL_OFFSET;
use crate::memory::{active_table, alloc_frame, dealloc_frame}; use crate::memory::{active_table, alloc_frame, dealloc_frame};
use log::*;
use rcore_memory::paging::*; use rcore_memory::paging::*;
use x86_64::instructions::tlb; use x86_64::instructions::tlb;
use x86_64::PhysAddr;
use x86_64::registers::control::{Cr3, Cr3Flags}; use x86_64::registers::control::{Cr3, Cr3Flags};
use x86_64::structures::paging::{ use x86_64::structures::paging::{
page_table::{PageTable as x86PageTable, PageTableEntry, PageTableFlags as EF}, frame::PhysFrame as Frame,
mapper::{Mapper, RecursivePageTable}, mapper::{Mapper, RecursivePageTable},
page::{Page, PageRange, Size4KiB}, page::{Page, PageRange, Size4KiB},
frame::PhysFrame as Frame, page_table::{PageTable as x86PageTable, PageTableEntry, PageTableFlags as EF},
FrameAllocator, FrameDeallocator FrameAllocator, FrameDeallocator,
}; };
use crate::consts::KERNEL_OFFSET; use x86_64::PhysAddr;
use log::*;
pub trait PageExt { pub trait PageExt {
fn of_addr(address: usize) -> Self; fn of_addr(address: usize) -> Self;
@ -47,7 +47,12 @@ impl PageTable for ActivePageTable {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry { fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE; let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE;
unsafe { 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(); flush.flush();
} }
} }
@ -64,14 +69,19 @@ impl PageTable for ActivePageTable {
fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> { fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> {
for level in 0..3 { for level in 0..3 {
let entry = get_entry_ptr(addr, 4 - level); 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))) } unsafe { Some(&mut *(get_entry_ptr(addr, 1))) }
} }
} }
impl PageTableExt for ActivePageTable { impl PageTableExt for ActivePageTable {
const TEMP_PAGE_ADDR: usize = KERNEL_OFFSET | 0xcafeb000; // FIXME: the default value 0xcafebe000 is so low that allocation might overwrite it sometimes.
// However, putting it to KERNEL_OFFSET | 0xcafeb000 has unintended effects.
// Someone needs to reconsider this and use an ultimate solution.
// const TEMP_PAGE_ADDR: usize = KERNEL_OFFSET | 0xcafeb000;
} }
impl ActivePageTable { impl ActivePageTable {
@ -82,34 +92,64 @@ impl ActivePageTable {
impl Entry for PageEntry { impl Entry for PageEntry {
fn update(&mut self) { 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); let addr = VirtAddr::new_unchecked((self as *const _ as u64) << 9);
flush(addr); flush(addr);
} }
fn accessed(&self) -> bool { self.0.flags().contains(EF::ACCESSED) } fn accessed(&self) -> bool {
fn dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) } self.0.flags().contains(EF::ACCESSED)
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITABLE) } }
fn present(&self) -> bool { self.0.flags().contains(EF::PRESENT) } fn dirty(&self) -> bool {
fn clear_accessed(&mut self) { self.as_flags().remove(EF::ACCESSED); } self.0.flags().contains(EF::DIRTY)
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 writable(&self) -> bool {
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::PRESENT, value); } self.0.flags().contains(EF::WRITABLE)
fn target(&self) -> usize { self.0.addr().as_u64() as usize } }
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) { fn set_target(&mut self, target: usize) {
let flags = self.0.flags(); let flags = self.0.flags();
self.0.set_addr(PhysAddr::new(target as u64), flags); self.0.set_addr(PhysAddr::new(target as u64), flags);
} }
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::BIT_10) } fn writable_shared(&self) -> bool {
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::BIT_9) } 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) { fn set_shared(&mut self, writable: bool) {
let flags = self.as_flags(); let flags = self.as_flags();
flags.set(EF::BIT_10, writable); flags.set(EF::BIT_10, writable);
flags.set(EF::BIT_9, !writable); flags.set(EF::BIT_9, !writable);
} }
fn clear_shared(&mut self) { self.as_flags().remove(EF::BIT_9 | EF::BIT_10); } fn clear_shared(&mut self) {
fn swapped(&self) -> bool { self.0.flags().contains(EF::BIT_11) } self.as_flags().remove(EF::BIT_9 | EF::BIT_10);
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 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) { fn set_user(&mut self, value: bool) {
self.as_flags().set(EF::USER_ACCESSIBLE, value); self.as_flags().set(EF::USER_ACCESSIBLE, value);
if value { if value {
@ -122,10 +162,16 @@ impl Entry for PageEntry {
} }
} }
} }
fn execute(&self) -> bool { !self.0.flags().contains(EF::NO_EXECUTE) } fn execute(&self) -> bool {
fn set_execute(&mut self, value: bool) { self.as_flags().set(EF::NO_EXECUTE, !value); } !self.0.flags().contains(EF::NO_EXECUTE)
fn mmio(&self) -> u8 { 0 } }
fn set_mmio(&mut self, _value: u8) { } 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 { fn get_entry_ptr(addr: usize, level: u8) -> *mut PageEntry {
@ -176,7 +222,10 @@ impl InactivePageTable for InactivePageTable0 {
} }
unsafe fn set_token(token: usize) { 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 { fn active_token() -> usize {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
//! Implement Device //! Implement Device
use spin::RwLock;
use rcore_fs::dev::*; use rcore_fs::dev::*;
use spin::RwLock;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::driver::ide; use crate::arch::driver::ide;
@ -9,9 +9,12 @@ use crate::arch::driver::ide;
pub struct MemBuf(RwLock<&'static mut [u8]>); pub struct MemBuf(RwLock<&'static mut [u8]>);
impl MemBuf { 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; 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 { fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool {
use core::slice; use core::slice;
assert!(buf.len() >= ide::BLOCK_SIZE); assert!(buf.len() >= ide::BLOCK_SIZE);
let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; let buf =
unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
self.read(block_id as u64, 1, buf).is_ok() self.read(block_id as u64, 1, buf).is_ok()
} }
fn write_at(&self, block_id: usize, buf: &[u8]) -> bool { 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) }; 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() self.write(block_id as u64, 1, buf).is_ok()
} }
} }

View File

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

View File

@ -0,0 +1,40 @@
use core::fmt;
use super::FileHandle;
use crate::net::Socket;
use crate::syscall::SysResult;
use alloc::boxed::Box;
// TODO: merge FileLike to FileHandle ?
// TODO: fix dup and remove Clone
#[derive(Clone)]
pub enum FileLike {
File(FileHandle),
Socket(Box<dyn Socket>),
}
impl FileLike {
pub fn read(&mut self, buf: &mut [u8]) -> SysResult {
let len = match self {
FileLike::File(file) => file.read(buf)?,
FileLike::Socket(socket) => socket.read(buf).0?,
};
Ok(len)
}
pub fn write(&mut self, buf: &[u8]) -> SysResult {
let len = match self {
FileLike::File(file) => file.write(buf)?,
FileLike::Socket(socket) => socket.write(buf, None)?,
};
Ok(len)
}
}
impl fmt::Debug for FileLike {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FileLike::File(_) => write!(f, "File"),
FileLike::Socket(_) => write!(f, "Socket"),
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,43 +1,556 @@
use alloc::sync::Arc;
use crate::arch::rand; use crate::arch::rand;
use crate::drivers::{NET_DRIVERS, SOCKET_ACTIVITY}; use crate::drivers::{NET_DRIVERS, SOCKET_ACTIVITY};
use crate::sync::SpinNoIrqLock as Mutex; use crate::sync::SpinNoIrqLock as Mutex;
use crate::syscall::*; use crate::syscall::*;
use alloc::boxed::Box;
use smoltcp::socket::*; use smoltcp::socket::*;
use smoltcp::wire::*; use smoltcp::wire::*;
///
pub trait Socket: Send + Sync {
fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint);
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult;
fn poll(&self) -> (bool, bool, bool); // (in, out, err)
fn connect(&mut self, endpoint: IpEndpoint) -> SysResult;
fn bind(&mut self, endpoint: IpEndpoint) -> SysResult {
Err(SysError::EINVAL)
}
fn listen(&mut self) -> SysResult {
Err(SysError::EINVAL)
}
fn shutdown(&self) -> SysResult {
Err(SysError::EINVAL)
}
fn accept(&mut self) -> Result<(Box<dyn Socket>, IpEndpoint), SysError> {
Err(SysError::EINVAL)
}
fn endpoint(&self) -> Option<IpEndpoint> {
None
}
fn remote_endpoint(&self) -> Option<IpEndpoint> {
None
}
fn box_clone(&self) -> Box<dyn Socket>;
}
impl Clone for Box<dyn Socket> {
fn clone(&self) -> Self {
self.box_clone()
}
}
lazy_static! { lazy_static! {
pub static ref SOCKETS: Arc<Mutex<SocketSet<'static, 'static, 'static>>> = /// Global SocketSet in smoltcp.
Arc::new(Mutex::new(SocketSet::new(vec![]))); ///
/// Because smoltcp is a single thread network stack,
/// every socket operation needs to lock this.
pub static ref SOCKETS: Mutex<SocketSet<'static, 'static, 'static>> =
Mutex::new(SocketSet::new(vec![]));
} }
#[derive(Clone, Debug)] #[derive(Debug, Clone)]
pub struct TcpSocketState { pub struct TcpSocketState {
pub local_endpoint: Option<IpEndpoint>, // save local endpoint for bind() handle: GlobalSocketHandle,
pub is_listening: bool, local_endpoint: Option<IpEndpoint>, // save local endpoint for bind()
is_listening: bool,
} }
#[derive(Clone, Debug)] #[derive(Debug, Clone)]
pub struct UdpSocketState { pub struct UdpSocketState {
pub remote_endpoint: Option<IpEndpoint>, // remember remote endpoint for connect() handle: GlobalSocketHandle,
remote_endpoint: Option<IpEndpoint>, // remember remote endpoint for connect()
} }
#[derive(Clone, Debug)] #[derive(Debug, Clone)]
pub enum SocketType { pub struct RawSocketState {
Raw, handle: GlobalSocketHandle,
Tcp(TcpSocketState),
Udp(UdpSocketState),
Icmp,
} }
/// A wrapper for `SocketHandle`.
/// Auto increase and decrease reference count on Clone and Drop.
#[derive(Debug)] #[derive(Debug)]
pub struct SocketWrapper { struct GlobalSocketHandle(SocketHandle);
pub handle: SocketHandle,
pub socket_type: SocketType, impl Clone for GlobalSocketHandle {
fn clone(&self) -> Self {
SOCKETS.lock().retain(self.0);
Self(self.0)
}
} }
pub fn get_ephemeral_port() -> u16 { impl Drop for GlobalSocketHandle {
fn drop(&mut self) {
let mut sockets = SOCKETS.lock();
sockets.release(self.0);
sockets.prune();
// send FIN immediately when applicable
drop(sockets);
poll_ifaces();
}
}
impl TcpSocketState {
pub fn new() -> Self {
let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]);
let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
let handle = GlobalSocketHandle(SOCKETS.lock().add(socket));
TcpSocketState {
handle,
local_endpoint: None,
is_listening: false,
}
}
}
impl Socket for TcpSocketState {
fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) {
spin_and_wait(&[&SOCKET_ACTIVITY], move || {
poll_ifaces();
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
if socket.is_open() {
if let Ok(size) = socket.recv_slice(data) {
if size > 0 {
let endpoint = socket.remote_endpoint();
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
return Some((Ok(size), endpoint));
}
}
} else {
return Some((Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED));
}
None
})
}
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
if socket.is_open() {
if socket.can_send() {
match socket.send_slice(&data) {
Ok(size) => {
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
Ok(size)
}
Err(err) => Err(SysError::ENOBUFS),
}
} else {
Err(SysError::ENOBUFS)
}
} else {
Err(SysError::ENOTCONN)
}
}
fn poll(&self) -> (bool, bool, bool) {
let mut sockets = SOCKETS.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0);
let (mut input, mut output, mut err) = (false, false, false);
if self.is_listening && socket.is_active() {
// a new connection
input = true;
} else if !socket.is_open() {
err = true;
} else {
if socket.can_recv() {
input = true;
}
if socket.can_send() {
output = true;
}
}
(input, output, err)
}
fn connect(&mut self, endpoint: IpEndpoint) -> SysResult {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
let temp_port = get_ephemeral_port();
match socket.connect(endpoint, temp_port) {
Ok(()) => {
// avoid deadlock
drop(socket);
drop(sockets);
// wait for connection result
loop {
poll_ifaces();
let mut sockets = SOCKETS.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0);
match socket.state() {
TcpState::SynSent => {
// still connecting
drop(socket);
drop(sockets);
debug!("poll for connection wait");
SOCKET_ACTIVITY._wait();
}
TcpState::Established => {
break Ok(0);
}
_ => {
break Err(SysError::ECONNREFUSED);
}
}
}
}
Err(_) => Err(SysError::ENOBUFS),
}
}
fn bind(&mut self, mut endpoint: IpEndpoint) -> SysResult {
if endpoint.port == 0 {
endpoint.port = get_ephemeral_port();
}
self.local_endpoint = Some(endpoint);
self.is_listening = false;
Ok(0)
}
fn listen(&mut self) -> SysResult {
if self.is_listening {
// it is ok to listen twice
return Ok(0);
}
let local_endpoint = self.local_endpoint.ok_or(SysError::EINVAL)?;
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
info!("socket listening on {:?}", local_endpoint);
if socket.is_listening() {
return Ok(0);
}
match socket.listen(local_endpoint) {
Ok(()) => {
self.is_listening = true;
Ok(0)
}
Err(_) => Err(SysError::EINVAL),
}
}
fn shutdown(&self) -> SysResult {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
socket.close();
Ok(0)
}
fn accept(&mut self) -> Result<(Box<dyn Socket>, IpEndpoint), SysError> {
let endpoint = self.local_endpoint.ok_or(SysError::EINVAL)?;
loop {
let mut sockets = SOCKETS.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0);
if socket.is_active() {
let remote_endpoint = socket.remote_endpoint();
drop(socket);
let new_socket = {
let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]);
let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]);
let mut socket = TcpSocket::new(rx_buffer, tx_buffer);
socket.listen(endpoint).unwrap();
let new_handle = GlobalSocketHandle(sockets.add(socket));
let old_handle = ::core::mem::replace(&mut self.handle, new_handle);
Box::new(TcpSocketState {
handle: old_handle,
local_endpoint: self.local_endpoint,
is_listening: false,
})
};
drop(sockets);
poll_ifaces();
return Ok((new_socket, remote_endpoint));
}
// avoid deadlock
drop(socket);
drop(sockets);
SOCKET_ACTIVITY._wait();
}
}
fn endpoint(&self) -> Option<IpEndpoint> {
self.local_endpoint.clone().or_else(|| {
let mut sockets = SOCKETS.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0);
let endpoint = socket.local_endpoint();
if endpoint.port != 0 {
Some(endpoint)
} else {
None
}
})
}
fn remote_endpoint(&self) -> Option<IpEndpoint> {
let mut sockets = SOCKETS.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0);
if socket.is_open() {
Some(socket.remote_endpoint())
} else {
None
}
}
fn box_clone(&self) -> Box<dyn Socket> {
Box::new(self.clone())
}
}
impl UdpSocketState {
pub fn new() -> Self {
let rx_buffer = UdpSocketBuffer::new(
vec![UdpPacketMetadata::EMPTY; UDP_METADATA_BUF],
vec![0; UDP_RECVBUF],
);
let tx_buffer = UdpSocketBuffer::new(
vec![UdpPacketMetadata::EMPTY; UDP_METADATA_BUF],
vec![0; UDP_SENDBUF],
);
let socket = UdpSocket::new(rx_buffer, tx_buffer);
let handle = GlobalSocketHandle(SOCKETS.lock().add(socket));
UdpSocketState {
handle,
remote_endpoint: None,
}
}
}
impl Socket for UdpSocketState {
fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) {
loop {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<UdpSocket>(self.handle.0);
if socket.is_open() {
if let Ok((size, remote_endpoint)) = socket.recv_slice(data) {
let endpoint = remote_endpoint;
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
return (Ok(size), endpoint);
}
} else {
return (Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED);
}
// avoid deadlock
drop(socket);
SOCKET_ACTIVITY._wait()
}
}
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult {
let remote_endpoint = {
if let Some(ref endpoint) = sendto_endpoint {
endpoint
} else if let Some(ref endpoint) = self.remote_endpoint {
endpoint
} else {
return Err(SysError::ENOTCONN);
}
};
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<UdpSocket>(self.handle.0);
if socket.endpoint().port == 0 {
let temp_port = get_ephemeral_port();
socket
.bind(IpEndpoint::new(IpAddress::Unspecified, temp_port))
.unwrap();
}
if socket.can_send() {
match socket.send_slice(&data, *remote_endpoint) {
Ok(()) => {
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
Ok(data.len())
}
Err(err) => Err(SysError::ENOBUFS),
}
} else {
Err(SysError::ENOBUFS)
}
}
fn poll(&self) -> (bool, bool, bool) {
let mut sockets = SOCKETS.lock();
let socket = sockets.get::<UdpSocket>(self.handle.0);
let (mut input, mut output, err) = (false, false, false);
if socket.can_recv() {
input = true;
}
if socket.can_send() {
output = true;
}
(input, output, err)
}
fn connect(&mut self, endpoint: IpEndpoint) -> SysResult {
self.remote_endpoint = Some(endpoint);
Ok(0)
}
fn bind(&mut self, endpoint: IpEndpoint) -> SysResult {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<UdpSocket>(self.handle.0);
match socket.bind(endpoint) {
Ok(()) => Ok(0),
Err(_) => Err(SysError::EINVAL),
}
}
fn endpoint(&self) -> Option<IpEndpoint> {
let mut sockets = SOCKETS.lock();
let socket = sockets.get::<UdpSocket>(self.handle.0);
let endpoint = socket.endpoint();
if endpoint.port != 0 {
Some(endpoint)
} else {
None
}
}
fn remote_endpoint(&self) -> Option<IpEndpoint> {
self.remote_endpoint.clone()
}
fn box_clone(&self) -> Box<dyn Socket> {
Box::new(self.clone())
}
}
impl RawSocketState {
pub fn new(protocol: u8) -> Self {
let rx_buffer = RawSocketBuffer::new(
vec![RawPacketMetadata::EMPTY; RAW_METADATA_BUF],
vec![0; RAW_RECVBUF],
);
let tx_buffer = RawSocketBuffer::new(
vec![RawPacketMetadata::EMPTY; RAW_METADATA_BUF],
vec![0; RAW_SENDBUF],
);
let socket = RawSocket::new(
IpVersion::Ipv4,
IpProtocol::from(protocol),
rx_buffer,
tx_buffer,
);
let handle = GlobalSocketHandle(SOCKETS.lock().add(socket));
RawSocketState { handle }
}
}
impl Socket for RawSocketState {
fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) {
loop {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<RawSocket>(self.handle.0);
if let Ok(size) = socket.recv_slice(data) {
let packet = Ipv4Packet::new_unchecked(data);
return (
Ok(size),
IpEndpoint {
addr: IpAddress::Ipv4(packet.src_addr()),
port: 0,
},
);
}
// avoid deadlock
drop(socket);
drop(sockets);
SOCKET_ACTIVITY._wait()
}
}
fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult {
if let Some(endpoint) = sendto_endpoint {
// temporary solution
let iface = &*(NET_DRIVERS.read()[0]);
let v4_src = iface.ipv4_address().unwrap();
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<RawSocket>(self.handle.0);
if let IpAddress::Ipv4(v4_dst) = endpoint.addr {
let len = data.len();
// using 20-byte IPv4 header
let mut buffer = vec![0u8; len + 20];
let mut packet = Ipv4Packet::new_unchecked(&mut buffer);
packet.set_version(4);
packet.set_header_len(20);
packet.set_total_len((20 + len) as u16);
packet.set_protocol(socket.ip_protocol().into());
packet.set_src_addr(v4_src);
packet.set_dst_addr(v4_dst);
let payload = packet.payload_mut();
payload.copy_from_slice(data);
packet.fill_checksum();
socket.send_slice(&buffer).unwrap();
// avoid deadlock
drop(socket);
drop(sockets);
iface.poll();
Ok(len)
} else {
unimplemented!("ip type")
}
} else {
Err(SysError::ENOTCONN)
}
}
fn poll(&self) -> (bool, bool, bool) {
unimplemented!()
}
fn connect(&mut self, _endpoint: IpEndpoint) -> SysResult {
unimplemented!()
}
fn box_clone(&self) -> Box<dyn Socket> {
Box::new(self.clone())
}
}
fn get_ephemeral_port() -> u16 {
// TODO selects non-conflict high port // TODO selects non-conflict high port
static mut EPHEMERAL_PORT: u16 = 0; static mut EPHEMERAL_PORT: u16 = 0;
unsafe { unsafe {
@ -54,197 +567,19 @@ pub fn get_ephemeral_port() -> u16 {
} }
/// Safety: call this without SOCKETS locked /// Safety: call this without SOCKETS locked
pub fn poll_ifaces() { fn poll_ifaces() {
for iface in NET_DRIVERS.read().iter() { for iface in NET_DRIVERS.read().iter() {
iface.poll(); iface.poll();
} }
} }
impl Drop for SocketWrapper { pub const TCP_SENDBUF: usize = 512 * 1024; // 512K
fn drop(&mut self) { pub const TCP_RECVBUF: usize = 512 * 1024; // 512K
let mut sockets = SOCKETS.lock();
sockets.release(self.handle);
sockets.prune();
// send FIN immediately when applicable const UDP_METADATA_BUF: usize = 1024;
drop(sockets); const UDP_SENDBUF: usize = 64 * 1024; // 64K
poll_ifaces(); const UDP_RECVBUF: usize = 64 * 1024; // 64K
}
}
impl SocketWrapper { const RAW_METADATA_BUF: usize = 2;
pub fn write(&self, data: &[u8], sendto_endpoint: Option<IpEndpoint>) -> SysResult { const RAW_SENDBUF: usize = 2 * 1024; // 2K
if let SocketType::Raw = self.socket_type { const RAW_RECVBUF: usize = 2 * 1024; // 2K
if let Some(endpoint) = sendto_endpoint {
// temporary solution
let iface = &*(NET_DRIVERS.read()[0]);
let v4_src = iface.ipv4_address().unwrap();
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<RawSocket>(self.handle);
if let IpAddress::Ipv4(v4_dst) = endpoint.addr {
let len = data.len();
// using 20-byte IPv4 header
let mut buffer = vec![0u8; len + 20];
let mut packet = Ipv4Packet::new_unchecked(&mut buffer);
packet.set_version(4);
packet.set_header_len(20);
packet.set_total_len((20 + len) as u16);
packet.set_protocol(socket.ip_protocol().into());
packet.set_src_addr(v4_src);
packet.set_dst_addr(v4_dst);
let payload = packet.payload_mut();
payload.copy_from_slice(data);
packet.fill_checksum();
socket.send_slice(&buffer).unwrap();
// avoid deadlock
drop(socket);
drop(sockets);
iface.poll();
Ok(len)
} else {
unimplemented!("ip type")
}
} else {
Err(SysError::ENOTCONN)
}
} else if let SocketType::Tcp(_) = self.socket_type {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle);
if socket.is_open() {
if socket.can_send() {
match socket.send_slice(&data) {
Ok(size) => {
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
Ok(size)
}
Err(err) => Err(SysError::ENOBUFS),
}
} else {
Err(SysError::ENOBUFS)
}
} else {
Err(SysError::ENOTCONN)
}
} else if let SocketType::Udp(ref state) = self.socket_type {
let remote_endpoint = {
if let Some(ref endpoint) = sendto_endpoint {
endpoint
} else if let Some(ref endpoint) = state.remote_endpoint {
endpoint
} else {
return Err(SysError::ENOTCONN);
}
};
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<UdpSocket>(self.handle);
if socket.endpoint().port == 0 {
let temp_port = get_ephemeral_port();
socket
.bind(IpEndpoint::new(IpAddress::Unspecified, temp_port))
.unwrap();
}
if socket.can_send() {
match socket.send_slice(&data, *remote_endpoint) {
Ok(()) => {
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
Ok(data.len())
}
Err(err) => Err(SysError::ENOBUFS),
}
} else {
Err(SysError::ENOBUFS)
}
} else {
unimplemented!("socket type")
}
}
pub fn read(&self, data: &mut [u8]) -> (SysResult, IpEndpoint) {
if let SocketType::Raw = self.socket_type {
loop {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<RawSocket>(self.handle);
if let Ok(size) = socket.recv_slice(data) {
let packet = Ipv4Packet::new_unchecked(data);
return (
Ok(size),
IpEndpoint {
addr: IpAddress::Ipv4(packet.src_addr()),
port: 0,
},
);
}
// avoid deadlock
drop(socket);
drop(sockets);
SOCKET_ACTIVITY._wait()
}
} else if let SocketType::Tcp(_) = self.socket_type {
spin_and_wait(&[&SOCKET_ACTIVITY], move || {
poll_ifaces();
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle);
if socket.is_open() {
if let Ok(size) = socket.recv_slice(data) {
if size > 0 {
let endpoint = socket.remote_endpoint();
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
return Some((Ok(size), endpoint));
}
}
} else {
return Some((Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED));
}
None
})
} else if let SocketType::Udp(ref state) = self.socket_type {
loop {
let mut sockets = SOCKETS.lock();
let mut socket = sockets.get::<UdpSocket>(self.handle);
if socket.is_open() {
if let Ok((size, remote_endpoint)) = socket.recv_slice(data) {
let endpoint = remote_endpoint;
// avoid deadlock
drop(socket);
drop(sockets);
poll_ifaces();
return (Ok(size), endpoint);
}
} else {
return (Err(SysError::ENOTCONN), IpEndpoint::UNSPECIFIED);
}
// avoid deadlock
drop(socket);
SOCKET_ACTIVITY._wait()
}
} else {
unimplemented!("socket type")
}
}
}

View File

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

View File

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

View File

@ -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::fmt;
use core::str;
use log::*; use log::*;
use spin::{Mutex, RwLock};
use xmas_elf::{ElfFile, header, program::{Flags, Type, SegmentData}};
use rcore_memory::PAGE_SIZE; use rcore_memory::PAGE_SIZE;
use rcore_thread::Tid; use rcore_thread::Tid;
use core::str; use spin::RwLock;
use xmas_elf::{
header,
program::{Flags, SegmentData, Type},
ElfFile,
};
use crate::arch::interrupt::{Context, TrapFrame}; use crate::arch::interrupt::{Context, TrapFrame};
use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH};
use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet}; use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet};
use crate::fs::{FileHandle, OpenOptions, INodeExt, FOLLOW_MAX_DEPTH}; use crate::net::{Socket, SOCKETS};
use crate::sync::Condvar; use crate::sync::{Condvar, SpinNoIrqLock as Mutex};
use crate::net::{SocketWrapper, SOCKETS};
use super::abi::{self, ProcInitInfo}; use super::abi::{self, ProcInitInfo};
@ -26,24 +30,6 @@ pub struct Thread {
pub proc: Arc<Mutex<Process>>, pub proc: Arc<Mutex<Process>>,
} }
#[derive(Clone)]
pub enum FileLike {
File(FileHandle),
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)
},
}
}
}
/// Pid type /// Pid type
/// For strong type separation /// For strong type separation
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
@ -104,7 +90,8 @@ pub struct Process {
/// Records the mapping between pid and Process struct. /// Records the mapping between pid and Process struct.
lazy_static! { 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` /// Let `rcore_thread` can switch between our `Thread`
@ -128,7 +115,9 @@ impl rcore_thread::Context for Thread {
} }
// add it to threads // add it to threads
proc.threads.push(tid); 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 +145,7 @@ impl Thread {
} }
/// Make a new kernel thread starting from `entry` with `arg` /// 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 vm = MemorySet::new();
let kstack = KernelStack::new(); let kstack = KernelStack::new();
Box::new(Thread { Box::new(Thread {
@ -174,14 +163,15 @@ impl Thread {
children: Vec::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
child_exit: Arc::new(Condvar::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` /// Make a new user process from ELF `data`
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<Thread> 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 // Parse ELF
let elf = ElfFile::new(data).expect("failed to read elf"); let elf = ElfFile::new(data).expect("failed to read elf");
@ -192,8 +182,8 @@ impl Thread {
// Check ELF type // Check ELF type
match elf.header.pt2.type_().as_type() { match elf.header.pt2.type_().as_type() {
header::Type::Executable => {}, header::Type::Executable => {}
header::Type::SharedObject => {}, header::Type::SharedObject => {}
_ => panic!("ELF is not executable or shared object"), _ => panic!("ELF is not executable or shared object"),
} }
@ -220,13 +210,19 @@ impl Thread {
let mut vm = elf.make_memory_set(); let mut vm = elf.make_memory_set();
// User stack // 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 mut ustack_top = {
let (ustack_buttom, ustack_top) = match is32 { let (ustack_buttom, ustack_top) = match is32 {
true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE), true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE),
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE), false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
}; };
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 ustack_top
}; };
@ -246,7 +242,7 @@ impl Thread {
}, },
}; };
unsafe { unsafe {
vm.with(|| { ustack_top = init_info.push_at(ustack_top) }); vm.with(|| ustack_top = init_info.push_at(ustack_top));
} }
trace!("{:#x?}", vm); trace!("{:#x?}", vm);
@ -254,16 +250,45 @@ impl Thread {
let kstack = KernelStack::new(); let kstack = KernelStack::new();
let mut files = BTreeMap::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(
files.insert(1, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false }))); 0,
files.insert(2, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false }))); 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; let entry_addr = elf.header.pt2.entry_point() as usize;
Box::new(Thread { Box::new(Thread {
context: unsafe { context: unsafe {
Context::new_user_thread( Context::new_user_thread(entry_addr, ustack_top, kstack.top(), is32, vm.token())
entry_addr, ustack_top, kstack.top(), is32, vm.token())
}, },
kstack, kstack,
clear_child_tid: 0, clear_child_tid: 0,
@ -277,7 +302,7 @@ impl Thread {
children: Vec::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
child_exit: Arc::new(Condvar::new()), child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new() child_exit_code: BTreeMap::new(),
})), })),
}) })
} }
@ -297,21 +322,12 @@ impl Thread {
// NoMMU: coping data has been done in `vm.clone()` // NoMMU: coping data has been done in `vm.clone()`
for area in vm.iter() { for area in vm.iter() {
let data = Vec::<u8>::from(unsafe { area.as_slice() }); let data = Vec::<u8>::from(unsafe { area.as_slice() });
unsafe { vm.with(|| { unsafe { vm.with(|| area.as_slice_mut().copy_from_slice(data.as_slice())) }
area.as_slice_mut().copy_from_slice(data.as_slice())
}) }
} }
debug!("fork: temporary copy data!"); debug!("fork: temporary copy data!");
let kstack = KernelStack::new(); let kstack = KernelStack::new();
let mut sockets = SOCKETS.lock();
for (_fd, file) in files.iter() {
if let FileLike::Socket(wrapper) = file {
sockets.retain(wrapper.handle);
}
}
Box::new(Thread { Box::new(Thread {
context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) }, context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) },
kstack, kstack,
@ -326,13 +342,19 @@ impl Thread {
children: Vec::new(), children: Vec::new(),
threads: Vec::new(), threads: Vec::new(),
child_exit: Arc::new(Condvar::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. /// 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 kstack = KernelStack::new();
let token = self.proc.lock().vm.token(); let token = self.proc.lock().vm.token();
Box::new(Thread { Box::new(Thread {
@ -371,7 +393,9 @@ impl ToMemoryAttr for Flags {
fn to_attr(&self) -> MemoryAttr { fn to_attr(&self) -> MemoryAttr {
let mut flags = MemoryAttr::default().user(); let mut flags = MemoryAttr::default().user();
// FIXME: handle readonly // FIXME: handle readonly
if self.is_execute() { flags = flags.execute(); } if self.is_execute() {
flags = flags.execute();
}
flags flags
} }
} }
@ -406,7 +430,13 @@ impl ElfExt for ElfFile<'_> {
// Get target slice // Get target slice
let target = { 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) } unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
}; };
// Copy data // Copy data
@ -423,29 +453,34 @@ impl ElfExt for ElfFile<'_> {
} }
fn get_interpreter(&self) -> Result<&str, &str> { 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)) .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)? { let mut data = match header.get_data(self)? {
SegmentData::Undefined(data) => data, SegmentData::Undefined(data) => data,
_ => unreachable!(), _ => unreachable!(),
}; };
// skip NULL // skip NULL
while let Some(0) = data.last() { while let Some(0) = data.last() {
data = &data[..data.len()-1]; data = &data[..data.len() - 1];
} }
let path = str::from_utf8(data) let path = str::from_utf8(data).map_err(|_| "failed to convert to utf8")?;
.map_err(|_| "failed to convert to utf8")?;
Ok(path) Ok(path)
} }
fn get_phdr_vaddr(&self) -> Option<u64> { fn get_phdr_vaddr(&self) -> Option<u64> {
if let Some(phdr) = self.program_iter() if let Some(phdr) = self
.find(|ph| ph.get_type() == Ok(Type::Phdr)) { .program_iter()
.find(|ph| ph.get_type() == Ok(Type::Phdr))
{
// if phdr exists in program header, use it // if phdr exists in program header, use it
Some(phdr.virtual_addr()) Some(phdr.virtual_addr())
} else if let Some(elf_addr) = self.program_iter() } else if let Some(elf_addr) = self
.find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) { .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. // otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
Some(elf_addr.virtual_addr() + self.header.pt2.ph_offset()) Some(elf_addr.virtual_addr() + self.header.pt2.ph_offset())
} else { } else {

View File

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

View File

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

View File

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

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