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:
commit
b6f1b3c926
@ -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 +
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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 {}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>;
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,4 +29,4 @@ impl Linear {
|
|||||||
pub fn new(offset: isize) -> Self {
|
pub fn new(offset: isize) -> Self {
|
||||||
Linear { offset }
|
Linear { offset }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -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(()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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" }
|
@ -1,2 +1 @@
|
|||||||
fn main() {
|
fn main() {}
|
||||||
}
|
|
||||||
|
@ -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::*;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
20
kernel/Cargo.lock
generated
@ -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"
|
||||||
|
@ -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" }
|
||||||
|
@ -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)
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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::*;
|
||||||
|
@ -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::*;
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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"]
|
||||||
|
@ -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
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
pub fn rand() -> u64 {
|
pub fn rand() -> u64 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
pub fn read_epoch() -> u64 {
|
pub fn read_epoch() -> u64 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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`.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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"));
|
||||||
|
@ -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
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
pub fn rand() -> u64 {
|
pub fn rand() -> u64 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
40
kernel/src/fs/file_like.rs
Normal file
40
kernel/src/fs/file_like.rs
Normal 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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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!();
|
||||||
}
|
}
|
||||||
|
@ -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"]
|
||||||
|
@ -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")]
|
||||||
|
@ -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) {}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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']);
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user