Add comments in ch6

This commit is contained in:
hypocrasy 2022-04-30 16:04:58 +08:00
parent cea2febe35
commit f9346edad1
35 changed files with 374 additions and 116 deletions

View file

@ -1,3 +1,4 @@
//! Implementation of [`PageTableEntry`] and [`PageTable`].
use super::{frame_alloc, FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
use alloc::string::String;
use alloc::vec;
@ -19,39 +20,49 @@ bitflags! {
#[derive(Copy, Clone)]
#[repr(C)]
/// page table entry structure
pub struct PageTableEntry {
///PTE
pub bits: usize,
}
impl PageTableEntry {
///Create a PTE from ppn
pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self {
PageTableEntry {
bits: ppn.0 << 10 | flags.bits as usize,
}
}
///Return an empty PTE
pub fn empty() -> Self {
PageTableEntry { bits: 0 }
}
///Return 44bit ppn
pub fn ppn(&self) -> PhysPageNum {
(self.bits >> 10 & ((1usize << 44) - 1)).into()
}
///Return 10bit flag
pub fn flags(&self) -> PTEFlags {
PTEFlags::from_bits(self.bits as u8).unwrap()
}
///Check PTE valid
pub fn is_valid(&self) -> bool {
(self.flags() & PTEFlags::V) != PTEFlags::empty()
}
///Check PTE readable
pub fn readable(&self) -> bool {
(self.flags() & PTEFlags::R) != PTEFlags::empty()
}
///Check PTE writable
pub fn writable(&self) -> bool {
(self.flags() & PTEFlags::W) != PTEFlags::empty()
}
///Check PTE executable
pub fn executable(&self) -> bool {
(self.flags() & PTEFlags::X) != PTEFlags::empty()
}
}
///Record root ppn and has the same lifetime as 1 and 2 level `PageTableEntry`
pub struct PageTable {
root_ppn: PhysPageNum,
frames: Vec<FrameTracker>,
@ -59,6 +70,7 @@ pub struct PageTable {
/// Assume that it won't oom when creating/mapping.
impl PageTable {
/// Create an empty `PageTable`
pub fn new() -> Self {
let frame = frame_alloc().unwrap();
PageTable {
@ -73,6 +85,7 @@ impl PageTable {
frames: Vec::new(),
}
}
/// Find phsical address by virtual address, create a frame if not exist
fn find_pte_create(&mut self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
let idxs = vpn.indexes();
let mut ppn = self.root_ppn;
@ -92,6 +105,7 @@ impl PageTable {
}
result
}
/// Find phsical address by virtual address
fn find_pte(&self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
let idxs = vpn.indexes();
let mut ppn = self.root_ppn;
@ -110,20 +124,24 @@ impl PageTable {
result
}
#[allow(unused)]
/// Create a mapping form `vpn` to `ppn`
pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
let pte = self.find_pte_create(vpn).unwrap();
assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
*pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
}
#[allow(unused)]
/// Delete a mapping form `vpn`
pub fn unmap(&mut self, vpn: VirtPageNum) {
let pte = self.find_pte(vpn).unwrap();
assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
*pte = PageTableEntry::empty();
}
/// Translate `VirtPageNum` to `PageTableEntry`
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
self.find_pte(vpn).map(|pte| *pte)
}
/// Translate `VirtAddr` to `PhysAddr`
pub fn translate_va(&self, va: VirtAddr) -> Option<PhysAddr> {
self.find_pte(va.clone().floor()).map(|pte| {
let aligned_pa: PhysAddr = pte.ppn().into();
@ -132,12 +150,13 @@ impl PageTable {
(aligned_pa_usize + offset).into()
})
}
/// Get root ppn
pub fn token(&self) -> usize {
8usize << 60 | self.root_ppn.0
}
}
pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> {
/// Translate a pointer to a mutable u8 Vec through page table
pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> {
let page_table = PageTable::from_token(token);
let mut start = ptr as usize;
let end = start + len;
@ -159,7 +178,7 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
v
}
/// Load a string from other address spaces into kernel space without an end `\0`.
/// Translate a pointer to a mutable u8 Vec end with `\0` through page table to a `String`
pub fn translated_str(token: usize, ptr: *const u8) -> String {
let page_table = PageTable::from_token(token);
let mut string = String::new();
@ -179,6 +198,7 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String {
}
#[allow(unused)]
///Translate a generic through page table and return a reference
pub fn translated_ref<T>(token: usize, ptr: *const T) -> &'static T {
let page_table = PageTable::from_token(token);
page_table
@ -186,7 +206,7 @@ pub fn translated_ref<T>(token: usize, ptr: *const T) -> &'static T {
.unwrap()
.get_ref()
}
///Translate a generic through page table and return a mutable reference
pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
let page_table = PageTable::from_token(token);
let va = ptr as usize;
@ -195,15 +215,18 @@ pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
.unwrap()
.get_mut()
}
///Array of u8 slice that user communicate with os
pub struct UserBuffer {
///U8 vec
pub buffers: Vec<&'static mut [u8]>,
}
impl UserBuffer {
///Create a `UserBuffer` by parameter
pub fn new(buffers: Vec<&'static mut [u8]>) -> Self {
Self { buffers }
}
///Length of `UserBuffer`
pub fn len(&self) -> usize {
let mut total: usize = 0;
for b in self.buffers.iter() {
@ -224,7 +247,7 @@ impl IntoIterator for UserBuffer {
}
}
}
/// Iterator of `UserBuffer`
pub struct UserBufferIterator {
buffers: Vec<&'static mut [u8]>,
current_buffer: usize,