Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
11 changes: 11 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ members = [
"crates/spinlock",
"crates/timer_list",
"crates/tuple_for_each",
"crates/loongarch64",

"modules/axalloc",
"modules/axconfig",
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,12 @@ 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
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 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;
// 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) };
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")] {
mod loongarch64;
pub use self::loongarch64::*;
}
}
11 changes: 11 additions & 0 deletions crates/loongarch64/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "loongarch64"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bit_field = "0.10.1"
log = "0.4"
cfg-if = "1.0"
33 changes: 33 additions & 0 deletions crates/loongarch64/src/asm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! Assembly instructions

macro_rules! instruction {
($(#[$attr:meta])*, $fnname:ident, $asm:expr) => (
$(#[$attr])*
#[inline]
pub unsafe fn $fnname() {
match () {
#[cfg(target_arch = "loongarch64")]
() => core::arch::asm!($asm),

#[cfg(not(target_arch = "loongarch64"))]
() => unimplemented!(),
}
}
)
}

instruction!(
/// `nop` instruction wrapper
///
/// Generates a no-operation. Useful to prevent delay loops from being optimized away.
, nop, "nop");
instruction!(
/// `EBREAK` instruction wrapper
///
/// Generates a breakpoint exception.
, r#break, "break");
instruction!(
/// `EBREAK` instruction wrapper
///
/// The format is `idle level`. What is level is still unknown. Temporarily use `1` as `level`.
, idle, "idle 1");
21 changes: 21 additions & 0 deletions crates/loongarch64/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
pub const LOONGARCH_IOCSR_IPI_STATUS: usize = 0x1000;
pub const LOONGARCH_IOCSR_IPI_EN: usize = 0x1004;
pub const LOONGARCH_IOCSR_IPI_SET: usize = 0x1008;
pub const LOONGARCH_IOCSR_IPI_CLEAR: usize = 0x100c;
pub const LOONGARCH_CSR_MAIL_BUF0: usize = 0x1020;
pub const LOONGARCH_CSR_MAIL_BUF1: usize = 0x1028;
pub const LOONGARCH_CSR_MAIL_BUF2: usize = 0x1030;
pub const LOONGARCH_CSR_MAIL_BUF3: usize = 0x1038;

pub const IOCSR_MBUF_SEND_CPU_SHIFT: usize = 16;
pub const IOCSR_MBUF_SEND_BUF_SHIFT: usize = 32;
pub const IOCSR_MBUF_SEND_H32_MASK: usize = 0xFFFF_FFFF_0000_0000;

pub const LOONGARCH_IOCSR_IPI_SEND: usize = 0x1040;
pub const IOCSR_IPI_SEND_IP_SHIFT: usize = 0;
pub const IOCSR_IPI_SEND_CPU_SHIFT: usize = 16;
pub const IOCSR_IPI_SEND_BLOCKING: u32 = 1 << 31;

pub const LOONGARCH_IOCSR_MBUF_SEND: usize = 0x1048;
pub const IOCSR_MBUF_SEND_BLOCKING: u64 = 1 << 31;
pub const IOCSR_MBUF_SEND_BOX_SHIFT: usize = 2;
96 changes: 96 additions & 0 deletions crates/loongarch64/src/cpu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use bit_field::BitField;
use core::arch::asm;
#[derive(Debug, Clone, Copy)]
pub enum CpuMode {
User = 3,
Supervisor = 0,
}

pub struct CPUCFG {
bits: usize,
}

impl CPUCFG {
// 读取index对应字的内容
pub fn read(index: usize) -> Self {
let mut bits;
unsafe {
asm!("cpucfg {},{}",out(reg) bits,in(reg) index);
}
Self { bits }
}
pub fn get_bit(&self, index: usize) -> bool {
self.bits.get_bit(index)
}
pub fn get_bits(&self, start: usize, end: usize) -> usize {
self.bits.get_bits(start..=end)
}
}

// 获取处理器标识
pub fn get_prid() -> usize {
let cfg = CPUCFG::read(0);
cfg.get_bits(0, 31)
}

// 获取架构信息
pub fn get_arch() -> usize {
let cfg = CPUCFG::read(1);
cfg.get_bits(0, 1)
}

pub fn get_mmu_support_page() -> bool {
let cfg = CPUCFG::read(1);
cfg.get_bit(2)
}

pub fn get_support_iocsr() -> bool {
let cfg = CPUCFG::read(1);
cfg.get_bit(3)
}

// 获取支持的物理地址位数
pub fn get_palen() -> usize {
let cfg = CPUCFG::read(1);
cfg.get_bits(4, 11) + 1
}

// 获取支持的虚拟地址位数
pub fn get_valen() -> usize {
let cfg = CPUCFG::read(1);
cfg.get_bits(12, 19) + 1
}
// 是否支持非对齐访存
pub fn get_ual() -> bool {
let cfg = CPUCFG::read(1);
cfg.get_bit(20)
}

pub fn get_support_read_forbid() -> bool {
let cfg = CPUCFG::read(1);
cfg.get_bit(21)
}
pub fn get_support_execution_protection() -> bool {
let cfg = CPUCFG::read(1);
cfg.get_bit(22)
}
pub fn get_support_rplv() -> bool {
let cfg = CPUCFG::read(1);
cfg.get_bit(23)
}
pub fn get_support_huge_page() -> bool {
let cfg = CPUCFG::read(1);
cfg.get_bit(24)
}
pub fn get_support_rva() -> bool {
let cfg = CPUCFG::read(3);
cfg.get_bit(12)
}
pub fn get_support_rva_len() -> usize {
let cfg = CPUCFG::read(3);
cfg.get_bits(13, 16) + 1
}
pub fn get_support_lspw() -> bool {
let cfg = CPUCFG::read(2);
cfg.get_bit(21)
}
53 changes: 53 additions & 0 deletions crates/loongarch64/src/extioi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use super::loongson::{
iocsr_read_b, iocsr_read_d, iocsr_read_w, iocsr_write_b, iocsr_write_d, iocsr_write_h,
iocsr_write_w, LOONGARCH_IOCSR_EXRIOI_NODETYPE_BASE, LOONGARCH_IOCSR_EXTIOI_EN_BASE,
LOONGARCH_IOCSR_EXTIOI_ISR_BASE, LOONGARCH_IOCSR_EXTIOI_MAP_BASE,
LOONGARCH_IOCSR_EXTIOI_ROUTE_BASE,
};
use super::ls7a::{KEYBOARD_IRQ, MOUSE_IRQ, UART0_IRQ};
use super::register::csr::Register;
use super::register::estat::Estat;
use bit_field::BitField;
use log::{debug, info};
/// 初始化外部中断
pub fn extioi_init() {
let estat = Estat::read();
debug!("before_extioi_init_estat={:#x?}", estat.get_val());
/* let mut enable = 0;
enable
.set_bit(KEYBOARD_IRQ, true)
.set_bit(MOUSE_IRQ, true)
.set_bit(UART0_IRQ, true);
info!("extioi_init: enable = {:#b}", enable);*/
// 使能外部设备中断
// iocsr_write_d(LOONGARCH_IOCSR_EXTIOI_EN_BASE, enable);

// extioi[31:0] map to cpu irq pin INT1, other to INT0
//路由到INT1上
iocsr_write_b(LOONGARCH_IOCSR_EXTIOI_MAP_BASE, 0x1);
// extioi IRQ 0-7 route to core 0, use node type 0
//路由到EXT_IOI_node_type0指向的0号处理器上
iocsr_write_w(LOONGARCH_IOCSR_EXTIOI_ROUTE_BASE, 0x0);
// nodetype0 set to 1, always trigger at node 0 */
//固定分发模式时,只在0号处理器上触发
iocsr_write_h(LOONGARCH_IOCSR_EXRIOI_NODETYPE_BASE, 0x1);

//检查扩展i/o触发器是不是全0,即没有被触发的中断
let extioi_isr = iocsr_read_b(LOONGARCH_IOCSR_EXTIOI_ISR_BASE);
debug!("extioi_init: extioi_isr = {:#b}", extioi_isr);
let current_trigger = extioi_claim();
debug!("extioi_init: current_trigger = {:#b}", current_trigger);
assert_eq!(extioi_isr, 0);
let estat = Estat::read();
debug!("after_extioi_init_estat={:#x?}", estat.get_val());
debug!("extioi_init: current_trigger = {:#b}", current_trigger);
}

// ask the extioi what interrupt we should serve.
pub fn extioi_claim() -> u64 {
iocsr_read_d(LOONGARCH_IOCSR_EXTIOI_ISR_BASE)
}

pub fn extioi_complete(irq: u64) {
iocsr_write_d(LOONGARCH_IOCSR_EXTIOI_ISR_BASE, irq);
}
76 changes: 76 additions & 0 deletions crates/loongarch64/src/ipi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::consts::*;
use bit_field::BitField;
use core::arch::asm;
pub fn iocsr_write_u32(addr: usize, value: u32) {
unsafe {
asm!("iocsrwr.w {},{}", in(reg) value,in(reg) addr);
}
}

pub fn iocsr_read_u32(addr: usize) -> u32 {
let mut value: u32;
unsafe {
asm!("iocsrrd.w {},{}", out(reg) value, in(reg) addr);
}
value
}

pub fn iocsr_write_u64(addr: usize, value: u64) {
unsafe {
asm!("iocsrwr.d {},{}", in(reg) value, in(reg) addr);
}
}

pub fn iocsr_read_u64(addr: usize) -> u64 {
let mut value: u64;
unsafe {
asm!("iocsrrd.d {},{}", out(reg) value, in(reg) addr);
}
value
}

fn iocsr_mbuf_send_box_lo(box_: usize) -> usize {
box_ << 1
}
fn iocsr_mbuf_send_box_hi(box_: usize) -> usize {
(box_ << 1) + 1
}

pub fn csr_mail_send(entry: u64, cpu: usize, mailbox: usize) {
let mut val: u64;
val = IOCSR_MBUF_SEND_BLOCKING;
val |= (iocsr_mbuf_send_box_hi(mailbox) << IOCSR_MBUF_SEND_BOX_SHIFT) as u64;
val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT) as u64;
val |= entry & IOCSR_MBUF_SEND_H32_MASK as u64;
iocsr_write_u64(LOONGARCH_IOCSR_MBUF_SEND, val);
val = IOCSR_MBUF_SEND_BLOCKING;
val |= (iocsr_mbuf_send_box_lo(mailbox) << IOCSR_MBUF_SEND_BOX_SHIFT) as u64;
val |= (cpu << IOCSR_MBUF_SEND_CPU_SHIFT) as u64;
val |= entry << IOCSR_MBUF_SEND_BUF_SHIFT;
iocsr_write_u64(LOONGARCH_IOCSR_MBUF_SEND, val);
}

/// IPI_Send 0x1040 WO 32 位中断分发寄存器
/// `[31]` 等待完成标志,置 1 时会等待中断生效
///
/// `[30:26]` 保留
///
/// `[25:16]` 处理器核号
///
/// `[15:5]` 保留
///
/// `[4:0]` 中断向量号,对应 IPI_Status 中的向量
pub fn ipi_write_action(cpu: usize, action: u32) {
let mut val: u32 = IOCSR_IPI_SEND_BLOCKING;
for i in 0..32 {
if action.get_bit(i) {
val |= (cpu << IOCSR_IPI_SEND_CPU_SHIFT) as u32;
val |= i as u32;
iocsr_write_u32(LOONGARCH_IOCSR_IPI_SEND, val);
}
}
}

pub fn send_ipi_single(cpu: usize, action: u32) {
ipi_write_action(cpu, action);
}
Loading