mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 19:03:27 +00:00
Split kernel mode and user mode page table
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
c26eac757a
commit
aeea333945
@ -6,7 +6,6 @@ use pod::Pod;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bus::pci::PciDeviceLocation,
|
bus::pci::PciDeviceLocation,
|
||||||
config::PAGE_SIZE,
|
|
||||||
vm::{
|
vm::{
|
||||||
page_table::{PageTableConfig, PageTableError},
|
page_table::{PageTableConfig, PageTableError},
|
||||||
Paddr, PageTable, Vaddr, VmAllocOptions, VmFrame, VmFrameVec, VmIo,
|
Paddr, PageTable, Vaddr, VmAllocOptions, VmFrame, VmFrameVec, VmIo,
|
||||||
@ -61,14 +60,14 @@ impl RootTable {
|
|||||||
&mut self,
|
&mut self,
|
||||||
device: PciDeviceLocation,
|
device: PciDeviceLocation,
|
||||||
vaddr: Vaddr,
|
vaddr: Vaddr,
|
||||||
paddr: Paddr,
|
frame: &VmFrame,
|
||||||
) -> Result<(), ContextTableError> {
|
) -> Result<(), ContextTableError> {
|
||||||
if device.device >= 32 || device.function >= 8 {
|
if device.device >= 32 || device.function >= 8 {
|
||||||
return Err(ContextTableError::InvalidDeviceId);
|
return Err(ContextTableError::InvalidDeviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get_or_create_context_table(device)
|
self.get_or_create_context_table(device)
|
||||||
.map(device, vaddr, paddr & !(PAGE_SIZE - 1))?;
|
.map(device, vaddr, frame)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -262,7 +261,7 @@ impl ContextTable {
|
|||||||
|
|
||||||
if !bus_entry.present() {
|
if !bus_entry.present() {
|
||||||
let table: PageTable<PageTableEntry> = PageTable::new(PageTableConfig {
|
let table: PageTable<PageTableEntry> = PageTable::new(PageTableConfig {
|
||||||
address_width: crate::vm::page_table::AddressWidth::Level3PageTable,
|
address_width: crate::vm::page_table::AddressWidth::Level3,
|
||||||
});
|
});
|
||||||
let address = table.root_paddr();
|
let address = table.root_paddr();
|
||||||
self.page_tables.insert(address, table);
|
self.page_tables.insert(address, table);
|
||||||
@ -286,7 +285,7 @@ impl ContextTable {
|
|||||||
&mut self,
|
&mut self,
|
||||||
device: PciDeviceLocation,
|
device: PciDeviceLocation,
|
||||||
vaddr: Vaddr,
|
vaddr: Vaddr,
|
||||||
paddr: Paddr,
|
frame: &VmFrame,
|
||||||
) -> Result<(), ContextTableError> {
|
) -> Result<(), ContextTableError> {
|
||||||
if device.device >= 32 || device.function >= 8 {
|
if device.device >= 32 || device.function >= 8 {
|
||||||
return Err(ContextTableError::InvalidDeviceId);
|
return Err(ContextTableError::InvalidDeviceId);
|
||||||
@ -294,7 +293,7 @@ impl ContextTable {
|
|||||||
self.get_or_create_page_table(device)
|
self.get_or_create_page_table(device)
|
||||||
.map(
|
.map(
|
||||||
vaddr,
|
vaddr,
|
||||||
paddr,
|
frame,
|
||||||
PageTableFlags::WRITABLE | PageTableFlags::READABLE | PageTableFlags::LAST_PAGE,
|
PageTableFlags::WRITABLE | PageTableFlags::READABLE | PageTableFlags::LAST_PAGE,
|
||||||
)
|
)
|
||||||
.map_err(ContextTableError::ModificationError)
|
.map_err(ContextTableError::ModificationError)
|
||||||
|
@ -3,7 +3,7 @@ mod fault;
|
|||||||
mod remapping;
|
mod remapping;
|
||||||
mod second_stage;
|
mod second_stage;
|
||||||
|
|
||||||
use crate::sync::Mutex;
|
use crate::{sync::Mutex, vm::VmFrame};
|
||||||
use log::info;
|
use log::info;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ use crate::{
|
|||||||
bus::pci::PciDeviceLocation,
|
bus::pci::PciDeviceLocation,
|
||||||
vm::{
|
vm::{
|
||||||
page_table::{PageTableConfig, PageTableError},
|
page_table::{PageTableConfig, PageTableError},
|
||||||
Paddr, PageTable, Vaddr,
|
PageTable, Vaddr,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ pub enum IommuError {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Mapping an incorrect address may lead to a kernel data leak.
|
/// Mapping an incorrect address may lead to a kernel data leak.
|
||||||
pub(crate) unsafe fn map(vaddr: Vaddr, paddr: Paddr) -> Result<(), IommuError> {
|
pub(crate) unsafe fn map(vaddr: Vaddr, frame: &VmFrame) -> Result<(), IommuError> {
|
||||||
let Some(table) = PAGE_TABLE.get() else {
|
let Some(table) = PAGE_TABLE.get() else {
|
||||||
return Err(IommuError::NoIommu);
|
return Err(IommuError::NoIommu);
|
||||||
};
|
};
|
||||||
@ -41,7 +41,7 @@ pub(crate) unsafe fn map(vaddr: Vaddr, paddr: Paddr) -> Result<(), IommuError> {
|
|||||||
function: 0,
|
function: 0,
|
||||||
},
|
},
|
||||||
vaddr,
|
vaddr,
|
||||||
paddr,
|
frame,
|
||||||
)
|
)
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
context_table::ContextTableError::InvalidDeviceId => unreachable!(),
|
context_table::ContextTableError::InvalidDeviceId => unreachable!(),
|
||||||
@ -78,7 +78,7 @@ pub(crate) fn init() -> Result<(), IommuError> {
|
|||||||
let mut root_table = RootTable::new();
|
let mut root_table = RootTable::new();
|
||||||
// For all PCI Device, use the same page table.
|
// For all PCI Device, use the same page table.
|
||||||
let page_table: PageTable<PageTableEntry> = PageTable::new(PageTableConfig {
|
let page_table: PageTable<PageTableEntry> = PageTable::new(PageTableConfig {
|
||||||
address_width: crate::vm::page_table::AddressWidth::Level3PageTable,
|
address_width: crate::vm::page_table::AddressWidth::Level3,
|
||||||
});
|
});
|
||||||
for table in PciDeviceLocation::all() {
|
for table in PciDeviceLocation::all() {
|
||||||
root_table.specify_device_page_table(table, page_table.clone())
|
root_table.specify_device_page_table(table, page_table.clone())
|
||||||
|
@ -45,6 +45,18 @@ pub fn tlb_flush(vaddr: Vaddr) {
|
|||||||
tlb::flush(VirtAddr::new(vaddr as u64));
|
tlb::flush(VirtAddr::new(vaddr as u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn is_user_vaddr(vaddr: Vaddr) -> bool {
|
||||||
|
// FIXME: Support 3/5 level page table.
|
||||||
|
// 47 = 12(offset) + 4 * 9(index) - 1
|
||||||
|
(vaddr >> 47) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn is_kernel_vaddr(vaddr: Vaddr) -> bool {
|
||||||
|
// FIXME: Support 3/5 level page table.
|
||||||
|
// 47 = 12(offset) + 4 * 9(index) - 1
|
||||||
|
((vaddr >> 47) & 0x1) == 1
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Pod)]
|
#[derive(Clone, Copy, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PageTableEntry(usize);
|
pub struct PageTableEntry(usize);
|
||||||
|
@ -50,7 +50,7 @@ impl VmFrameVec {
|
|||||||
for frame in frames.iter_mut() {
|
for frame in frames.iter_mut() {
|
||||||
// Safety: The address is controlled by frame allocator.
|
// Safety: The address is controlled by frame allocator.
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Err(err) = iommu::map(frame.start_paddr(), frame.start_paddr()) {
|
if let Err(err) = iommu::map(frame.start_paddr(), frame) {
|
||||||
match err {
|
match err {
|
||||||
// do nothing
|
// do nothing
|
||||||
iommu::IommuError::NoIommu => {}
|
iommu::IommuError::NoIommu => {}
|
||||||
|
@ -163,9 +163,9 @@ impl MemorySet {
|
|||||||
// TODO: check overlap
|
// TODO: check overlap
|
||||||
if let Entry::Vacant(e) = self.areas.entry(area.start_va) {
|
if let Entry::Vacant(e) = self.areas.entry(area.start_va) {
|
||||||
let area = e.insert(area);
|
let area = e.insert(area);
|
||||||
for (va, pa) in area.mapper.iter() {
|
for (va, frame) in area.mapper.iter() {
|
||||||
debug_assert!(pa.start_paddr() < PHYS_OFFSET);
|
debug_assert!(frame.start_paddr() < PHYS_OFFSET);
|
||||||
self.pt.map(*va, pa.start_paddr(), area.flags).unwrap();
|
self.pt.map(*va, frame, area.flags).unwrap();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!(
|
||||||
@ -191,7 +191,7 @@ impl MemorySet {
|
|||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut page_table = PageTable::new(PageTableConfig {
|
let mut page_table = PageTable::new(PageTableConfig {
|
||||||
address_width: super::page_table::AddressWidth::Level4PageTable,
|
address_width: super::page_table::AddressWidth::Level4,
|
||||||
});
|
});
|
||||||
let mapped_pte = crate::arch::mm::ALL_MAPPED_PTE.lock();
|
let mapped_pte = crate::arch::mm::ALL_MAPPED_PTE.lock();
|
||||||
for (index, pte) in mapped_pte.iter() {
|
for (index, pte) in mapped_pte.iter() {
|
||||||
@ -300,7 +300,7 @@ impl fmt::Debug for MemorySet {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("MemorySet")
|
f.debug_struct("MemorySet")
|
||||||
.field("areas", &self.areas)
|
.field("areas", &self.areas)
|
||||||
.field("page_table_root", &self.pt.root_pa)
|
.field("page_table_root", &self.pt.root_paddr())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@ pub static FRAMEBUFFER_REGIONS: Once<Vec<MemoryRegion>> = Once::new();
|
|||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
let memory_regions = crate::boot::memory_regions().to_owned();
|
let memory_regions = crate::boot::memory_regions().to_owned();
|
||||||
frame_allocator::init(&memory_regions);
|
frame_allocator::init(&memory_regions);
|
||||||
|
page_table::init();
|
||||||
|
|
||||||
let mut framebuffer_regions = Vec::new();
|
let mut framebuffer_regions = Vec::new();
|
||||||
for i in memory_regions.iter() {
|
for i in memory_regions.iter() {
|
||||||
|
@ -3,14 +3,16 @@ use super::{
|
|||||||
frame_allocator, paddr_to_vaddr, VmAllocOptions, VmFrameVec, {Paddr, Vaddr},
|
frame_allocator, paddr_to_vaddr, VmAllocOptions, VmFrameVec, {Paddr, Vaddr},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::mm::{tlb_flush, PageTableEntry},
|
arch::mm::{is_kernel_vaddr, is_user_vaddr, tlb_flush, PageTableEntry},
|
||||||
config::{ENTRY_COUNT, PAGE_SIZE},
|
config::{ENTRY_COUNT, PAGE_SIZE},
|
||||||
|
sync::SpinLock,
|
||||||
vm::VmFrame,
|
vm::VmFrame,
|
||||||
};
|
};
|
||||||
use alloc::{vec, vec::Vec};
|
use alloc::{vec, vec::Vec};
|
||||||
use core::{fmt::Debug, marker::PhantomData, mem::size_of};
|
use core::{fmt::Debug, marker::PhantomData, mem::size_of};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use pod::Pod;
|
use pod::Pod;
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
pub trait PageTableFlagsTrait: Clone + Copy + Sized + Pod + Debug {
|
pub trait PageTableFlagsTrait: Clone + Copy + Sized + Pod + Debug {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
@ -89,11 +91,10 @@ pub struct PageTableConfig {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(usize)]
|
#[repr(usize)]
|
||||||
#[allow(clippy::enum_variant_names)]
|
|
||||||
pub enum AddressWidth {
|
pub enum AddressWidth {
|
||||||
Level3PageTable = 3,
|
Level3 = 3,
|
||||||
Level4PageTable = 4,
|
Level4 = 4,
|
||||||
Level5PageTable = 5,
|
Level5 = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -104,43 +105,119 @@ pub enum PageTableError {
|
|||||||
/// 2. The mapping is already invalid before unmap operation.
|
/// 2. The mapping is already invalid before unmap operation.
|
||||||
/// 3. The mapping is not exists before protect operation.
|
/// 3. The mapping is not exists before protect operation.
|
||||||
InvalidModification,
|
InvalidModification,
|
||||||
|
InvalidVaddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static KERNEL_PAGE_TABLE: Once<SpinLock<PageTable<PageTableEntry, KernelMode>>> = Once::new();
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UserMode {}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct KernelMode {}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PageTable<T: PageTableEntryTrait> {
|
pub struct PageTable<T: PageTableEntryTrait, M = UserMode> {
|
||||||
pub root_pa: Paddr,
|
root_paddr: Paddr,
|
||||||
/// store all the physical frame that the page table need to map all the frame e.g. the frame of the root_pa
|
/// store all the physical frame that the page table need to map all the frame e.g. the frame of the root_pa
|
||||||
tables: Vec<VmFrame>,
|
tables: Vec<VmFrame>,
|
||||||
config: PageTableConfig,
|
config: PageTableConfig,
|
||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<(T, M)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PageTableEntryTrait> PageTable<T> {
|
impl<T: PageTableEntryTrait> PageTable<T, UserMode> {
|
||||||
pub fn new(config: PageTableConfig) -> Self {
|
pub fn new(config: PageTableConfig) -> Self {
|
||||||
let root_frame = frame_allocator::alloc_zero(VmFrameFlags::empty()).unwrap();
|
let root_frame = frame_allocator::alloc_zero(VmFrameFlags::empty()).unwrap();
|
||||||
Self {
|
Self {
|
||||||
root_pa: root_frame.start_paddr(),
|
root_paddr: root_frame.start_paddr(),
|
||||||
tables: vec![root_frame],
|
tables: vec![root_frame],
|
||||||
config,
|
config,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the page table structure according to the physical address, note that the created page table can only use the page_walk function without create.
|
pub fn map(
|
||||||
|
&mut self,
|
||||||
|
vaddr: Vaddr,
|
||||||
|
frame: &VmFrame,
|
||||||
|
flags: T::F,
|
||||||
|
) -> Result<(), PageTableError> {
|
||||||
|
if is_kernel_vaddr(vaddr) {
|
||||||
|
return Err(PageTableError::InvalidVaddr);
|
||||||
|
}
|
||||||
|
// Safety:
|
||||||
|
// 1. The vaddr belongs to user mode program and does not affect the kernel mapping.
|
||||||
|
// 2. The area where the physical address islocated at untyped memory and does not affect kernel security.
|
||||||
|
unsafe { self.do_map(vaddr, frame.start_paddr(), flags) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmap(&mut self, vaddr: Vaddr) -> Result<(), PageTableError> {
|
||||||
|
if is_kernel_vaddr(vaddr) {
|
||||||
|
return Err(PageTableError::InvalidVaddr);
|
||||||
|
}
|
||||||
|
// Safety: The vaddr belongs to user mode program and does not affect the kernel mapping.
|
||||||
|
unsafe { self.do_unmap(vaddr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<(), PageTableError> {
|
||||||
|
if is_kernel_vaddr(vaddr) {
|
||||||
|
return Err(PageTableError::InvalidVaddr);
|
||||||
|
}
|
||||||
|
// Safety: The vaddr belongs to user mode program and does not affect the kernel mapping.
|
||||||
|
unsafe { self.do_protect(vaddr, flags) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PageTableEntryTrait> PageTable<T, KernelMode> {
|
||||||
|
/// Mapping `vaddr` to `paddr` with flags. The `vaddr` should not be at the low address
|
||||||
|
/// (memory belonging to the user mode program).
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// User should ensure the physical address is valid and only invoke the `page_walk` function without creating new PTE.
|
/// Modifying kernel mappings is considered unsafe, and incorrect operation may cause crashes.
|
||||||
///
|
/// User must take care of the consequences when using this API.
|
||||||
pub unsafe fn from_paddr(config: PageTableConfig, paddr: Paddr) -> Self {
|
pub unsafe fn map(
|
||||||
Self {
|
&mut self,
|
||||||
root_pa: paddr,
|
vaddr: Vaddr,
|
||||||
tables: Vec::new(),
|
paddr: Paddr,
|
||||||
config,
|
flags: T::F,
|
||||||
_phantom: PhantomData,
|
) -> Result<(), PageTableError> {
|
||||||
|
if is_user_vaddr(vaddr) {
|
||||||
|
return Err(PageTableError::InvalidVaddr);
|
||||||
}
|
}
|
||||||
|
self.do_map(vaddr, paddr, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unmap `vaddr`. The `vaddr` should not be at the low address
|
||||||
|
/// (memory belonging to the user mode program).
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Modifying kernel mappings is considered unsafe, and incorrect operation may cause crashes.
|
||||||
|
/// User must take care of the consequences when using this API.
|
||||||
|
pub unsafe fn unmap(&mut self, vaddr: Vaddr) -> Result<(), PageTableError> {
|
||||||
|
if is_user_vaddr(vaddr) {
|
||||||
|
return Err(PageTableError::InvalidVaddr);
|
||||||
|
}
|
||||||
|
self.do_unmap(vaddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the flags mapped at `vaddr`. The `vaddr` should not be at the low address
|
||||||
|
/// (memory belonging to the user mode program).
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Modifying kernel mappings is considered unsafe, and incorrect operation may cause crashes.
|
||||||
|
/// User must take care of the consequences when using this API.
|
||||||
|
pub unsafe fn protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<(), PageTableError> {
|
||||||
|
if is_user_vaddr(vaddr) {
|
||||||
|
return Err(PageTableError::InvalidVaddr);
|
||||||
|
}
|
||||||
|
self.do_protect(vaddr, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PageTableEntryTrait, M> PageTable<T, M> {
|
||||||
/// Add a new mapping directly in the root page table.
|
/// Add a new mapping directly in the root page table.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -149,12 +226,23 @@ impl<T: PageTableEntryTrait> PageTable<T> {
|
|||||||
///
|
///
|
||||||
pub unsafe fn add_root_mapping(&mut self, index: usize, pte: &T) {
|
pub unsafe fn add_root_mapping(&mut self, index: usize, pte: &T) {
|
||||||
debug_assert!((index + 1) * size_of::<T>() <= PAGE_SIZE);
|
debug_assert!((index + 1) * size_of::<T>() <= PAGE_SIZE);
|
||||||
// Safety: The root_pa is refer to the root of a valid page table.
|
// Safety: The root_paddr is refer to the root of a valid page table.
|
||||||
let root_ptes: &mut [T] = table_of(self.root_pa).unwrap();
|
let root_ptes: &mut [T] = table_of(self.root_paddr).unwrap();
|
||||||
root_ptes[index] = *pte;
|
root_ptes[index] = *pte;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map(&mut self, vaddr: Vaddr, paddr: Paddr, flags: T::F) -> Result<(), PageTableError> {
|
/// Mapping `vaddr` to `paddr` with flags.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function allows arbitrary modifications to the page table.
|
||||||
|
/// Incorrect modifications may cause the kernel to crash (e.g., changing the linear mapping.).
|
||||||
|
unsafe fn do_map(
|
||||||
|
&mut self,
|
||||||
|
vaddr: Vaddr,
|
||||||
|
paddr: Paddr,
|
||||||
|
flags: T::F,
|
||||||
|
) -> Result<(), PageTableError> {
|
||||||
let last_entry = self.page_walk(vaddr, true).unwrap();
|
let last_entry = self.page_walk(vaddr, true).unwrap();
|
||||||
trace!(
|
trace!(
|
||||||
"Page Table: Map vaddr:{:x?}, paddr:{:x?}, flags:{:x?}",
|
"Page Table: Map vaddr:{:x?}, paddr:{:x?}, flags:{:x?}",
|
||||||
@ -181,7 +269,7 @@ impl<T: PageTableEntryTrait> PageTable<T> {
|
|||||||
// Safety: The offset does not exceed the value of PAGE_SIZE.
|
// Safety: The offset does not exceed the value of PAGE_SIZE.
|
||||||
// It only change the memory controlled by page table.
|
// It only change the memory controlled by page table.
|
||||||
let mut current: &mut T = unsafe {
|
let mut current: &mut T = unsafe {
|
||||||
&mut *(paddr_to_vaddr(self.root_pa + size_of::<T>() * T::page_index(vaddr, count))
|
&mut *(paddr_to_vaddr(self.root_paddr + size_of::<T>() * T::page_index(vaddr, count))
|
||||||
as *mut T)
|
as *mut T)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -220,7 +308,13 @@ impl<T: PageTableEntryTrait> PageTable<T> {
|
|||||||
Some(current)
|
Some(current)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap(&mut self, vaddr: Vaddr) -> Result<(), PageTableError> {
|
/// Unmap `vaddr`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function allows arbitrary modifications to the page table.
|
||||||
|
/// Incorrect modifications may cause the kernel to crash (e.g., unmap the linear mapping.).
|
||||||
|
unsafe fn do_unmap(&mut self, vaddr: Vaddr) -> Result<(), PageTableError> {
|
||||||
let last_entry = self.page_walk(vaddr, false).unwrap();
|
let last_entry = self.page_walk(vaddr, false).unwrap();
|
||||||
trace!("Page Table: Unmap vaddr:{:x?}", vaddr);
|
trace!("Page Table: Unmap vaddr:{:x?}", vaddr);
|
||||||
if last_entry.is_unused() && !last_entry.flags().is_present() {
|
if last_entry.is_unused() && !last_entry.flags().is_present() {
|
||||||
@ -231,7 +325,14 @@ impl<T: PageTableEntryTrait> PageTable<T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<(), PageTableError> {
|
/// Modify the flags mapped at `vaddr`
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function allows arbitrary modifications to the page table.
|
||||||
|
/// Incorrect modifications may cause the kernel to crash
|
||||||
|
/// (e.g., make the linear mapping visible to the user mode applications.).
|
||||||
|
unsafe fn do_protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<(), PageTableError> {
|
||||||
let last_entry = self.page_walk(vaddr, false).unwrap();
|
let last_entry = self.page_walk(vaddr, false).unwrap();
|
||||||
trace!("Page Table: Protect vaddr:{:x?}, flags:{:x?}", vaddr, flags);
|
trace!("Page Table: Protect vaddr:{:x?}, flags:{:x?}", vaddr, flags);
|
||||||
if last_entry.is_unused() || !last_entry.flags().is_present() {
|
if last_entry.is_unused() || !last_entry.flags().is_present() {
|
||||||
@ -243,7 +344,7 @@ impl<T: PageTableEntryTrait> PageTable<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_paddr(&self) -> Paddr {
|
pub fn root_paddr(&self) -> Paddr {
|
||||||
self.root_pa
|
self.root_paddr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,22 +364,25 @@ pub unsafe fn table_of<'a, T: PageTableEntryTrait>(pa: Paddr) -> Option<&'a mut
|
|||||||
|
|
||||||
/// translate a virtual address to physical address which cannot use offset to get physical address
|
/// translate a virtual address to physical address which cannot use offset to get physical address
|
||||||
pub fn vaddr_to_paddr(vaddr: Vaddr) -> Option<Paddr> {
|
pub fn vaddr_to_paddr(vaddr: Vaddr) -> Option<Paddr> {
|
||||||
#[cfg(target_arch = "x86_64")]
|
let mut page_table = KERNEL_PAGE_TABLE.get().unwrap().lock();
|
||||||
let (page_directory_base, _) = x86_64::registers::control::Cr3::read();
|
// Although we bypass the unsafe APIs provided by KernelMode, the purpose here is
|
||||||
|
// only to obtain the corresponding physical address according to the mapping.
|
||||||
// TODO: Read and use different level page table.
|
|
||||||
// Safety: The page_directory_base is valid since it is read from PDBR.
|
|
||||||
// We only use this instance to do the page walk without creating.
|
|
||||||
let mut page_table: PageTable<PageTableEntry> = unsafe {
|
|
||||||
PageTable::from_paddr(
|
|
||||||
PageTableConfig {
|
|
||||||
address_width: AddressWidth::Level4PageTable,
|
|
||||||
},
|
|
||||||
page_directory_base.start_address().as_u64() as usize,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let page_directory_base = page_directory_base.start_address().as_u64() as usize;
|
|
||||||
let last_entry = page_table.page_walk(vaddr, false)?;
|
let last_entry = page_table.page_walk(vaddr, false)?;
|
||||||
// FIXME: Support huge page
|
// FIXME: Support huge page
|
||||||
Some(last_entry.paddr() + (vaddr & (PAGE_SIZE - 1)))
|
Some(last_entry.paddr() + (vaddr & (PAGE_SIZE - 1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
KERNEL_PAGE_TABLE.call_once(|| {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
let (page_directory_base, _) = x86_64::registers::control::Cr3::read();
|
||||||
|
SpinLock::new(PageTable {
|
||||||
|
root_paddr: page_directory_base.start_address().as_u64() as usize,
|
||||||
|
tables: Vec::new(),
|
||||||
|
config: PageTableConfig {
|
||||||
|
address_width: AddressWidth::Level4,
|
||||||
|
},
|
||||||
|
_phantom: PhantomData,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -40,7 +40,7 @@ impl VmSpace {
|
|||||||
pub unsafe fn activate(&self) {
|
pub unsafe fn activate(&self) {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
crate::arch::x86::mm::activate_page_table(
|
crate::arch::x86::mm::activate_page_table(
|
||||||
self.memory_set.lock().pt.root_pa,
|
self.memory_set.lock().pt.root_paddr(),
|
||||||
x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE,
|
x86_64::registers::control::Cr3Flags::PAGE_LEVEL_CACHE_DISABLE,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user