1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-22 16:16:16 +04:00

Finish add more comment for kernel and finish set user memory swappable.

This commit is contained in:
lcy1996 2018-10-23 00:00:09 +08:00
parent 0a81014007
commit 63349ade19
6 changed files with 137 additions and 34 deletions

View File

@ -13,7 +13,7 @@ use core::ops::Range;
/// alloc: allocate a free bit.
/// dealloc: free an allocated bit.
///
/// insert: mark bits in the range as allocated
/// insert: mark bits in the range as allocated (available)
/// remove: reverse of insert
///
/// any: whether there are free bits remaining
@ -38,7 +38,7 @@ pub type BitAlloc256M = BitAllocCascade16<BitAlloc16M>;
/// Implement the bit allocator by segment tree algorithm.
#[derive(Default)]
pub struct BitAllocCascade16<T: BitAlloc> {
bitset: u16,
bitset: u16, // for each bit, 1 indicates available, 0 indicates inavailable
sub: [T; 16],
}

View File

@ -20,7 +20,7 @@ pub trait InactivePageTable {
*/
fn new() -> Self;
/*
** @brief create a inactive page table without kernel memory mapped
** @brief create an inactive page table without kernel memory mapped
** @retval InactivePageTable the created inactive page table
*/
fn new_bare() -> Self;
@ -180,7 +180,7 @@ impl MemoryArea {
}
}
/*
** @brief map the memory area from the physice address in a page table
** @brief unmap the memory area from the physice address in a page table
** @param pt: &mut T::Active the page table to use
** @retval none
*/
@ -194,6 +194,14 @@ impl MemoryArea {
pt.unmap(addr);
}
}
pub fn get_start_addr(&self) -> VirtAddr {
self.start_addr
}
pub fn get_end_addr(&self) -> VirtAddr{
self.end_addr
}
}
/// The attributes of the memory

View File

@ -98,6 +98,15 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
swapper,
}
}
/*
** @brief set a virtual address (a page) swappable
** @param addr: VirtAddr the target page's virtual address
*/
pub fn set_swappable(&mut self, addr: VirtAddr){
self.swap_manager.push(addr);
}
/*
** @brief map the virtual address to a target physics address as swappable
** @param addr: VirtAddr the virual address to map
@ -180,12 +189,13 @@ impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
** of beginning of the page
** @retval bool whether swap in happens.
*/
pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> Option<PhysAddr>) -> bool {
pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool {
if !self.page_table.get_entry(addr).swapped() {
return false;
}
// Allocate a frame, if failed, swap out a page
let frame = alloc_frame().unwrap_or_else(|| self.swap_out_any().ok().unwrap());
//let frame = alloc_frame().unwrap_or_else(|| self.swap_out_any().ok().unwrap());
let frame = alloc_frame();
self.swap_in(addr, frame).ok().unwrap();
true
}
@ -220,7 +230,7 @@ impl<T: PageTable, M: SwapManager, S: Swapper> DerefMut for SwapExt<T, M, S> {
mod test {
use super::*;
use super::mock_swapper::MockSwapper;
use alloc::{arc::Arc, boxed::Box};
use alloc::{sync::Arc, boxed::Box};
use core::cell::RefCell;
use paging::MockPageTable;

View File

@ -58,6 +58,7 @@ impl PageTable for ActivePageTable {
let page = Page::of_addr(VirtAddr::new(addr));
let frame = Frame::of_addr(PhysAddr::new(target as u32));
// map the page to the frame using FrameAllocatorForRiscv
// we may need frame allocator to alloc frame for new page table(first/second)
self.0.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
.unwrap().flush();
self.get_entry(addr)
@ -135,6 +136,14 @@ impl ActivePageTable {
pub unsafe fn new() -> Self {
ActivePageTable(RecursivePageTable::new(&mut *ROOT_PAGE_TABLE).unwrap())
}
/*
* @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));
@ -148,7 +157,7 @@ impl ActivePageTable {
self.unmap(0xcafebabe);
}
}
/// implementation for the Entry trait in /crate/memory/src/paging/mod.rs
impl Entry for PageEntry {
fn update(&mut self) {
let addr = VirtAddr::new((self as *const _ as usize) << 10);
@ -176,8 +185,9 @@ impl Entry for PageEntry {
flags.set(EF::RESERVED2, !writable);
}
fn clear_shared(&mut self) { self.as_flags().remove(EF::RESERVED1 | EF::RESERVED2); }
fn swapped(&self) -> bool { unimplemented!() }
fn set_swapped(&mut self, value: bool) { unimplemented!() }
// valid property must be 0 used when swapped
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 user(&self) -> bool { self.0.flags().contains(EF::USER) }
fn set_user(&mut self, value: bool) { self.as_flags().set(EF::USER, value); }
fn execute(&self) -> bool { self.0.flags().contains(EF::EXECUTABLE) }
@ -198,12 +208,24 @@ pub struct InactivePageTable0 {
impl InactivePageTable for InactivePageTable0 {
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 {
let frame = Self::alloc_frame().map(|target| Frame::of_addr(PhysAddr::new(target as u32)))
.expect("failed to allocate frame");
@ -214,6 +236,12 @@ impl InactivePageTable for InactivePageTable0 {
InactivePageTable0 { p2_frame: frame }
}
/*
* @param:
* f: a function to do something for a muatable activepagetable
* @brief:
* temporarily map the pagetable as an active page and apply f on the it
*/
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) {
active_table().with_temporary_map(&satp::read().frame(), |active_table, p2_table: &mut RvPageTable| {
let backup = p2_table[RECURSIVE_PAGE_PML4].clone();
@ -275,6 +303,10 @@ impl InactivePageTable for InactivePageTable0 {
}
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];

View File

@ -22,26 +22,6 @@ lazy_static! {
pub static ref FRAME_ALLOCATOR: Mutex<FrameAlloc> = Mutex::new(FrameAlloc::default());
}
pub fn alloc_frame() -> Option<usize> {
let ret = FRAME_ALLOCATOR.lock().alloc().map(|id| id * PAGE_SIZE + MEMORY_OFFSET);
trace!("Allocate frame: {:x?}", ret);
ret
}
pub fn dealloc_frame(target: usize) {
trace!("Deallocate frame: {:x}", target);
FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
}
// alloc from heap
pub fn alloc_stack() -> Stack {
use alloc::alloc::{alloc, Layout};
const STACK_SIZE: usize = 0x8000;
let bottom = unsafe{ alloc(Layout::from_size_align(STACK_SIZE, 0x8000).unwrap()) } as usize;
let top = bottom + STACK_SIZE;
Stack { top, bottom }
}
lazy_static! {
static ref ACTIVE_TABLE: Mutex<CowExt<ActivePageTable>> = Mutex::new(unsafe {
CowExt::new(ActivePageTable::new())
@ -63,6 +43,36 @@ pub fn active_table_swap() -> MutexGuard<'static, SwapExt<ActivePageTable, fifo:
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> {
// 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);
//do we need : unsafe { ACTIVE_TABLE_SWAP.force_unlock(); } ???
Some(ret.unwrap_or_else(|| active_table_swap().swap_out_any().ok().unwrap()))
}
pub fn dealloc_frame(target: usize) {
trace!("Deallocate frame: {:x}", target);
FRAME_ALLOCATOR.lock().dealloc((target - MEMORY_OFFSET) / PAGE_SIZE);
}
// alloc from heap
pub fn alloc_stack() -> Stack {
use alloc::alloc::{alloc, Layout};
const STACK_SIZE: usize = 0x8000;
let bottom = unsafe{ alloc(Layout::from_size_align(STACK_SIZE, 0x8000).unwrap()) } as usize;
let top = bottom + STACK_SIZE;
Stack { top, bottom }
}
/*
* @param:
* addr: the virtual address of the page fault
@ -72,14 +82,14 @@ pub fn active_table_swap() -> MutexGuard<'static, SwapExt<ActivePageTable, fifo:
* Return true to continue, false to halt
*/
pub fn page_fault_handler(addr: usize) -> bool {
// Handle copy on write
// Handle copy on write (not being used now)
unsafe { ACTIVE_TABLE.force_unlock(); }
if active_table().page_fault_handler(addr, || alloc_frame().unwrap()){
return true;
}
// handle the swap in/out
unsafe { ACTIVE_TABLE_SWAP.force_unlock(); }
if active_table_swap().page_fault_handler(addr, || alloc_frame()){
if active_table_swap().page_fault_handler(addr, || alloc_frame().unwrap()){
return true;
}
false

View File

@ -1,7 +1,8 @@
use arch::interrupt::{TrapFrame, Context as ArchContext};
use memory::{MemoryArea, MemoryAttr, MemorySet};
use memory::{MemoryArea, MemoryAttr, MemorySet, active_table_swap};
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}};
use core::fmt::{Debug, Error, Formatter};
use ucore_memory::{Page};
pub struct Context {
arch: ArchContext,
@ -9,13 +10,29 @@ pub struct Context {
}
impl ::ucore_process::processor::Context for Context {
/*
* @param:
* target: the target process context
* @brief:
* switch to the target process context
*/
unsafe fn switch(&mut self, target: &mut Self) {
super::PROCESSOR.try().unwrap().force_unlock();
self.arch.switch(&mut target.arch);
use core::mem::forget;
// don't run the distructor of processor()
forget(super::processor());
}
/*
* @param:
* entry: the program entry for the process
* arg: a0 (a parameter)
* @brief:
* new a kernel thread Context
* @retval:
* the new kernel thread Context
*/
fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Self {
let ms = MemorySet::new();
Context {
@ -34,6 +51,14 @@ impl Context {
}
/// Make a new user thread from ELF data
/*
* @param:
* data: the ELF data stream
* @brief:
* make a new thread from ELF data
* @retval:
* the new user thread Context
*/
pub fn new_user(data: &[u8]) -> Self {
// Parse elf
let elf = ElfFile::new(data).expect("failed to read elf");
@ -81,6 +106,15 @@ impl Context {
});
}
//set the user Memory pages in the memory set swappable
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();
active_table_swap().set_swappable(addr);
}
}
info!("finish setting memory swappable.");
Context {
arch: unsafe {
ArchContext::new_user_thread(
@ -123,6 +157,14 @@ impl Debug for Context {
}
}
/*
* @param:
* elf: the source ELF file
* @brief:
* generate a memory set according to the elf file
* @retval:
* the new memory set
*/
fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> MemorySet {
let mut set = MemorySet::new();
for ph in elf.program_iter() {
@ -131,9 +173,10 @@ fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> MemorySet {
}
let (virt_addr, mem_size, flags) = match ph {
ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),//???
};
set.push(MemoryArea::new(virt_addr, virt_addr + mem_size, memory_attr_from(flags), ""));
}
set
}