Add PageFlags to abstract differences between architectures
This commit is contained in:
+48
-9
@@ -2,6 +2,7 @@ use crate::{
|
||||
Arch,
|
||||
MemoryArea,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
};
|
||||
|
||||
@@ -11,16 +12,26 @@ pub struct AArch64Arch;
|
||||
impl Arch for AArch64Arch {
|
||||
const PAGE_SHIFT: usize = 12; // 4096 bytes
|
||||
const PAGE_ENTRY_SHIFT: usize = 9; // 512 entries, 8 bytes each
|
||||
const PAGE_LEVELS: usize = 4; // PML4, PDP, PD, PT
|
||||
const PAGE_LEVELS: usize = 4; // L0, L1, L2, L3
|
||||
|
||||
//TODO
|
||||
const ENTRY_ADDRESS_SHIFT: usize = 52;
|
||||
const ENTRY_FLAG_DEFAULT_PAGE: usize
|
||||
= Self::ENTRY_FLAG_PRESENT
|
||||
| 1 << 10 // Access flag
|
||||
;
|
||||
const ENTRY_FLAG_DEFAULT_TABLE: usize
|
||||
= Self::ENTRY_FLAG_PRESENT
|
||||
| 1 << 1 // Table flag
|
||||
| 1 << 10 // Access flag
|
||||
;
|
||||
const ENTRY_FLAG_PRESENT: usize = 1 << 0;
|
||||
const ENTRY_FLAG_WRITABLE: usize = 1 << 1;
|
||||
const ENTRY_FLAG_USER: usize = 1 << 2;
|
||||
const ENTRY_FLAG_HUGE: usize = 1 << 7;
|
||||
const ENTRY_FLAG_GLOBAL: usize = 1 << 8;
|
||||
const ENTRY_FLAG_NO_EXEC: usize = 1 << 63;
|
||||
const ENTRY_FLAG_READONLY: usize = 1 << 7;
|
||||
const ENTRY_FLAG_READWRITE: usize = 0;
|
||||
const ENTRY_FLAG_USER: usize = 1 << 6;
|
||||
// This sets both userspace and privileged execute never
|
||||
//TODO: Separate the two?
|
||||
const ENTRY_FLAG_NO_EXEC: usize = 0b11 << 53;
|
||||
|
||||
const PHYS_OFFSET: usize = Self::PAGE_NEGATIVE_MASK + (Self::PAGE_ADDRESS_SIZE >> 1); // PML4 slot 256 and onwards
|
||||
|
||||
@@ -30,17 +41,45 @@ impl Arch for AArch64Arch {
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn invalidate(address: VirtualAddress) {
|
||||
unimplemented!()
|
||||
//TODO: can one address be invalidated?
|
||||
Self::invalidate_all();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn invalidate_all() {
|
||||
asm!("tlbi vmalle1is");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn table() -> PhysicalAddress {
|
||||
unimplemented!()
|
||||
let address: usize;
|
||||
//TODO: set this dynamically
|
||||
let table_kind = TableKind::Kernel;
|
||||
match table_kind {
|
||||
TableKind::User => {
|
||||
asm!("mrs {0}, ttbr0_el1", out(reg) address);
|
||||
},
|
||||
TableKind::Kernel => {
|
||||
asm!("mrs {0}, ttbr1_el1", out(reg) address);
|
||||
}
|
||||
}
|
||||
PhysicalAddress::new(address)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn set_table(address: PhysicalAddress) {
|
||||
unimplemented!()
|
||||
//TODO: set this dynamically
|
||||
let table_kind = TableKind::Kernel;
|
||||
match table_kind {
|
||||
TableKind::User => {
|
||||
asm!("msr ttbr0_el1, {0}", in(reg) address.data());
|
||||
},
|
||||
TableKind::Kernel => {
|
||||
asm!("msr ttbr1_el1, {0}", in(reg) address.data());
|
||||
}
|
||||
}
|
||||
//TODO: Does this need to be called?
|
||||
Self::invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -27,7 +27,8 @@ impl Arch for EmulateArch {
|
||||
const ENTRY_FLAG_DEFAULT_PAGE: usize = X8664Arch::ENTRY_FLAG_DEFAULT_PAGE;
|
||||
const ENTRY_FLAG_DEFAULT_TABLE: usize = X8664Arch::ENTRY_FLAG_DEFAULT_TABLE;
|
||||
const ENTRY_FLAG_PRESENT: usize = X8664Arch::ENTRY_FLAG_PRESENT;
|
||||
const ENTRY_FLAG_WRITABLE: usize = X8664Arch::ENTRY_FLAG_WRITABLE;
|
||||
const ENTRY_FLAG_READONLY: usize = X8664Arch::ENTRY_FLAG_READONLY;
|
||||
const ENTRY_FLAG_READWRITE: usize = X8664Arch::ENTRY_FLAG_READWRITE;
|
||||
const ENTRY_FLAG_USER: usize = X8664Arch::ENTRY_FLAG_USER;
|
||||
const ENTRY_FLAG_NO_EXEC: usize = X8664Arch::ENTRY_FLAG_NO_EXEC;
|
||||
|
||||
@@ -40,7 +41,7 @@ impl Arch for EmulateArch {
|
||||
// PML4 index 256 (PHYS_OFFSET) link to PDP
|
||||
let pml4 = 0;
|
||||
let pdp = pml4 + Self::PAGE_SIZE;
|
||||
let flags = Self::ENTRY_FLAG_WRITABLE | Self::ENTRY_FLAG_PRESENT;
|
||||
let flags = Self::ENTRY_FLAG_READWRITE | Self::ENTRY_FLAG_PRESENT;
|
||||
machine.write_phys::<usize>(PhysicalAddress::new(pml4 + 256 * Self::PAGE_ENTRY_SIZE), pdp | flags);
|
||||
|
||||
// PDP link to PD
|
||||
@@ -200,7 +201,7 @@ impl<A: Arch> Machine<A> {
|
||||
}
|
||||
|
||||
if let Some((phys, flags)) = self.translate(virt) {
|
||||
if flags & A::ENTRY_FLAG_WRITABLE != 0 {
|
||||
if flags & A::ENTRY_FLAG_READWRITE != 0 {
|
||||
self.write_phys(phys, value);
|
||||
} else {
|
||||
panic!("write: 0x{:X} size 0x{:X} not writable", virt_data, size);
|
||||
@@ -218,7 +219,7 @@ impl<A: Arch> Machine<A> {
|
||||
}
|
||||
|
||||
if let Some((phys, flags)) = self.translate(virt) {
|
||||
if flags & A::ENTRY_FLAG_WRITABLE != 0 {
|
||||
if flags & A::ENTRY_FLAG_READWRITE != 0 {
|
||||
self.write_phys_bytes(phys, value, count);
|
||||
} else {
|
||||
panic!("write_bytes: 0x{:X} count 0x{:X} not writable", virt_data, count);
|
||||
|
||||
+2
-1
@@ -25,7 +25,8 @@ pub trait Arch: Clone + Copy {
|
||||
const ENTRY_FLAG_DEFAULT_PAGE: usize;
|
||||
const ENTRY_FLAG_DEFAULT_TABLE: usize;
|
||||
const ENTRY_FLAG_PRESENT: usize;
|
||||
const ENTRY_FLAG_WRITABLE: usize;
|
||||
const ENTRY_FLAG_READONLY: usize;
|
||||
const ENTRY_FLAG_READWRITE: usize;
|
||||
const ENTRY_FLAG_USER: usize;
|
||||
const ENTRY_FLAG_NO_EXEC: usize;
|
||||
|
||||
|
||||
+4
-3
@@ -14,10 +14,11 @@ impl Arch for X8664Arch {
|
||||
const PAGE_LEVELS: usize = 4; // PML4, PDP, PD, PT
|
||||
|
||||
const ENTRY_ADDRESS_SHIFT: usize = 52;
|
||||
const ENTRY_FLAG_DEFAULT_PAGE: usize = ENTRY_FLAG_PRESENT;
|
||||
const ENTRY_FLAG_DEFAULT_TABLE: usize = ENTRY_FLAG_PRESENT;
|
||||
const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT;
|
||||
const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT;
|
||||
const ENTRY_FLAG_PRESENT: usize = 1 << 0;
|
||||
const ENTRY_FLAG_WRITABLE: usize = 1 << 1;
|
||||
const ENTRY_FLAG_READONLY: usize = 0;
|
||||
const ENTRY_FLAG_READWRITE: usize = 1 << 1;
|
||||
const ENTRY_FLAG_USER: usize = 1 << 2;
|
||||
// Not used: const ENTRY_FLAG_HUGE: usize = 1 << 7;
|
||||
// Not used: const ENTRY_FLAG_GLOBAL: usize = 1 << 8;
|
||||
|
||||
+3
-2
@@ -10,6 +10,7 @@ use rmm::{
|
||||
FrameAllocator,
|
||||
FrameCount,
|
||||
MemoryArea,
|
||||
PageFlags,
|
||||
PageFlushAll,
|
||||
PageMapper,
|
||||
PageTable,
|
||||
@@ -190,7 +191,7 @@ unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
A::ENTRY_FLAG_WRITABLE
|
||||
PageFlags::<A>::new().write(true)
|
||||
).expect("failed to map page to frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
@@ -238,7 +239,7 @@ unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
|
||||
let virt = VirtualAddress::new(MEGABYTE + i * A::PAGE_SIZE);
|
||||
let flush = mapper.map(
|
||||
virt,
|
||||
A::ENTRY_FLAG_USER | A::ENTRY_FLAG_WRITABLE
|
||||
PageFlags::<A>::new().user(true).write(true)
|
||||
).expect("failed to map page");
|
||||
flush_all.consume(flush);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::Arch;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct PageFlags<A> {
|
||||
data: usize,
|
||||
phantom: PhantomData<A>,
|
||||
}
|
||||
|
||||
impl<A: Arch> PageFlags<A> {
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
unsafe {
|
||||
Self::from_data(
|
||||
// Flags set to present, kernel space, read-only, no-execute by default
|
||||
A::ENTRY_FLAG_DEFAULT_PAGE |
|
||||
A::ENTRY_FLAG_READONLY |
|
||||
A::ENTRY_FLAG_NO_EXEC
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn from_data(data: usize) -> Self {
|
||||
Self { data, phantom: PhantomData }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn data(&self) -> usize {
|
||||
self.data
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn custom_flag(mut self, flag: usize, value: bool) -> Self {
|
||||
if value {
|
||||
self.data |= flag;
|
||||
} else {
|
||||
self.data &= !flag;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn user(self, value: bool) -> Self {
|
||||
self.custom_flag(A::ENTRY_FLAG_USER, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn write(self, value: bool) -> Self {
|
||||
// Architecture may use readonly or readwrite, support either
|
||||
self.custom_flag(A::ENTRY_FLAG_READONLY, !value)
|
||||
.custom_flag(A::ENTRY_FLAG_READWRITE, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn execute(self, value: bool) -> Self {
|
||||
//TODO: write xor execute?
|
||||
self.custom_flag(A::ENTRY_FLAG_NO_EXEC, !value)
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -4,6 +4,7 @@ use crate::{
|
||||
Arch,
|
||||
FrameAllocator,
|
||||
PageEntry,
|
||||
PageFlags,
|
||||
PageFlush,
|
||||
PageTable,
|
||||
PhysicalAddress,
|
||||
@@ -47,15 +48,15 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn map(&mut self, virt: VirtualAddress, flags: usize) -> Option<PageFlush<A>> {
|
||||
pub unsafe fn map(&mut self, virt: VirtualAddress, flags: PageFlags<A>) -> Option<PageFlush<A>> {
|
||||
let phys = self.allocator.allocate_one()?;
|
||||
self.map_phys(virt, phys, flags)
|
||||
}
|
||||
|
||||
pub unsafe fn map_phys(&mut self, virt: VirtualAddress, phys: PhysicalAddress, flags: usize) -> Option<PageFlush<A>> {
|
||||
pub unsafe fn map_phys(&mut self, virt: VirtualAddress, phys: PhysicalAddress, flags: PageFlags<A>) -> Option<PageFlush<A>> {
|
||||
//TODO: verify virt and phys are aligned
|
||||
//TODO: verify flags have correct bits
|
||||
let entry = PageEntry::new(phys.data() | flags | A::ENTRY_FLAG_DEFAULT_PAGE);
|
||||
let entry = PageEntry::new(phys.data() | flags.data());
|
||||
let mut table = self.table();
|
||||
loop {
|
||||
let i = table.index_of(virt)?;
|
||||
@@ -70,7 +71,7 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> {
|
||||
None => {
|
||||
let next_phys = self.allocator.allocate_one()?;
|
||||
//TODO: correct flags?
|
||||
table.set_entry(i, PageEntry::new(next_phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_DEFAULT_TABLE));
|
||||
table.set_entry(i, PageEntry::new(next_phys.data() | A::ENTRY_FLAG_READWRITE | A::ENTRY_FLAG_DEFAULT_TABLE));
|
||||
table.next(i)?
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
pub use self::{
|
||||
entry::*,
|
||||
flags::*,
|
||||
flush::*,
|
||||
mapper::*,
|
||||
table::*,
|
||||
};
|
||||
|
||||
mod entry;
|
||||
mod flags;
|
||||
mod flush;
|
||||
mod mapper;
|
||||
mod table;
|
||||
|
||||
Reference in New Issue
Block a user