Merge remote-tracking branch 'origin/aarch64-rebase'
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
use crate::{
|
||||
Arch,
|
||||
MemoryArea,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
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; // L0, L1, L2, L3
|
||||
|
||||
//TODO
|
||||
const ENTRY_ADDRESS_SHIFT: usize = 52;
|
||||
const ENTRY_FLAG_DEFAULT_PAGE: usize
|
||||
= Self::ENTRY_FLAG_PRESENT
|
||||
| 1 << 1 // Page flag
|
||||
| 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_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;
|
||||
|
||||
//TODO: adjust to match x86_64?
|
||||
const PHYS_OFFSET: usize = 0xfffffe0000000000;
|
||||
|
||||
unsafe fn init() -> &'static [MemoryArea] {
|
||||
unimplemented!("AArch64Arch::init unimplemented");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn invalidate(address: VirtualAddress) {
|
||||
//TODO: can one address be invalidated?
|
||||
Self::invalidate_all();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn invalidate_all() {
|
||||
asm!("tlbi vmalle1is");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn table() -> PhysicalAddress {
|
||||
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) {
|
||||
//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();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Arch;
|
||||
use super::AArch64Arch;
|
||||
|
||||
#[test]
|
||||
fn constants() {
|
||||
assert_eq!(AArch64Arch::PAGE_SIZE, 4096);
|
||||
assert_eq!(AArch64Arch::PAGE_OFFSET_MASK, 0xFFF);
|
||||
assert_eq!(AArch64Arch::PAGE_ADDRESS_SHIFT, 48);
|
||||
assert_eq!(AArch64Arch::PAGE_ADDRESS_SIZE, 0x0001_0000_0000_0000);
|
||||
assert_eq!(AArch64Arch::PAGE_ADDRESS_MASK, 0x0000_FFFF_FFFF_F000);
|
||||
assert_eq!(AArch64Arch::PAGE_ENTRY_SIZE, 8);
|
||||
assert_eq!(AArch64Arch::PAGE_ENTRIES, 512);
|
||||
assert_eq!(AArch64Arch::PAGE_ENTRY_MASK, 0x1FF);
|
||||
assert_eq!(AArch64Arch::PAGE_NEGATIVE_MASK, 0xFFFF_0000_0000_0000);
|
||||
|
||||
assert_eq!(AArch64Arch::ENTRY_ADDRESS_SIZE, 0x0010_0000_0000_0000);
|
||||
assert_eq!(AArch64Arch::ENTRY_ADDRESS_MASK, 0x000F_FFFF_FFFF_F000);
|
||||
assert_eq!(AArch64Arch::ENTRY_FLAGS_MASK, 0xFFF0_0000_0000_0FFF);
|
||||
|
||||
assert_eq!(AArch64Arch::PHYS_OFFSET, 0xFFFF_8000_0000_0000);
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -24,11 +24,12 @@ impl Arch for EmulateArch {
|
||||
const PAGE_LEVELS: usize = X8664Arch::PAGE_LEVELS;
|
||||
|
||||
const ENTRY_ADDRESS_SHIFT: usize = X8664Arch::ENTRY_ADDRESS_SHIFT;
|
||||
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_HUGE: usize = X8664Arch::ENTRY_FLAG_HUGE;
|
||||
const ENTRY_FLAG_GLOBAL: usize = X8664Arch::ENTRY_FLAG_GLOBAL;
|
||||
const ENTRY_FLAG_NO_EXEC: usize = X8664Arch::ENTRY_FLAG_NO_EXEC;
|
||||
|
||||
const PHYS_OFFSET: usize = X8664Arch::PHYS_OFFSET;
|
||||
@@ -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);
|
||||
|
||||
+6
-3
@@ -6,10 +6,12 @@ use crate::{
|
||||
VirtualAddress,
|
||||
};
|
||||
|
||||
pub use self::aarch64::AArch64Arch;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::emulate::EmulateArch;
|
||||
pub use self::x86_64::X8664Arch;
|
||||
|
||||
mod aarch64;
|
||||
#[cfg(feature = "std")]
|
||||
mod emulate;
|
||||
mod x86_64;
|
||||
@@ -20,11 +22,12 @@ pub trait Arch: Clone + Copy {
|
||||
const PAGE_LEVELS: usize;
|
||||
|
||||
const ENTRY_ADDRESS_SHIFT: usize;
|
||||
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_HUGE: usize;
|
||||
const ENTRY_FLAG_GLOBAL: usize;
|
||||
const ENTRY_FLAG_NO_EXEC: usize;
|
||||
|
||||
const PHYS_OFFSET: usize;
|
||||
|
||||
+6
-3
@@ -14,11 +14,14 @@ 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 = 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;
|
||||
const ENTRY_FLAG_HUGE: usize = 1 << 7;
|
||||
const ENTRY_FLAG_GLOBAL: usize = 1 << 8;
|
||||
// Not used: const ENTRY_FLAG_HUGE: usize = 1 << 7;
|
||||
// Not used: const ENTRY_FLAG_GLOBAL: usize = 1 << 8;
|
||||
const ENTRY_FLAG_NO_EXEC: usize = 1 << 63;
|
||||
|
||||
const PHYS_OFFSET: usize = Self::PAGE_NEGATIVE_MASK + (Self::PAGE_ADDRESS_SIZE >> 1); // PML4 slot 256 and onwards
|
||||
|
||||
+12
-2
@@ -17,7 +17,17 @@ pub const MEGABYTE: usize = KILOBYTE * KILOBYTE;
|
||||
pub const GIGABYTE: usize = KILOBYTE * MEGABYTE;
|
||||
pub const TERABYTE: usize = KILOBYTE * GIGABYTE;
|
||||
|
||||
// Physical memory address
|
||||
/// Specific table to be used, needed on some architectures
|
||||
//TODO: Use this throughout the code
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub enum TableKind {
|
||||
/// Userspace page table
|
||||
User,
|
||||
/// Kernel page table
|
||||
Kernel,
|
||||
}
|
||||
|
||||
/// Physical memory address
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
#[repr(transparent)]
|
||||
pub struct PhysicalAddress(usize);
|
||||
@@ -39,7 +49,7 @@ impl PhysicalAddress {
|
||||
}
|
||||
}
|
||||
|
||||
// Virtual memory address
|
||||
/// Virtual memory address
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
#[repr(transparent)]
|
||||
pub struct VirtualAddress(usize);
|
||||
|
||||
+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)]
|
||||
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_PRESENT);
|
||||
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_PRESENT));
|
||||
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