-
Notifications
You must be signed in to change notification settings - Fork 423
feat: add basic loongarch64 support #126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 11 commits
34de609
fabae91
7aa5260
42fdc45
ad413d0
a2b1f30
f4c2b70
3606df6
e83ec55
a1fa046
f20bf83
754b950
2d41808
b7c3360
ccd44e1
b2c67b7
38f0e86
e81c425
2d32006
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,3 +6,4 @@ | |
| actual.out | ||
| qemu.log | ||
| rusty-tags.vi | ||
| .idea | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| smp = 1 | ||
| build_mode = release | ||
| log_level = debug | ||
|
|
||
| Primary CPU 0 started, | ||
| Found physcial memory regions: | ||
| .text (READ | EXECUTE | RESERVED) | ||
| .rodata (READ | RESERVED) | ||
| .data .tdata .tbss .percpu (READ | WRITE | RESERVED) | ||
| .percpu (READ | WRITE | RESERVED) | ||
| boot stack (READ | WRITE | RESERVED) | ||
| .bss (READ | WRITE | RESERVED) | ||
| free memory (READ | WRITE | FREE) | ||
| Initialize platform devices... | ||
| Primary CPU 0 init OK. | ||
| Running exception tests... | ||
| Exception(Breakpoint) @ 0x[0-9a-f]\{16\} | ||
| Exception tests run OK! | ||
| Shutting down... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| use core::arch::asm; | ||
|
|
||
| /// Bit 2: Supervisor Interrupt Enable | ||
| const IE_BIT: usize = 1 << 2; | ||
|
|
||
| #[inline] | ||
| pub fn local_irq_save_and_disable() -> usize { | ||
| let mut flags: usize = 0; | ||
| // clear the `IE` bit, and return the old CSR | ||
| unsafe { asm!("csrxchg {}, {}, 0x0", inout(reg) flags, in(reg) IE_BIT) }; | ||
| flags & IE_BIT | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn local_irq_restore(mut flags: usize) { | ||
| // restore the `IE` bit | ||
| unsafe { asm!("csrxchg {}, {}, 0x0", inout(reg) flags, in(reg) IE_BIT) }; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| //! LoongArch64 specific page table structures. | ||
|
|
||
| use crate::{PageTable64, PagingMetaData}; | ||
|
|
||
| use page_table_entry::loongarch64::LA64PTE; | ||
| /// Metadata of LoongArch64 page tables. | ||
| #[derive(Copy, Clone, Debug)] | ||
| pub struct LA64MetaData; | ||
|
|
||
| impl const PagingMetaData for LA64MetaData { | ||
| const LEVELS: usize = 4; | ||
| const PA_MAX_BITS: usize = 48; | ||
| const VA_MAX_BITS: usize = 48; | ||
| } | ||
|
|
||
| pub type LA64PageTable<I> = PageTable64<LA64MetaData, LA64PTE, I>; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| //! 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: usize { | ||
| /// 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 with 2 bits. | ||
| const PLVL = 1 << 2; | ||
| const PLVH = 1 << 3; | ||
| /// Memory Access Type controls the type of access, such as whether it | ||
| /// can be cached by Cache, etc. | ||
| const MATL = 1 << 4; | ||
| 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 higher 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 | PTEFlags::PLVH) { | ||
| ret |= Self::USER; | ||
| } | ||
| if !f.contains(PTEFlags::MATL) { | ||
equation314 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ret |= Self::DEVICE; | ||
| } else { | ||
| ret |= Self::UNCACHED; | ||
| } | ||
| 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 | ||
| } | ||
| } | ||
|
|
||
| #[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 flags = PTEFlags::from(flags); | ||
| Self(flags.bits() as u64 | ((paddr.as_usize()) as u64 & Self::PHYS_ADDR_MASK)) | ||
| } | ||
| fn new_table(paddr: PhysAddr) -> Self { | ||
| Self(PTEFlags::V.bits() as u64 | ((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 as usize).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 flags = PTEFlags::from(flags); | ||
| self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits() as u64; | ||
| } | ||
|
|
||
| fn is_unused(&self) -> bool { | ||
| self.0 == 0 | ||
| } | ||
| fn is_present(&self) -> bool { | ||
| PTEFlags::from_bits_truncate(self.0 as usize).contains(PTEFlags::V) | ||
| } | ||
| fn is_huge(&self) -> bool { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reasons for not supporting huge pages? |
||
| false | ||
| } | ||
| 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()) | ||
| .field("is_unused", &self.is_unused()) | ||
| .field("is_present", &self.is_present()) | ||
| .field("is_huge", &self.is_huge()) | ||
| .finish() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,8 @@ pub fn get_local_thread_pointer() -> usize { | |
| core::arch::asm!("mv {}, gp", out(reg) tp) | ||
| } else if #[cfg(target_arch = "aarch64")] { | ||
| core::arch::asm!("mrs {}, TPIDR_EL1", out(reg) tp) | ||
| } else if #[cfg(target_arch = "loongarch64")] { | ||
equation314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| core::arch::asm!("move {}, $21", out(reg) tp) | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -108,6 +110,8 @@ pub fn set_local_thread_pointer(cpu_id: usize) { | |
| core::arch::asm!("mv gp, {}", in(reg) tp) | ||
| } else if #[cfg(target_arch = "aarch64")] { | ||
| core::arch::asm!("msr TPIDR_EL1, {}", in(reg) tp) | ||
| }else if #[cfg(target_arch = "loongarch64")] { | ||
|
||
| core::arch::asm!("move $r21, {}", in(reg) tp) | ||
| } | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.