mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 08:06:17 +04:00
Merge branch 'master' into arch-aarch64
This commit is contained in:
commit
aa5bd3041b
@ -8,10 +8,12 @@ Going to be the next generation teaching operating system.
|
|||||||
|
|
||||||
Supported architectures: x86_64, RISCV32IMA(S/M), AArch64
|
Supported architectures: x86_64, RISCV32IMA(S/M), AArch64
|
||||||
|
|
||||||
Tested boards: QEMU, Raspberry Pi 3B+
|
Tested boards: QEMU, labeled-RISCV, Raspberry Pi 3B+
|
||||||
|
|
||||||
[Dev docs](https://rucore.gitbook.io/rust-os-docs/) (in Chinese)
|
[Dev docs](https://rucore.gitbook.io/rust-os-docs/) (in Chinese)
|
||||||
|
|
||||||
|
![demo](./docs/2_OSLab/os2atc/demo.png)
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
This is a project of THU courses:
|
This is a project of THU courses:
|
||||||
|
@ -1,416 +0,0 @@
|
|||||||
//! memory set, area
|
|
||||||
//! and the inactive page table
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::fmt::{Debug, Error, Formatter};
|
|
||||||
use super::*;
|
|
||||||
use crate::paging::*;
|
|
||||||
|
|
||||||
/// an inactive page table
|
|
||||||
/// Note: InactivePageTable is not a PageTable
|
|
||||||
/// but it can be activated and "become" a PageTable
|
|
||||||
/// Why this trait is in this file?(seems should in paging/mod.rs)
|
|
||||||
pub trait InactivePageTable {
|
|
||||||
/// the active version of page table
|
|
||||||
type Active: PageTable;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** @brief create a inactive page table with kernel memory mapped
|
|
||||||
** @retval InactivePageTable the created inactive page table
|
|
||||||
*/
|
|
||||||
fn new() -> Self;
|
|
||||||
/*
|
|
||||||
** @brief create an inactive page table without kernel memory mapped
|
|
||||||
** @retval InactivePageTable the created inactive page table
|
|
||||||
*/
|
|
||||||
fn new_bare() -> Self;
|
|
||||||
/*
|
|
||||||
** @brief temporarily active the page table and edit it
|
|
||||||
** @retval impl FnOnce(&mut Self::Active)
|
|
||||||
** the function of the editing action,
|
|
||||||
** which takes a temporarily activated page table as param
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn edit(&mut self, f: impl FnOnce(&mut Self::Active));
|
|
||||||
/*
|
|
||||||
** @brief activate the inactive page table
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
unsafe fn activate(&self);
|
|
||||||
/*
|
|
||||||
** @brief execute function with this inactive page table
|
|
||||||
** @param f: impl FnOnce() the function to be executed
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T;
|
|
||||||
/*
|
|
||||||
** @brief get the token of the inactive page table
|
|
||||||
** @retval usize the token of the inactive page table
|
|
||||||
*/
|
|
||||||
fn token(&self) -> usize;
|
|
||||||
|
|
||||||
/// Why the methods below are in this trait?
|
|
||||||
/*
|
|
||||||
** @brief allocate a frame for use
|
|
||||||
** @retval Option<PhysAddr> the physics address of the beginning of allocated frame, if present
|
|
||||||
*/
|
|
||||||
fn alloc_frame() -> Option<PhysAddr>;
|
|
||||||
/*
|
|
||||||
** @brief deallocate a frame for use
|
|
||||||
** @param PhysAddr the physics address of the beginning of frame to be deallocated
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn dealloc_frame(target: PhysAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// a continuous memory space when the same attribute
|
|
||||||
/// like `vma_struct` in ucore
|
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
|
||||||
pub struct MemoryArea {
|
|
||||||
start_addr: VirtAddr,
|
|
||||||
end_addr: VirtAddr,
|
|
||||||
phys_start_addr: Option<PhysAddr>,
|
|
||||||
flags: MemoryAttr,
|
|
||||||
name: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemoryArea {
|
|
||||||
/*
|
|
||||||
** @brief create a memory area from virtual address
|
|
||||||
** @param start_addr: VirtAddr the virtual address of beginning of the area
|
|
||||||
** @param end_addr: VirtAddr the virtual address of end of the area
|
|
||||||
** @param flags: MemoryAttr the common memory attribute of the memory area
|
|
||||||
** @param name: &'static str the name of the memory area
|
|
||||||
** @retval MemoryArea the memory area created
|
|
||||||
*/
|
|
||||||
pub fn new(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self {
|
|
||||||
assert!(start_addr <= end_addr, "invalid memory area");
|
|
||||||
MemoryArea { start_addr, end_addr, phys_start_addr: None, flags, name }
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief create a memory area from virtual address which is identically mapped
|
|
||||||
** @param start_addr: VirtAddr the virtual address of beginning of the area
|
|
||||||
** @param end_addr: VirtAddr the virtual address of end of the area
|
|
||||||
** @param flags: MemoryAttr the common memory attribute of the memory area
|
|
||||||
** @param name: &'static str the name of the memory area
|
|
||||||
** @retval MemoryArea the memory area created
|
|
||||||
*/
|
|
||||||
pub fn new_identity(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self {
|
|
||||||
assert!(start_addr <= end_addr, "invalid memory area");
|
|
||||||
MemoryArea { start_addr, end_addr, phys_start_addr: Some(start_addr), flags, name }
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief create a memory area from physics address
|
|
||||||
** @param start_addr: PhysAddr the physics address of beginning of the area
|
|
||||||
** @param end_addr: PhysAddr the physics address of end of the area
|
|
||||||
** @param offset: usiz the offset between physics address and virtual address
|
|
||||||
** @param flags: MemoryAttr the common memory attribute of the memory area
|
|
||||||
** @param name: &'static str the name of the memory area
|
|
||||||
** @retval MemoryArea the memory area created
|
|
||||||
*/
|
|
||||||
pub fn new_physical(phys_start_addr: PhysAddr, phys_end_addr: PhysAddr, offset: usize, flags: MemoryAttr, name: &'static str) -> Self {
|
|
||||||
let start_addr = phys_start_addr + offset;
|
|
||||||
let end_addr = phys_end_addr + offset;
|
|
||||||
assert!(start_addr <= end_addr, "invalid memory area");
|
|
||||||
let phys_start_addr = Some(phys_start_addr);
|
|
||||||
MemoryArea { start_addr, end_addr, phys_start_addr, flags, name }
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief get slice of the content in the memory area
|
|
||||||
** @retval &[u8] the slice of the content in the memory area
|
|
||||||
*/
|
|
||||||
pub unsafe fn as_slice(&self) -> &[u8] {
|
|
||||||
use core::slice;
|
|
||||||
slice::from_raw_parts(self.start_addr as *const u8, self.end_addr - self.start_addr)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief get mutable slice of the content in the memory area
|
|
||||||
** @retval &mut[u8] the mutable slice of the content in the memory area
|
|
||||||
*/
|
|
||||||
pub unsafe fn as_slice_mut(&self) -> &mut [u8] {
|
|
||||||
use core::slice;
|
|
||||||
slice::from_raw_parts_mut(self.start_addr as *mut u8, self.end_addr - self.start_addr)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief test whether a virtual address is in the memory area
|
|
||||||
** @param addr: VirtAddr the virtual address to test
|
|
||||||
** @retval bool whether the virtual address is in the memory area
|
|
||||||
*/
|
|
||||||
pub fn contains(&self, addr: VirtAddr) -> bool {
|
|
||||||
addr >= self.start_addr && addr < self.end_addr
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief test whether the memory area is overlap with another memory area
|
|
||||||
** @param other: &MemoryArea another memory area to test
|
|
||||||
** @retval bool whether the memory area is overlap with another memory area
|
|
||||||
*/
|
|
||||||
fn is_overlap_with(&self, other: &MemoryArea) -> bool {
|
|
||||||
let p0 = Page::of_addr(self.start_addr);
|
|
||||||
let p1 = Page::of_addr(self.end_addr - 1) + 1;
|
|
||||||
let p2 = Page::of_addr(other.start_addr);
|
|
||||||
let p3 = Page::of_addr(other.end_addr - 1) + 1;
|
|
||||||
!(p1 <= p2 || p0 >= p3)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief map the memory area to the physice address in a page table
|
|
||||||
** @param pt: &mut T::Active the page table to use
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn map<T: InactivePageTable>(&self, pt: &mut T::Active) {
|
|
||||||
match self.phys_start_addr {
|
|
||||||
Some(phys_start) => {
|
|
||||||
for page in Page::range_of(self.start_addr, self.end_addr) {
|
|
||||||
let addr = page.start_address();
|
|
||||||
let target = page.start_address() - self.start_addr + phys_start;
|
|
||||||
self.flags.apply(pt.map(addr, target));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
for page in Page::range_of(self.start_addr, self.end_addr) {
|
|
||||||
let addr = page.start_address();
|
|
||||||
let target = T::alloc_frame().expect("failed to allocate frame");
|
|
||||||
self.flags.apply(pt.map(addr, target));
|
|
||||||
// for frame delayed allocation
|
|
||||||
// let entry = pt.map(addr,0);
|
|
||||||
// self.flags.apply(entry);
|
|
||||||
// let entry = pt.get_entry(addr).expect("fail to get entry");
|
|
||||||
// entry.set_present(false);
|
|
||||||
// entry.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief unmap the memory area from the physice address in a page table
|
|
||||||
** @param pt: &mut T::Active the page table to use
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn unmap<T: InactivePageTable>(&self, pt: &mut T::Active) {
|
|
||||||
for page in Page::range_of(self.start_addr, self.end_addr) {
|
|
||||||
let addr = page.start_address();
|
|
||||||
if self.phys_start_addr.is_none() {
|
|
||||||
if pt.get_entry(addr).expect("fail to get entry").present(){
|
|
||||||
let target = pt.get_entry(addr).expect("fail to get entry").target();
|
|
||||||
T::dealloc_frame(target);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// set valid for pt.unmap function
|
|
||||||
pt.get_entry(addr).expect("fail to get entry").set_present(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pt.unmap(addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_start_addr(&self) -> VirtAddr {
|
|
||||||
self.start_addr
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_end_addr(&self) -> VirtAddr{
|
|
||||||
self.end_addr
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_flags(&self) -> &MemoryAttr{
|
|
||||||
&self.flags
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The attributes of the memory
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
|
||||||
pub struct MemoryAttr {
|
|
||||||
user: bool,
|
|
||||||
readonly: bool,
|
|
||||||
execute: bool,
|
|
||||||
hide: bool,
|
|
||||||
mmio: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemoryAttr {
|
|
||||||
/*
|
|
||||||
** @brief set the memory attribute's user bit
|
|
||||||
** @retval MemoryAttr the memory attribute itself
|
|
||||||
*/
|
|
||||||
pub fn user(mut self) -> Self {
|
|
||||||
self.user = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief set the memory attribute's readonly bit
|
|
||||||
** @retval MemoryAttr the memory attribute itself
|
|
||||||
*/
|
|
||||||
pub fn readonly(mut self) -> Self {
|
|
||||||
self.readonly = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief set the memory attribute's execute bit
|
|
||||||
** @retval MemoryAttr the memory attribute itself
|
|
||||||
*/
|
|
||||||
pub fn execute(mut self) -> Self {
|
|
||||||
self.execute = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief set the MMIO type
|
|
||||||
** @retval MemoryAttr the memory attribute itself
|
|
||||||
*/
|
|
||||||
pub fn mmio(mut self, value: u8) -> Self {
|
|
||||||
self.mmio = value;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief set the memory attribute's hide bit
|
|
||||||
** @retval MemoryAttr the memory attribute itself
|
|
||||||
*/
|
|
||||||
pub fn hide(mut self) -> Self {
|
|
||||||
self.hide = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief apply the memory attribute to a page table entry
|
|
||||||
** @param entry: &mut impl Entry
|
|
||||||
** the page table entry to apply the attribute
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn apply(&self, entry: &mut impl Entry) {
|
|
||||||
if self.user { entry.set_user(true); }
|
|
||||||
if self.readonly { entry.set_writable(false); }
|
|
||||||
if self.execute { entry.set_execute(true); }
|
|
||||||
if self.mmio != 0 { entry.set_mmio(self.mmio); }
|
|
||||||
if self.hide { entry.set_present(false); }
|
|
||||||
if self.user || self.readonly || self.execute || self.mmio != 0 || self.hide { entry.update(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// set of memory space with multiple memory area with associated page table and stack space
|
|
||||||
/// like `mm_struct` in ucore
|
|
||||||
pub struct MemorySet<T: InactivePageTable> {
|
|
||||||
areas: Vec<MemoryArea>,
|
|
||||||
page_table: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InactivePageTable> MemorySet<T> {
|
|
||||||
/*
|
|
||||||
** @brief create a memory set
|
|
||||||
** @retval MemorySet<T> the memory set created
|
|
||||||
*/
|
|
||||||
pub fn new() -> Self {
|
|
||||||
MemorySet {
|
|
||||||
areas: Vec::<MemoryArea>::new(),
|
|
||||||
page_table: T::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn new_bare() -> Self {
|
|
||||||
MemorySet {
|
|
||||||
areas: Vec::<MemoryArea>::new(),
|
|
||||||
page_table: T::new_bare(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief find the memory area from virtual address
|
|
||||||
** @param addr: VirtAddr the virtual address to find
|
|
||||||
** @retval Option<&MemoryArea> the memory area with the virtual address, if presented
|
|
||||||
*/
|
|
||||||
pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> {
|
|
||||||
self.areas.iter().find(|area| area.contains(addr))
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief add the memory area to the memory set
|
|
||||||
** @param area: MemoryArea the memory area to add
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
pub fn push(&mut self, area: MemoryArea) {
|
|
||||||
assert!(self.areas.iter()
|
|
||||||
.find(|other| area.is_overlap_with(other))
|
|
||||||
.is_none(), "memory area overlap");
|
|
||||||
self.page_table.edit(|pt| area.map::<T>(pt));
|
|
||||||
self.areas.push(area);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief get iterator of the memory area
|
|
||||||
** @retval impl Iterator<Item=&MemoryArea>
|
|
||||||
** the memory area iterator
|
|
||||||
*/
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
|
|
||||||
self.areas.iter()
|
|
||||||
}
|
|
||||||
pub fn edit(&mut self, f: impl FnOnce(&mut T::Active)) {
|
|
||||||
self.page_table.edit(f);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief execute function with the associated page table
|
|
||||||
** @param f: impl FnOnce() the function to be executed
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
pub unsafe fn with(&self, f: impl FnOnce()) {
|
|
||||||
self.page_table.with(f);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief activate the associated page table
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
pub unsafe fn activate(&self) {
|
|
||||||
self.page_table.activate();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief get the token of the associated page table
|
|
||||||
** @retval usize the token of the inactive page table
|
|
||||||
*/
|
|
||||||
pub fn token(&self) -> usize {
|
|
||||||
self.page_table.token()
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
** @brief clear the memory set
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
let Self { ref mut page_table, ref mut areas, .. } = self;
|
|
||||||
page_table.edit(|pt| {
|
|
||||||
for area in areas.iter() {
|
|
||||||
area.unmap::<T>(pt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
areas.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** @brief get the mutable reference for the inactive page table
|
|
||||||
** @retval: &mut T the mutable reference of the inactive page table
|
|
||||||
*/
|
|
||||||
pub fn get_page_table_mut(&mut self) -> &mut T{
|
|
||||||
&mut self.page_table
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InactivePageTable> Clone for MemorySet<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let mut page_table = T::new();
|
|
||||||
page_table.edit(|pt| {
|
|
||||||
for area in self.areas.iter() {
|
|
||||||
area.map::<T>(pt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
info!("finish map in clone!");
|
|
||||||
MemorySet {
|
|
||||||
areas: self.areas.clone(),
|
|
||||||
page_table,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InactivePageTable> Drop for MemorySet<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
info!("come into drop func for memoryset");
|
|
||||||
self.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InactivePageTable> Debug for MemorySet<T> {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
f.debug_list()
|
|
||||||
.entries(self.areas.iter())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
34
crate/memory/src/memory_set/handler/byframe.rs
Normal file
34
crate/memory/src/memory_set/handler/byframe.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ByFrame<T: FrameAllocator> {
|
||||||
|
flags: MemoryAttr,
|
||||||
|
allocator: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FrameAllocator> MemoryHandler for ByFrame<T> {
|
||||||
|
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||||
|
let target = self.allocator.alloc().expect("failed to allocate frame");
|
||||||
|
self.flags.apply(pt.map(addr, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||||
|
let target = pt.get_entry(addr).expect("fail to get entry").target();
|
||||||
|
self.allocator.dealloc(target);
|
||||||
|
pt.unmap(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_fault_handler(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FrameAllocator> ByFrame<T> {
|
||||||
|
pub fn new(flags: MemoryAttr, allocator: T) -> Self {
|
||||||
|
ByFrame { flags, allocator }
|
||||||
|
}
|
||||||
|
}
|
45
crate/memory/src/memory_set/handler/delay.rs
Normal file
45
crate/memory/src/memory_set/handler/delay.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Delay<T: FrameAllocator> {
|
||||||
|
flags: MemoryAttr,
|
||||||
|
allocator: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FrameAllocator> MemoryHandler for Delay<T> {
|
||||||
|
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||||
|
let entry = pt.map(addr, 0);
|
||||||
|
entry.set_present(false);
|
||||||
|
entry.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||||
|
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||||
|
if entry.present() {
|
||||||
|
self.allocator.dealloc(entry.target());
|
||||||
|
pt.unmap(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_fault_handler(&self, pt: &mut PageTable, addr: VirtAddr) -> bool {
|
||||||
|
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||||
|
if entry.present() {
|
||||||
|
// not a delay case
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let frame = self.allocator.alloc().expect("failed to alloc frame");
|
||||||
|
entry.set_target(frame);
|
||||||
|
self.flags.apply(entry);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FrameAllocator> Delay<T> {
|
||||||
|
pub fn new(flags: MemoryAttr, allocator: T) -> Self {
|
||||||
|
Delay { flags, allocator }
|
||||||
|
}
|
||||||
|
}
|
32
crate/memory/src/memory_set/handler/linear.rs
Normal file
32
crate/memory/src/memory_set/handler/linear.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct Linear {
|
||||||
|
offset: isize,
|
||||||
|
flags: MemoryAttr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryHandler for Linear {
|
||||||
|
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||||
|
let target = (addr as isize + self.offset) as PhysAddr;
|
||||||
|
self.flags.apply(pt.map(addr, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||||
|
pt.unmap(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_fault_handler(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Linear {
|
||||||
|
pub fn new(offset: isize, flags: MemoryAttr) -> Self {
|
||||||
|
Linear { offset, flags }
|
||||||
|
}
|
||||||
|
}
|
29
crate/memory/src/memory_set/handler/mod.rs
Normal file
29
crate/memory/src/memory_set/handler/mod.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
// here may be a interesting part for lab
|
||||||
|
pub trait MemoryHandler: Debug + 'static {
|
||||||
|
fn box_clone(&self) -> Box<MemoryHandler>;
|
||||||
|
fn map(&self, pt: &mut PageTable, addr: VirtAddr);
|
||||||
|
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr);
|
||||||
|
fn page_fault_handler(&self, pt: &mut PageTable, addr: VirtAddr) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Box<MemoryHandler> {
|
||||||
|
fn clone(&self) -> Box<MemoryHandler> {
|
||||||
|
self.box_clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FrameAllocator: Debug + Clone + 'static {
|
||||||
|
fn alloc(&self) -> Option<PhysAddr>;
|
||||||
|
fn dealloc(&self, target: PhysAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod linear;
|
||||||
|
mod byframe;
|
||||||
|
mod delay;
|
||||||
|
//mod swap;
|
||||||
|
|
||||||
|
pub use self::linear::Linear;
|
||||||
|
pub use self::byframe::ByFrame;
|
||||||
|
pub use self::delay::Delay;
|
274
crate/memory/src/memory_set/mod.rs
Normal file
274
crate/memory/src/memory_set/mod.rs
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
//! memory set, area
|
||||||
|
//! and the inactive page table
|
||||||
|
|
||||||
|
use alloc::{vec::Vec, boxed::Box};
|
||||||
|
use core::fmt::{Debug, Error, Formatter};
|
||||||
|
use super::*;
|
||||||
|
use crate::paging::*;
|
||||||
|
use self::handler::MemoryHandler;
|
||||||
|
|
||||||
|
pub mod handler;
|
||||||
|
|
||||||
|
/// a continuous memory space when the same attribute
|
||||||
|
/// like `vma_struct` in ucore
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MemoryArea {
|
||||||
|
start_addr: VirtAddr,
|
||||||
|
end_addr: VirtAddr,
|
||||||
|
handler: Box<MemoryHandler>,
|
||||||
|
name: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryArea {
|
||||||
|
/*
|
||||||
|
** @brief get slice of the content in the memory area
|
||||||
|
** @retval &[u8] the slice of the content in the memory area
|
||||||
|
*/
|
||||||
|
pub unsafe fn as_slice(&self) -> &[u8] {
|
||||||
|
::core::slice::from_raw_parts(self.start_addr as *const u8, self.end_addr - self.start_addr)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief get mutable slice of the content in the memory area
|
||||||
|
** @retval &mut[u8] the mutable slice of the content in the memory area
|
||||||
|
*/
|
||||||
|
pub unsafe fn as_slice_mut(&self) -> &mut [u8] {
|
||||||
|
::core::slice::from_raw_parts_mut(self.start_addr as *mut u8, self.end_addr - self.start_addr)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief test whether a virtual address is in the memory area
|
||||||
|
** @param addr: VirtAddr the virtual address to test
|
||||||
|
** @retval bool whether the virtual address is in the memory area
|
||||||
|
*/
|
||||||
|
pub fn contains(&self, addr: VirtAddr) -> bool {
|
||||||
|
addr >= self.start_addr && addr < self.end_addr
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief test whether the memory area is overlap with another memory area
|
||||||
|
** @param other: &MemoryArea another memory area to test
|
||||||
|
** @retval bool whether the memory area is overlap with another memory area
|
||||||
|
*/
|
||||||
|
fn is_overlap_with(&self, other: &MemoryArea) -> bool {
|
||||||
|
let p0 = Page::of_addr(self.start_addr);
|
||||||
|
let p1 = Page::of_addr(self.end_addr - 1) + 1;
|
||||||
|
let p2 = Page::of_addr(other.start_addr);
|
||||||
|
let p3 = Page::of_addr(other.end_addr - 1) + 1;
|
||||||
|
!(p1 <= p2 || p0 >= p3)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief map the memory area to the physice address in a page table
|
||||||
|
** @param pt: &mut T::Active the page table to use
|
||||||
|
** @retval none
|
||||||
|
*/
|
||||||
|
fn map(&self, pt: &mut PageTable) {
|
||||||
|
for page in Page::range_of(self.start_addr, self.end_addr) {
|
||||||
|
self.handler.map(pt, page.start_address());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief unmap the memory area from the physice address in a page table
|
||||||
|
** @param pt: &mut T::Active the page table to use
|
||||||
|
** @retval none
|
||||||
|
*/
|
||||||
|
fn unmap(&self, pt: &mut PageTable) {
|
||||||
|
for page in Page::range_of(self.start_addr, self.end_addr) {
|
||||||
|
self.handler.unmap(pt, page.start_address());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The attributes of the memory
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||||
|
pub struct MemoryAttr {
|
||||||
|
user: bool,
|
||||||
|
readonly: bool,
|
||||||
|
execute: bool,
|
||||||
|
mmio: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryAttr {
|
||||||
|
/*
|
||||||
|
** @brief set the memory attribute's user bit
|
||||||
|
** @retval MemoryAttr the memory attribute itself
|
||||||
|
*/
|
||||||
|
pub fn user(mut self) -> Self {
|
||||||
|
self.user = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief set the memory attribute's readonly bit
|
||||||
|
** @retval MemoryAttr the memory attribute itself
|
||||||
|
*/
|
||||||
|
pub fn readonly(mut self) -> Self {
|
||||||
|
self.readonly = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief set the memory attribute's execute bit
|
||||||
|
** @retval MemoryAttr the memory attribute itself
|
||||||
|
*/
|
||||||
|
pub fn execute(mut self) -> Self {
|
||||||
|
self.execute = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief set the MMIO type
|
||||||
|
** @retval MemoryAttr the memory attribute itself
|
||||||
|
*/
|
||||||
|
pub fn mmio(mut self, value: u8) -> Self {
|
||||||
|
self.mmio = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief apply the memory attribute to a page table entry
|
||||||
|
** @param entry: &mut impl Entry
|
||||||
|
** the page table entry to apply the attribute
|
||||||
|
** @retval none
|
||||||
|
*/
|
||||||
|
pub fn apply(&self, entry: &mut Entry) {
|
||||||
|
entry.set_present(true);
|
||||||
|
entry.set_user(self.user);
|
||||||
|
entry.set_writable(!self.readonly);
|
||||||
|
entry.set_execute(self.execute);
|
||||||
|
entry.set_mmio(self.mmio);
|
||||||
|
entry.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set of memory space with multiple memory area with associated page table and stack space
|
||||||
|
/// like `mm_struct` in ucore
|
||||||
|
pub struct MemorySet<T: InactivePageTable> {
|
||||||
|
areas: Vec<MemoryArea>,
|
||||||
|
page_table: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: InactivePageTable> MemorySet<T> {
|
||||||
|
/*
|
||||||
|
** @brief create a memory set
|
||||||
|
** @retval MemorySet<T> the memory set created
|
||||||
|
*/
|
||||||
|
pub fn new() -> Self {
|
||||||
|
MemorySet {
|
||||||
|
areas: Vec::new(),
|
||||||
|
page_table: T::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_bare() -> Self {
|
||||||
|
MemorySet {
|
||||||
|
areas: Vec::new(),
|
||||||
|
page_table: T::new_bare(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief find the memory area from virtual address
|
||||||
|
** @param addr: VirtAddr the virtual address to find
|
||||||
|
** @retval Option<&MemoryArea> the memory area with the virtual address, if presented
|
||||||
|
*/
|
||||||
|
pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> {
|
||||||
|
self.areas.iter().find(|area| area.contains(addr))
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief add the memory area to the memory set
|
||||||
|
** @param area: MemoryArea the memory area to add
|
||||||
|
** @retval none
|
||||||
|
*/
|
||||||
|
pub fn push(&mut self, start_addr: VirtAddr, end_addr: VirtAddr, handler: impl MemoryHandler, name: &'static str) {
|
||||||
|
assert!(start_addr <= end_addr, "invalid memory area");
|
||||||
|
let area = MemoryArea { start_addr, end_addr, handler: Box::new(handler), name };
|
||||||
|
assert!(self.areas.iter()
|
||||||
|
.find(|other| area.is_overlap_with(other))
|
||||||
|
.is_none(), "memory area overlap");
|
||||||
|
self.page_table.edit(|pt| area.map(pt));
|
||||||
|
self.areas.push(area);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief get iterator of the memory area
|
||||||
|
** @retval impl Iterator<Item=&MemoryArea>
|
||||||
|
** the memory area iterator
|
||||||
|
*/
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
|
||||||
|
self.areas.iter()
|
||||||
|
}
|
||||||
|
pub fn edit(&mut self, f: impl FnOnce(&mut T::Active)) {
|
||||||
|
self.page_table.edit(f);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief execute function with the associated page table
|
||||||
|
** @param f: impl FnOnce() the function to be executed
|
||||||
|
** @retval none
|
||||||
|
*/
|
||||||
|
pub unsafe fn with(&self, f: impl FnOnce()) {
|
||||||
|
self.page_table.with(f);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief activate the associated page table
|
||||||
|
** @retval none
|
||||||
|
*/
|
||||||
|
pub unsafe fn activate(&self) {
|
||||||
|
self.page_table.activate();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief get the token of the associated page table
|
||||||
|
** @retval usize the token of the inactive page table
|
||||||
|
*/
|
||||||
|
pub fn token(&self) -> usize {
|
||||||
|
self.page_table.token()
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** @brief clear the memory set
|
||||||
|
** @retval none
|
||||||
|
*/
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
let Self { ref mut page_table, ref mut areas, .. } = self;
|
||||||
|
page_table.edit(|pt| {
|
||||||
|
for area in areas.iter() {
|
||||||
|
area.unmap(pt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
areas.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** @brief get the mutable reference for the inactive page table
|
||||||
|
** @retval: &mut T the mutable reference of the inactive page table
|
||||||
|
*/
|
||||||
|
pub fn get_page_table_mut(&mut self) -> &mut T{
|
||||||
|
&mut self.page_table
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn page_fault_handler(&mut self, addr: VirtAddr) -> bool {
|
||||||
|
let area = self.areas.iter().find(|area| area.contains(addr));
|
||||||
|
match area {
|
||||||
|
Some(area) => self.page_table.edit(|pt| area.handler.page_fault_handler(pt, addr)),
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: InactivePageTable> Clone for MemorySet<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let mut page_table = T::new();
|
||||||
|
page_table.edit(|pt| {
|
||||||
|
for area in self.areas.iter() {
|
||||||
|
area.map(pt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
MemorySet {
|
||||||
|
areas: self.areas.clone(),
|
||||||
|
page_table,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: InactivePageTable> Drop for MemorySet<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: InactivePageTable> Debug for MemorySet<T> {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
f.debug_list()
|
||||||
|
.entries(self.areas.iter())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
15
crate/memory/src/paging/ext.rs
Normal file
15
crate/memory/src/paging/ext.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//! Helper functions
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub trait PageTableExt: PageTable {
|
||||||
|
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 {
|
||||||
|
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 ret = f(self, data);
|
||||||
|
self.unmap(Self::TEMP_PAGE_ADDR);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
@ -57,14 +57,16 @@ impl Entry for MockEntry {
|
|||||||
fn set_user(&mut self, value: bool) { unimplemented!() }
|
fn set_user(&mut self, value: bool) { unimplemented!() }
|
||||||
fn execute(&self) -> bool { unimplemented!() }
|
fn execute(&self) -> bool { unimplemented!() }
|
||||||
fn set_execute(&mut self, value: bool) { unimplemented!() }
|
fn set_execute(&mut self, value: bool) { unimplemented!() }
|
||||||
|
fn mmio(&self) -> bool { unimplemented!() }
|
||||||
|
fn set_mmio(&mut self, value: bool) { 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 Self::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];
|
||||||
assert!(!entry.present);
|
assert!(!entry.present);
|
||||||
entry.present = true;
|
entry.present = true;
|
||||||
@ -77,7 +79,7 @@ impl PageTable for MockPageTable {
|
|||||||
assert!(entry.present);
|
assert!(entry.present);
|
||||||
entry.present = false;
|
entry.present = false;
|
||||||
}
|
}
|
||||||
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::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] {
|
||||||
|
@ -3,208 +3,149 @@
|
|||||||
//! Implemented for every architecture, used by OS.
|
//! Implemented for every architecture, used by OS.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::memory_set::InactivePageTable;
|
use log::*;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub use self::mock_page_table::MockPageTable;
|
pub use self::mock_page_table::MockPageTable;
|
||||||
|
pub use self::ext::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mock_page_table;
|
mod mock_page_table;
|
||||||
|
mod ext;
|
||||||
|
|
||||||
|
|
||||||
// trait for PageTable
|
|
||||||
pub trait PageTable {
|
pub trait PageTable {
|
||||||
type Entry: Entry;
|
// type Entry: Entry;
|
||||||
/*
|
|
||||||
** @brief map a virual address to the target physics address
|
/// Map a page of virual address `addr` to the frame of physics address `target`
|
||||||
** @param addr: VirtAddr the virual address to map
|
/// Return the page table entry of the mapped virual address
|
||||||
** @param target: VirtAddr the target physics address
|
fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Entry;
|
||||||
** @retval Entry the page table entry of the mapped virual address
|
|
||||||
*/
|
/// Unmap a page of virual address `addr`
|
||||||
fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Self::Entry;
|
|
||||||
/*
|
|
||||||
** @brief unmap a virual address from physics address
|
|
||||||
** @param addr: VirtAddr the virual address to unmap
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn unmap(&mut self, addr: VirtAddr);
|
fn unmap(&mut self, addr: VirtAddr);
|
||||||
/*
|
|
||||||
** @brief get the page table entry of a virual address
|
/// Get the page table entry of a page of virual address `addr`
|
||||||
** @param addr: VirtAddr the virual address
|
/// If its page do not exist, return `None`
|
||||||
** @retval Entry the page table entry of the virual address
|
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Entry>;
|
||||||
*/
|
|
||||||
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::Entry>;
|
/// Get a mutable reference of the content of a page of virtual address `addr`
|
||||||
// For testing with mock
|
/// Used for testing with mock
|
||||||
/*
|
fn get_page_slice_mut<'a>(&mut self, addr: VirtAddr) -> &'a mut [u8] {
|
||||||
** @brief used for testing with mock
|
unsafe { core::slice::from_raw_parts_mut((addr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) }
|
||||||
** get a mutable reference of the content of a page from a virtual address
|
}
|
||||||
** @param addr: VirtAddr the virual address of the page
|
/// Read data from virtual address `addr`
|
||||||
** @retval &'b mut [u8] mutable reference of the content of a page as array of bytes
|
/// Used for testing with mock
|
||||||
*/
|
fn read(&mut self, addr: VirtAddr) -> u8 {
|
||||||
fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8];
|
unsafe { (addr as *const u8).read() }
|
||||||
/*
|
}
|
||||||
** @brief used for testing with mock
|
|
||||||
** read data from a virtual address
|
/// Write data to virtual address `addr`
|
||||||
** @param addr: VirtAddr the virual address of data to read
|
/// Used for testing with mock
|
||||||
** @retval u8 the data read
|
fn write(&mut self, addr: VirtAddr, data: u8) {
|
||||||
*/
|
unsafe { (addr as *mut u8).write(data) }
|
||||||
fn read(&mut self, addr: VirtAddr) -> u8;
|
}
|
||||||
/*
|
|
||||||
** @brief used for testing with mock
|
|
||||||
** write data to a virtual address
|
|
||||||
** @param addr: VirtAddr the virual address of data to write
|
|
||||||
** @param data: u8 the data to write
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn write(&mut self, addr: VirtAddr, data: u8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Page Table Entry
|
||||||
// trait for Entry in PageTable
|
|
||||||
pub trait Entry {
|
pub trait Entry {
|
||||||
/*
|
/// Make all changes take effect.
|
||||||
** @brief force update this page table entry
|
///
|
||||||
** IMPORTANT!
|
/// IMPORTANT!
|
||||||
** This must be called after any change to ensure it become effective.
|
/// This must be called after any change to ensure it become effective.
|
||||||
** Usually this will make a flush to TLB/MMU.
|
/// Usually it will cause a TLB/MMU flush.
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn update(&mut self);
|
fn update(&mut self);
|
||||||
/*
|
/// A bit set by hardware when the page is accessed
|
||||||
** @brief get the accessed bit of the entry
|
|
||||||
** Will be set when accessed
|
|
||||||
** @retval bool the accessed bit
|
|
||||||
*/
|
|
||||||
fn accessed(&self) -> bool;
|
fn accessed(&self) -> bool;
|
||||||
/*
|
/// A bit set by hardware when the page is written
|
||||||
** @brief get the dirty bit of the entry
|
|
||||||
** Will be set when written
|
|
||||||
** @retval bool the dirty bit
|
|
||||||
*/
|
|
||||||
fn dirty(&self) -> bool;
|
fn dirty(&self) -> bool;
|
||||||
/*
|
/// Will PageFault when try to write page where writable=0
|
||||||
** @brief get the writable bit of the entry
|
|
||||||
** Will PageFault when try to write page where writable=0
|
|
||||||
** @retval bool the writable bit
|
|
||||||
*/
|
|
||||||
fn writable(&self) -> bool;
|
fn writable(&self) -> bool;
|
||||||
/*
|
/// Will PageFault when try to access page where present=0
|
||||||
** @brief get the present bit of the entry
|
|
||||||
** Will PageFault when try to access page where present=0
|
|
||||||
** @retval bool the present bit
|
|
||||||
*/
|
|
||||||
fn present(&self) -> bool;
|
fn present(&self) -> bool;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** @brief clear the accessed bit
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn clear_accessed(&mut self);
|
fn clear_accessed(&mut self);
|
||||||
/*
|
|
||||||
** @brief clear the dirty bit
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn clear_dirty(&mut self);
|
fn clear_dirty(&mut self);
|
||||||
/*
|
|
||||||
** @brief set value of writable bit
|
|
||||||
** @param value: bool the writable bit value
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn set_writable(&mut self, value: bool);
|
fn set_writable(&mut self, value: bool);
|
||||||
/*
|
|
||||||
** @brief set value of present bit
|
|
||||||
** @param value: bool the present bit value
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn set_present(&mut self, value: bool);
|
fn set_present(&mut self, value: bool);
|
||||||
|
|
||||||
/*
|
/// The target physics address in the entry
|
||||||
** @brief get the target physics address in the entry
|
/// Can be used for other purpose if present=0
|
||||||
** can be used for other purpose if present=0
|
|
||||||
** @retval target: PhysAddr the target physics address
|
|
||||||
*/
|
|
||||||
fn target(&self) -> PhysAddr;
|
fn target(&self) -> PhysAddr;
|
||||||
/*
|
|
||||||
** @brief set the target physics address in the entry
|
|
||||||
** @param target: PhysAddr the target physics address
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn set_target(&mut self, target: PhysAddr);
|
fn set_target(&mut self, target: PhysAddr);
|
||||||
|
|
||||||
// For Copy-on-write extension
|
// For Copy-on-write
|
||||||
/*
|
|
||||||
** @brief used for Copy-on-write extension
|
|
||||||
** get the writable and shared bit
|
|
||||||
** @retval value: bool the writable and shared bit
|
|
||||||
*/
|
|
||||||
fn writable_shared(&self) -> bool;
|
fn writable_shared(&self) -> bool;
|
||||||
/*
|
|
||||||
** @brief used for Copy-on-write extension
|
|
||||||
** get the readonly and shared bit
|
|
||||||
** @retval value: bool the readonly and shared bit
|
|
||||||
*/
|
|
||||||
fn readonly_shared(&self) -> bool;
|
fn readonly_shared(&self) -> bool;
|
||||||
/*
|
|
||||||
** @brief used for Copy-on-write extension
|
|
||||||
** mark the page as (writable or readonly) shared
|
|
||||||
** @param writable: bool if it is true, set the page as writable and shared
|
|
||||||
** else set the page as readonly and shared
|
|
||||||
** @retval value: none
|
|
||||||
*/
|
|
||||||
fn set_shared(&mut self, writable: bool);
|
fn set_shared(&mut self, writable: bool);
|
||||||
/*
|
|
||||||
** @brief used for Copy-on-write extension
|
|
||||||
** mark the page as not shared
|
|
||||||
** @retval value: none
|
|
||||||
*/
|
|
||||||
fn clear_shared(&mut self);
|
fn clear_shared(&mut self);
|
||||||
|
|
||||||
// For Swap extension
|
// For Swap
|
||||||
/*
|
|
||||||
** @brief used for Swap extension
|
|
||||||
** get the swapped bit
|
|
||||||
** @retval value: bool the swapped bit
|
|
||||||
*/
|
|
||||||
fn swapped(&self) -> bool;
|
fn swapped(&self) -> bool;
|
||||||
/*
|
|
||||||
** @brief used for Swap extension
|
|
||||||
** set the swapped bit
|
|
||||||
** @param value: bool the swapped bit value
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn set_swapped(&mut self, value: bool);
|
fn set_swapped(&mut self, value: bool);
|
||||||
|
|
||||||
/*
|
|
||||||
** @brief get the user bit of the entry
|
|
||||||
** @retval bool the user bit
|
|
||||||
*/
|
|
||||||
fn user(&self) -> bool;
|
fn user(&self) -> bool;
|
||||||
/*
|
|
||||||
** @brief set value of user bit
|
|
||||||
** @param value: bool the user bit value
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn set_user(&mut self, value: bool);
|
fn set_user(&mut self, value: bool);
|
||||||
/*
|
|
||||||
** @brief get the execute bit of the entry
|
|
||||||
** @retval bool the execute bit
|
|
||||||
*/
|
|
||||||
fn execute(&self) -> bool;
|
fn execute(&self) -> bool;
|
||||||
/*
|
|
||||||
** @brief set value of user bit
|
|
||||||
** @param value: bool the execute bit value
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn set_execute(&mut self, value: bool);
|
fn set_execute(&mut self, value: bool);
|
||||||
/*
|
|
||||||
** @brief get MMIO type
|
|
||||||
** (e.g. aarch64 can have normal/device/normal_non_cacheable memory)
|
|
||||||
** @retval u8 the MMIO type
|
|
||||||
*/
|
|
||||||
fn mmio(&self) -> u8;
|
fn mmio(&self) -> u8;
|
||||||
/*
|
|
||||||
** @brief set MMIO type
|
|
||||||
** @param value: u8 the MMIO type
|
|
||||||
** @retval none
|
|
||||||
*/
|
|
||||||
fn set_mmio(&mut self, value: u8);
|
fn set_mmio(&mut self, value: u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An inactive page table
|
||||||
|
/// Note: InactivePageTable is not a PageTable
|
||||||
|
/// but it can be activated and "become" a PageTable
|
||||||
|
pub trait InactivePageTable: Sized {
|
||||||
|
/// the active version of page table
|
||||||
|
type Active: PageTable;
|
||||||
|
|
||||||
|
/// Create a new page table with kernel memory mapped
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut pt = Self::new_bare();
|
||||||
|
pt.map_kernel();
|
||||||
|
pt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new page table without kernel memory mapped
|
||||||
|
fn new_bare() -> Self;
|
||||||
|
|
||||||
|
/// Map kernel segments
|
||||||
|
fn map_kernel(&mut self);
|
||||||
|
|
||||||
|
/// CR3 on x86, SATP on RISCV, TTBR on AArch64
|
||||||
|
fn token(&self) -> usize;
|
||||||
|
unsafe fn set_token(token: usize);
|
||||||
|
fn active_token() -> usize;
|
||||||
|
fn flush_tlb();
|
||||||
|
|
||||||
|
/// Make this page table editable
|
||||||
|
/// Set the recursive entry of current active page table to this
|
||||||
|
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T;
|
||||||
|
|
||||||
|
/// Activate this page table
|
||||||
|
unsafe fn activate(&self) {
|
||||||
|
let old_token = Self::active_token();
|
||||||
|
let new_token = self.token();
|
||||||
|
debug!("switch table {:x?} -> {:x?}", old_token, new_token);
|
||||||
|
if old_token != new_token {
|
||||||
|
Self::set_token(new_token);
|
||||||
|
Self::flush_tlb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute function `f` with this page table activated
|
||||||
|
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
|
||||||
|
let old_token = Self::active_token();
|
||||||
|
let new_token = self.token();
|
||||||
|
debug!("switch table {:x?} -> {:x?}", old_token, new_token);
|
||||||
|
if old_token != new_token {
|
||||||
|
Self::set_token(new_token);
|
||||||
|
Self::flush_tlb();
|
||||||
|
}
|
||||||
|
let ret = f();
|
||||||
|
debug!("switch table {:x?} -> {:x?}", new_token, old_token);
|
||||||
|
if old_token != new_token {
|
||||||
|
Self::set_token(old_token);
|
||||||
|
Self::flush_tlb();
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::paging::*;
|
use super::paging::*;
|
||||||
use super::memory_set::InactivePageTable;
|
|
||||||
use super::addr::Frame;
|
use super::addr::Frame;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
BIN
docs/2_OSLab/os2atc/demo.png
Normal file
BIN
docs/2_OSLab/os2atc/demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 316 KiB |
616
docs/2_OSLab/os2atc/ucore_os_in_rust.md
Normal file
616
docs/2_OSLab/os2atc/ucore_os_in_rust.md
Normal file
@ -0,0 +1,616 @@
|
|||||||
|
<!-- page_number: true -->
|
||||||
|
<!-- $width:12in -->
|
||||||
|
<!-- $height: 6.75in -->
|
||||||
|
|
||||||
|
# Rust版 uCore OS 的设计与实现
|
||||||
|
## Design and implementation of uCore OS in Rust
|
||||||
|
|
||||||
|
王润基
|
||||||
|
清华大学计算机系
|
||||||
|
|
||||||
|
2018.12.16 @ OS2ATC
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 提纲
|
||||||
|
|
||||||
|
## 简介:Rust uCore OS是什么?
|
||||||
|
## 动机:为什么要用Rust写OS?
|
||||||
|
## 体会:用Rust写OS有何好处?
|
||||||
|
## 未来:接下来会做什么?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 简介:Rust uCore OS是什么?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# uCore OS
|
||||||
|
|
||||||
|
清华大学教学操作系统
|
||||||
|
|
||||||
|
参考 xv6 & jos in MIT, OS161 in Harvard, Linux
|
||||||
|
|
||||||
|
用C语言编写的宏内核OS
|
||||||
|
|
||||||
|
* [ucore_os_lab](https://github.com/chyyuu/ucore_os_lab):操作系统课实验
|
||||||
|
* [ucore_os_plus](https://github.com/chyyuu/ucore_os_plus):教学科研系统
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# uCore OS in Rust -- RustOS
|
||||||
|
|
||||||
|
2018年操作系统课大实验项目
|
||||||
|
|
||||||
|
“用Rust语言重新实现uCore”
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
之后在OS专题训练课上推广,目前:
|
||||||
|
|
||||||
|
支持三大平台:x86_64, RISCV32, AArch64
|
||||||
|
支持硬件:计算所Labeled-RISCV,树莓派3B
|
||||||
|
支持多核CPU
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 大实验选题列举
|
||||||
|
|
||||||
|
OS:
|
||||||
|
* RustOS for x86_64 SMP
|
||||||
|
* Rustable - ucore 在 arm 平台的 rust 移植
|
||||||
|
* Rucore with LKM Drivers
|
||||||
|
|
||||||
|
OS专题训练:
|
||||||
|
* RustOS 上树莓派 USB 与 VideoCore IV 显卡驱动的移植
|
||||||
|
* RustOS 多核移植与基于PARD框架的线程级Label管理
|
||||||
|
* RustOS wiki完善与教学lab实验的制作
|
||||||
|
* RustOS 参考sv6的多核实现和优化
|
||||||
|
* RustOS 移植到 rv64 及llvm编译器支持
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 动机:为什么要用Rust写OS?
|
||||||
|
|
||||||
|
* C语言有何不足?
|
||||||
|
* Rust解决了哪些痛点?
|
||||||
|
* 条件是否成熟?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# C语言有何不足?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 简单?简陋?
|
||||||
|
|
||||||
|
C语言简单、直接,为OS而生。
|
||||||
|
但从现代编程语言的角度看,C语言有些简陋,难以表达复杂逻辑和抽象。
|
||||||
|
|
||||||
|
![90%](./C.jpg)
|
||||||
|
*上图出自[一篇知乎回答](https://www.zhihu.com/question/25038841/answer/44396770)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 缺乏对OOP和接口的语言级支持
|
||||||
|
C中常用函数指针实现接口:
|
||||||
|
```c
|
||||||
|
struct device {
|
||||||
|
size_t d_blocks;
|
||||||
|
size_t d_blocksize;
|
||||||
|
int (*d_open)(struct device *dev, uint32_t open_flags);
|
||||||
|
int (*d_close)(struct device *dev);
|
||||||
|
int (*d_io)(struct device *dev, struct iobuf *iob, bool write);
|
||||||
|
int (*d_ioctl)(struct device *dev, int op, void *data);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 缺乏基础数据结构支持
|
||||||
|
|
||||||
|
OS中常用的侵入式链表(摘自ucore_os_lab):
|
||||||
|
```c
|
||||||
|
// 链表节点
|
||||||
|
struct list_entry {
|
||||||
|
struct list_entry *prev, *next;
|
||||||
|
};
|
||||||
|
// 在宿主类型中嵌入链表节点
|
||||||
|
struct Page {
|
||||||
|
list_entry_t page_link;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
// 从list类型转化回宿主类型
|
||||||
|
#_define le2page(le, member) \
|
||||||
|
to_struct((le), struct Page, member)
|
||||||
|
#_define offsetof(type, member) \
|
||||||
|
((size_t)(&((type *)0)->member))
|
||||||
|
#_define to_struct(ptr, type, member) \
|
||||||
|
((type *)((char *)(ptr) - offsetof(type, member)))
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 缺乏工程模块系统
|
||||||
|
|
||||||
|
* 编译配置复杂
|
||||||
|
* 难以复用代码
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SegmentFault!
|
||||||
|
|
||||||
|
悬空指针,重复释放,数据竞争……
|
||||||
|
|
||||||
|
#
|
||||||
|
![60%](./pointer.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Rust解决了哪些痛点?
|
||||||
|
|
||||||
|
* 强类型,内存安全,线程安全——减少Bug!
|
||||||
|
* 现代语言特性——提升开发体验
|
||||||
|
* 完善的模块系统——方便代码复用
|
||||||
|
* 零开销抽象——能写OS的根本保障
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 是时候尝试Rust了!
|
||||||
|
|
||||||
|
### 社区:[Redox](https://www.redox-os.org)
|
||||||
|
全功能Rust OS,微内核架构,支持GUI
|
||||||
|
|
||||||
|
### 教学:[CS140e](https://web.stanford.edu/class/cs140e/)
|
||||||
|
斯坦福大学实验性OS课程,2018年新开设
|
||||||
|
Rust编写OS,面向ARM,在树莓派3上运行
|
||||||
|
|
||||||
|
### 兴趣:[Writing an OS in Rust](https://os.phil-opp.com)
|
||||||
|
手把手带你用Rust编写OS的系列博客
|
||||||
|
面向x86_64,教程极为详尽
|
||||||
|
作者为Rust编写OS提供了大量开源工具
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 万事俱备,只是……
|
||||||
|
# 还不会Rust怎么办?
|
||||||
|
|
||||||
|
编写OS是学习Rust的高效途径!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 体会:用Rust写OS有何好处?
|
||||||
|
|
||||||
|
* 内存与线程安全:减少Bug
|
||||||
|
* 包管理系统:复用已有代码
|
||||||
|
* 接口与泛型:内核模块化
|
||||||
|
* 所有权和RAII机制:简化资源管理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 安全!
|
||||||
|
|
||||||
|
类型系统 + 所有权机制 + 生命周期机制
|
||||||
|
|
||||||
|
=> 内存安全 + 线程安全
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rust如何减少Bug
|
||||||
|
|
||||||
|
### 消除了越界访问
|
||||||
|
=> panic
|
||||||
|
|
||||||
|
### 消除了因生命周期导致的非法访存
|
||||||
|
=> 编译错误
|
||||||
|
|
||||||
|
### 消除了数据竞争
|
||||||
|
=> 死锁
|
||||||
|
|
||||||
|
### 缩小了Bug的查找范围
|
||||||
|
=> unsafe块
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rust如何减少Bug
|
||||||
|
|
||||||
|
* 大部分低级错误在编译期避免
|
||||||
|
* 少数逻辑错误在运行时暴露
|
||||||
|
* 难以发现的错误被限制了范围
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 充分利用现成轮子
|
||||||
|
|
||||||
|
引用的外部库(crate):
|
||||||
|
* `alloc`: 容器
|
||||||
|
* `log`: 日志
|
||||||
|
* `spin`: 自旋锁
|
||||||
|
* `xmas-elf`: 解析ELF文件
|
||||||
|
* `linked_list_allocator`: 堆分配算法
|
||||||
|
* `uart_116500`: 串口驱动
|
||||||
|
* `x86_64`: 包装汇编指令,封装页表等数据结构
|
||||||
|
|
||||||
|
更好地专注于OS核心逻辑!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 制造我们自己的轮子
|
||||||
|
|
||||||
|
仿照`x86_64`库,并基于社区现有成果,
|
||||||
|
我们分别实现了`riscv`和`aarch64`库。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 内核模块化
|
||||||
|
|
||||||
|
ucore_os_lab = 内存管理 + 进程管理 + 文件系统
|
||||||
|
|
||||||
|
lab1-lab8,层层依赖,高度耦合。
|
||||||
|
|
||||||
|
然而它们在逻辑上互不相关,理应分开。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 内核模块化
|
||||||
|
|
||||||
|
每个部分作为独立的crate存在,互不依赖。
|
||||||
|
|
||||||
|
内核通过实现它们的接口,把它们粘合在一起。
|
||||||
|
|
||||||
|
可以分别内部单元测试,然后放在一起集成测试。
|
||||||
|
|
||||||
|
配合泛型,可做到零开销。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 内存模块
|
||||||
|
|
||||||
|
接口:页表,页表项,缺页处理函数
|
||||||
|
|
||||||
|
功能:面向进程的虚存管理(`mm_struct`)
|
||||||
|
-------支持内存置换、写时复制、延迟分配等机制
|
||||||
|
|
||||||
|
### 线程模块
|
||||||
|
|
||||||
|
接口:上下文切换,新线程的构造
|
||||||
|
|
||||||
|
功能:线程调度和管理
|
||||||
|
|
||||||
|
### 文件系统
|
||||||
|
|
||||||
|
接口:块设备,VFS(虚拟文件系统)
|
||||||
|
|
||||||
|
功能:文件操作和管理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 内存模块——接口
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub trait PageTable {
|
||||||
|
fn map(&mut self, addr: VirtAddr, target: PhysAddr)
|
||||||
|
-> &mut Entry;
|
||||||
|
fn unmap(&mut self, addr: VirtAddr);
|
||||||
|
fn get_entry(&mut self, addr: VirtAddr)
|
||||||
|
-> Option<&mut Entry>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Entry {
|
||||||
|
fn update(&mut self); // flush TLB
|
||||||
|
fn present(&self) -> bool;
|
||||||
|
fn target(&self) -> PhysAddr;
|
||||||
|
fn set_present(&mut self, value: bool);
|
||||||
|
fn set_target(&mut self, target: PhysAddr);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 内存模块——面向接口的上层实现
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct MemoryArea {
|
||||||
|
start_addr: VirtAddr,
|
||||||
|
end_addr: VirtAddr,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryArea {
|
||||||
|
fn map(&self, pt: &mut PageTable) {
|
||||||
|
for page in Page::range_of(self.start_addr, self.end_addr) {
|
||||||
|
let target = alloc_frame();
|
||||||
|
pt.map(addr, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
为一段连续的虚拟地址空间 映射页表项。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 内存模块——接口的Mock实现
|
||||||
|
```rust
|
||||||
|
pub struct MockPageTable {
|
||||||
|
entries: [MockEntry; PAGE_COUNT],
|
||||||
|
data: [u8; PAGE_SIZE * PAGE_COUNT],
|
||||||
|
page_fault_handler: Option<PageFaultHandler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTable for MockPageTable {
|
||||||
|
fn map(...) {...}
|
||||||
|
fn unmap(...) {...}
|
||||||
|
fn get_entry(...) {...}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MockPageTable {
|
||||||
|
fn read(&mut self, addr: VirtAddr) -> u8 {...}
|
||||||
|
fn write(&mut self, addr: VirtAddr, data: u8) {...}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
实现一个仿真页表,模拟地址转换的过程,从数组中存取数据。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 内存模块——基于Mock的单元测试
|
||||||
|
```rust
|
||||||
|
#[test]
|
||||||
|
fn memory_area_map() {
|
||||||
|
let mut pt = MockPageTable {...};
|
||||||
|
let area = MemoryArea {...};
|
||||||
|
|
||||||
|
area.map(&mut pt);
|
||||||
|
|
||||||
|
pt.write(0x1000, 1);
|
||||||
|
assert_eq!(pt.read(0x1000), 1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
可用`cargo test`在任意环境下运行单元测试,不依赖QEMU。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 线程模块——接口与实现
|
||||||
|
```rust
|
||||||
|
pub trait Context {
|
||||||
|
unsafe extern "C"
|
||||||
|
fn switch_to(&mut self, target: &mut Context);
|
||||||
|
}
|
||||||
|
pub struct X86Context {
|
||||||
|
rip: usize,
|
||||||
|
... // callee-saved registers
|
||||||
|
}
|
||||||
|
impl Context for X86Context {
|
||||||
|
unsafe extern "C" // Store caller-saved registers
|
||||||
|
fn switch_to(&mut self, target: &mut Context) {
|
||||||
|
// Store callee-saved registers
|
||||||
|
// Restore callee-saved registers
|
||||||
|
} // Restore caller-saved registers
|
||||||
|
}
|
||||||
|
```
|
||||||
|
上下文切换:保存和恢复寄存器
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 线程模块——面向接口的上层实现
|
||||||
|
```rust
|
||||||
|
/// 管理所有线程的状态及调度,全局唯一
|
||||||
|
pub struct ProcessManager {...}
|
||||||
|
/// 线程执行者,每个CPU核对应一个
|
||||||
|
pub struct Processor {
|
||||||
|
manager: Arc<ProcessManager>,
|
||||||
|
context: Box<Context>,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
impl Processor {
|
||||||
|
/// 调度线程,无限循环
|
||||||
|
fn run(&mut self) -> ! { loop {
|
||||||
|
let mut process = self.manager.pop();
|
||||||
|
unsafe { self.context.switch_to(&mut process); }
|
||||||
|
self.manager.push(process);
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
每个CPU核不断地从运行队列中:取出线程-运行-放回
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 线程模块——兼容标准库的高层封装
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// thread.rs
|
||||||
|
pub fn current() -> Thread {...}
|
||||||
|
pub fn sleep(dur: Duration) {...}
|
||||||
|
pub fn spawn<F, T>(f: F) -> JoinHandle<T> {...}
|
||||||
|
pub fn yield_now() {...}
|
||||||
|
pub fn park() {...}
|
||||||
|
```
|
||||||
|
在上页基础上进一步封装。
|
||||||
|
提供和标准库`std::thread`完全一致的上层接口。
|
||||||
|
使得依赖std的多线程代码,可以方便地迁移到内核中。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 所有权和RAII机制:简化资源管理
|
||||||
|
|
||||||
|
OS需要管理复杂的资源
|
||||||
|
资源之间有复杂的共享和依赖关系
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
![80%](./resources.png)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
进程的对象结构:
|
||||||
|
```rust
|
||||||
|
pub struct Process {
|
||||||
|
context: Context,
|
||||||
|
kstack: KernelStack,
|
||||||
|
memory: MemorySet,
|
||||||
|
files: BTreeMap<usize, Arc<Mutex<File>>>,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
将资源封装成对象,在析构函数中释放资源。
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct KernelStack {
|
||||||
|
ptr: *mut u8,
|
||||||
|
layout: Layout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for KernelStack {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe{ dealloc(self.ptr, self.layout); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
当对象的生命周期结束时,资源自动释放。
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct Process {
|
||||||
|
context: Context,
|
||||||
|
kstack: KernelStack,
|
||||||
|
memory: MemorySet,
|
||||||
|
files: BTreeMap<usize, Arc<Mutex<File>>>,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProcessManager {
|
||||||
|
procs: BTreeMap<usize, Process>,
|
||||||
|
}
|
||||||
|
impl ProcessManager {
|
||||||
|
pub fn remove(&mut self, pid: usize) {
|
||||||
|
self.procs.remove(&pid);
|
||||||
|
// All resources have been released here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Rust vs C
|
||||||
|
|
||||||
|
## 代码风格
|
||||||
|
|
||||||
|
||Rust|C|
|
||||||
|
|-|-|-|
|
||||||
|
|数据结构|泛型容器(Vec)|侵入式(链表)|
|
||||||
|
|全局变量|少量|大量|
|
||||||
|
|数据分布|倾向分散|倾向集中|
|
||||||
|
|数据类型|鼓励自定义类型|基础类型|
|
||||||
|
|思维方式|所有权+生命周期|数据+行为|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 代码量
|
||||||
|
|
||||||
|
||Rust|C|
|
||||||
|
|-|-|-|
|
||||||
|
|内存管理|1600|1800|
|
||||||
|
|线程管理|1200|1200|
|
||||||
|
|文件系统|1300|3400|
|
||||||
|
|同步互斥|500|400|
|
||||||
|
|内核其它|800|1200|
|
||||||
|
|共计|5400|8000|
|
||||||
|
|
||||||
|
*使用`loc`统计代码行数,基于RISCV版本,粗略计算*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 语言能力
|
||||||
|
|
||||||
|
在底层:
|
||||||
|
* 具有同等的底层操作能力
|
||||||
|
* 二者具有良好的互操作性
|
||||||
|
|
||||||
|
在上层:
|
||||||
|
* Rust能编写更加安全的代码,减少Bug
|
||||||
|
* Rust具有更好的表达能力,胜任复杂逻辑
|
||||||
|
* Rust具有更强的抽象能力,有助于代码的分离和复用
|
||||||
|
|
||||||
|
——Rust更加适合编写OS!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Rust的问题
|
||||||
|
|
||||||
|
学习曲线过于陡峭!
|
||||||
|
|
||||||
|
所有权、生命周期等机制难以驾驭!
|
||||||
|
|
||||||
|
初学者大部分时间在与编译器作斗争。
|
||||||
|
|
||||||
|
一种可能的解决方案:
|
||||||
|
* 先用unsafe、C风格实现
|
||||||
|
* 再逐步消除unsafe、重构成Rust风格
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 未来:接下来会做什么?
|
||||||
|
|
||||||
|
* 真机测试:HiFiveU, K210等RISCV64开发板
|
||||||
|
* 教学实验:2019年操作系统课实验
|
||||||
|
* 功能完善:实现POSIX接口
|
||||||
|
* 性能优化:发掘Rust的潜力
|
||||||
|
* 对比借鉴:其它有趣OS
|
||||||
|
* 潜力探索:async异步机制
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 其它有趣OS
|
||||||
|
|
||||||
|
### [Tock](https://www.tockos.org)
|
||||||
|
|
||||||
|
Rust编写的嵌入式操作系统
|
||||||
|
|
||||||
|
关注:Capsule内核模块设计,进程的内存分配策略……
|
||||||
|
|
||||||
|
### [Biscuit](https://github.com/mit-pdos/biscuit)
|
||||||
|
|
||||||
|
Golang编写的POSIX兼容OS,MIT出品
|
||||||
|
|
||||||
|
关注:Go异步机制,Go vs Rust
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 潜力探索:async无栈协程应用于OS内核的探讨
|
||||||
|
|
||||||
|
async-await:用户态异步编程机制
|
||||||
|
|
||||||
|
用同步的方式,编写异步的代码。
|
||||||
|
|
||||||
|
背后的实现机制和OS线程调度高度一致。
|
||||||
|
|
||||||
|
能否应用于Kernel中?与传统线程机制相比有何优缺点?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 感谢
|
||||||
|
|
||||||
|
### 指导老师
|
||||||
|
陈渝,向勇
|
||||||
|
|
||||||
|
### 参与开发的同学们
|
||||||
|
王润基,戴臻旸,王纪霆
|
||||||
|
贾越凯,寇明阳,孔彦
|
||||||
|
刘辰屹,陈秋昊,朱书聪
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 欢迎试玩!
|
||||||
|
|
||||||
|
![40%](demo.png)
|
||||||
|
GitHub:https://github.com/wangrunji0408/RustOS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 感谢聆听
|
||||||
|
# Q&A
|
BIN
docs/2_OSLab/os2atc/ucore_os_in_rust.pdf
Normal file
BIN
docs/2_OSLab/os2atc/ucore_os_in_rust.pdf
Normal file
Binary file not shown.
@ -32,14 +32,16 @@ target := $(arch)-blog_os
|
|||||||
kernel := target/$(target)/$(mode)/ucore
|
kernel := target/$(target)/$(mode)/ucore
|
||||||
bin := target/$(target)/$(mode)/kernel.bin
|
bin := target/$(target)/$(mode)/kernel.bin
|
||||||
bootimage := target/$(target)/bootimage.bin
|
bootimage := target/$(target)/bootimage.bin
|
||||||
|
|
||||||
user_dir := ../user
|
user_dir := ../user
|
||||||
user_bin_path := $(user_dir)/target/$(arch)-ucore/debug
|
|
||||||
user_bins := $(patsubst $(user_bin_path)/%.d, $(user_bin_path)/%, $(wildcard $(user_bin_path)/*.d))
|
|
||||||
user_obj := build/$(arch)/user.o
|
|
||||||
|
|
||||||
export ARCH = $(arch)
|
export ARCH = $(arch)
|
||||||
export SFSIMG = $(user_dir)/build/user-$(arch).img
|
export SMP = $(smp)
|
||||||
|
#export SFSIMG = $(user_dir)/build/user-$(arch).img
|
||||||
|
ifeq ($(arch), x86_64)
|
||||||
|
export SFSIMG = $(user_dir)/img/ucore-i386.img
|
||||||
|
else
|
||||||
|
export SFSIMG = $(user_dir)/img/ucore-$(arch).img
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(arch), aarch64)
|
ifeq ($(arch), aarch64)
|
||||||
graphic ?= on
|
graphic ?= on
|
||||||
@ -209,11 +211,6 @@ endif
|
|||||||
sfsimg:
|
sfsimg:
|
||||||
@cd $(user_dir) && make sfsimg
|
@cd $(user_dir) && make sfsimg
|
||||||
|
|
||||||
# make user.o from binary files
|
|
||||||
$(user_obj): $(user_bins)
|
|
||||||
@cd $(user_bin_path) && \
|
|
||||||
$(ld) -o $(abspath $@) $(patsubst %, -b binary %, $(notdir $(user_bins)))
|
|
||||||
|
|
||||||
|
|
||||||
### install ###
|
### install ###
|
||||||
ifeq ($(board), raspi3)
|
ifeq ($(board), raspi3)
|
||||||
|
@ -145,6 +145,13 @@ impl Framebuffer {
|
|||||||
use crate::arch::memory;
|
use crate::arch::memory;
|
||||||
let paddr = info.bus_addr & !0xC0000000;
|
let paddr = info.bus_addr & !0xC0000000;
|
||||||
let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb") as u32;
|
let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb") as u32;
|
||||||
|
if vaddr == 0 {
|
||||||
|
Err(format!(
|
||||||
|
"cannot remap memory range [{:#x?}..{:#x?}]",
|
||||||
|
paddr,
|
||||||
|
paddr + info.screen_size
|
||||||
|
))?;
|
||||||
|
}
|
||||||
Ok(Framebuffer {
|
Ok(Framebuffer {
|
||||||
buf: ColorBuffer::new(color_depth, vaddr, info.screen_size),
|
buf: ColorBuffer::new(color_depth, vaddr, info.screen_size),
|
||||||
color_depth,
|
color_depth,
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
//! Memory initialization for aarch64.
|
//! Memory initialization for aarch64.
|
||||||
|
|
||||||
use crate::memory::{init_heap, MemoryArea, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
|
use crate::memory::{init_heap, Linear, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
|
||||||
use super::paging::MMIOType;
|
use super::paging::MMIOType;
|
||||||
use aarch64::paging::{memory_attribute::*, PhysFrame as Frame};
|
use aarch64::paging::{memory_attribute::*, PhysFrame as Frame};
|
||||||
use aarch64::{addr::*, barrier, regs::*};
|
use aarch64::{addr::*, barrier, regs::*};
|
||||||
use atags::atags::Atags;
|
use atags::atags::Atags;
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use spin::Mutex;
|
|
||||||
use ucore_memory::PAGE_SIZE;
|
use ucore_memory::PAGE_SIZE;
|
||||||
|
|
||||||
/// Memory initialization.
|
/// Memory initialization.
|
||||||
@ -100,41 +98,31 @@ fn init_frame_allocator() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
static mut KERNEL_MEMORY_SET: Option<MemorySet> = None;
|
||||||
pub static ref KERNEL_MEMORY_SET: Mutex<MemorySet> = Mutex::new(MemorySet::new_bare());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// remap kernel page table after all initialization.
|
/// remap kernel page table after all initialization.
|
||||||
fn remap_the_kernel() {
|
fn remap_the_kernel() {
|
||||||
let mut ms = KERNEL_MEMORY_SET.lock();
|
let mut ms = MemorySet::new_bare();
|
||||||
ms.push(MemoryArea::new_identity(0, bootstacktop as usize, MemoryAttr::default(), "kstack"));
|
ms.push(0, bootstacktop as usize, Linear::new(0, MemoryAttr::default()), "kstack");
|
||||||
ms.push(MemoryArea::new_identity(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), "text"));
|
ms.push(stext as usize, etext as usize, Linear::new(0, MemoryAttr::default().execute().readonly()), "text");
|
||||||
ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data"));
|
ms.push(sdata as usize, edata as usize, Linear::new(0, MemoryAttr::default()), "data");
|
||||||
ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata"));
|
ms.push(srodata as usize, erodata as usize, Linear::new(0, MemoryAttr::default().readonly()), "rodata");
|
||||||
ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss"));
|
ms.push(sbss as usize, ebss as usize, Linear::new(0, MemoryAttr::default()), "bss");
|
||||||
|
|
||||||
use super::board::{IO_REMAP_BASE, IO_REMAP_END};
|
use super::board::{IO_REMAP_BASE, IO_REMAP_END};
|
||||||
ms.push(MemoryArea::new_identity(
|
ms.push(IO_REMAP_BASE, IO_REMAP_END, Linear::new(0, MemoryAttr::default().mmio(MMIOType::Device as u8)), "io_remap");
|
||||||
IO_REMAP_BASE,
|
|
||||||
IO_REMAP_END,
|
|
||||||
MemoryAttr::default().mmio(MMIOType::Device as u8),
|
|
||||||
"io_remap",
|
|
||||||
));
|
|
||||||
|
|
||||||
unsafe { ms.get_page_table_mut().activate_as_kernel() }
|
unsafe { ms.get_page_table_mut().activate_as_kernel() }
|
||||||
|
unsafe { KERNEL_MEMORY_SET = Some(ms) }
|
||||||
info!("kernel remap end");
|
info!("kernel remap end");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ioremap(start: usize, len: usize, name: &'static str) -> usize {
|
pub fn ioremap(start: usize, len: usize, name: &'static str) -> usize {
|
||||||
let mut ms = KERNEL_MEMORY_SET.lock();
|
if let Some(ms) = unsafe { KERNEL_MEMORY_SET.as_mut() } {
|
||||||
let area = MemoryArea::new_identity(
|
ms.push(start, start + len, Linear::new(0, MemoryAttr::default().mmio(MMIOType::NormalNonCacheable as u8)), name);
|
||||||
start,
|
return start;
|
||||||
start + len,
|
}
|
||||||
MemoryAttr::default().mmio(MMIOType::NormalNonCacheable as u8),
|
0
|
||||||
name,
|
|
||||||
);
|
|
||||||
ms.push(area);
|
|
||||||
start
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the (start address, end address) of the available memory on this
|
/// Returns the (start address, end address) of the available memory on this
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
//! Page table implementations for aarch64.
|
//! Page table implementations for aarch64.
|
||||||
use ucore_memory::memory_set::*;
|
|
||||||
use ucore_memory::PAGE_SIZE;
|
|
||||||
use ucore_memory::paging::*;
|
use ucore_memory::paging::*;
|
||||||
use aarch64::asm::{tlb_invalidate, tlb_invalidate_all, flush_icache_all, ttbr_el1_read, ttbr_el1_write};
|
use aarch64::asm::{tlb_invalidate, tlb_invalidate_all, flush_icache_all, ttbr_el1_read, ttbr_el1_write};
|
||||||
use aarch64::{PhysAddr, VirtAddr};
|
use aarch64::{PhysAddr, VirtAddr};
|
||||||
@ -9,7 +7,7 @@ use aarch64::paging::{FrameAllocator, FrameDeallocator, Page, PhysFrame as Frame
|
|||||||
use aarch64::paging::memory_attribute::*;
|
use aarch64::paging::memory_attribute::*;
|
||||||
use log::*;
|
use log::*;
|
||||||
// Depends on kernel
|
// Depends on kernel
|
||||||
use crate::consts::RECURSIVE_INDEX;
|
use crate::consts::{KERNEL_PML4, RECURSIVE_INDEX};
|
||||||
use crate::memory::{active_table, alloc_frame, dealloc_frame};
|
use crate::memory::{active_table, alloc_frame, dealloc_frame};
|
||||||
|
|
||||||
// need 3 page
|
// need 3 page
|
||||||
@ -49,9 +47,7 @@ pub struct ActivePageTable(RecursivePageTable<'static>);
|
|||||||
pub struct PageEntry(PageTableEntry);
|
pub struct PageEntry(PageTableEntry);
|
||||||
|
|
||||||
impl PageTable for ActivePageTable {
|
impl PageTable for ActivePageTable {
|
||||||
type Entry = PageEntry;
|
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
|
||||||
|
|
||||||
fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry {
|
|
||||||
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), Frame::of_addr(target), flags, attr, &mut FrameAllocatorForAarch64)
|
self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, attr, &mut FrameAllocatorForAarch64)
|
||||||
@ -64,27 +60,16 @@ impl PageTable for ActivePageTable {
|
|||||||
flush.flush();
|
flush.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_entry(&mut self, vaddr: usize) -> Option<&mut PageEntry> {
|
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)
|
let entry_addr = ((vaddr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39)
|
||||||
| (vaddr & 0xffff_0000_0000_0000);
|
| (vaddr & 0xffff_0000_0000_0000);
|
||||||
Some(unsafe { &mut *(entry_addr as *mut PageEntry) })
|
Some(unsafe { &mut *(entry_addr as *mut PageEntry) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: usize) -> &'b mut [u8] {
|
|
||||||
use core::slice;
|
|
||||||
unsafe { slice::from_raw_parts_mut((addr & !0xfffusize) as *mut u8, PAGE_SIZE) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, addr: usize) -> u8 {
|
|
||||||
unsafe { *(addr as *const u8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, addr: usize, data: u8) {
|
|
||||||
unsafe { *(addr as *mut u8) = data; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PageTableExt for ActivePageTable {}
|
||||||
|
|
||||||
const ROOT_PAGE_TABLE: *mut Aarch64PageTable =
|
const ROOT_PAGE_TABLE: *mut Aarch64PageTable =
|
||||||
((RECURSIVE_INDEX << 39) | (RECURSIVE_INDEX << 30) | (RECURSIVE_INDEX << 21) | (RECURSIVE_INDEX << 12)) as *mut Aarch64PageTable;
|
((RECURSIVE_INDEX << 39) | (RECURSIVE_INDEX << 30) | (RECURSIVE_INDEX << 21) | (RECURSIVE_INDEX << 12)) as *mut Aarch64PageTable;
|
||||||
|
|
||||||
@ -92,18 +77,6 @@ impl ActivePageTable {
|
|||||||
pub unsafe fn new() -> Self {
|
pub unsafe fn new() -> Self {
|
||||||
ActivePageTable(RecursivePageTable::new(&mut *(ROOT_PAGE_TABLE as *mut _)).unwrap())
|
ActivePageTable(RecursivePageTable::new(&mut *(ROOT_PAGE_TABLE as *mut _)).unwrap())
|
||||||
}
|
}
|
||||||
fn with_temporary_map(&mut self, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut Aarch64PageTable)) {
|
|
||||||
// Create a temporary page
|
|
||||||
let page = Page::of_addr(0xcafebabe);
|
|
||||||
assert!(self.0.translate_page(page).is_none(), "temporary page is already mapped");
|
|
||||||
// Map it to table
|
|
||||||
self.map(page.start_address().as_u64() as usize, frame.start_address().as_u64() as usize);
|
|
||||||
// Call f
|
|
||||||
let table = unsafe { &mut *page.start_address().as_mut_ptr() };
|
|
||||||
f(self, table);
|
|
||||||
// Unmap the page
|
|
||||||
self.unmap(0xcafebabe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@ -217,9 +190,9 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_bare() -> Self {
|
fn new_bare() -> Self {
|
||||||
let frame = Self::alloc_frame().map(|target| Frame::of_addr(target))
|
let target = alloc_frame().expect("failed to allocate frame");
|
||||||
.expect("failed to allocate frame");
|
let frame = Frame::of_addr(target);
|
||||||
active_table().with_temporary_map(&frame, |_, 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());
|
||||||
@ -227,8 +200,35 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
InactivePageTable0 { p4_frame: frame }
|
InactivePageTable0 { p4_frame: frame }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) {
|
fn map_kernel(&mut self) {
|
||||||
active_table().with_temporary_map(&ttbr_el1_read(0), |active_table, p4_table: &mut Aarch64PageTable| {
|
let table = unsafe { &mut *ROOT_PAGE_TABLE };
|
||||||
|
let e0 = table[KERNEL_PML4].clone();
|
||||||
|
assert!(!e0.is_unused());
|
||||||
|
|
||||||
|
self.edit(|_| {
|
||||||
|
table[KERNEL_PML4].set_frame(Frame::containing_address(e0.addr()), EF::default(), MairNormal::attr_value());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token(&self) -> usize {
|
||||||
|
self.p4_frame.start_address().as_u64() as usize // as TTBRx_EL1
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_token(token: usize) {
|
||||||
|
ttbr_el1_write(1, Frame::containing_address(PhysAddr::new(token as u64)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active_token() -> usize {
|
||||||
|
ttbr_el1_read(1).start_address().as_u64() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_tlb() {
|
||||||
|
tlb_invalidate_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
|
||||||
|
let target = ttbr_el1_read(0).start_address().as_u64() as usize;
|
||||||
|
active_table().with_temporary_map(target, |active_table, p4_table: &mut Aarch64PageTable| {
|
||||||
let backup = p4_table[RECURSIVE_INDEX].clone();
|
let backup = p4_table[RECURSIVE_INDEX].clone();
|
||||||
let old_frame = ttbr_el1_read(1);
|
let old_frame = ttbr_el1_read(1);
|
||||||
|
|
||||||
@ -238,54 +238,14 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
tlb_invalidate_all();
|
tlb_invalidate_all();
|
||||||
|
|
||||||
// execute f in the new context
|
// execute f in the new context
|
||||||
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(1, old_frame);
|
ttbr_el1_write(1, old_frame);
|
||||||
tlb_invalidate_all();
|
tlb_invalidate_all();
|
||||||
});
|
ret
|
||||||
}
|
})
|
||||||
|
|
||||||
unsafe fn activate(&self) {
|
|
||||||
let old_frame = ttbr_el1_read(1);
|
|
||||||
let new_frame = self.p4_frame.clone();
|
|
||||||
debug!("switch TTBR1 {:?} -> {:?}", old_frame, new_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
ttbr_el1_write(1, new_frame);
|
|
||||||
tlb_invalidate_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
|
|
||||||
// Just need to switch the user TTBR
|
|
||||||
let old_frame = ttbr_el1_read(1);
|
|
||||||
let new_frame = self.p4_frame.clone();
|
|
||||||
debug!("switch TTBR1 {:?} -> {:?}", old_frame, new_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
ttbr_el1_write(1, new_frame);
|
|
||||||
tlb_invalidate_all();
|
|
||||||
}
|
|
||||||
let ret = f();
|
|
||||||
debug!("switch TTBR1 {:?} -> {:?}", new_frame, old_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
ttbr_el1_write(1, old_frame);
|
|
||||||
tlb_invalidate_all();
|
|
||||||
flush_icache_all();
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn token(&self) -> usize {
|
|
||||||
self.p4_frame.start_address().as_u64() as usize // as TTBRx_EL1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_frame() -> Option<usize> {
|
|
||||||
alloc_frame()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dealloc_frame(target: usize) {
|
|
||||||
dealloc_frame(target)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,7 +266,7 @@ impl InactivePageTable0 {
|
|||||||
impl Drop for InactivePageTable0 {
|
impl Drop for InactivePageTable0 {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!("PageTable dropping: {:?}", self);
|
info!("PageTable dropping: {:?}", self);
|
||||||
Self::dealloc_frame(self.p4_frame.start_address().as_u64() as usize);
|
dealloc_frame(self.p4_frame.start_address().as_u64() as usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ pub extern fn __mulsi3(mut a: u32, mut b: u32) -> u32 {
|
|||||||
|
|
||||||
while a > 0 {
|
while a > 0 {
|
||||||
if a & 1 > 0 {
|
if a & 1 > 0 {
|
||||||
r += b;
|
r = r.overflowing_add(b).0;
|
||||||
}
|
}
|
||||||
a >>= 1;
|
a >>= 1;
|
||||||
b <<= 1;
|
b <<= 1;
|
||||||
|
@ -2,7 +2,7 @@ use core::{slice, mem};
|
|||||||
use riscv::{addr::*, register::sstatus};
|
use riscv::{addr::*, register::sstatus};
|
||||||
use ucore_memory::PAGE_SIZE;
|
use ucore_memory::PAGE_SIZE;
|
||||||
use log::*;
|
use log::*;
|
||||||
use crate::memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, MEMORY_ALLOCATOR};
|
use crate::memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, MEMORY_ALLOCATOR, Linear};
|
||||||
use crate::consts::{MEMORY_OFFSET, MEMORY_END};
|
use crate::consts::{MEMORY_OFFSET, MEMORY_END};
|
||||||
|
|
||||||
#[cfg(feature = "no_mmu")]
|
#[cfg(feature = "no_mmu")]
|
||||||
@ -78,11 +78,11 @@ fn init_frame_allocator() {
|
|||||||
fn remap_the_kernel() {
|
fn remap_the_kernel() {
|
||||||
let mut ms = MemorySet::new_bare();
|
let mut ms = MemorySet::new_bare();
|
||||||
#[cfg(feature = "no_bbl")]
|
#[cfg(feature = "no_bbl")]
|
||||||
ms.push(MemoryArea::new_identity(0x10000000, 0x10000008, MemoryAttr::default(), "serial"));
|
ms.push(0x10000000, 0x10000008, Linear::new(0, MemoryAttr::default()), "serial");
|
||||||
ms.push(MemoryArea::new_identity(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), "text"));
|
ms.push(stext as usize, etext as usize, Linear::new(0, MemoryAttr::default().execute().readonly()), "text");
|
||||||
ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data"));
|
ms.push(sdata as usize, edata as usize, Linear::new(0, MemoryAttr::default()), "data");
|
||||||
ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata"));
|
ms.push(srodata as usize, erodata as usize, Linear::new(0, MemoryAttr::default().readonly()), "rodata");
|
||||||
ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss"));
|
ms.push(sbss as usize, ebss as usize, Linear::new(0, MemoryAttr::default()), "bss");
|
||||||
unsafe { ms.activate(); }
|
unsafe { ms.activate(); }
|
||||||
unsafe { SATP = ms.token(); }
|
unsafe { SATP = ms.token(); }
|
||||||
mem::forget(ms);
|
mem::forget(ms);
|
||||||
|
@ -31,19 +31,16 @@ pub fn setup_page_table(frame: Frame) {
|
|||||||
p2.map_identity(KERNEL_P2_INDEX + 1, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE);
|
p2.map_identity(KERNEL_P2_INDEX + 1, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE);
|
||||||
p2.map_identity(KERNEL_P2_INDEX + 2, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE);
|
p2.map_identity(KERNEL_P2_INDEX + 2, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE);
|
||||||
|
|
||||||
use riscv::register::satp;
|
|
||||||
unsafe { satp::set(satp::Mode::Sv32, 0, frame); }
|
unsafe { satp::set(satp::Mode::Sv32, 0, frame); }
|
||||||
sfence_vma_all();
|
sfence_vma_all();
|
||||||
info!("setup init page table end");
|
info!("setup init page table end");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ActivePageTable(RecursivePageTable<'static>);
|
pub struct ActivePageTable(RecursivePageTable<'static>, PageEntry);
|
||||||
|
|
||||||
pub struct PageEntry(PageTableEntry);
|
pub struct PageEntry(PageTableEntry, Page);
|
||||||
|
|
||||||
impl PageTable for ActivePageTable {
|
impl PageTable for ActivePageTable {
|
||||||
type Entry = PageEntry;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @param:
|
* @param:
|
||||||
* addr: the virtual addr to be matched
|
* addr: the virtual addr to be matched
|
||||||
@ -53,7 +50,7 @@ impl PageTable for ActivePageTable {
|
|||||||
* @retval:
|
* @retval:
|
||||||
* the matched PageEntry
|
* the matched PageEntry
|
||||||
*/
|
*/
|
||||||
fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry {
|
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
|
||||||
// the flag for the new page entry
|
// the flag for the new page entry
|
||||||
let flags = EF::VALID | EF::READABLE | EF::WRITABLE;
|
let flags = EF::VALID | EF::READABLE | EF::WRITABLE;
|
||||||
// here page is for the virtual address while frame is for the physical, both of them is 4096 bytes align
|
// here page is for the virtual address while frame is for the physical, both of them is 4096 bytes align
|
||||||
@ -86,96 +83,56 @@ impl PageTable for ActivePageTable {
|
|||||||
* @retval:
|
* @retval:
|
||||||
* a mutable PageEntry reference of 'addr'
|
* a mutable PageEntry reference of 'addr'
|
||||||
*/
|
*/
|
||||||
fn get_entry(&mut self, addr: usize) -> Option<&mut PageEntry> {
|
fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> {
|
||||||
if unsafe { !(*ROOT_PAGE_TABLE)[addr >> 22].flags().contains(EF::VALID) } {
|
let p2 = unsafe { ROOT_PAGE_TABLE.as_mut().unwrap() };
|
||||||
|
let page = Page::of_addr(VirtAddr::new(addr));
|
||||||
|
if !p2[page.p2_index()].flags().contains(EF::VALID) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let page = Page::of_addr(VirtAddr::new(addr));
|
let entry = edit_entry_of(&page, |entry| *entry);
|
||||||
// ???
|
self.1 = PageEntry(entry, page);
|
||||||
let _ = self.0.translate_page(page);
|
Some(&mut self.1)
|
||||||
let entry_addr = ((addr >> 10) & ((1 << 22) - 4)) | (RECURSIVE_INDEX << 22);
|
|
||||||
unsafe { Some(&mut *(entry_addr as *mut PageEntry)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param:
|
|
||||||
* addr:the input (virutal) address
|
|
||||||
* @brief:
|
|
||||||
* get the addr's memory page slice
|
|
||||||
* @retval:
|
|
||||||
* a mutable reference slice of 'addr' 's page
|
|
||||||
*/
|
|
||||||
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: usize) -> &'b mut [u8] {
|
|
||||||
use core::slice;
|
|
||||||
unsafe { slice::from_raw_parts_mut((addr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param:
|
|
||||||
* addr: virtual address
|
|
||||||
* @brief:
|
|
||||||
* get the address's content
|
|
||||||
* @retval:
|
|
||||||
* the content(u8) of 'addr'
|
|
||||||
*/
|
|
||||||
fn read(&mut self, addr: usize) -> u8 {
|
|
||||||
unsafe { *(addr as *const u8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param:
|
|
||||||
* addr: virtual address
|
|
||||||
* @brief:
|
|
||||||
* write the address's content
|
|
||||||
*/
|
|
||||||
fn write(&mut self, addr: usize, data: u8) {
|
|
||||||
unsafe { *(addr as *mut u8) = data; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn edit_entry_of<T>(page: &Page, f: impl FnOnce(&mut PageTableEntry) -> T) -> T {
|
||||||
|
let p2_flags = unsafe { (*ROOT_PAGE_TABLE)[page.p2_index()].flags_mut() };
|
||||||
|
p2_flags.insert(EF::READABLE | EF::WRITABLE);
|
||||||
|
let entry_addr = (RECURSIVE_INDEX << 22) | (page.p2_index() << 12) | (page.p1_index() << 2);
|
||||||
|
let entry = unsafe { &mut *(entry_addr as *mut PageTableEntry) };
|
||||||
|
let ret = f(entry);
|
||||||
|
p2_flags.remove(EF::READABLE | EF::WRITABLE);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTableExt for ActivePageTable {}
|
||||||
|
|
||||||
// define the ROOT_PAGE_TABLE, and the virtual address of it?
|
// define the ROOT_PAGE_TABLE, and the virtual address of it?
|
||||||
const ROOT_PAGE_TABLE: *mut RvPageTable =
|
const ROOT_PAGE_TABLE: *mut RvPageTable =
|
||||||
(((RECURSIVE_INDEX << 10) | (RECURSIVE_INDEX + 1)) << 12) as *mut RvPageTable;
|
(((RECURSIVE_INDEX << 10) | (RECURSIVE_INDEX + 1)) << 12) as *mut RvPageTable;
|
||||||
|
|
||||||
impl ActivePageTable {
|
impl ActivePageTable {
|
||||||
pub unsafe fn new() -> Self {
|
pub unsafe fn new() -> Self {
|
||||||
ActivePageTable(RecursivePageTable::new(&mut *ROOT_PAGE_TABLE).unwrap())
|
ActivePageTable(
|
||||||
}
|
RecursivePageTable::new(&mut *ROOT_PAGE_TABLE).unwrap(),
|
||||||
|
::core::mem::zeroed()
|
||||||
/*
|
)
|
||||||
* @param:
|
|
||||||
* frame: the target physical frame which will be temporarily mapped
|
|
||||||
* f: the function you would like to apply for once
|
|
||||||
* @brief:
|
|
||||||
* do something on the target physical frame?
|
|
||||||
*/
|
|
||||||
fn with_temporary_map(&mut self, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut RvPageTable)) {
|
|
||||||
// Create a temporary page
|
|
||||||
let page = Page::of_addr(VirtAddr::new(0xcafebabe));
|
|
||||||
assert!(self.0.translate_page(page).is_none(), "temporary page is already mapped");
|
|
||||||
// Map it to table
|
|
||||||
self.map(page.start_address().as_usize(), frame.start_address().as_u32() as usize);
|
|
||||||
// Call f
|
|
||||||
let table = unsafe { &mut *(page.start_address().as_usize() as *mut _) };
|
|
||||||
f(self, table);
|
|
||||||
// Unmap the page
|
|
||||||
self.unmap(0xcafebabe);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// 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) {
|
||||||
let addr = VirtAddr::new((self as *const _ as usize) << 10);
|
edit_entry_of(&self.1, |entry| *entry = self.0);
|
||||||
sfence_vma(0, addr);
|
sfence_vma(0, self.1.start_address());
|
||||||
}
|
}
|
||||||
fn accessed(&self) -> bool { self.0.flags().contains(EF::ACCESSED) }
|
fn accessed(&self) -> bool { self.0.flags().contains(EF::ACCESSED) }
|
||||||
fn dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) }
|
fn dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) }
|
||||||
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITABLE) }
|
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITABLE) }
|
||||||
fn present(&self) -> bool { self.0.flags().contains(EF::VALID | EF::READABLE) }
|
fn present(&self) -> bool { self.0.flags().contains(EF::VALID | EF::READABLE) }
|
||||||
fn clear_accessed(&mut self) { self.as_flags().remove(EF::ACCESSED); }
|
fn clear_accessed(&mut self) { self.0.flags_mut().remove(EF::ACCESSED); }
|
||||||
fn clear_dirty(&mut self) { self.as_flags().remove(EF::DIRTY); }
|
fn clear_dirty(&mut self) { self.0.flags_mut().remove(EF::DIRTY); }
|
||||||
fn set_writable(&mut self, value: bool) { self.as_flags().set(EF::WRITABLE, value); }
|
fn set_writable(&mut self, value: bool) { self.0.flags_mut().set(EF::WRITABLE, value); }
|
||||||
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::VALID | EF::READABLE, 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_u32() as usize }
|
fn target(&self) -> usize { self.0.addr().as_u32() 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();
|
||||||
@ -185,27 +142,21 @@ impl Entry for PageEntry {
|
|||||||
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::RESERVED1) }
|
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::RESERVED1) }
|
||||||
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::RESERVED2) }
|
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.as_flags();
|
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.as_flags().remove(EF::RESERVED1 | EF::RESERVED2); }
|
fn clear_shared(&mut self) { self.0.flags_mut().remove(EF::RESERVED1 | EF::RESERVED2); }
|
||||||
fn swapped(&self) -> bool { self.0.flags().contains(EF::RESERVED1) }
|
fn swapped(&self) -> bool { self.0.flags().contains(EF::RESERVED1) }
|
||||||
fn set_swapped(&mut self, value: bool) { self.as_flags().set(EF::RESERVED1, value); }
|
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 user(&self) -> bool { self.0.flags().contains(EF::USER) }
|
||||||
fn set_user(&mut self, value: bool) { self.as_flags().set(EF::USER, value); }
|
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 execute(&self) -> bool { self.0.flags().contains(EF::EXECUTABLE) }
|
||||||
fn set_execute(&mut self, value: bool) { self.as_flags().set(EF::EXECUTABLE, value); }
|
fn set_execute(&mut self, value: bool) { self.0.flags_mut().set(EF::EXECUTABLE, value); }
|
||||||
fn mmio(&self) -> u8 { 0 }
|
fn mmio(&self) -> u8 { 0 }
|
||||||
fn set_mmio(&mut self, _value: u8) { }
|
fn set_mmio(&mut self, _value: u8) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageEntry {
|
|
||||||
fn as_flags(&mut self) -> &mut EF {
|
|
||||||
unsafe { &mut *(self as *mut _ as *mut EF) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InactivePageTable0 {
|
pub struct InactivePageTable0 {
|
||||||
p2_frame: Frame,
|
p2_frame: Frame,
|
||||||
@ -214,42 +165,50 @@ pub struct InactivePageTable0 {
|
|||||||
impl InactivePageTable for InactivePageTable0 {
|
impl InactivePageTable for InactivePageTable0 {
|
||||||
type Active = ActivePageTable;
|
type Active = ActivePageTable;
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief:
|
|
||||||
* get a new pagetable (for a new process or thread)
|
|
||||||
* @retbal:
|
|
||||||
* the new pagetable
|
|
||||||
*/
|
|
||||||
fn new() -> Self {
|
|
||||||
let mut pt = Self::new_bare();
|
|
||||||
pt.map_kernel();
|
|
||||||
pt
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief:
|
|
||||||
* allocate a new frame and then self-mapping it and regard it as the inactivepagetale
|
|
||||||
* retval:
|
|
||||||
* the inactive page table
|
|
||||||
*/
|
|
||||||
fn new_bare() -> Self {
|
fn new_bare() -> Self {
|
||||||
let frame = Self::alloc_frame().map(|target| Frame::of_addr(PhysAddr::new(target as u32)))
|
let target = alloc_frame().expect("failed to allocate frame");
|
||||||
.expect("failed to allocate frame");
|
let frame = Frame::of_addr(PhysAddr::new(target as u32));
|
||||||
active_table().with_temporary_map(&frame, |_, table: &mut RvPageTable| {
|
active_table().with_temporary_map(target, |_, table: &mut RvPageTable| {
|
||||||
table.zero();
|
table.zero();
|
||||||
table.set_recursive(RECURSIVE_INDEX, frame.clone());
|
table.set_recursive(RECURSIVE_INDEX, frame.clone());
|
||||||
});
|
});
|
||||||
InactivePageTable0 { p2_frame: frame }
|
InactivePageTable0 { p2_frame: frame }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
fn map_kernel(&mut self) {
|
||||||
* @param:
|
let table = unsafe { &mut *ROOT_PAGE_TABLE };
|
||||||
* f: a function to do something with the temporary modified activate page table
|
let e0 = table[0x40];
|
||||||
* @brief:
|
let e1 = table[KERNEL_P2_INDEX];
|
||||||
* temporarily map the inactive pagetable as an active p2page and apply f on the temporary modified active page table
|
let e2 = table[KERNEL_P2_INDEX + 1];
|
||||||
*/
|
let e3 = table[KERNEL_P2_INDEX + 2];
|
||||||
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) {
|
|
||||||
active_table().with_temporary_map(&satp::read().frame(), |active_table, p2_table: &mut RvPageTable| {
|
self.edit(|_| {
|
||||||
|
table[0x40] = e0;
|
||||||
|
table[KERNEL_P2_INDEX] = e1;
|
||||||
|
table[KERNEL_P2_INDEX + 1] = e2;
|
||||||
|
table[KERNEL_P2_INDEX + 2] = e3;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token(&self) -> usize {
|
||||||
|
self.p2_frame.number() | (1 << 31) // as satp
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_token(token: usize) {
|
||||||
|
asm!("csrw 0x180, $0" :: "r"(token) :: "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active_token() -> usize {
|
||||||
|
satp::read().bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_tlb() {
|
||||||
|
sfence_vma_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
|
||||||
|
let target = satp::read().frame().start_address().as_u32() as usize;
|
||||||
|
active_table().with_temporary_map(target, |active_table, p2_table: &mut RvPageTable| {
|
||||||
let backup = p2_table[RECURSIVE_INDEX].clone();
|
let backup = p2_table[RECURSIVE_INDEX].clone();
|
||||||
|
|
||||||
// overwrite recursive mapping
|
// overwrite recursive mapping
|
||||||
@ -257,102 +216,21 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
sfence_vma_all();
|
sfence_vma_all();
|
||||||
|
|
||||||
// execute f in the new context
|
// execute f in the new context
|
||||||
f(active_table);
|
let ret = f(active_table);
|
||||||
|
|
||||||
// restore recursive mapping to original p2 table
|
// restore recursive mapping to original p2 table
|
||||||
p2_table[RECURSIVE_INDEX] = backup;
|
p2_table[RECURSIVE_INDEX] = backup;
|
||||||
sfence_vma_all();
|
sfence_vma_all();
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
ret
|
||||||
* @brief:
|
})
|
||||||
* active self as the current active page table
|
|
||||||
*/
|
|
||||||
unsafe fn activate(&self) {
|
|
||||||
let old_frame = satp::read().frame();
|
|
||||||
let new_frame = self.p2_frame.clone();
|
|
||||||
debug!("switch table {:x?} -> {:x?}", old_frame, new_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
satp::set(satp::Mode::Sv32, 0, new_frame);
|
|
||||||
sfence_vma_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param:
|
|
||||||
* f: the function to run when temporarily activate self as current page table
|
|
||||||
* @brief:
|
|
||||||
* Temporarily activate self and run the process, and return the return value of f
|
|
||||||
* @retval:
|
|
||||||
* the return value of f
|
|
||||||
*/
|
|
||||||
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
|
|
||||||
let old_frame = satp::read().frame();
|
|
||||||
let new_frame = self.p2_frame.clone();
|
|
||||||
debug!("switch table {:x?} -> {:x?}", old_frame, new_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
satp::set(satp::Mode::Sv32, 0, new_frame);
|
|
||||||
sfence_vma_all();
|
|
||||||
}
|
|
||||||
let target = f();
|
|
||||||
debug!("switch table {:x?} -> {:x?}", new_frame, old_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
satp::set(satp::Mode::Sv32, 0, old_frame);
|
|
||||||
sfence_vma_all();
|
|
||||||
}
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief:
|
|
||||||
* get the token of self, the token is self's pagetable frame's starting physical address
|
|
||||||
* @retval:
|
|
||||||
* self token
|
|
||||||
*/
|
|
||||||
fn token(&self) -> usize {
|
|
||||||
self.p2_frame.number() | (1 << 31) // as satp
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_frame() -> Option<usize> {
|
|
||||||
alloc_frame()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dealloc_frame(target: usize) {
|
|
||||||
dealloc_frame(target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InactivePageTable0 {
|
|
||||||
/*
|
|
||||||
* @brief:
|
|
||||||
* map the kernel code memory address (p2 page table) in the new inactive page table according the current active page table
|
|
||||||
*/
|
|
||||||
fn map_kernel(&mut self) {
|
|
||||||
let table = unsafe { &mut *ROOT_PAGE_TABLE };
|
|
||||||
let e0 = table[0x40];
|
|
||||||
let e1 = table[KERNEL_P2_INDEX];
|
|
||||||
assert!(!e1.is_unused());
|
|
||||||
// for larger heap memroy
|
|
||||||
let e2 = table[KERNEL_P2_INDEX + 1];
|
|
||||||
assert!(!e2.is_unused());
|
|
||||||
let e3 = table[KERNEL_P2_INDEX + 2];
|
|
||||||
assert!(!e2.is_unused());
|
|
||||||
|
|
||||||
self.edit(|_| {
|
|
||||||
table[0x40] = e0;
|
|
||||||
table[KERNEL_P2_INDEX].set(e1.frame(), EF::VALID | EF::GLOBAL);
|
|
||||||
// for larger heap memroy
|
|
||||||
table[KERNEL_P2_INDEX + 1].set(e2.frame(), EF::VALID | EF::GLOBAL);
|
|
||||||
table[KERNEL_P2_INDEX + 2].set(e3.frame(), EF::VALID | EF::GLOBAL);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for InactivePageTable0 {
|
impl Drop for InactivePageTable0 {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!("PageTable dropping: {:?}", self);
|
info!("PageTable dropping: {:?}", self);
|
||||||
Self::dealloc_frame(self.p2_frame.start_address().as_u32() as usize);
|
dealloc_frame(self.p2_frame.start_address().as_u32() as usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use bit_allocator::{BitAlloc, BitAlloc64K};
|
|
||||||
// Depends on kernel
|
// Depends on kernel
|
||||||
use crate::memory::{active_table, alloc_frame, dealloc_frame};
|
use crate::memory::{active_table, alloc_frame, dealloc_frame};
|
||||||
use spin::{Mutex, MutexGuard};
|
use spin::{Mutex, MutexGuard};
|
||||||
@ -44,9 +43,7 @@ pub struct ActivePageTable(RecursivePageTable<'static>);
|
|||||||
pub struct PageEntry(PageTableEntry);
|
pub struct PageEntry(PageTableEntry);
|
||||||
|
|
||||||
impl PageTable for ActivePageTable {
|
impl PageTable for ActivePageTable {
|
||||||
type Entry = PageEntry;
|
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
|
||||||
|
|
||||||
fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry {
|
|
||||||
let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE;
|
let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE;
|
||||||
self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, &mut FrameAllocatorForX86)
|
self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, &mut FrameAllocatorForX86)
|
||||||
.unwrap().flush();
|
.unwrap().flush();
|
||||||
@ -58,44 +55,21 @@ impl PageTable for ActivePageTable {
|
|||||||
flush.flush();
|
flush.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_entry(&mut self, addr: usize) -> Option<&mut PageEntry> {
|
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))) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: usize) -> &'b mut [u8] {
|
|
||||||
use core::slice;
|
|
||||||
unsafe { slice::from_raw_parts_mut((addr & !0xfffusize) as *mut u8, PAGE_SIZE) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, addr: usize) -> u8 {
|
|
||||||
unsafe { *(addr as *const u8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, addr: usize, data: u8) {
|
|
||||||
unsafe { *(addr as *mut u8) = data; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PageTableExt for ActivePageTable {}
|
||||||
|
|
||||||
impl ActivePageTable {
|
impl ActivePageTable {
|
||||||
pub unsafe fn new() -> Self {
|
pub unsafe fn new() -> Self {
|
||||||
ActivePageTable(RecursivePageTable::new(&mut *(0xffffffff_fffff000 as *mut _)).unwrap())
|
ActivePageTable(RecursivePageTable::new(&mut *(0xffffffff_fffff000 as *mut _)).unwrap())
|
||||||
}
|
}
|
||||||
fn with_temporary_map(&mut self, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut x86PageTable)) {
|
|
||||||
// Create a temporary page
|
|
||||||
let page = Page::of_addr(0xcafebabe);
|
|
||||||
assert!(self.0.translate_page(page).is_none(), "temporary page is already mapped");
|
|
||||||
// Map it to table
|
|
||||||
self.map(page.start_address().as_u64() as usize, frame.start_address().as_u64() as usize);
|
|
||||||
// Call f
|
|
||||||
let table = unsafe { &mut *page.start_address().as_mut_ptr() };
|
|
||||||
f(self, table);
|
|
||||||
// Unmap the page
|
|
||||||
self.unmap(0xcafebabe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entry for PageEntry {
|
impl Entry for PageEntry {
|
||||||
@ -166,16 +140,10 @@ pub struct InactivePageTable0 {
|
|||||||
impl InactivePageTable for InactivePageTable0 {
|
impl InactivePageTable for InactivePageTable0 {
|
||||||
type Active = ActivePageTable;
|
type Active = ActivePageTable;
|
||||||
|
|
||||||
fn new() -> Self {
|
|
||||||
let mut pt = Self::new_bare();
|
|
||||||
pt.map_kernel();
|
|
||||||
pt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_bare() -> Self {
|
fn new_bare() -> Self {
|
||||||
let frame = Self::alloc_frame().map(|target| Frame::of_addr(target))
|
let target = alloc_frame().expect("failed to allocate frame");
|
||||||
.expect("failed to allocate frame");
|
let frame = Frame::of_addr(target);
|
||||||
active_table().with_temporary_map(&frame, |_, table: &mut x86PageTable| {
|
active_table().with_temporary_map(target, |_, table: &mut x86PageTable| {
|
||||||
table.zero();
|
table.zero();
|
||||||
// set up recursive mapping for the table
|
// set up recursive mapping for the table
|
||||||
table[511].set_frame(frame.clone(), EF::PRESENT | EF::WRITABLE);
|
table[511].set_frame(frame.clone(), EF::PRESENT | EF::WRITABLE);
|
||||||
@ -183,61 +151,6 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
InactivePageTable0 { p4_frame: frame }
|
InactivePageTable0 { p4_frame: frame }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) {
|
|
||||||
active_table().with_temporary_map(&Cr3::read().0, |active_table, p4_table: &mut x86PageTable| {
|
|
||||||
let backup = p4_table[0o777].clone();
|
|
||||||
|
|
||||||
// overwrite recursive mapping
|
|
||||||
p4_table[0o777].set_frame(self.p4_frame.clone(), EF::PRESENT | EF::WRITABLE);
|
|
||||||
tlb::flush_all();
|
|
||||||
|
|
||||||
// execute f in the new context
|
|
||||||
f(active_table);
|
|
||||||
|
|
||||||
// restore recursive mapping to original p4 table
|
|
||||||
p4_table[0o777] = backup;
|
|
||||||
tlb::flush_all();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn activate(&self) {
|
|
||||||
let old_frame = Cr3::read().0;
|
|
||||||
let new_frame = self.p4_frame.clone();
|
|
||||||
debug!("switch table {:?} -> {:?}", old_frame, new_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
Cr3::write(new_frame, Cr3Flags::empty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
|
|
||||||
let old_frame = Cr3::read().0;
|
|
||||||
let new_frame = self.p4_frame.clone();
|
|
||||||
debug!("switch table {:?} -> {:?}", old_frame, new_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
Cr3::write(new_frame, Cr3Flags::empty());
|
|
||||||
}
|
|
||||||
let ret = f();
|
|
||||||
debug!("switch table {:?} -> {:?}", new_frame, old_frame);
|
|
||||||
if old_frame != new_frame {
|
|
||||||
Cr3::write(old_frame, Cr3Flags::empty());
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn token(&self) -> usize {
|
|
||||||
self.p4_frame.start_address().as_u64() as usize // as CR3
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloc_frame() -> Option<usize> {
|
|
||||||
alloc_frame()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dealloc_frame(target: usize) {
|
|
||||||
dealloc_frame(target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InactivePageTable0 {
|
|
||||||
fn map_kernel(&mut self) {
|
fn map_kernel(&mut self) {
|
||||||
let mut table = unsafe { &mut *(0xffffffff_fffff000 as *mut x86PageTable) };
|
let mut table = unsafe { &mut *(0xffffffff_fffff000 as *mut x86PageTable) };
|
||||||
// Kernel at 0xffff_ff00_0000_0000
|
// Kernel at 0xffff_ff00_0000_0000
|
||||||
@ -249,12 +162,47 @@ impl InactivePageTable0 {
|
|||||||
table[175].set_addr(estack.addr(), estack.flags() | EF::GLOBAL);
|
table[175].set_addr(estack.addr(), estack.flags() | EF::GLOBAL);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn token(&self) -> usize {
|
||||||
|
self.p4_frame.start_address().as_u64() as usize // as CR3
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_token(token: usize) {
|
||||||
|
Cr3::write(Frame::containing_address(PhysAddr::new(token as u64)), Cr3Flags::empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active_token() -> usize {
|
||||||
|
Cr3::read().0.start_address().as_u64() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_tlb() {
|
||||||
|
tlb::flush_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
|
||||||
|
let target = Cr3::read().0.start_address().as_u64() as usize;
|
||||||
|
active_table().with_temporary_map(target, |active_table, p4_table: &mut x86PageTable| {
|
||||||
|
let backup = p4_table[0o777].clone();
|
||||||
|
|
||||||
|
// overwrite recursive mapping
|
||||||
|
p4_table[0o777].set_frame(self.p4_frame.clone(), EF::PRESENT | EF::WRITABLE);
|
||||||
|
tlb::flush_all();
|
||||||
|
|
||||||
|
// execute f in the new context
|
||||||
|
let ret = f(active_table);
|
||||||
|
|
||||||
|
// restore recursive mapping to original p4 table
|
||||||
|
p4_table[0o777] = backup;
|
||||||
|
tlb::flush_all();
|
||||||
|
ret
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for InactivePageTable0 {
|
impl Drop for InactivePageTable0 {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!("PageTable dropping: {:?}", self);
|
info!("PageTable dropping: {:?}", self);
|
||||||
Self::dealloc_frame(self.p4_frame.start_address().as_u64() as usize);
|
dealloc_frame(self.p4_frame.start_address().as_u64() as usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use crate::consts::MEMORY_OFFSET;
|
|||||||
use super::HEAP_ALLOCATOR;
|
use super::HEAP_ALLOCATOR;
|
||||||
use ucore_memory::{*, paging::PageTable};
|
use ucore_memory::{*, paging::PageTable};
|
||||||
use ucore_memory::cow::CowExt;
|
use ucore_memory::cow::CowExt;
|
||||||
pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, InactivePageTable};
|
pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, handler::*};
|
||||||
use ucore_memory::swap::*;
|
use ucore_memory::swap::*;
|
||||||
use crate::process::{process};
|
use crate::process::{process};
|
||||||
use crate::sync::{SpinNoIrqLock, SpinNoIrq, MutexGuard};
|
use crate::sync::{SpinNoIrqLock, SpinNoIrq, MutexGuard};
|
||||||
@ -46,33 +46,29 @@ pub fn active_table() -> MutexGuard<'static, CowExt<ActivePageTable>, SpinNoIrq>
|
|||||||
ACTIVE_TABLE.lock()
|
ACTIVE_TABLE.lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page table for swap in and out
|
|
||||||
lazy_static!{
|
#[derive(Debug, Clone, Copy)]
|
||||||
static ref ACTIVE_TABLE_SWAP: SpinNoIrqLock<SwapExt<ActivePageTable, fifo::FifoSwapManager, mock_swapper::MockSwapper>> =
|
pub struct GlobalFrameAlloc;
|
||||||
SpinNoIrqLock::new(unsafe{SwapExt::new(ActivePageTable::new(), fifo::FifoSwapManager::default(), mock_swapper::MockSwapper::default())});
|
|
||||||
|
impl FrameAllocator for GlobalFrameAlloc {
|
||||||
|
fn alloc(&self) -> Option<usize> {
|
||||||
|
// get the real address of the alloc frame
|
||||||
|
let ret = FRAME_ALLOCATOR.lock().alloc().map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
|
||||||
|
trace!("Allocate frame: {:x?}", ret);
|
||||||
|
ret
|
||||||
|
// TODO: try to swap out when alloc failed
|
||||||
|
}
|
||||||
|
fn dealloc(&self, target: usize) {
|
||||||
|
trace!("Deallocate frame: {:x}", target);
|
||||||
|
FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_table_swap() -> MutexGuard<'static, SwapExt<ActivePageTable, fifo::FifoSwapManager, mock_swapper::MockSwapper>, SpinNoIrq>{
|
|
||||||
ACTIVE_TABLE_SWAP.lock()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief:
|
|
||||||
* allocate a free physical frame, if no free frame, then swap out one page and reture mapped frame as the free one
|
|
||||||
* @retval:
|
|
||||||
* the physical address for the allocated frame
|
|
||||||
*/
|
|
||||||
pub fn alloc_frame() -> Option<usize> {
|
pub fn alloc_frame() -> Option<usize> {
|
||||||
// get the real address of the alloc frame
|
GlobalFrameAlloc.alloc()
|
||||||
let ret = FRAME_ALLOCATOR.lock().alloc().map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
|
|
||||||
trace!("Allocate frame: {:x?}", ret);
|
|
||||||
//do we need : unsafe { ACTIVE_TABLE_SWAP.force_unlock(); } ???
|
|
||||||
Some(ret.unwrap_or_else(|| active_table_swap().swap_out_any::<InactivePageTable0>().ok().expect("fail to swap out page")))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dealloc_frame(target: usize) {
|
pub fn dealloc_frame(target: usize) {
|
||||||
trace!("Deallocate frame: {:x}", target);
|
GlobalFrameAlloc.dealloc(target);
|
||||||
FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KernelStack(usize);
|
pub struct KernelStack(usize);
|
||||||
@ -97,44 +93,12 @@ impl Drop for KernelStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/// Handle page fault at `addr`.
|
||||||
* @param:
|
/// Return true to continue, false to halt.
|
||||||
* addr: the virtual address of the page fault
|
|
||||||
* @brief:
|
|
||||||
* handle page fault
|
|
||||||
* @retval:
|
|
||||||
* Return true to continue, false to halt
|
|
||||||
*/
|
|
||||||
#[cfg(not(feature = "no_mmu"))]
|
#[cfg(not(feature = "no_mmu"))]
|
||||||
pub fn page_fault_handler(addr: usize) -> bool {
|
pub fn page_fault_handler(addr: usize) -> bool {
|
||||||
info!("start handling swap in/out page fault");
|
info!("start handling swap in/out page fault");
|
||||||
//unsafe { ACTIVE_TABLE_SWAP.force_unlock(); }
|
process().memory_set.page_fault_handler(addr)
|
||||||
|
|
||||||
/*LAB3 EXERCISE 1: YOUR STUDENT NUMBER
|
|
||||||
* handle the frame deallocated
|
|
||||||
*/
|
|
||||||
|
|
||||||
info!("get pt from processor()");
|
|
||||||
if process().memory_set.find_area(addr).is_none(){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pt = process().memory_set.get_page_table_mut();
|
|
||||||
info!("pt got");
|
|
||||||
if active_table_swap().page_fault_handler(pt as *mut InactivePageTable0, addr, true, || alloc_frame().expect("fail to alloc frame")){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
// Handle copy on write (not being used now)
|
|
||||||
/*
|
|
||||||
unsafe { ACTIVE_TABLE.force_unlock(); }
|
|
||||||
if active_table().page_fault_handler(addr, || alloc_frame().expect("fail to alloc frame")){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_heap() {
|
pub fn init_heap() {
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
use crate::arch::interrupt::{TrapFrame, Context as ArchContext};
|
use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::Vec};
|
||||||
use crate::memory::{MemoryArea, MemoryAttr, MemorySet, KernelStack, active_table_swap, alloc_frame, InactivePageTable0};
|
|
||||||
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type, SegmentData}};
|
use log::*;
|
||||||
use core::fmt::{Debug, Error, Formatter};
|
|
||||||
use alloc::{boxed::Box, collections::BTreeMap, vec::Vec, sync::Arc, string::String};
|
|
||||||
use ucore_memory::{Page};
|
|
||||||
use ucore_memory::memory_set::*;
|
|
||||||
use ucore_process::Context;
|
|
||||||
use simple_filesystem::file::File;
|
use simple_filesystem::file::File;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use log::*;
|
use ucore_process::Context;
|
||||||
|
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, SegmentData, Type}};
|
||||||
|
|
||||||
|
use crate::arch::interrupt::{Context as ArchContext, TrapFrame};
|
||||||
|
use crate::memory::{ByFrame, Delay, FrameAllocator, GlobalFrameAlloc, KernelStack, MemoryArea, MemoryAttr, MemorySet};
|
||||||
|
|
||||||
// TODO: avoid pub
|
// TODO: avoid pub
|
||||||
pub struct ContextImpl {
|
pub struct Process {
|
||||||
pub arch: ArchContext,
|
pub arch: ArchContext,
|
||||||
pub memory_set: MemorySet,
|
pub memory_set: MemorySet,
|
||||||
pub kstack: KernelStack,
|
pub kstack: KernelStack,
|
||||||
@ -20,17 +18,17 @@ pub struct ContextImpl {
|
|||||||
pub cwd: String,
|
pub cwd: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context for ContextImpl {
|
impl Context for Process {
|
||||||
unsafe fn switch_to(&mut self, target: &mut Context) {
|
unsafe fn switch_to(&mut self, target: &mut Context) {
|
||||||
use core::mem::transmute;
|
use core::mem::transmute;
|
||||||
let (target, _): (&mut ContextImpl, *const ()) = transmute(target);
|
let (target, _): (&mut Process, *const ()) = transmute(target);
|
||||||
self.arch.switch(&mut target.arch);
|
self.arch.switch(&mut target.arch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextImpl {
|
impl Process {
|
||||||
pub unsafe fn new_init() -> Box<Context> {
|
pub unsafe fn new_init() -> Box<Context> {
|
||||||
Box::new(ContextImpl {
|
Box::new(Process {
|
||||||
arch: ArchContext::null(),
|
arch: ArchContext::null(),
|
||||||
memory_set: MemorySet::new(),
|
memory_set: MemorySet::new(),
|
||||||
kstack: KernelStack::new(),
|
kstack: KernelStack::new(),
|
||||||
@ -42,7 +40,7 @@ impl ContextImpl {
|
|||||||
pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
|
pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
|
||||||
let memory_set = MemorySet::new();
|
let memory_set = MemorySet::new();
|
||||||
let kstack = KernelStack::new();
|
let kstack = KernelStack::new();
|
||||||
Box::new(ContextImpl {
|
Box::new(Process {
|
||||||
arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) },
|
arch: unsafe { ArchContext::new_kernel_thread(entry, arg, kstack.top(), memory_set.token()) },
|
||||||
memory_set,
|
memory_set,
|
||||||
kstack,
|
kstack,
|
||||||
@ -52,7 +50,7 @@ impl ContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make a new user thread from ELF data
|
/// Make a new user thread from ELF data
|
||||||
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<ContextImpl>
|
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<Process>
|
||||||
where Iter: Iterator<Item=&'a str>
|
where Iter: Iterator<Item=&'a str>
|
||||||
{
|
{
|
||||||
// Parse elf
|
// Parse elf
|
||||||
@ -82,7 +80,7 @@ impl ContextImpl {
|
|||||||
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),
|
||||||
};
|
};
|
||||||
memory_set.push(MemoryArea::new(ustack_buttom, ustack_top, MemoryAttr::default().user(), "user_stack"));
|
memory_set.push(ustack_buttom, ustack_top, ByFrame::new(MemoryAttr::default().user(), GlobalFrameAlloc), "user_stack");
|
||||||
ustack_top
|
ustack_top
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_mmu")]
|
#[cfg(feature = "no_mmu")]
|
||||||
@ -96,10 +94,7 @@ impl ContextImpl {
|
|||||||
|
|
||||||
let kstack = KernelStack::new();
|
let kstack = KernelStack::new();
|
||||||
|
|
||||||
//set the user Memory pages in the memory set swappable
|
Box::new(Process {
|
||||||
memory_set_map_swappable(&mut memory_set);
|
|
||||||
|
|
||||||
Box::new(ContextImpl {
|
|
||||||
arch: unsafe {
|
arch: unsafe {
|
||||||
ArchContext::new_user_thread(
|
ArchContext::new_user_thread(
|
||||||
entry_addr, ustack_top, kstack.top(), is32, memory_set.token())
|
entry_addr, ustack_top, kstack.top(), is32, memory_set.token())
|
||||||
@ -131,10 +126,7 @@ impl ContextImpl {
|
|||||||
info!("temporary copy data!");
|
info!("temporary copy data!");
|
||||||
let kstack = KernelStack::new();
|
let kstack = KernelStack::new();
|
||||||
|
|
||||||
memory_set_map_swappable(&mut memory_set);
|
Box::new(Process {
|
||||||
info!("FORK() finsihed!");
|
|
||||||
|
|
||||||
Box::new(ContextImpl {
|
|
||||||
arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) },
|
arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) },
|
||||||
memory_set,
|
memory_set,
|
||||||
kstack,
|
kstack,
|
||||||
@ -144,33 +136,6 @@ impl ContextImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_mmu"))]
|
|
||||||
impl Drop for ContextImpl {
|
|
||||||
fn drop(&mut self){
|
|
||||||
info!("come in to drop for ContextImpl");
|
|
||||||
//set the user Memory pages in the memory set unswappable
|
|
||||||
let Self {ref mut arch, ref mut memory_set, ref mut kstack, ..} = self;
|
|
||||||
let pt = {
|
|
||||||
memory_set.get_page_table_mut() as *mut InactivePageTable0
|
|
||||||
};
|
|
||||||
for area in memory_set.iter(){
|
|
||||||
for page in Page::range_of(area.get_start_addr(), area.get_end_addr()) {
|
|
||||||
let addr = page.start_address();
|
|
||||||
unsafe {
|
|
||||||
active_table_swap().remove_from_swappable(pt, addr, || alloc_frame().expect("alloc frame failed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug!("Finishing setting pages unswappable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for ContextImpl {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "{:x?}", self.arch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Push a slice at the stack. Return the new sp.
|
/// Push a slice at the stack. Return the new sp.
|
||||||
unsafe fn push_slice<T: Copy>(mut sp: usize, vs: &[T]) -> usize {
|
unsafe fn push_slice<T: Copy>(mut sp: usize, vs: &[T]) -> usize {
|
||||||
use core::{mem::{size_of, align_of}, slice};
|
use core::{mem::{size_of, align_of}, slice};
|
||||||
@ -200,7 +165,7 @@ unsafe fn push_args_at_stack<'a, Iter>(args: Iter, stack_top: usize) -> usize
|
|||||||
|
|
||||||
/// Generate a MemorySet according to the ELF file.
|
/// Generate a MemorySet according to the ELF file.
|
||||||
/// Also return the real entry point address.
|
/// Also return the real entry point address.
|
||||||
fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> (MemorySet, usize) {
|
fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) {
|
||||||
debug!("come in to memory_set_from");
|
debug!("come in to memory_set_from");
|
||||||
let mut ms = MemorySet::new();
|
let mut ms = MemorySet::new();
|
||||||
let mut entry = None;
|
let mut entry = None;
|
||||||
@ -221,7 +186,7 @@ fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> (MemorySet, usize) {
|
|||||||
let target = ms.push(mem_size);
|
let target = ms.push(mem_size);
|
||||||
#[cfg(not(feature = "no_mmu"))]
|
#[cfg(not(feature = "no_mmu"))]
|
||||||
let target = {
|
let target = {
|
||||||
ms.push(MemoryArea::new(virt_addr, virt_addr + mem_size, memory_attr_from(ph.flags()), ""));
|
ms.push(virt_addr, virt_addr + mem_size, ByFrame::new(memory_attr_from(ph.flags()), 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
|
||||||
@ -248,29 +213,3 @@ fn memory_attr_from(elf_flags: Flags) -> MemoryAttr {
|
|||||||
if elf_flags.is_execute() { flags = flags.execute(); }
|
if elf_flags.is_execute() { flags = flags.execute(); }
|
||||||
flags
|
flags
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @param:
|
|
||||||
* memory_set: the target MemorySet to set swappable
|
|
||||||
* @brief:
|
|
||||||
* map the memory area in the memory_set swappalbe, specially for the user process
|
|
||||||
*/
|
|
||||||
#[cfg(not(feature = "no_mmu"))]
|
|
||||||
pub fn memory_set_map_swappable(memory_set: &mut MemorySet) {
|
|
||||||
info!("COME INTO memory set map swappable!");
|
|
||||||
let pt = unsafe {
|
|
||||||
memory_set.get_page_table_mut() as *mut InactivePageTable0
|
|
||||||
};
|
|
||||||
for area in memory_set.iter(){
|
|
||||||
for page in Page::range_of(area.get_start_addr(), area.get_end_addr()) {
|
|
||||||
let addr = page.start_address();
|
|
||||||
unsafe { active_table_swap().set_swappable(pt, addr); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info!("Finishing setting pages swappable");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "no_mmu")]
|
|
||||||
pub fn memory_set_map_swappable(memory_set: &mut MemorySet) {
|
|
||||||
// NOTE: This function may disappear after refactor memory crate
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
pub use self::context::ContextImpl;
|
pub use self::context::Process;
|
||||||
pub use ucore_process::*;
|
pub use ucore_process::*;
|
||||||
use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM};
|
use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM};
|
||||||
use crate::arch::cpu;
|
use crate::arch::cpu;
|
||||||
@ -17,15 +17,18 @@ pub fn init() {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
for cpu_id in 0..MAX_CPU_NUM {
|
for cpu_id in 0..MAX_CPU_NUM {
|
||||||
PROCESSORS[cpu_id].init(cpu_id, ContextImpl::new_init(), manager.clone());
|
PROCESSORS[cpu_id].init(cpu_id, Process::new_init(), manager.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add idle threads
|
||||||
extern fn idle(_arg: usize) -> ! {
|
extern fn idle(_arg: usize) -> ! {
|
||||||
loop { cpu::halt(); }
|
loop { cpu::halt(); }
|
||||||
}
|
}
|
||||||
for i in 0..4 {
|
use core::str::FromStr;
|
||||||
manager.add(ContextImpl::new_kernel(idle, i), 0);
|
let cores = usize::from_str(env!("SMP")).unwrap();
|
||||||
|
for i in 0..cores {
|
||||||
|
manager.add(Process::new_kernel(idle, i), 0);
|
||||||
}
|
}
|
||||||
crate::shell::run_user_shell();
|
crate::shell::run_user_shell();
|
||||||
|
|
||||||
@ -35,9 +38,11 @@ pub fn init() {
|
|||||||
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 thread struct
|
/// Get current thread struct
|
||||||
pub fn process() -> &'static mut ContextImpl {
|
///
|
||||||
|
/// FIXME: It's obviously unsafe to get &mut !
|
||||||
|
pub fn process() -> &'static mut Process {
|
||||||
use core::mem::transmute;
|
use core::mem::transmute;
|
||||||
let (process, _): (&mut ContextImpl, *const ()) = unsafe {
|
let (process, _): (&mut Process, *const ()) = unsafe {
|
||||||
transmute(processor().context())
|
transmute(processor().context())
|
||||||
};
|
};
|
||||||
process
|
process
|
||||||
@ -53,5 +58,5 @@ 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 fn(usize) -> !, arg: usize) -> Box<Context> {
|
||||||
ContextImpl::new_kernel(entry, arg)
|
Process::new_kernel(entry, arg)
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,12 @@ use crate::process::*;
|
|||||||
|
|
||||||
pub fn run_user_shell() {
|
pub fn run_user_shell() {
|
||||||
if let Ok(inode) = ROOT_INODE.lookup("sh") {
|
if let Ok(inode) = ROOT_INODE.lookup("sh") {
|
||||||
|
println!("Going to user mode shell.");
|
||||||
|
println!("Use 'ls' to list available programs.");
|
||||||
let data = inode.read_as_vec().unwrap();
|
let data = inode.read_as_vec().unwrap();
|
||||||
processor().manager().add(ContextImpl::new_user(data.as_slice(), "sh".split(' ')), 0);
|
processor().manager().add(Process::new_user(data.as_slice(), "sh".split(' ')), 0);
|
||||||
} else {
|
} else {
|
||||||
processor().manager().add(ContextImpl::new_kernel(shell, 0), 0);
|
processor().manager().add(Process::new_kernel(shell, 0), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ pub extern fn shell(_arg: usize) -> ! {
|
|||||||
let name = cmd.split(' ').next().unwrap();
|
let name = cmd.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(ContextImpl::new_user(data.as_slice(), cmd.split(' ')), thread::current().id());
|
let pid = processor().manager().add(Process::new_user(data.as_slice(), cmd.split(' ')), thread::current().id());
|
||||||
unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
|
unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
|
||||||
} else {
|
} else {
|
||||||
println!("Program not exist");
|
println!("Program not exist");
|
||||||
|
@ -208,7 +208,7 @@ fn sys_exec(name: *const u8, argc: usize, argv: *const *const u8, tf: &mut TrapF
|
|||||||
|
|
||||||
// Make new Context
|
// Make new Context
|
||||||
let iter = args.iter().map(|s| s.as_str());
|
let iter = args.iter().map(|s| s.as_str());
|
||||||
let mut context = ContextImpl::new_user(buf.as_slice(), iter);
|
let mut context = Process::new_user(buf.as_slice(), iter);
|
||||||
|
|
||||||
// Activate new page table
|
// Activate new page table
|
||||||
unsafe { context.memory_set.activate(); }
|
unsafe { context.memory_set.activate(); }
|
||||||
|
Loading…
Reference in New Issue
Block a user