Files
RedBear-OS/src/arch/x86/paging/mod.rs
T
2024-01-17 13:52:01 -07:00

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)
}