add: memory area

This commit is contained in:
jackfiled 2024-08-03 20:13:12 +08:00
parent 2bac1464a1
commit bfaf29e5d4
13 changed files with 743 additions and 110 deletions

25
os/Cargo.lock generated
View File

@ -8,6 +8,21 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "buddy_system_allocator"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4e85e760e105b46ae0bd1236578793c6c147ae7463fe95c8350296b8bfcb830"
dependencies = [
"spin 0.7.1",
]
[[package]] [[package]]
name = "critical-section" name = "critical-section"
version = "1.1.2" version = "1.1.2"
@ -30,7 +45,7 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
dependencies = [ dependencies = [
"spin", "spin 0.9.8",
] ]
[[package]] [[package]]
@ -52,6 +67,8 @@ checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
name = "os" name = "os"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"bitflags",
"buddy_system_allocator",
"lazy_static", "lazy_static",
"riscv", "riscv",
"sbi-rt", "sbi-rt",
@ -86,6 +103,12 @@ dependencies = [
"static_assertions", "static_assertions",
] ]
[[package]]
name = "spin"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13287b4da9d1207a4f4929ac390916d64eacfe236a487e9a9f5b3be392be5162"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.9.8" version = "0.9.8"

View File

@ -7,3 +7,5 @@ edition = "2021"
sbi-rt = { version = "0.0.2", features = ["legacy"] } sbi-rt = { version = "0.0.2", features = ["legacy"] }
lazy_static = { version = "1.4.0", features = ["spin_no_std"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
riscv = { version = "0.10.0" } riscv = { version = "0.10.0" }
buddy_system_allocator = {version = "0.6"}
bitflags = {version = "2.6"}

View File

@ -1 +1,5 @@
pub const CLOCK_FREQUENCY: usize = 10000000; pub const CLOCK_FREQUENCY: usize = 10000000;
pub const MEMORY_END: usize = 0x8800_0000;
pub const MMIO: &[(usize, usize)] = &[
(0x0010_0000, 0x00_2000)
];

View File

@ -1,8 +1,17 @@
pub const USER_STACK_SIZE: usize = 4096; pub const USER_STACK_SIZE: usize = 4096;
pub const KERNEL_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
pub const KERNEL_HEAP_SIZE: usize = 0x30_0000;
pub const PAGE_SIZE: usize = 0x1000;
pub const PAGE_SIZE_BITS: usize = 0xc;
pub const MAX_APP_NUM: usize = 4; pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
pub const APP_BASE_ADDRESS: usize = 0x80400000; pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
pub const APP_SIZE_LIMIT: usize = 0x20000;
pub use crate::boards::qemu::CLOCK_FREQUENCY; /// Return (bottom, top) of a kernel stack in kernel space
pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
let bottom = top - KERNEL_STACK_SIZE;
(bottom, top)
}
pub use crate::boards::qemu::{CLOCK_FREQUENCY, MEMORY_END, MMIO};

View File

@ -1,100 +0,0 @@
use crate::config::{
APP_BASE_ADDRESS, APP_SIZE_LIMIT, KERNEL_STACK_SIZE, MAX_APP_NUM, USER_STACK_SIZE,
};
use crate::log_information;
use crate::trap::context::TrapContext;
use core::arch::asm;
#[repr(align(4096))]
#[derive(Copy, Clone)]
struct KernelStack {
data: [u8; KERNEL_STACK_SIZE],
}
#[repr(align(4096))]
#[derive(Copy, Clone)]
struct UserStack {
data: [u8; USER_STACK_SIZE],
}
static KERNEL_STACK: [KernelStack; MAX_APP_NUM] = [KernelStack {
data: [0; KERNEL_STACK_SIZE],
}; MAX_APP_NUM];
static USER_STACK: [UserStack; MAX_APP_NUM] = [UserStack {
data: [0; USER_STACK_SIZE],
}; MAX_APP_NUM];
impl KernelStack {
fn get_sp(&self) -> usize {
self.data.as_ptr() as usize + KERNEL_STACK_SIZE
}
pub fn push_context(&self, trap_context: TrapContext) -> usize {
let pointer = (self.get_sp() - size_of::<TrapContext>()) as *mut TrapContext;
unsafe {
*pointer = trap_context;
}
pointer as usize
}
}
impl UserStack {
fn get_sp(&self) -> usize {
self.data.as_ptr() as usize + USER_STACK_SIZE
}
}
pub fn get_app_num() -> usize {
extern "C" {
fn _num_app();
}
let app_num_ptr = _num_app as usize as *const usize;
unsafe { app_num_ptr.read_volatile() }
}
pub fn load_apps() {
extern "C" {
fn _num_app();
}
let app_num_ptr = _num_app as usize as *const usize;
let app_num = unsafe { app_num_ptr.read_volatile() };
let app_start = unsafe { core::slice::from_raw_parts(app_num_ptr.add(1), app_num + 1) };
for i in 0..app_num {
let base_address = APP_BASE_ADDRESS + i * APP_SIZE_LIMIT;
// 清除目标的内存区域
for address in base_address..base_address + APP_SIZE_LIMIT {
unsafe {
(address as *mut u8).write_volatile(0);
}
}
// 将程序从数据段复制过来
let source = unsafe {
core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i])
};
let destination =
unsafe { core::slice::from_raw_parts_mut(base_address as *mut u8, source.len()) };
destination.copy_from_slice(source);
}
log_information!("Load {} applications in memory.", app_num);
unsafe {
asm!("fence.i");
}
}
pub fn initialize_app_context(app_id: usize) -> usize {
KERNEL_STACK[app_id].push_context(TrapContext::init_application_context(
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT,
USER_STACK[app_id].get_sp(),
))
}

View File

@ -1,5 +1,7 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(alloc_error_handler)]
extern crate alloc;
use crate::utils::clear_bss; use crate::utils::clear_bss;
use core::arch::global_asm; use core::arch::global_asm;
@ -7,7 +9,6 @@ use core::arch::global_asm;
mod boards; mod boards;
mod config; mod config;
mod console; mod console;
mod loader;
mod sbi; mod sbi;
mod sync; mod sync;
mod syscall; mod syscall;
@ -15,6 +16,7 @@ mod task;
mod timer; mod timer;
mod trap; mod trap;
mod utils; mod utils;
mod memory;
global_asm!(include_str!("entry.asm")); global_asm!(include_str!("entry.asm"));
global_asm!(include_str!("link_app.asm")); global_asm!(include_str!("link_app.asm"));
@ -24,8 +26,6 @@ fn rust_main() -> ! {
clear_bss(); clear_bss();
log_information!("Hello, rCore!"); log_information!("Hello, rCore!");
trap::init(); trap::init();
loader::load_apps();
task::run_first_task();
unreachable!() unreachable!()
} }

5
os/src/memory.rs Normal file
View File

@ -0,0 +1,5 @@
mod heap_allocator;
mod address;
mod page_table;
mod frame_allocator;
mod memory_set;

256
os/src/memory/address.rs Normal file
View File

@ -0,0 +1,256 @@
use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
use core::fmt::{Debug, Formatter};
use core::slice::from_raw_parts_mut;
use crate::memory::page_table::PageTableEntry;
// 在SV39模式下物理地址的宽度为56虚拟地址的宽度为39
pub const PHYSICAL_ADDRESS_WIDTH: usize = 56;
pub const PHYSICAL_PAGE_NUMBER_WIDTH: usize = PHYSICAL_ADDRESS_WIDTH - PAGE_SIZE_BITS;
pub const VIRTUAL_ADDRESS_WIDTH: usize = 39;
pub const VIRTUAL_PAGE_NUMBER_WIDTH: usize = VIRTUAL_ADDRESS_WIDTH - PAGE_SIZE_BITS;
/// 物理地址
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PhysicalAddress(pub usize);
impl PhysicalAddress {
pub fn page_offset(&self) -> usize {
self.0 & (PAGE_SIZE - 1)
}
pub fn floor(&self) -> PhysicalPageNumber {
PhysicalPageNumber(self.0 / PAGE_SIZE)
}
pub fn ceil(&self) -> PhysicalPageNumber {
if self.0 == 0 {
PhysicalPageNumber(0)
} else {
PhysicalPageNumber((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE)
}
}
pub fn is_aligned(&self) -> bool {
self.page_offset() == 0
}
}
impl Debug for PhysicalAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!("Physical address: {:#x}.", self.0))
}
}
impl From<usize> for PhysicalAddress {
fn from(value: usize) -> Self {
Self(value & ((1 << PHYSICAL_ADDRESS_WIDTH) - 1))
}
}
impl From<PhysicalAddress> for usize {
fn from(value: PhysicalAddress) -> Self {
value.0
}
}
impl From<PhysicalAddress> for PhysicalPageNumber {
fn from(value: PhysicalAddress) -> Self {
assert_eq!(value.page_offset(), 0);
value.floor()
}
}
impl From<PhysicalPageNumber> for PhysicalAddress {
fn from(value: PhysicalPageNumber) -> Self {
Self(value.0 << PAGE_SIZE_BITS)
}
}
/// 物理页号
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PhysicalPageNumber(pub usize);
// 这里的unsafe只是为了绕过编译器的生命周期检查
impl PhysicalPageNumber {
pub fn get_page_table_entry_array(&self) -> &'static mut [PageTableEntry] {
let address: PhysicalAddress = (*self).into();
unsafe {
// 一个页表的大小是2^12 byte
// 页表项的大小是8 byte
// 所有一共有2^9
from_raw_parts_mut(address.0 as *mut PageTableEntry, 512)
}
}
pub fn get_bytes_array(&self) -> &'static mut [u8] {
let address: PhysicalAddress = (*self).into();
unsafe {
from_raw_parts_mut(address.0 as *mut u8, PAGE_SIZE)
}
}
pub fn get_mut<T>(&self) ->&'static mut T {
let address: PhysicalAddress = (*self).into();
unsafe {
(address.0 as *mut T).as_mut().unwrap()
}
}
}
impl Debug for PhysicalPageNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!("Physical page number: {:#x}.", self.0))
}
}
impl From<usize> for PhysicalPageNumber {
fn from(value: usize) -> Self {
Self(value & ((1 << PHYSICAL_PAGE_NUMBER_WIDTH) - 1))
}
}
impl From<PhysicalPageNumber> for usize {
fn from(value: PhysicalPageNumber) -> Self {
value.0
}
}
/// 虚拟地址
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct VirtualAddress(pub usize);
impl VirtualAddress {
pub fn page_offset(&self) -> usize {
self.0 & (PAGE_SIZE - 1)
}
pub fn is_aligned(&self) -> bool {
self.page_offset() == 0
}
pub fn floor(&self) -> VirtualPageNumber {
VirtualPageNumber(self.0 / PAGE_SIZE)
}
pub fn ceil(&self) -> VirtualPageNumber {
VirtualPageNumber((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE)
}
}
impl Debug for VirtualAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!("Virtual address: {:#x}.", self.0))
}
}
impl From<usize> for VirtualAddress {
fn from(value: usize) -> Self {
Self(value & ((1 << VIRTUAL_ADDRESS_WIDTH) - 1))
}
}
impl From<VirtualAddress> for usize {
fn from(value: VirtualAddress) -> Self {
value.0
}
}
/// 虚拟页号
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct VirtualPageNumber(pub usize);
impl VirtualPageNumber {
pub fn get_indexes(&self) -> [usize; 3] {
let mut number = self.0;
let mut indexes = [0usize; 3];
for i in 0..3 {
indexes[i] = number & (1 << 9 - 1);
number = number >> 9;
}
indexes
}
pub fn step(&mut self) {
self.0 += 1;
}
}
impl Debug for VirtualPageNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!("Virtual page number: {:#x}.", self.0))
}
}
impl From<usize> for VirtualPageNumber {
fn from(value: usize) -> Self {
Self(value & ((1 << VIRTUAL_PAGE_NUMBER_WIDTH) - 1))
}
}
impl From<VirtualPageNumber> for usize {
fn from(value: VirtualPageNumber) -> Self {
value.0
}
}
#[derive(Copy, Clone)]
pub struct VirtualPageSpan {
left: VirtualPageNumber,
right: VirtualPageNumber
}
impl VirtualPageSpan {
pub fn new(start: VirtualPageNumber, end: VirtualPageNumber) -> Self {
Self {
left: start,
right: end
}
}
pub fn get_start(&self) -> VirtualPageNumber {
self.left
}
pub fn get_end(&self) -> VirtualPageNumber {
self.right
}
}
impl IntoIterator for VirtualPageSpan {
type Item = VirtualPageNumber;
type IntoIter = VirtualPageSpanIterator;
fn into_iter(self) -> Self::IntoIter {
VirtualPageSpanIterator::new(&self)
}
}
pub struct VirtualPageSpanIterator {
current: VirtualPageNumber,
end: VirtualPageNumber
}
impl VirtualPageSpanIterator {
fn new(span: &VirtualPageSpan) -> Self {
Self {
current: span.left,
end: span.right
}
}
}
impl Iterator for VirtualPageSpanIterator {
type Item = VirtualPageNumber;
fn next(&mut self) -> Option<Self::Item> {
if self.current == self.end {
None
} else {
let t = self.current;
self.current.step();
Some(t)
}
}
}

View File

@ -0,0 +1,110 @@
use crate::config::MEMORY_END;
use crate::memory::address::{PhysicalAddress, PhysicalPageNumber};
use crate::sync::single_cell::SingleCell;
use alloc::vec;
use alloc::vec::Vec;
use lazy_static::lazy_static;
trait FrameAllocator {
fn new() -> Self;
fn alloc(&mut self) -> Option<PhysicalPageNumber>;
fn dealloc(&mut self, page_number: PhysicalPageNumber);
}
struct StackedFrameAllocator {
current: usize,
end: usize,
recycled: Vec<usize>,
}
impl FrameAllocator for StackedFrameAllocator {
fn new() -> Self {
Self {
current: 0,
end: 0,
recycled: vec![],
}
}
fn alloc(&mut self) -> Option<PhysicalPageNumber> {
if let Some(page_num) = self.recycled.pop() {
Some(page_num.into())
} else {
if self.current == self.end {
None
} else {
self.current += 1;
Some((self.current - 1).into())
}
}
}
fn dealloc(&mut self, page_number: PhysicalPageNumber) {
let page_number = page_number.0;
if page_number >= self.current
|| self.recycled.iter().find(|&p| *p == page_number).is_some()
{
panic!(
"Frame physical page number={:#x} has not been allocated.",
page_number
);
}
self.recycled.push(page_number);
}
}
impl StackedFrameAllocator {
pub fn init(&mut self, l: PhysicalPageNumber, r: PhysicalPageNumber) {
self.current = l.0;
self.end = r.0;
}
}
pub struct FrameTracker {
pub page_number: PhysicalPageNumber
}
impl FrameTracker {
fn new(page_number: PhysicalPageNumber) -> Self {
// 清空页帧中的内容
let byte_array = page_number.get_bytes_array();
for i in byte_array.as_mut() {
*i = 0;
}
Self {
page_number
}
}
}
impl Drop for FrameTracker {
fn drop(&mut self) {
FRAME_ALLOCATOR.exclusive_borrow().dealloc(self.page_number);
}
}
lazy_static! {
static ref FRAME_ALLOCATOR: SingleCell<StackedFrameAllocator> =
SingleCell::new(StackedFrameAllocator::new());
}
pub fn initialize_frame_allocator() {
extern "C" {
fn ekernel();
}
FRAME_ALLOCATOR.exclusive_borrow().init(
PhysicalAddress::from(ekernel as usize).ceil(),
PhysicalAddress::from(MEMORY_END).floor(),
)
}
pub fn allocate_frame() -> Option<FrameTracker> {
FRAME_ALLOCATOR.exclusive_borrow().alloc().map(|p| FrameTracker::new(p))
}

View File

@ -0,0 +1,20 @@
use buddy_system_allocator::LockedHeap;
use crate::config::KERNEL_HEAP_SIZE;
#[global_allocator]
static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty();
static mut HEAP_SPACE: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE];
pub fn init_heap() {
unsafe {
HEAP_ALLOCATOR
.lock()
.init(HEAP_SPACE.as_ptr() as usize, KERNEL_HEAP_SIZE);
}
}
#[alloc_error_handler]
pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! {
panic!("Heap allocation failed, layout: {:?}", layout);
}

145
os/src/memory/memory_set.rs Normal file
View File

@ -0,0 +1,145 @@
use alloc::collections::BTreeMap;
use alloc::vec;
use alloc::vec::Vec;
use bitflags::bitflags;
use crate::config::PAGE_SIZE;
use crate::memory::address::{PhysicalPageNumber, VirtualAddress, VirtualPageNumber, VirtualPageSpan};
use crate::memory::frame_allocator::{allocate_frame, FrameTracker};
use crate::memory::page_table::{PageTable, PageTableEntryFlags};
/// 虚拟地址的映射方式
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum MapType {
/// 恒等映射
Identical,
/// 新分配物理页帧
Framed
}
bitflags! {
/// 逻辑段的权限控制
/// 只是PageTableEntryFlags的子集
/// 其他的标志位对于权限控制无用,只和地址转换有关
pub struct MapPermission: u8 {
const R = 1 << 1;
const W = 1 << 2;
const X = 1 << 3;
const U = 1 << 4;
}
}
/// 一段地址连续的虚拟内存
pub struct MapArea {
virtual_page_span: VirtualPageSpan,
data_frames: BTreeMap<VirtualPageNumber, FrameTracker>,
map_type: MapType,
map_permission: MapPermission
}
impl MapArea {
pub fn new(
start: VirtualAddress,
end: VirtualAddress,
map_type: MapType,
map_permission: MapPermission
) -> Self {
let start = start.floor();
let end = end.ceil();
Self {
virtual_page_span: VirtualPageSpan::new(start, end),
data_frames: BTreeMap::new(),
map_type,
map_permission
}
}
pub fn map(&mut self, page_table: &mut PageTable) {
for page_number in self.virtual_page_span {
self.map_one(page_table, page_number);
}
}
pub fn unmap(&mut self, page_table: &mut PageTable) {
for page_number in self.virtual_page_span {
self.unmap_one(page_table, page_number);
}
}
/// Copy data into this MapArea
/// The data is start-aligned and shorter than MapArea!
pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) {
assert_eq!(self.map_type, MapType::Framed);
let mut start = 0;
let mut current_page_number = self.virtual_page_span.get_start();
let length = data.len();
loop {
let source = &data[start..length.min(start + PAGE_SIZE)];
let destination = &mut page_table
.translate(current_page_number)
.unwrap()
.physical_page_numer()
.get_bytes_array()[..source.len()];
destination.copy_from_slice(source);
start += PAGE_SIZE;
if start >= length {
break
}
// 自增
current_page_number.step()
}
}
fn map_one(&mut self, page_table: &mut PageTable, virtual_page_number: VirtualPageNumber) {
let physical_page_number = match self.map_type {
MapType::Identical => {
// 使用和虚拟页号一样的物理页号
PhysicalPageNumber(virtual_page_number.0)
},
MapType::Framed => {
// 分配新的物理页帧
let frame = allocate_frame().unwrap();
let frame_number = frame.page_number;
self.data_frames.insert(virtual_page_number, frame);
frame_number
}
};
let flags = PageTableEntryFlags::from_bits(self.map_permission.bits()).unwrap();
page_table.map(virtual_page_number, physical_page_number, flags);
}
fn unmap_one(&mut self, page_table: &mut PageTable, virtual_page_number: VirtualPageNumber) {
match self.map_type {
MapType::Framed => {
self.data_frames.remove(&virtual_page_number);
},
_ => {}
}
page_table.unmap(virtual_page_number);
}
}
pub struct MemorySet {
page_table: PageTable,
areas: Vec<MapArea>
}
impl MemorySet {
pub fn new_bare() -> Self {
Self {
page_table: PageTable::new(),
areas: vec![]
}
}
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
}
}

161
os/src/memory/page_table.rs Normal file
View File

@ -0,0 +1,161 @@
use crate::memory::address::{PhysicalPageNumber, VirtualPageNumber, PHYSICAL_PAGE_NUMBER_WIDTH};
use crate::memory::frame_allocator::{allocate_frame, FrameTracker};
use alloc::vec;
use alloc::vec::Vec;
use bitflags::bitflags;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PageTableEntryFlags: u8 {
/// Valid
const V = 1 << 0;
///Read
const R = 1 << 1;
/// Write
const W = 1 << 2;
/// Execute
const X = 1 << 3;
/// User
const U = 1 << 4;
/// unknown
const G = 1 << 5;
/// Accessed
const A = 1 << 6;
/// Dirty
const D = 1 << 7;
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct PageTableEntry {
pub bits: usize,
}
impl PageTableEntry {
pub fn new(page_num: PhysicalPageNumber, flags: PageTableEntryFlags) -> Self {
Self {
bits: page_num.0 << 10 | flags.bits() as usize,
}
}
pub fn empty() -> Self {
Self { bits: 0 }
}
pub fn physical_page_numer(&self) -> PhysicalPageNumber {
(self.bits >> 10 & (1usize << PHYSICAL_PAGE_NUMBER_WIDTH - 1)).into()
}
pub fn flags(&self) -> PageTableEntryFlags {
PageTableEntryFlags::from_bits(self.bits as u8).unwrap()
}
pub fn is_valid(&self) -> bool {
(self.flags() & PageTableEntryFlags::V) != PageTableEntryFlags::empty()
}
pub fn readable(&self) -> bool {
(self.flags() & PageTableEntryFlags::R) != PageTableEntryFlags::empty()
}
pub fn writable(&self) -> bool {
(self.flags() & PageTableEntryFlags::W) != PageTableEntryFlags::empty()
}
pub fn executable(&self) -> bool {
(self.flags() & PageTableEntryFlags::X) != PageTableEntryFlags::empty()
}
}
pub struct PageTable {
root_page_number: PhysicalPageNumber,
frames: Vec<FrameTracker>,
}
impl PageTable {
pub fn new() -> Self {
let frame = allocate_frame().unwrap();
Self {
root_page_number: frame.page_number,
frames: vec![frame],
}
}
pub fn map(
&mut self,
virtual_page_number: VirtualPageNumber,
physical_page_number: PhysicalPageNumber,
flags: PageTableEntryFlags,
) {
let entry = self.find_entry_or_create(virtual_page_number);
assert!(
!entry.is_valid(),
"Virtual page number {:?} is mapped before mapping.",
virtual_page_number
);
*entry = PageTableEntry::new(physical_page_number, flags | PageTableEntryFlags::V);
}
pub fn unmap(&mut self, virtual_page_number: VirtualPageNumber) {
let entry = self.find_entry(virtual_page_number).unwrap();
assert!(
entry.is_valid(),
"Virtual page number {:?} is invalid before unmapping",
virtual_page_number
);
*entry = PageTableEntry::empty();
}
/// 从satp寄存器创建临时的页表
/// 方便在用户空间时手动查看页表
pub fn from_token(satp: usize) -> Self {
Self {
root_page_number: PhysicalPageNumber::from(
satp & ((1usize << PHYSICAL_PAGE_NUMBER_WIDTH) - 1),
),
frames: vec![],
}
}
pub fn translate(&self, virtual_page_number: VirtualPageNumber) -> Option<PageTableEntry> {
self.find_entry(virtual_page_number).map(|e| e.clone())
}
fn find_entry_or_create(&mut self, page_number: VirtualPageNumber) -> &mut PageTableEntry {
let indexes = page_number.get_indexes();
let mut physical_page_number = self.root_page_number;
for i in 0..2 {
let entry = &mut physical_page_number.get_page_table_entry_array()[indexes[i]];
// 当V是1其他都是0的页帧就是页表
if !entry.is_valid() {
let frame = allocate_frame().unwrap();
*entry = PageTableEntry::new(frame.page_number, PageTableEntryFlags::V);
self.frames.push(frame);
}
physical_page_number = entry.physical_page_numer();
}
&mut physical_page_number.get_page_table_entry_array()[indexes[2]]
}
fn find_entry(&self, page_number: VirtualPageNumber) -> Option<&mut PageTableEntry> {
let indexes = page_number.get_indexes();
let mut physical_page_number = self.root_page_number;
for i in 0..2 {
let entry = &mut physical_page_number.get_page_table_entry_array()[indexes[i]];
if !entry.is_valid() {
return None;
}
physical_page_number = entry.physical_page_numer();
}
Some(&mut physical_page_number.get_page_table_entry_array()[indexes[2]])
}
}

View File

@ -1,7 +1,5 @@
use lazy_static::lazy_static; use lazy_static::lazy_static;
use crate::config::MAX_APP_NUM;
use crate::loader::{get_app_num, initialize_app_context};
use crate::log_information; use crate::log_information;
use crate::sbi::shutdown; use crate::sbi::shutdown;
use crate::sync::single_cell::SingleCell; use crate::sync::single_cell::SingleCell;