156 lines
3.5 KiB
Rust
156 lines
3.5 KiB
Rust
//! # Paging
|
|
//! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html)
|
|
|
|
use core::{mem, ptr};
|
|
use x86::msr;
|
|
|
|
use self::mapper::PageFlushAll;
|
|
|
|
pub use super::CurrentRmmArch as RmmA;
|
|
pub use rmm::{Arch as RmmArch, Flusher, PageFlags, PhysicalAddress, TableKind, VirtualAddress};
|
|
|
|
pub type PageMapper = rmm::PageMapper<RmmA, crate::arch::rmm::LockedAllocator>;
|
|
pub use crate::rmm::KernelMapper;
|
|
|
|
pub mod entry {
|
|
bitflags! {
|
|
pub struct EntryFlags: usize {
|
|
const NO_CACHE = 1 << 4;
|
|
const HUGE_PAGE = 1 << 7;
|
|
const GLOBAL = 1 << 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod mapper;
|
|
|
|
/// Number of entries per page table
|
|
pub const ENTRY_COUNT: usize = RmmA::PAGE_ENTRIES;
|
|
|
|
/// Size of pages
|
|
pub const PAGE_SIZE: usize = RmmA::PAGE_SIZE;
|
|
|
|
/// Setup page attribute table
|
|
#[cold]
|
|
unsafe fn init_pat() {
|
|
let uncacheable = 0;
|
|
let write_combining = 1;
|
|
let write_through = 4;
|
|
//let write_protected = 5;
|
|
let write_back = 6;
|
|
let uncached = 7;
|
|
|
|
let pat0 = write_back;
|
|
let pat1 = write_through;
|
|
let pat2 = uncached;
|
|
let pat3 = uncacheable;
|
|
|
|
let pat4 = write_combining;
|
|
let pat5 = pat1;
|
|
let pat6 = pat2;
|
|
let pat7 = pat3;
|
|
|
|
msr::wrmsr(
|
|
msr::IA32_PAT,
|
|
pat7 << 56
|
|
| pat6 << 48
|
|
| pat5 << 40
|
|
| pat4 << 32
|
|
| pat3 << 24
|
|
| pat2 << 16
|
|
| pat1 << 8
|
|
| pat0,
|
|
);
|
|
}
|
|
|
|
#[cold]
|
|
pub unsafe fn init() {
|
|
init_pat();
|
|
}
|
|
|
|
/// Page
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct Page {
|
|
number: usize,
|
|
}
|
|
|
|
impl Page {
|
|
pub fn start_address(self) -> VirtualAddress {
|
|
VirtualAddress::new(self.number * PAGE_SIZE)
|
|
}
|
|
|
|
pub fn p4_index(self) -> usize {
|
|
(self.number >> 27) & 0o777
|
|
}
|
|
|
|
pub fn p3_index(self) -> usize {
|
|
(self.number >> 18) & 0o777
|
|
}
|
|
|
|
pub fn p2_index(self) -> usize {
|
|
(self.number >> 9) & 0o777
|
|
}
|
|
|
|
pub fn p1_index(self) -> usize {
|
|
self.number & 0o777
|
|
}
|
|
|
|
pub fn containing_address(address: VirtualAddress) -> Page {
|
|
//TODO assert!(address.data() < 0x0000_8000_0000_0000 || address.data() >= 0xffff_8000_0000_0000,
|
|
// "invalid address: 0x{:x}", address.data());
|
|
Page {
|
|
number: address.data() / PAGE_SIZE,
|
|
}
|
|
}
|
|
|
|
pub fn range_inclusive(start: Page, r#final: Page) -> PageIter {
|
|
PageIter {
|
|
start,
|
|
end: r#final.next(),
|
|
}
|
|
}
|
|
pub fn range_exclusive(start: Page, end: Page) -> PageIter {
|
|
PageIter { start, end }
|
|
}
|
|
|
|
pub fn next(self) -> Page {
|
|
self.next_by(1)
|
|
}
|
|
pub fn next_by(self, n: usize) -> Page {
|
|
Self {
|
|
number: self.number + n,
|
|
}
|
|
}
|
|
pub fn offset_from(self, other: Self) -> usize {
|
|
self.number - other.number
|
|
}
|
|
}
|
|
|
|
pub struct PageIter {
|
|
start: Page,
|
|
end: Page,
|
|
}
|
|
|
|
impl Iterator for PageIter {
|
|
type Item = Page;
|
|
|
|
fn next(&mut self) -> Option<Page> {
|
|
if self.start < self.end {
|
|
let page = self.start;
|
|
self.start = self.start.next();
|
|
Some(page)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Round down to the nearest multiple of page size
|
|
pub fn round_down_pages(number: usize) -> usize {
|
|
number - number % PAGE_SIZE
|
|
}
|
|
/// Round up to the nearest multiple of page size
|
|
pub fn round_up_pages(number: usize) -> usize {
|
|
round_down_pages(number + PAGE_SIZE - 1)
|
|
}
|