Skip to content

Commit

Permalink
feat: add loongarch64 support
Browse files Browse the repository at this point in the history
  • Loading branch information
yfblock committed Jan 14, 2025
1 parent a8b47c8 commit 6b5444d
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
fail-fast: false
matrix:
rust-toolchain: [nightly]
targets: [x86_64-unknown-linux-gnu, x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none-softfloat]
targets: [x86_64-unknown-linux-gnu, x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none-softfloat, loongarch64-unknown-none-softfloat]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
Expand Down
152 changes: 152 additions & 0 deletions page_table_entry/src/arch/loongarch64.rs
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()
}
}
3 changes: 3 additions & 0 deletions page_table_entry/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ pub mod riscv;

#[cfg(any(target_arch = "aarch64", doc))]
pub mod aarch64;

#[cfg(any(target_arch = "loongarch64", doc))]
pub mod loongarch64;
35 changes: 35 additions & 0 deletions page_table_multiarch/src/arch/loongarch64.rs
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>;
3 changes: 3 additions & 0 deletions page_table_multiarch/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ pub mod riscv;

#[cfg(any(target_arch = "aarch64", doc))]
pub mod aarch64;

#[cfg(any(target_arch = "loongarch64", doc))]
pub mod loongarch64;

0 comments on commit 6b5444d

Please sign in to comment.