Skip to content
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

feat: add basic loongarch64 support #126

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
actual.out
qemu.log
rusty-tags.vi
.idea
10 changes: 10 additions & 0 deletions Cargo.lock
equation314 marked this conversation as resolved.
Show resolved Hide resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,13 @@ else ifeq ($(ARCH), aarch64)
ACCEL ?= n
PLATFORM_NAME ?= aarch64-qemu-virt
TARGET := aarch64-unknown-none-softfloat
else ifeq ($(ARCH), loongarch64)
ACCEL ?= n
PLATFORM_NAME ?= loongarch64-qemu-virt
TARGET := loongarch64-unknown-none
BUS := pci
else
$(error "ARCH" must be one of "x86_64", "riscv64", or "aarch64")
$(error "ARCH" must be one of "x86_64", "riscv64", "aarch64" or "loongarch64")
endif

export AX_ARCH=$(ARCH)
Expand All @@ -118,6 +123,9 @@ export AX_GW=$(GW)

# Binutils
CROSS_COMPILE ?= $(ARCH)-linux-musl-
ifeq ($(ARCH), loongarch64)
CROSS_COMPILE := $(ARCH)-unknown-linux-gnu-
endif
CC := $(CROSS_COMPILE)gcc
AR := $(CROSS_COMPILE)ar
RANLIB := $(CROSS_COMPILE)ranlib
Expand Down
19 changes: 19 additions & 0 deletions apps/exception/expect_debug_loongarch64.out
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...
2 changes: 2 additions & 0 deletions apps/exception/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ fn raise_break_exception() {
asm!("brk #0");
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
asm!("ebreak");
#[cfg(any(target_arch = "loongarch64"))]
asm!("break 0");
}
}

Expand Down
19 changes: 19 additions & 0 deletions crates/kernel_guard/src/arch/loongarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use core::arch::asm;

#[inline]
pub fn local_irq_save_and_disable() -> usize {
let mut flags: usize = 0;
let ie_mask: usize = 1 << 2;
equation314 marked this conversation as resolved.
Show resolved Hide resolved
// clear the `IE` bit, and return the old CSR
// unsafe { asm!("csrrd {}, 0x0", out(reg) flags) };
unsafe { asm!("csrxchg {}, {}, 0x0", inout(reg)flags, in(reg) ie_mask) };
equation314 marked this conversation as resolved.
Show resolved Hide resolved
flags & ie_mask
}

#[inline]
#[allow(unused_assignments)]
pub fn local_irq_restore(mut flags: usize) {
// restore the `IE` bit
let mask: usize = 1 << 2;
unsafe { asm!("csrxchg {}, {}, 0x0", inout(reg)flags, in(reg) mask) };
}
3 changes: 3 additions & 0 deletions crates/kernel_guard/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use self::aarch64::*;
}else if #[cfg(target_arch = "loongarch64")] {
equation314 marked this conversation as resolved.
Show resolved Hide resolved
mod loongarch64;
pub use self::loongarch64::*;
}
}
16 changes: 16 additions & 0 deletions crates/page_table/src/arch/loongarch64.rs
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>;
3 changes: 3 additions & 0 deletions crates/page_table/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;
148 changes: 148 additions & 0 deletions crates/page_table_entry/src/arch/loongarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//! 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 highter than PLV.
equation314 marked this conversation as resolved.
Show resolved Hide resolved
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) {
equation314 marked this conversation as resolved.
Show resolved Hide resolved
if f.contains(PTEFlags::PLVH) {
ret |= Self::USER;
}
}
if !f.contains(PTEFlags::MATL) {
equation314 marked this conversation as resolved.
Show resolved Hide resolved
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
}
}

#[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 {
Copy link
Member

Choose a reason for hiding this comment

The 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()
}
}
3 changes: 3 additions & 0 deletions crates/page_table_entry/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ pub mod riscv;
// TODO: `#[cfg(any(target_arch = "aarch64", doc))]` does not work.
#[doc(cfg(target_arch = "aarch64"))]
pub mod aarch64;

#[doc(cfg(target_arch = "loongarch64"))]
pub mod loongarch64;
4 changes: 4 additions & 0 deletions crates/percpu/src/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}, $tp", out(reg) tp)
equation314 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -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")] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add space

core::arch::asm!("move $r21, {}", in(reg) tp)
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions crates/percpu_macros/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ pub fn gen_offset(symbol: &Ident) -> proc_macro2::TokenStream {
out(reg) value,
VAR = sym #symbol,
);
#[cfg(any(target_arch = "loongarch64"))]
::core::arch::asm!(
"la.abs {0}, {VAR}",
out(reg) value,
VAR = sym #symbol,
);
}
value
}
Expand All @@ -58,6 +64,8 @@ pub fn gen_current_ptr(symbol: &Ident, ty: &Type) -> proc_macro2::TokenStream {
::core::arch::asm!("mrs {}, TPIDR_EL1", out(reg) base);
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
::core::arch::asm!("mv {}, gp", out(reg) base);
#[cfg(any(target_arch = "loongarch64"))]
::core::arch::asm!("move {}, $r21", out(reg) base);
(base + self.offset()) as *const #ty
}
})
Expand Down
2 changes: 2 additions & 0 deletions modules/axhal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,7 @@ arm_gic = { path = "../../crates/arm_gic" }
arm_pl011 = { path = "../../crates/arm_pl011" }
dw_apb_uart = { path = "../../crates/dw_apb_uart" }

[target.'cfg(target_arch = "loongarch64")'.dependencies]
loongarch64 = {git = "https://github.com/Godones/loongArch64",package = "loongArch64" }
equation314 marked this conversation as resolved.
Show resolved Hide resolved
[build-dependencies]
axconfig = { path = "../axconfig" }
2 changes: 1 addition & 1 deletion modules/axhal/linker.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ SECTIONS
. = ALIGN(4K);
_edata = .;

.bss : ALIGN(4K) {
.bss : AT(.) ALIGN(4K) {
boot_stack = .;
*(.bss.stack)
. = ALIGN(4K);
Expand Down
Loading