-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
194 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
//! loongarch64 page table entries. | ||
use crate::{GenericPTE, MappingFlags}; | ||
use core::fmt; | ||
use memory_addr::PhysAddr; | ||
|
||
bitflags::bitflags! { | ||
/// Page-table entry flags. | ||
#[derive(Debug)] | ||
pub struct PTEFlags: u64 { | ||
/// Whether the PTE is valid. | ||
const V = 1 << 0; | ||
/// Indicates the virtual page has been written since the last time the | ||
/// D bit was cleared. | ||
const D = 1 << 1; | ||
/// Privilege Level Low Bit | ||
const PLVL = 1 << 2; | ||
/// Privilege Level High Bit | ||
const PLVH = 1 << 3; | ||
/// Memory Access Type Low Bit | ||
/// controls the type of access | ||
const MATL = 1 << 4; | ||
/// Memory Access Type High Bit | ||
const MATH = 1 << 5; | ||
/// Designates a global mapping OR Whether the page is huge page. | ||
const GH = 1 << 6; | ||
/// Whether the physical page is exist. | ||
const P = 1 << 7; | ||
/// Whether the page is writable. | ||
const W = 1 << 8; | ||
/// Designates a global mapping when using huge page. | ||
const G = 1 << 12; | ||
/// Whether the page is not readable. | ||
const NR = 1 << 61; | ||
/// Whether the page is not executable. | ||
const NX = 1 << 62; | ||
/// Whether the privilege Level is restricted. When RPLV is 0, the PTE | ||
/// can be accessed by any program with privilege Level highter than PLV. | ||
const RPLV = 1 << 63; | ||
} | ||
} | ||
|
||
impl From<PTEFlags> for MappingFlags { | ||
fn from(f: PTEFlags) -> Self { | ||
let mut ret = Self::empty(); | ||
if !f.contains(PTEFlags::NR) { | ||
ret |= Self::READ; | ||
} | ||
if f.contains(PTEFlags::W) { | ||
ret |= Self::WRITE; | ||
} | ||
if !f.contains(PTEFlags::NX) { | ||
ret |= Self::EXECUTE; | ||
} | ||
if f.contains(PTEFlags::PLVL) && f.contains(PTEFlags::PLVH) { | ||
ret |= Self::USER; | ||
} | ||
if !f.contains(PTEFlags::MATL) { | ||
ret |= Self::DEVICE; | ||
} | ||
|
||
ret | ||
} | ||
} | ||
|
||
impl From<MappingFlags> for PTEFlags { | ||
fn from(f: MappingFlags) -> Self { | ||
if f.is_empty() { | ||
return Self::empty(); | ||
} | ||
let mut ret = Self::V; | ||
if !f.contains(MappingFlags::READ) { | ||
ret |= Self::NR; | ||
} | ||
if f.contains(MappingFlags::WRITE) { | ||
ret |= Self::W; | ||
} | ||
if !f.contains(MappingFlags::EXECUTE) { | ||
ret |= Self::NX; | ||
} | ||
if f.contains(MappingFlags::USER) { | ||
ret |= Self::PLVH | Self::PLVL; | ||
} | ||
if !f.contains(MappingFlags::DEVICE) { | ||
ret |= Self::MATL; | ||
} | ||
ret | ||
} | ||
} | ||
|
||
/// page table entry for loongarch64 system | ||
#[derive(Clone, Copy)] | ||
#[repr(transparent)] | ||
pub struct LA64PTE(u64); | ||
|
||
impl LA64PTE { | ||
const PHYS_ADDR_MASK: u64 = 0x0000_ffff_ffff_f000; // bits 12..48 | ||
} | ||
|
||
impl GenericPTE for LA64PTE { | ||
fn new_page(paddr: PhysAddr, flags: MappingFlags, is_huge: bool) -> Self { | ||
let mut flags = PTEFlags::from(flags); | ||
if is_huge { | ||
flags |= PTEFlags::GH; | ||
} | ||
Self(flags.bits() | ((paddr.as_usize()) as u64 & Self::PHYS_ADDR_MASK)) | ||
} | ||
fn new_table(paddr: PhysAddr) -> Self { | ||
Self((paddr.as_usize() as u64) & Self::PHYS_ADDR_MASK) | ||
} | ||
fn paddr(&self) -> PhysAddr { | ||
PhysAddr::from((self.0 & Self::PHYS_ADDR_MASK) as usize) | ||
} | ||
fn flags(&self) -> MappingFlags { | ||
PTEFlags::from_bits_truncate(self.0).into() | ||
} | ||
fn set_paddr(&mut self, paddr: PhysAddr) { | ||
self.0 = (self.0 & !Self::PHYS_ADDR_MASK) | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK) | ||
} | ||
fn set_flags(&mut self, flags: MappingFlags, is_huge: bool) { | ||
let mut flags = PTEFlags::from(flags); | ||
if is_huge { | ||
flags |= PTEFlags::GH; | ||
} | ||
self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits(); | ||
} | ||
fn bits(self) -> usize { | ||
self.0 as usize | ||
} | ||
fn is_unused(&self) -> bool { | ||
self.0 == 0 | ||
} | ||
fn is_present(&self) -> bool { | ||
PTEFlags::from_bits_truncate(self.0).contains(PTEFlags::P) | ||
} | ||
fn is_huge(&self) -> bool { | ||
PTEFlags::from_bits_truncate(self.0).contains(PTEFlags::GH) | ||
} | ||
fn clear(&mut self) { | ||
self.0 = 0 | ||
} | ||
} | ||
|
||
impl fmt::Debug for LA64PTE { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
let mut f = f.debug_struct("LA64PTE"); | ||
f.field("raw", &self.0) | ||
.field("paddr", &self.paddr()) | ||
.field("flags", &self.flags()) | ||
.finish() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
//! LoongArch64 specific page table structures. | ||
use crate::{PageTable64, PagingMetaData}; | ||
use core::arch::asm; | ||
|
||
use page_table_entry::loongarch64::LA64PTE; | ||
/// Metadata of LoongArch64 page tables. | ||
#[derive(Copy, Clone, Debug)] | ||
pub struct LA64MetaData; | ||
|
||
impl PagingMetaData for LA64MetaData { | ||
const LEVELS: usize = 3; | ||
const PA_MAX_BITS: usize = 48; | ||
const VA_MAX_BITS: usize = 48; | ||
type VirtAddr = memory_addr::VirtAddr; | ||
|
||
fn vaddr_is_valid(vaddr: usize) -> bool { | ||
let top_bits = vaddr >> Self::VA_MAX_BITS; | ||
top_bits == 0 || top_bits == 0xffff || top_bits == 0x9000 || top_bits == 0x8000 | ||
} | ||
|
||
#[inline] | ||
fn flush_tlb(vaddr: Option<memory_addr::VirtAddr>) { | ||
unsafe { | ||
if let Some(vaddr) = vaddr { | ||
asm!("dbar 0; invtlb 0x05, $r0, {reg}", reg = in(reg) vaddr.as_usize()); | ||
} else { | ||
asm!("dbar 0; invtlb 0x00, $r0, $r0"); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// loongarch64 page table | ||
pub type LA64PageTable<I> = PageTable64<LA64MetaData, LA64PTE, I>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters