From 34de609f1ccd65b40d6ed8b18253751dda4e9f3f Mon Sep 17 00:00:00 2001 From: Godones <1925466036@qq.com> Date: Mon, 18 Sep 2023 19:53:53 +0800 Subject: [PATCH 01/19] feat: add basic loongarch64 support - Refactor the [repo](https://github.com/aoooos/arceos) code to merge - Use standard toolchain - Fix the compile command --- .gitignore | 1 + Cargo.lock | 10 + Cargo.toml | 1 + Makefile | 6 +- crates/kernel_guard/src/arch/loongarch64.rs | 19 ++ crates/kernel_guard/src/arch/mod.rs | 3 + crates/loongarch64/Cargo.toml | 10 + crates/loongarch64/src/asm.rs | 33 ++++ crates/loongarch64/src/consts.rs | 21 +++ crates/loongarch64/src/cpu.rs | 96 ++++++++++ crates/loongarch64/src/extioi.rs | 53 ++++++ crates/loongarch64/src/ipi.rs | 76 ++++++++ crates/loongarch64/src/lib.rs | 15 ++ crates/loongarch64/src/loongson.rs | 61 ++++++ crates/loongarch64/src/ls7a.rs | 84 +++++++++ crates/loongarch64/src/mem.rs | 6 + crates/loongarch64/src/mod.rs | 17 ++ crates/loongarch64/src/register/badi.rs | 26 +++ crates/loongarch64/src/register/badv.rs | 27 +++ crates/loongarch64/src/register/cpuid.rs | 27 +++ crates/loongarch64/src/register/crmd.rs | 98 ++++++++++ crates/loongarch64/src/register/csr.rs | 58 ++++++ crates/loongarch64/src/register/dmwn.rs | 109 +++++++++++ crates/loongarch64/src/register/ecfg.rs | 51 +++++ crates/loongarch64/src/register/eentry.rs | 29 +++ crates/loongarch64/src/register/era.rs | 37 ++++ crates/loongarch64/src/register/estat.rs | 178 ++++++++++++++++++ crates/loongarch64/src/register/misc.rs | 40 ++++ crates/loongarch64/src/register/mod.rs | 26 +++ crates/loongarch64/src/register/prcfg1.rs | 34 ++++ crates/loongarch64/src/register/prcfg2.rs | 25 +++ crates/loongarch64/src/register/prcfg3.rs | 46 +++++ crates/loongarch64/src/register/prmd.rs | 65 +++++++ crates/loongarch64/src/register/rvacfg.rs | 37 ++++ crates/loongarch64/src/register/saven.rs | 35 ++++ crates/loongarch64/src/register/tcfg.rs | 61 ++++++ crates/loongarch64/src/register/ticlr.rs | 33 ++++ crates/loongarch64/src/register/time.rs | 30 +++ crates/loongarch64/src/register/tval.rs | 21 +++ crates/loongarch64/src/rtc.rs | 80 ++++++++ crates/loongarch64/src/tlb/asid.rs | 40 ++++ crates/loongarch64/src/tlb/mod.rs | 35 ++++ crates/loongarch64/src/tlb/pgd.rs | 28 +++ crates/loongarch64/src/tlb/pgdh.rs | 33 ++++ crates/loongarch64/src/tlb/pgdl.rs | 33 ++++ crates/loongarch64/src/tlb/pwch.rs | 51 +++++ crates/loongarch64/src/tlb/pwcl.rs | 99 ++++++++++ crates/loongarch64/src/tlb/stlbps.rs | 32 ++++ crates/loongarch64/src/tlb/tlbehi.rs | 37 ++++ crates/loongarch64/src/tlb/tlbelo.rs | 168 +++++++++++++++++ crates/loongarch64/src/tlb/tlbentry.rs | 37 ++++ crates/loongarch64/src/tlb/tlbidx.rs | 58 ++++++ crates/loongarch64/src/tlb/tlbrbadv.rs | 30 +++ crates/loongarch64/src/tlb/tlbrehi.rs | 46 +++++ crates/loongarch64/src/tlb/tlbrelo.rs | 154 +++++++++++++++ crates/loongarch64/src/tlb/tlbrera.rs | 46 +++++ crates/loongarch64/src/tlb/tlbrprmd.rs | 59 ++++++ crates/loongarch64/src/tlb/tlbrsave.rs | 1 + crates/percpu/src/imp.rs | 4 + crates/percpu_macros/src/arch.rs | 8 + modules/axhal/Cargo.toml | 4 + modules/axhal/linker.lds.S | 2 +- modules/axhal/src/arch/loongarch64/context.rs | 106 +++++++++++ modules/axhal/src/arch/loongarch64/mod.rs | 117 ++++++++++++ modules/axhal/src/arch/loongarch64/tlb.S | 105 +++++++++++ modules/axhal/src/arch/loongarch64/trap.S | 153 +++++++++++++++ modules/axhal/src/arch/loongarch64/trap.rs | 34 ++++ modules/axhal/src/arch/mod.rs | 3 + modules/axhal/src/cpu.rs | 8 + modules/axhal/src/platform/mod.rs | 5 +- .../platform/qemu_virt_loongarch64/boot.rs | 96 ++++++++++ .../platform/qemu_virt_loongarch64/console.rs | 77 ++++++++ .../src/platform/qemu_virt_loongarch64/irq.rs | 64 +++++++ .../src/platform/qemu_virt_loongarch64/mem.rs | 6 + .../platform/qemu_virt_loongarch64/misc.rs | 6 + .../src/platform/qemu_virt_loongarch64/mod.rs | 51 +++++ .../src/platform/qemu_virt_loongarch64/mp.rs | 15 ++ .../platform/qemu_virt_loongarch64/time.rs | 45 +++++ platforms/loongarch64-qemu-virt.toml | 35 ++++ scripts/make/cargo.mk | 4 + scripts/make/qemu.mk | 25 +++ tools/la64/efi-virtio.rom | Bin 0 -> 160768 bytes tools/la64/la-gdb.sh | 9 + tools/la64/la-qemu.sh | 11 ++ tools/la64/loongarch_bios_0310.bin | Bin 0 -> 4190208 bytes tools/la64/loongarch_bios_0310_debug.bin | Bin 0 -> 4190208 bytes 86 files changed, 3662 insertions(+), 3 deletions(-) create mode 100644 crates/kernel_guard/src/arch/loongarch64.rs create mode 100644 crates/loongarch64/Cargo.toml create mode 100644 crates/loongarch64/src/asm.rs create mode 100644 crates/loongarch64/src/consts.rs create mode 100644 crates/loongarch64/src/cpu.rs create mode 100644 crates/loongarch64/src/extioi.rs create mode 100644 crates/loongarch64/src/ipi.rs create mode 100644 crates/loongarch64/src/lib.rs create mode 100644 crates/loongarch64/src/loongson.rs create mode 100644 crates/loongarch64/src/ls7a.rs create mode 100644 crates/loongarch64/src/mem.rs create mode 100644 crates/loongarch64/src/mod.rs create mode 100644 crates/loongarch64/src/register/badi.rs create mode 100644 crates/loongarch64/src/register/badv.rs create mode 100644 crates/loongarch64/src/register/cpuid.rs create mode 100644 crates/loongarch64/src/register/crmd.rs create mode 100644 crates/loongarch64/src/register/csr.rs create mode 100644 crates/loongarch64/src/register/dmwn.rs create mode 100644 crates/loongarch64/src/register/ecfg.rs create mode 100644 crates/loongarch64/src/register/eentry.rs create mode 100644 crates/loongarch64/src/register/era.rs create mode 100644 crates/loongarch64/src/register/estat.rs create mode 100644 crates/loongarch64/src/register/misc.rs create mode 100644 crates/loongarch64/src/register/mod.rs create mode 100644 crates/loongarch64/src/register/prcfg1.rs create mode 100644 crates/loongarch64/src/register/prcfg2.rs create mode 100644 crates/loongarch64/src/register/prcfg3.rs create mode 100644 crates/loongarch64/src/register/prmd.rs create mode 100644 crates/loongarch64/src/register/rvacfg.rs create mode 100644 crates/loongarch64/src/register/saven.rs create mode 100644 crates/loongarch64/src/register/tcfg.rs create mode 100644 crates/loongarch64/src/register/ticlr.rs create mode 100644 crates/loongarch64/src/register/time.rs create mode 100644 crates/loongarch64/src/register/tval.rs create mode 100644 crates/loongarch64/src/rtc.rs create mode 100644 crates/loongarch64/src/tlb/asid.rs create mode 100644 crates/loongarch64/src/tlb/mod.rs create mode 100644 crates/loongarch64/src/tlb/pgd.rs create mode 100644 crates/loongarch64/src/tlb/pgdh.rs create mode 100644 crates/loongarch64/src/tlb/pgdl.rs create mode 100644 crates/loongarch64/src/tlb/pwch.rs create mode 100644 crates/loongarch64/src/tlb/pwcl.rs create mode 100644 crates/loongarch64/src/tlb/stlbps.rs create mode 100644 crates/loongarch64/src/tlb/tlbehi.rs create mode 100644 crates/loongarch64/src/tlb/tlbelo.rs create mode 100644 crates/loongarch64/src/tlb/tlbentry.rs create mode 100644 crates/loongarch64/src/tlb/tlbidx.rs create mode 100644 crates/loongarch64/src/tlb/tlbrbadv.rs create mode 100644 crates/loongarch64/src/tlb/tlbrehi.rs create mode 100644 crates/loongarch64/src/tlb/tlbrelo.rs create mode 100644 crates/loongarch64/src/tlb/tlbrera.rs create mode 100644 crates/loongarch64/src/tlb/tlbrprmd.rs create mode 100644 crates/loongarch64/src/tlb/tlbrsave.rs create mode 100644 modules/axhal/src/arch/loongarch64/context.rs create mode 100644 modules/axhal/src/arch/loongarch64/mod.rs create mode 100644 modules/axhal/src/arch/loongarch64/tlb.S create mode 100644 modules/axhal/src/arch/loongarch64/trap.S create mode 100644 modules/axhal/src/arch/loongarch64/trap.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/boot.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/console.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/irq.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/mem.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/misc.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/mod.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/mp.rs create mode 100644 modules/axhal/src/platform/qemu_virt_loongarch64/time.rs create mode 100644 platforms/loongarch64-qemu-virt.toml create mode 100644 tools/la64/efi-virtio.rom create mode 100755 tools/la64/la-gdb.sh create mode 100755 tools/la64/la-qemu.sh create mode 100644 tools/la64/loongarch_bios_0310.bin create mode 100644 tools/la64/loongarch_bios_0310_debug.bin diff --git a/.gitignore b/.gitignore index 9d91ac5720..305250feec 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ actual.out qemu.log rusty-tags.vi +.idea diff --git a/Cargo.lock b/Cargo.lock index b305bb4329..9460a40110 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,6 +372,7 @@ dependencies = [ "axalloc", "axconfig", "axlog", + "bit_field", "bitflags 2.4.0", "cfg-if", "crate_interface", @@ -380,6 +381,7 @@ dependencies = [ "kernel_guard", "lazy_init", "log", + "loongarch64", "memory_addr", "page_table", "page_table_entry", @@ -1222,6 +1224,14 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +[[package]] +name = "loongarch64" +version = "0.1.0" +dependencies = [ + "bit_field", + "log", +] + [[package]] name = "managed" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 1db098f126..fc6dc78bb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ members = [ "crates/spinlock", "crates/timer_list", "crates/tuple_for_each", + "crates/loongarch64", "modules/axalloc", "modules/axconfig", diff --git a/Makefile b/Makefile index b351596584..abe3ba1c1f 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/crates/kernel_guard/src/arch/loongarch64.rs b/crates/kernel_guard/src/arch/loongarch64.rs new file mode 100644 index 0000000000..d4a323854f --- /dev/null +++ b/crates/kernel_guard/src/arch/loongarch64.rs @@ -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) }; +} diff --git a/crates/kernel_guard/src/arch/mod.rs b/crates/kernel_guard/src/arch/mod.rs index 3a05149726..c5207deda8 100644 --- a/crates/kernel_guard/src/arch/mod.rs +++ b/crates/kernel_guard/src/arch/mod.rs @@ -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::*; } } diff --git a/crates/loongarch64/Cargo.toml b/crates/loongarch64/Cargo.toml new file mode 100644 index 0000000000..f4062b186e --- /dev/null +++ b/crates/loongarch64/Cargo.toml @@ -0,0 +1,10 @@ +[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" \ No newline at end of file diff --git a/crates/loongarch64/src/asm.rs b/crates/loongarch64/src/asm.rs new file mode 100644 index 0000000000..3b79353015 --- /dev/null +++ b/crates/loongarch64/src/asm.rs @@ -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"); diff --git a/crates/loongarch64/src/consts.rs b/crates/loongarch64/src/consts.rs new file mode 100644 index 0000000000..ba452d5d9a --- /dev/null +++ b/crates/loongarch64/src/consts.rs @@ -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; diff --git a/crates/loongarch64/src/cpu.rs b/crates/loongarch64/src/cpu.rs new file mode 100644 index 0000000000..e07284c136 --- /dev/null +++ b/crates/loongarch64/src/cpu.rs @@ -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) +} diff --git a/crates/loongarch64/src/extioi.rs b/crates/loongarch64/src/extioi.rs new file mode 100644 index 0000000000..31f33add26 --- /dev/null +++ b/crates/loongarch64/src/extioi.rs @@ -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); +} diff --git a/crates/loongarch64/src/ipi.rs b/crates/loongarch64/src/ipi.rs new file mode 100644 index 0000000000..6e661e5cc3 --- /dev/null +++ b/crates/loongarch64/src/ipi.rs @@ -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); +} diff --git a/crates/loongarch64/src/lib.rs b/crates/loongarch64/src/lib.rs new file mode 100644 index 0000000000..97a398234e --- /dev/null +++ b/crates/loongarch64/src/lib.rs @@ -0,0 +1,15 @@ +#![no_std] +#![allow(unused)] +pub mod asm; +pub mod consts; +pub mod cpu; +pub mod extioi; +pub mod ipi; +pub mod loongson; +pub mod ls7a; +pub mod mem; +pub mod register; +pub mod tlb; + +pub const VALEN: usize = 48; +pub const PALEN: usize = 48; diff --git a/crates/loongarch64/src/loongson.rs b/crates/loongarch64/src/loongson.rs new file mode 100644 index 0000000000..e3acf5b64a --- /dev/null +++ b/crates/loongarch64/src/loongson.rs @@ -0,0 +1,61 @@ +/* extioi registers */ +use core::arch::asm; + +pub const LOONGARCH_IOCSR_EXTIOI_EN_BASE: usize = 0x1600; //扩展 IO 中断[63:0]的中断使能配置 +pub const LOONGARCH_IOCSR_EXTIOI_ISR_BASE: usize = 0x1800; //路由至处理器核 0 的扩展 IO 中断[63:0]的中断状态 +pub const LOONGARCH_IOCSR_EXTIOI_MAP_BASE: usize = 0x14c0; //EXT_IOI[31:0]的引脚路由方式 +pub const LOONGARCH_IOCSR_EXTIOI_ROUTE_BASE: usize = 0x1c00; //EXT_IOI[0]的处理器核路由方式 +pub const LOONGARCH_IOCSR_EXRIOI_NODETYPE_BASE: usize = 0x14a0; //16 个结点的映射向量类型 0(软件配置 +pub const LOONGARCH_IOCSR_EXRIOI_SEND: usize = 0x1140; // 配置寄存器中增加了一个扩展 IO 中断触发寄存 + // 器,用于将对应的 IO 中断置位 + +/// 4 +pub fn iocsr_write_w(reg: usize, value: u32) { + unsafe { + asm!("iocsrwr.w {},{}", in(reg) value, in(reg) reg); + } +} +// 8 +pub fn iocsr_write_d(reg: usize, value: u64) { + unsafe { + asm!("iocsrwr.d {},{}", in(reg) value, in(reg) reg); + } +} +// 2 +pub fn iocsr_write_h(reg: usize, value: u16) { + unsafe { + asm!("iocsrwr.h {},{}", in(reg) value, in(reg) reg); + } +} +// 1 +pub fn iocsr_write_b(reg: usize, value: u8) { + unsafe { + asm!("iocsrwr.b {},{}", in(reg) value, in(reg) reg); + } +} + +pub fn iocsr_read_b(reg: usize) -> u8 { + let val: u8; + unsafe { + asm!("iocsrrd.b {},{}",out(reg) val, in(reg) reg); + } + val +} + +// 4 +pub fn iocsr_read_w(reg: usize) -> u32 { + let val: u32; + unsafe { + asm!("iocsrrd.w {},{}",out(reg) val, in(reg) reg); + } + val +} + +// 8 +pub fn iocsr_read_d(reg: usize) -> u64 { + let val: u64; + unsafe { + asm!("iocsrrd.d {},{}",out(reg) val, in(reg) reg); + } + val +} diff --git a/crates/loongarch64/src/ls7a.rs b/crates/loongarch64/src/ls7a.rs new file mode 100644 index 0000000000..a537d908d8 --- /dev/null +++ b/crates/loongarch64/src/ls7a.rs @@ -0,0 +1,84 @@ +/// LS7A桥片配置空间 +/// LS7A桥片配置空间--中断控制器起始地址 +/// 0x1000_0000~0x1000_0fff 4k +pub const LS7A_PCH_REG_BASE: usize = 0x1000_0000; +pub const LS7A_MISC_REG_BASE: usize = LS7A_PCH_REG_BASE + 0x00080000; +pub const LS7A_ACPI_REG_BASE: usize = LS7A_MISC_REG_BASE + 0x00050000; +pub const LS7A_RTC_REG_BASE: usize = LS7A_MISC_REG_BASE + 0x00050100; + +pub const UART0_IRQ: usize = 2; +pub const KEYBOARD_IRQ: usize = 3; +pub const MOUSE_IRQ: usize = 4; + +// 8042 Keyboard Controller +pub const LS7A_I8042_DATA: usize = 0x1fe00060; +pub const LS7A_I8042_COMMAND: usize = 0x1fe00064; +pub const LS7A_I8042_STATUS: usize = 0x1fe00064; + +pub const LS7A_INT_MASK_REG: usize = LS7A_PCH_REG_BASE + 0x020; //中断掩码寄存器低32位 +pub const LS7A_INT_EDGE_REG: usize = LS7A_PCH_REG_BASE + 0x060; //触发方式寄存器 +pub const LS7A_INT_CLEAR_REG: usize = LS7A_PCH_REG_BASE + 0x080; //边沿触发中断清除寄存器 +pub const LS7A_INT_HTMSI_VEC_REG: usize = LS7A_PCH_REG_BASE + 0x200; //HT 中断向量寄存器[ 7- 0] +pub const LS7A_INT_STATUS_REG: usize = LS7A_PCH_REG_BASE + 0x3a0; //中断状态(在服务)寄存器 ISR +pub const LS7A_INT_POL_REG: usize = LS7A_PCH_REG_BASE + 0x3e0; //中断触发电平选择寄存器 + +pub fn ls7a_read_w(addr: usize) -> u32 { + unsafe { (addr as *const u32).read_volatile() } +} + +pub fn ls7a_write_w(addr: usize, value: u32) { + unsafe { + (addr as *mut u32).write_volatile(value); + } +} +pub fn ls7a_write_b(addr: usize, value: u8) { + unsafe { + (addr as *mut u8).write_volatile(value); + } +} +pub fn ls7a_read_b(addr: usize) -> u8 { + unsafe { (addr as *const u8).read_volatile() } +} + +pub fn ls7a_read_d(addr: usize) -> u64 { + unsafe { (addr as *const u64).read_volatile() } +} + +pub fn ls7a_write_d(addr: usize, value: u64) { + unsafe { + (addr as *mut u64).write_volatile(value); + } +} + +/// 初始化ls7a中断控制器 +pub fn ls7a_intc_init() { + // enable uart0/keyboard/mouse + // 使能设备的中断 + ls7a_write_w( + LS7A_INT_MASK_REG, + !((0x1 << UART0_IRQ) | (0x1 << KEYBOARD_IRQ) | (0x1 << MOUSE_IRQ)), + ); + // 触发方式设置寄存器 + // 0:电平触发中断 + // 1:边沿触发中断 + // 这里设置为电平触发 + ls7a_write_w( + LS7A_INT_EDGE_REG, + 0x1 << (UART0_IRQ | KEYBOARD_IRQ | MOUSE_IRQ), + ); + // route to the same irq in extioi, pch_irq == extioi_irq + ls7a_write_b(LS7A_INT_HTMSI_VEC_REG + UART0_IRQ, UART0_IRQ as u8); + ls7a_write_b(LS7A_INT_HTMSI_VEC_REG + KEYBOARD_IRQ, KEYBOARD_IRQ as u8); + ls7a_write_b(LS7A_INT_HTMSI_VEC_REG + MOUSE_IRQ, MOUSE_IRQ as u8); + // 设置中断电平触发极性 + // 对于电平触发类型: + // 0:高电平触发; + // 1:低电平触发 + // 这里是高电平触发 + ls7a_write_w(LS7A_INT_POL_REG, 0x0); +} + +pub fn ls7a_intc_complete(irq: u64) { + // 将对应位写1 清除中断 + ls7a_write_d(LS7A_INT_CLEAR_REG, irq); +} diff --git a/crates/loongarch64/src/mem.rs b/crates/loongarch64/src/mem.rs new file mode 100644 index 0000000000..d49e26efac --- /dev/null +++ b/crates/loongarch64/src/mem.rs @@ -0,0 +1,6 @@ +pub enum AccessMemType { + Suc = 0, + Cc = 1, + Wuc = 2, + Saved = 3, +} diff --git a/crates/loongarch64/src/mod.rs b/crates/loongarch64/src/mod.rs new file mode 100644 index 0000000000..b7d0605e8e --- /dev/null +++ b/crates/loongarch64/src/mod.rs @@ -0,0 +1,17 @@ +pub mod cpu; +mod driver; +mod extioi; +mod loongson; +mod ls7a; +pub mod mem; +pub mod register; +mod rtc; +pub mod tlb; + +pub use driver::*; +pub use extioi::{extioi_claim, extioi_complete, extioi_init}; +pub use loongson::*; +pub use ls7a::*; +pub use rtc::{check_rtc, rtc_init, rtc_time_read}; + +pub use driver::{ahci_init, BLOCK_DEVICE}; diff --git a/crates/loongarch64/src/register/badi.rs b/crates/loongarch64/src/register/badi.rs new file mode 100644 index 0000000000..fada9edaad --- /dev/null +++ b/crates/loongarch64/src/register/badi.rs @@ -0,0 +1,26 @@ +use super::csr::Register; +//use super::csr::CSR_BADI; +use core::arch::asm; +// 该寄存器用于记录触发同步类例外的指令的指令码。所谓同步类例外是指除了中断(INT)、客户机 CSR +// 硬件修改例外(GCHC)、机器错误例外(MERR)之外的所有例外。 +#[derive(Debug)] +pub struct Badi { + bits: usize, +} + +impl Register for Badi { + fn read() -> Self { + let mut bits; + //unsafe { asm!("csrrd {},{}", out(reg) bits, const CSR_BADI ) } + unsafe { asm!("csrrd {},0x8", out(reg) bits ) } + Self { bits } + } + + fn write(&mut self) {} +} + +impl Badi { + pub fn get_val(&self) -> usize { + self.bits + } +} diff --git a/crates/loongarch64/src/register/badv.rs b/crates/loongarch64/src/register/badv.rs new file mode 100644 index 0000000000..db06f89f1f --- /dev/null +++ b/crates/loongarch64/src/register/badv.rs @@ -0,0 +1,27 @@ +use super::csr::Register; +use super::csr::CSR_BADV; +use core::arch::asm; +// 该寄存器用于触发地址错误相关例外时,记录出错的虚地址。此类例外包括: +#[derive(Debug)] +pub struct Badv { + bits: usize, +} + +impl Register for Badv { + fn read() -> Self { + let mut bits; + // unsafe { asm!("csrrd {},{}", out(reg) bits,const CSR_BADV ) } + unsafe { asm!("csrrd {},0x7", out(reg) bits ) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg) self.bits, const CSR_BADV) } + unsafe { asm!("csrwr {},0x7",in(reg) self.bits) } + } +} + +impl Badv { + pub fn get_value(&self) -> usize { + self.bits + } +} diff --git a/crates/loongarch64/src/register/cpuid.rs b/crates/loongarch64/src/register/cpuid.rs new file mode 100644 index 0000000000..00e16b678f --- /dev/null +++ b/crates/loongarch64/src/register/cpuid.rs @@ -0,0 +1,27 @@ +// 该寄存器中存有处理器核编号信息。 + +use super::csr::Register; +use super::csr::CSR_CPUID; +use core::arch::asm; +pub struct Cpuid { + bits: u32, +} + +impl Register for Cpuid { + fn read() -> Self { + let bits: u32; + + unsafe { + //asm!("csrrd {},{}",out(reg) bits, const CSR_CPUID); + asm!("csrrd {},0x20",out(reg) bits); + } + Self { bits } + } + fn write(&mut self) {} +} + +impl Cpuid { + pub fn get_val(&self) -> u32 { + self.bits + } +} diff --git a/crates/loongarch64/src/register/crmd.rs b/crates/loongarch64/src/register/crmd.rs new file mode 100644 index 0000000000..48286c2666 --- /dev/null +++ b/crates/loongarch64/src/register/crmd.rs @@ -0,0 +1,98 @@ +use super::super::cpu::CpuMode; +use super::csr::Register; +use super::csr::CSR_CRMD; +use bit_field::BitField; +use core::arch::asm; +// 当前模式信息 +#[repr(C)] +pub struct Crmd { + bits: usize, +} + +impl Register for Crmd { + fn read() -> Self { + //读取crmd的内容 + let mut crmd; + unsafe { + // asm!("csrrd {},{}", out(reg) crmd,const CSR_CRMD); + asm!("csrrd {},0x0", out(reg) crmd); + } + Crmd { bits: crmd } + } + fn write(&mut self) { + //写入crmd + unsafe { + // asm!("csrwr {},{}", in(reg) self.bits,const CSR_CRMD); + asm!("csrwr {},0x0", in(reg) self.bits); + } + } +} + +impl Crmd { + // 返回整个寄存器的内容 + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + self.bits = val; + self + } + // 返回当前特权级模式 + // 0-1位 + pub fn get_plv(&self) -> usize { + self.bits.get_bits(0..2) + } + // 设置特权级模式 + pub fn set_plv(&mut self, mode: CpuMode) -> &mut Self { + self.bits.set_bits(0..2, mode as usize); + self + } + // 设置全局中断使能 + // 第2位 + pub fn set_ie(&mut self, enable: bool) -> &mut Self { + self.bits.set_bit(2, enable); + self + } + // 获取全局中断使能 + pub fn get_ie(&self) -> bool { + self.bits.get_bit(2) + } + // 获取DA + pub fn get_da(&self) -> bool { + // 第3位 + self.bits.get_bit(3) + } + // 设置DA,直接地址翻译使能 + pub fn set_da(&mut self, da: bool) -> &mut Self { + self.bits.set_bit(3, da); + self + } + // 获取PG + // 第4位 + pub fn get_pg(&self) -> bool { + self.bits.get_bit(4) + } + // 设置PG,页翻译使能 + pub fn set_pg(&mut self, pg: bool) -> &mut Self { + self.bits.set_bit(4, pg); + self + } + // 获取直接地址翻译模式时,取指操作的存储访问类型 + // 在采用软件处理 TLB 重填的情况下,当软件将 PG 置为 1 时,需同时将 DATF 域置为 + // 0b01,即一致可缓存类型 + pub fn get_datf(&self) -> usize { + self.bits.get_bits(5..=6) + } + pub fn set_datf(&mut self, datf: usize) -> &mut Self { + self.bits.set_bits(5..=6, datf); + self + } + // 直接地址翻译模式时,load 和 store 操作的存储访问类型 + pub fn get_datm(&self) -> usize { + self.bits.get_bits(7..=8) + } + pub fn set_datm(&mut self, datm: usize) -> &mut Self { + self.bits.set_bits(7..=8, datm); + self + } +} diff --git a/crates/loongarch64/src/register/csr.rs b/crates/loongarch64/src/register/csr.rs new file mode 100644 index 0000000000..3b3758c8c4 --- /dev/null +++ b/crates/loongarch64/src/register/csr.rs @@ -0,0 +1,58 @@ +pub trait Register { + fn read() -> Self; + fn write(&mut self); +} +pub const CSR_CRMD: usize = 0x0; +pub const CSR_PRMD: usize = 0x1; +pub const CSR_EUEN: usize = 0x2; +pub const CSR_MISC: usize = 0x3; +pub const CSR_ECFG: usize = 0x4; +pub const CSR_ESTAT: usize = 0x5; +pub const CSR_ERA: usize = 0x6; +pub const CSR_BADV: usize = 0x7; +pub const CSR_BADI: usize = 0x8; +pub const CSR_EENTRY: usize = 0xC; +pub const CSR_TLBIDX: usize = 0x10; +pub const CSR_TLBEHI: usize = 0x11; + +pub const CSR_TLBELO: usize = 0x12; + +pub const CSR_ASID: usize = 0x18; +pub const CSR_PGDL: usize = 0x19; +pub const CSR_PGDH: usize = 0x1A; +pub const CSR_PGD: usize = 0x1B; +pub const CSR_PWCL: usize = 0x1C; +pub const CSR_PWCH: usize = 0x1D; +pub const CSR_STLBPS: usize = 0x1E; +pub const CSR_RVACFG: usize = 0x1F; +pub const CSR_CPUID: usize = 0x20; +pub const CSR_PRCFG1: usize = 0x21; +pub const CSR_PRCFG2: usize = 0x22; +pub const CSR_PRCFG3: usize = 0x23; +pub const CSR_SAVE: usize = 0x30; //0x30 + n(n[0-15] +pub const CSR_TID: usize = 0x40; +pub const CSR_TCFG: usize = 0x41; +pub const CSR_TVAL: usize = 0x42; +pub const CSR_CNTC: usize = 0x43; +pub const CSR_TICLR: usize = 0x44; + +pub const CSR_TLBRENTRY: usize = 0x88; +pub const CSR_TLBRBADV: usize = 0x89; +pub const CSR_TLBRERA: usize = 0x8A; +pub const CSR_TLBRSAVE: usize = 0x8B; + +pub const CSR_TLBRELO: usize = 0x8C; + +pub const CSR_TLBREHI: usize = 0x8E; +pub const CSR_TLBRPRMD: usize = 0x8F; + +pub const CSR_MERRCTL: usize = 0x90; +pub const CSR_MERRINF01: usize = 0x91; +pub const CSR_MERRINF02: usize = 0x92; +pub const CSR_MERRENTRY: usize = 0x93; +pub const CSR_MEMRERA: usize = 0x94; +pub const CSR_MEMRSAVE: usize = 0x95; + +pub const CSR_CTAG: usize = 0x98; + +pub const CSR_DMW: usize = 0x180; //0x180 + n(n[0-3] diff --git a/crates/loongarch64/src/register/dmwn.rs b/crates/loongarch64/src/register/dmwn.rs new file mode 100644 index 0000000000..716841c4ff --- /dev/null +++ b/crates/loongarch64/src/register/dmwn.rs @@ -0,0 +1,109 @@ +use super::csr::Register; +use bit_field::BitField; +use core::arch::asm; +// 直接地址映射配置窗口 +pub struct Dmw0 { + bits: usize, +} +pub struct Dmw1 { + bits: usize, +} +pub struct Dmw2 { + bits: usize, +} +pub struct Dmw3 { + bits: usize, +} + +impl Register for Dmw0 { + fn read() -> Self { + let mut bits: usize; + unsafe { asm!("csrrd {},0x180", out(reg) bits ) } + Dmw0 { bits } + } + fn write(&mut self) { + unsafe { asm!("csrwr {},0x180", in(reg) self.bits ) } + } +} +impl Dmw0 { + pub fn get_value(&self) -> usize { + self.bits + } + pub fn set_value(&mut self, value: usize) -> &mut Self { + self.bits = value; + self + } + pub fn set_plv_with_level(&mut self, level: usize, enable: bool) -> &mut Self { + assert!(level <= 3); + self.bits.set_bit(level, enable); + self + } + pub fn set_mat(&mut self, enable: bool) -> &mut Self { + self.bits.set_bit(4, enable); + self + } + pub fn set_vesg(&mut self, value: usize) -> &mut Self { + self.bits.set_bits(60..64, value); + self + } +} + +impl Register for Dmw1 { + fn read() -> Self { + let mut bits: usize; + unsafe { asm!("csrrd {},0x181", out(reg) bits ) } + Dmw1 { bits } + } + fn write(&mut self) { + unsafe { asm!("csrwr {},0x181", in(reg) self.bits ) } + } +} +impl Dmw1 { + pub fn get_value(&self) -> usize { + self.bits + } + pub fn set_value(&mut self, value: usize) -> &mut Self { + self.bits = value; + self + } +} + +impl Register for Dmw2 { + fn read() -> Self { + let mut bits: usize; + unsafe { asm!("csrrd {},0x182", out(reg) bits ) } + Dmw2 { bits } + } + fn write(&mut self) { + unsafe { asm!("csrwr {},0x182", in(reg) self.bits ) } + } +} +impl Dmw2 { + pub fn get_value(&self) -> usize { + self.bits + } + pub fn set_value(&mut self, value: usize) -> &mut Self { + self.bits = value; + self + } +} + +impl Register for Dmw3 { + fn read() -> Self { + let mut bits: usize; + unsafe { asm!("csrrd {},0x183", out(reg) bits ) } + Dmw3 { bits } + } + fn write(&mut self) { + unsafe { asm!("csrwr {},0x183", in(reg) self.bits ) } + } +} +impl Dmw3 { + pub fn get_value(&self) -> usize { + self.bits + } + pub fn set_value(&mut self, value: usize) -> &mut Self { + self.bits = value; + self + } +} diff --git a/crates/loongarch64/src/register/ecfg.rs b/crates/loongarch64/src/register/ecfg.rs new file mode 100644 index 0000000000..8fbb93ed67 --- /dev/null +++ b/crates/loongarch64/src/register/ecfg.rs @@ -0,0 +1,51 @@ +use super::csr::{Register, CSR_ECFG}; +use bit_field::BitField; +use core::arch::asm; +/// 控制例外和中断的入口地址计算方式,以及局部中断使能 +pub struct Ecfg { + bits: usize, +} +impl Register for Ecfg { + fn read() -> Self { + let mut bits; + // unsafe { asm!("csrrd {},{}", out(reg) bits,const CSR_ECFG ) } + unsafe { asm!("csrrd {},0x4", out(reg) bits ) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}", in(reg) self.bits,const CSR_ECFG ) } + unsafe { asm!("csrwr {},0x4", in(reg) self.bits ) } + } +} + +impl Ecfg { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + self.bits = val; + self + } + pub fn get_lie_with_index(&self, index: usize) -> bool { + // 中断位于0-12位,每一位代表一个局部中断 + assert!(index < 13); + self.bits.get_bit(index) + } + pub fn set_lie_with_index(&mut self, index: usize, val: bool) -> &mut Self { + // 中断位于0-12位,每一位代表一个局部中断 + assert!(index < 13); + self.bits.set_bit(index, val); + self + } + // 例外处理中断入口的间距 + // 16-18位 + // 当此值为0 时,例外处理中断入口是同一个地址 + // 不为0时,每个异常有自己的中断入口 + pub fn get_vs(&self) -> usize { + self.bits.get_bits(16..19) + } + pub fn set_vs(&mut self, value: usize) -> &mut Self { + self.bits.set_bits(16..19, value); + self + } +} diff --git a/crates/loongarch64/src/register/eentry.rs b/crates/loongarch64/src/register/eentry.rs new file mode 100644 index 0000000000..f66bb40fe6 --- /dev/null +++ b/crates/loongarch64/src/register/eentry.rs @@ -0,0 +1,29 @@ +//例外入口地址 + +use super::csr::Register; +use core::arch::asm; +pub struct Eentry { + bits: usize, +} +impl Register for Eentry { + fn read() -> Self { + let bits: usize; + unsafe { asm!("csrrd {},0xc", out(reg) bits, ) } + Eentry { bits } + } + fn write(&mut self) { + unsafe { asm!("csrwr {},0xc", in(reg) self.bits, ) } + } +} + +impl Eentry { + pub fn get_eentry(&self) -> usize { + // 12位以后,以页对齐 + self.bits + } + pub fn set_eentry(&mut self, eentry: usize) -> &mut Self { + assert!(eentry & 0xfff == 0); + self.bits = eentry; + self + } +} diff --git a/crates/loongarch64/src/register/era.rs b/crates/loongarch64/src/register/era.rs new file mode 100644 index 0000000000..a1103dfe6e --- /dev/null +++ b/crates/loongarch64/src/register/era.rs @@ -0,0 +1,37 @@ +use super::csr::{Register, CSR_ERA}; +use core::arch::asm; +// 该寄存器记录普通例外处理完毕之后的返回地址。当触发例外时,如果例外类型既不是 TLB 重填例外 +// 也不是机器错误例外,则触发例外的指令的 PC 将被记录在该寄存器中 +pub struct Era { + bits: usize, +} + +impl Register for Era { + fn read() -> Self { + //读取era的内容出来 + let mut era; + unsafe { + // asm!("csrrd {},{}", out(reg) era,const CSR_ERA); + asm!("csrrd {},0x6", out(reg) era); + } + Era { bits: era } + } + fn write(&mut self) { + //写入era的内容 + unsafe { + // asm!("csrwr {},{}", in(reg) self.bits,const CSR_ERA); + asm!("csrwr {},0x6", in(reg) self.bits); + } + } +} + +impl Era { + pub fn set_pc(&mut self, pc: usize) -> &mut Self { + self.bits = pc; + self + } + pub fn get_pc(&self) -> usize { + // 返回pc + self.bits + } +} diff --git a/crates/loongarch64/src/register/estat.rs b/crates/loongarch64/src/register/estat.rs new file mode 100644 index 0000000000..3fe95ae9b3 --- /dev/null +++ b/crates/loongarch64/src/register/estat.rs @@ -0,0 +1,178 @@ +use super::super::tlb::TLBREra; +use super::csr::Register; +use super::csr::CSR_ESTAT; +use super::ecfg::Ecfg; +use bit_field::BitField; +use core::arch::asm; +// 该寄存器记录例外的状态信息,包括所触发例外的一二级编码,以及各中断的状态 +#[derive(Debug, Clone, Copy)] +pub struct Estat { + pub bits: usize, +} + +impl Register for Estat { + fn read() -> Self { + //读取sstat的内容出来 + let mut bits; + unsafe { + // asm!("csrrd {},{}", out(reg) bits,const CSR_ESTAT); + asm!("csrrd {}, 0x5", out(reg) bits); + } + Estat { bits } + } + fn write(&mut self) { + unsafe { + // asm!("csrwr {},{}", in(reg) self.bits,const CSR_ESTAT); + asm!("csrwr {}, 0x5", in(reg) self.bits); + } + } +} + +impl Estat { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + self.bits = val; + self + } + pub fn get_is_with_index(&self, index: usize) -> bool { + // 0-12位为中断 + assert!(index < 13); + self.bits.get_bit(index) + } + // 只有写0和1位有效,这两位控制软件中断 + pub fn set_is_with_index(&mut self, index: usize, value: bool) -> &mut Self { + assert!(index < 13); + self.bits.set_bit(index, value); + self + } + // 例外类型一级编码。触发例外时: + // 如果是 TLB 重填例外或机器错误例外,该域保持不变; + // 否则,硬件会根据例外类型将表 7- 8 中 Ecode 栏定义的数值写入该域。 + //例外类型一级编号 21-16位 + pub fn get_ecode(&self) -> usize { + self.bits.get_bits(16..=21) + } + //例外类型二级编号 22-30位 + pub fn get_esubcode(&self) -> usize { + self.bits.get_bits(22..=30) + } + + pub fn cause(&self) -> Trap { + // 优先判断是否是重填异常 + let is_tlb_reload = TLBREra::read().get_is_tlbr(); + if is_tlb_reload { + return Trap::Exception(Exception::TLBRFill); + } + let ecode = self.get_ecode(); + if ecode == 0 { + // 仅当 CSR.ECFG.VS=0 时,表示是中断 + let ecfg = Ecfg::read(); + let ecfg_vs = ecfg.get_vs(); + if ecfg_vs == 0 { + // 读取中断位 + for index in (0..13).rev() { + if self.get_is_with_index(index) && ecfg.get_lie_with_index(index) { + //log::debug!("index={:#x?}", index); + return Trap::Interrupt(Interrupt::from_usize(index)); + } + } + } + return Trap::Unknown; + } + let sub_ecode = self.get_esubcode(); + match ecode { + 0x1 => Trap::Exception(Exception::LoadPageInvalid), // load + 0x2 => Trap::Exception(Exception::StorePageInvalid), // store + 0x3 => Trap::Exception(Exception::FetchPageInvalid), //取指操作页面不存在 + 0x4 => Trap::Exception(Exception::PageModification), //页修改例外 + 0x5 => Trap::Exception(Exception::PageNonReadable), //页不可读 + 0x6 => Trap::Exception(Exception::PageNonExecutable), //页不可执行 + 0x7 => Trap::Exception(Exception::PagePrivilegeIllegal), //页特权级不合规 + 0x8 => { + match sub_ecode { + 0x1 => Trap::Exception(Exception::FetchInstructionAddressError), //取指地址错误 + 0x2 => Trap::Exception(Exception::MemoryAccessInstructionAddressError), //访存地址访问错误 + _ => Trap::Unknown, + } + } + 0x9 => Trap::Exception(Exception::AddressAlignmentFault), //地址不对齐 + 0xa => Trap::Exception(Exception::BoundCheck), //越界例外 + 0xb => Trap::Exception(Exception::Syscall), //系统调用 + 0xc => Trap::Exception(Exception::Breakpoint), //调试中断 + 0xd => Trap::Exception(Exception::InstructionNonDefined), //指令不合规 + 0xe => Trap::Exception(Exception::InstructionPrivilegeError), //指令特权级不合规 + 0xf => Trap::Exception(Exception::FloatingPointInstructionDisable), //浮点处理器不可用 + _ => Trap::Unknown, + } + } +} + +// 异常类型 +#[derive(Debug, Clone, Copy)] +pub enum Exception { + LoadPageInvalid, + StorePageInvalid, + FetchPageInvalid, + PageModification, + PageNonReadable, + PageNonExecutable, + PagePrivilegeIllegal, + FetchInstructionAddressError, + MemoryAccessInstructionAddressError, //内存访问错误 + AddressAlignmentFault = 0x9, //地址不对齐 + BoundCheck = 0xA, //越界检查错误 + Syscall = 0xB, //系统调用 + Breakpoint = 0xC, //调试中断 + InstructionNonDefined = 0xD, //指令不合规 + InstructionPrivilegeError = 0xE, //特权指令不合规 + FloatingPointInstructionDisable = 0xF, //浮点不可用 + TLBRFill, //TLB重填 +} + +// 中断类型 +#[derive(Debug, Clone, Copy)] +pub enum Interrupt { + SWI0, //软件中断0 + SWI1, //软件中断1 + HWI0, //硬件中断0 + HWI1, //硬件中断1 + HWI2, //硬件中断2 + HWI3, //硬件中断3 + HWI4, //硬件中断4 + HWI5, //硬件中断5 + HWI6, //硬件中断6 + HWI7, //硬件中断7 + PMI, //性能监测计数溢出中断 + Timer, //定时器中断 + IPI, //多处理器间的中断 +} + +impl Interrupt { + pub fn from_usize(value: usize) -> Self { + match value { + 0 => Interrupt::SWI0, + 1 => Interrupt::SWI1, + 2 => Interrupt::HWI0, + 3 => Interrupt::HWI1, + 4 => Interrupt::HWI2, + 5 => Interrupt::HWI3, + 6 => Interrupt::HWI4, + 7 => Interrupt::HWI5, + 8 => Interrupt::HWI6, + 9 => Interrupt::HWI7, + 10 => Interrupt::PMI, + 11 => Interrupt::Timer, + 12 => Interrupt::IPI, + _ => panic!("invalid interrupt index"), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Trap { + Exception(Exception), + Interrupt(Interrupt), + Unknown, +} diff --git a/crates/loongarch64/src/register/misc.rs b/crates/loongarch64/src/register/misc.rs new file mode 100644 index 0000000000..6076148917 --- /dev/null +++ b/crates/loongarch64/src/register/misc.rs @@ -0,0 +1,40 @@ +use super::csr::{Register, CSR_MISC}; +use bit_field::BitField; +use core::arch::asm; + +pub struct Misc { + bits: u32, +} + +impl Register for Misc { + fn read() -> Self { + let bits: u32; + unsafe { + // asm!("csrrd {},{}",out(reg)bits,const CSR_MISC); + asm!("csrrd {},0x3",out(reg)bits); + } + Self { bits } + } + fn write(&mut self) { + unsafe { + // asm!("csrwr {},{}",in(reg)self.bits,const CSR_MISC); + asm!("csrwr {},0x3",in(reg)self.bits); + } + } +} +impl Misc { + pub fn get_enable_32_in_plv1(&self) -> bool { + self.bits.get_bit(1) + } + pub fn set_enable_32_in_plv1(&mut self, value: bool) -> &mut Self { + self.bits.set_bit(1, value); + self + } + pub fn get_enable_32_in_plv3(&self) -> bool { + self.bits.get_bit(3) + } + pub fn set_enable_32_in_plv3(&mut self, value: bool) -> &mut Self { + self.bits.set_bit(3, value); + self + } +} diff --git a/crates/loongarch64/src/register/mod.rs b/crates/loongarch64/src/register/mod.rs new file mode 100644 index 0000000000..aa360dfd87 --- /dev/null +++ b/crates/loongarch64/src/register/mod.rs @@ -0,0 +1,26 @@ +//! loongArch的一些寄存器 + +pub mod badi; +pub mod badv; +pub mod cpuid; +pub mod crmd; +pub mod csr; +pub mod dmwn; +pub mod ecfg; +pub mod eentry; +pub mod era; +pub mod estat; +mod misc; +pub mod prcfg1; +pub mod prcfg2; +pub mod prcfg3; +pub mod prmd; +pub mod rvacfg; +pub mod saven; +pub mod tcfg; +pub mod ticlr; +pub mod tval; + +pub mod time; + +pub use misc::Misc; diff --git a/crates/loongarch64/src/register/prcfg1.rs b/crates/loongarch64/src/register/prcfg1.rs new file mode 100644 index 0000000000..56d259d2aa --- /dev/null +++ b/crates/loongarch64/src/register/prcfg1.rs @@ -0,0 +1,34 @@ +use super::csr::{Register, CSR_PRCFG1}; +use bit_field::BitField; +use core::arch::asm; +#[derive(Debug)] +pub struct Prcfg1 { + // [0-3] Savenum 保存数据寄存器的数量 + // [4-11] TimerBits 定时器的位数-1 + // [12-14] 例外入口地址间距的 vs可以设置的最大值 + // [15-31] 0 + bits: usize, +} + +impl Register for Prcfg1 { + fn read() -> Self { + let mut bits; + // unsafe { asm!("csrrd {},{}", out(reg) bits,const CSR_PRCFG1 ) } + unsafe { asm!("csrrd {},0x21", out(reg) bits ) } + Self { bits } + } + fn write(&mut self) {} +} + +impl Prcfg1 { + pub fn get_save_num(&self) -> usize { + self.bits.get_bits(0..4) + } + pub fn get_timer_bits(&self) -> usize { + // 返回定时器的位数 + self.bits.get_bits(4..12) + 1 + } + pub fn get_vs_max(&self) -> usize { + self.bits.get_bits(12..15) + } +} diff --git a/crates/loongarch64/src/register/prcfg2.rs b/crates/loongarch64/src/register/prcfg2.rs new file mode 100644 index 0000000000..4eca4e160f --- /dev/null +++ b/crates/loongarch64/src/register/prcfg2.rs @@ -0,0 +1,25 @@ +use super::csr::Register; +use super::csr::CSR_PRCFG2; +use core::arch::asm; +// 指示 TLB 能够支持的页大小(Page Size)。当第 i 位为 1,表明支持 2 +// i字节大小的页 +pub struct Prcfg2 { + bits: usize, +} +impl Register for Prcfg2 { + fn read() -> Self { + let bits: usize; + unsafe { + // asm!("csrrd {},{}",out(reg) bits,const CSR_PRCFG2); + asm!("csrrd {},0x22",out(reg) bits); + } + Self { bits } + } + fn write(&mut self) {} +} + +impl Prcfg2 { + pub fn get_val(&self) -> usize { + self.bits + } +} diff --git a/crates/loongarch64/src/register/prcfg3.rs b/crates/loongarch64/src/register/prcfg3.rs new file mode 100644 index 0000000000..24bd1a15e2 --- /dev/null +++ b/crates/loongarch64/src/register/prcfg3.rs @@ -0,0 +1,46 @@ +use super::csr::Register; +use super::csr::CSR_PRCFG3; +use bit_field::BitField; +use core::arch::asm; +// 该寄存器包含一些特权资源的配置信息。 +pub struct Prcfg3 { + bits: u32, +} +impl Register for Prcfg3 { + fn read() -> Self { + let bits: u32; + unsafe { + // asm!("csrrd {},{}",out(reg) bits,const CSR_PRCFG3); + asm!("csrrd {},0x23",out(reg) bits); + } + Self { bits } + } + fn write(&mut self) {} +} + +impl Prcfg3 { + // 指示 TLB 组织方式: + // 0:没有 TLB; + // 1:一个全相联的多重页大小 TLB(MTLB) + // 2:一个全相联的多重页大小 TLB(MTLB)+一个组相联的单个页大小 TLB(STLB); + // 其它值:保留。 + + pub fn get_tlb_type(&self) -> u32 { + self.bits.get_bits(0..=3) + } + // 当 TLBType=1 或 2 时,该域的值是全相联多重页大小 TLB 的项数减 1 + pub fn get_mtlb_entries(&self) -> u32 { + self.bits.get_bits(4..=11) + } + + // STLBWays + pub fn get_stlb_ways(&self) -> u32 { + self.bits.get_bits(12..=19) + 1 + } + + // 当 TLBType=2 时,该域的值是组相联单个页大小 TLB 的每一路项数的幂指数,即每一 + // 路有 2 ^ STLBSets项。 + pub fn get_sltb_sets(&self) -> u32 { + self.bits.get_bits(20..=25) + } +} diff --git a/crates/loongarch64/src/register/prmd.rs b/crates/loongarch64/src/register/prmd.rs new file mode 100644 index 0000000000..cbd8b4b80c --- /dev/null +++ b/crates/loongarch64/src/register/prmd.rs @@ -0,0 +1,65 @@ +use super::super::cpu::CpuMode; +use super::csr::{Register, CSR_PRMD}; +use bit_field::BitField; +use core::arch::asm; +// 当触发例外时,如果例外类型不是 TLB 重填例外和机器错误例外,硬件会将此时处理器核的特权等级、 +// 全局中断使能和监视点使能位保存至例外前模式信息寄存器中,用于例外返回时恢复处理器核的现场 +pub struct Prmd { + bits: usize, +} + +impl Register for Prmd { + fn read() -> Self { + let mut bits; + // unsafe { asm!("csrrd {},{}", out(reg) bits ,const CSR_PRMD) } + unsafe { asm!("csrrd {},0x1", out(reg) bits) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}", in(reg) self.bits ,const CSR_PRMD) } + unsafe { asm!("csrwr {},0x1", in(reg) self.bits) } + } +} + +impl Prmd { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + self.bits = val; + self + } + + // 当触发例外时,如果例外类型不是 TLB 重填例外和机器错误例外,硬件会将 CSR.CRMD + // 中 PLV 域的旧值记录在这个域。 + // 当所处理的例外既不是 TLB 重填例外(CSR.TLBRERA.IsTLBR=0)也不是机器错误例外 + // (CSR.ERRCTL.IsMERR=0)时,执行 ERTN 指令从例外处理程序返回时,硬件会将这个 + // 域的值恢复到 CSR.CRMD 的 PLV 域 + pub fn get_pplv(&self) -> usize { + self.bits.get_bits(0..2) + } + pub fn set_pplv(&mut self, pplv: CpuMode) -> &mut Self { + //设置特权级 + // 用于在进入用户程序时设置特权级 + self.bits.set_bits(0..2, pplv as usize); + self + } + // 记录例外发生前的crmd.ie + pub fn get_pie(&self) -> bool { + self.bits.get_bit(2) + } + // 设置中断使能 + // 用于在进入用户程序时设置中断使能 + pub fn set_pie(&mut self, pie: bool) -> &mut Self { + self.bits.set_bit(2, pie); + self + } + + pub fn get_pwe(&self) -> bool { + self.bits.get_bit(3) + } + pub fn set_pwe(&mut self, pwe: bool) -> &mut Self { + self.bits.set_bit(3, pwe); + self + } +} diff --git a/crates/loongarch64/src/register/rvacfg.rs b/crates/loongarch64/src/register/rvacfg.rs new file mode 100644 index 0000000000..eeaa68bb20 --- /dev/null +++ b/crates/loongarch64/src/register/rvacfg.rs @@ -0,0 +1,37 @@ +use super::csr::Register; +use super::csr::CSR_RVACFG; +use core::arch::asm; +// 该寄存器用于控制虚地址缩减模式下被缩减的地址位宽。 +pub struct RvaCfg { + bits: u32, +} + +impl Register for RvaCfg { + fn read() -> Self { + let bits: u32; + unsafe { + // asm!("csrrd {},{}",out(reg) bits, const CSR_RVACFG); + asm!("csrrd {},0x1F",out(reg) bits); + } + Self { bits } + } + fn write(&mut self) { + unsafe { + // asm!("csrwr {},{}",in(reg) self.bits, const CSR_RVACFG); + asm!("csrwr {},0x1F",in(reg) self.bits); + } + } +} + +impl RvaCfg { + fn get_val(&self) -> u32 { + self.bits + } + // 虚地址缩减模式下,被缩减的高位地址的位数。可以配置为 0~8 之间的值。 + // 0 是一个特殊的配置值,意味着不启用虚地址缩减模式。 + // 如果配置的值大于 8,则处理器行为不确定 + fn set_val(&mut self, val: u32) -> &mut Self { + self.bits = val; + self + } +} diff --git a/crates/loongarch64/src/register/saven.rs b/crates/loongarch64/src/register/saven.rs new file mode 100644 index 0000000000..e4b3594991 --- /dev/null +++ b/crates/loongarch64/src/register/saven.rs @@ -0,0 +1,35 @@ +// 数据保存控制状态寄存器用于给系统软件暂存数据。每个数据保存寄存器可以存放一个通用寄存器的数据。 +// 数据保存寄存器最少实现 1 个,最多实现 16 个 + +use crate::register::csr::Register; +use core::arch::asm; + +pub struct SaveReg0 { + bits: usize, +} + +impl Register for SaveReg0 { + fn read() -> Self { + unsafe { + let mut bit: usize; + asm!("csrrd {},0x30",out(reg) bit); + Self { bits: bit } + } + } + + fn write(&mut self) { + unsafe { + asm!("csrwr {},0x30",in(reg) self.bits); + } + } +} + +impl SaveReg0 { + pub fn get_value(&self) -> usize { + self.bits + } + pub fn set_value(&mut self, value: usize) -> &mut Self { + self.bits = value; + self + } +} diff --git a/crates/loongarch64/src/register/tcfg.rs b/crates/loongarch64/src/register/tcfg.rs new file mode 100644 index 0000000000..28c9f827a1 --- /dev/null +++ b/crates/loongarch64/src/register/tcfg.rs @@ -0,0 +1,61 @@ +use super::csr::Register; +use bit_field::BitField; +use core::arch::asm; + +// 定时器寄存器 +// 该寄存器是软件配置定时器的接口。定时器的有效位数由实现决定,因此该寄存器中 TimeVal 域的位 +// 宽也将随之变化。 +#[derive(Debug)] +pub struct Tcfg { + // [0] 使能位 + // [1] 循环控制位 + // [2-]计时器数值, 为4的整数倍 + bits: usize, +} + +impl Register for Tcfg { + fn read() -> Self { + let mut tcfg; + unsafe { asm!("csrrd {} , 0x41", out(reg) tcfg, ) } + Self { bits: tcfg } + } + fn write(&mut self) { + unsafe { asm!("csrwr {}, 0x41", in(reg) self.bits, ) } + } +} + +impl Tcfg { + pub fn get_enable(&self) -> bool { + //第0位 + !self.bits.get_bit(0) + } + pub fn set_enable(&mut self, enable: bool) -> &mut Self { + self.bits.set_bit(0, enable); + self + } + pub fn get_loop(&self) -> bool { + //第1位 + self.bits.get_bit(1) + } + pub fn set_loop(&mut self, loop_: bool) -> &mut Self { + self.bits.set_bit(1, loop_); + self + } + pub fn get_initval(&self) -> usize { + //第2位开始 + (self.bits >> 2) << 2 + } + pub fn set_initval(&mut self, val: usize) -> &mut Self { + // 设置计数值, 只能是4的整数倍 + // 在数值末尾会补上2bit0 + self.bits.set_bits(2.., val >> 2); + self + } + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + self.bits = val; + self + } +} diff --git a/crates/loongarch64/src/register/ticlr.rs b/crates/loongarch64/src/register/ticlr.rs new file mode 100644 index 0000000000..7d87d8ee72 --- /dev/null +++ b/crates/loongarch64/src/register/ticlr.rs @@ -0,0 +1,33 @@ +use super::csr::{Register, CSR_TICLR}; +use bit_field::BitField; +use core::arch::asm; +pub struct Ticlr { + bits: u32, +} + +impl Register for Ticlr { + fn read() -> Self { + let mut ticlr; + // unsafe { asm!("csrrd {},{}", out(reg)ticlr,const CSR_TICLR) } + unsafe { asm!("csrrd {},0x44", out(reg)ticlr) } + Ticlr { bits: ticlr } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}", in(reg)self.bits,const CSR_TICLR) } + unsafe { asm!("csrwr {},0x44", in(reg)self.bits) } + } +} + +impl Ticlr { + pub fn set_val(&mut self, val: u32) -> &mut Self { + self.bits = val; + self + } + pub fn get_val(&self) -> u32 { + self.bits + } + pub fn clear_timer(&mut self) -> &mut Self { + self.bits.set_bit(0, true); + self + } +} diff --git a/crates/loongarch64/src/register/time.rs b/crates/loongarch64/src/register/time.rs new file mode 100644 index 0000000000..8acbd9bb9e --- /dev/null +++ b/crates/loongarch64/src/register/time.rs @@ -0,0 +1,30 @@ +use super::super::cpu::CPUCFG; +use core::arch::asm; +pub struct Time {} + +impl Time { + pub fn read() -> usize { + let mut counter: usize; + unsafe { + asm!( + "rdtime.d {},{}", + out(reg)counter, + out(reg)_, + ); + } + counter + } +} + +pub fn get_timer_freq() -> usize { + // 获取时钟晶振频率 + // 配置信息字index:4 + let base_freq = CPUCFG::read(4).get_bits(0, 31); + // 获取时钟倍频因子 + // 配置信息字index:5 位:0-15 + let mul = CPUCFG::read(5).get_bits(0, 15); + let div = CPUCFG::read(5).get_bits(16, 31); + // 计算时钟频率 + let cc_freq = base_freq * mul / div; + cc_freq +} diff --git a/crates/loongarch64/src/register/tval.rs b/crates/loongarch64/src/register/tval.rs new file mode 100644 index 0000000000..24e6638234 --- /dev/null +++ b/crates/loongarch64/src/register/tval.rs @@ -0,0 +1,21 @@ +use super::csr::{Register, CSR_TVAL}; +use core::arch::asm; +pub struct Tval { + bits: u32, +} + +impl Register for Tval { + fn read() -> Self { + let mut tval; + // unsafe { asm!("csrrd {},{}", out(reg)ticlr,const CSR_TICLR) } + unsafe { asm!("csrrd {},0x42", out(reg)tval) } + Tval { bits: tval } + } + fn write(&mut self) {} +} + +impl Tval { + pub fn get_val(&self) -> u32 { + self.bits + } +} diff --git a/crates/loongarch64/src/rtc.rs b/crates/loongarch64/src/rtc.rs new file mode 100644 index 0000000000..2fb9bf9fe7 --- /dev/null +++ b/crates/loongarch64/src/rtc.rs @@ -0,0 +1,80 @@ +use alloc::format; +use alloc::string::{String, ToString}; +use core::fmt::{Debug, Formatter}; +use rlibc::memcmp; +use crate::loongarch64::{ls7a_read_w, ls7a_write_w, LS7A_RTC_REG_BASE}; +use crate::println; +use bit_field::BitField; + +pub const RTC_YEAR: usize = 0x30; +pub const RTC_TOYREAD0: usize = 0x2c; //月日时分 +pub const RTC_CTRL: usize = 0x40; + +pub struct RtcTime { + pub year: u32, + pub month: u32, + pub day: u32, + pub hour: u32, + pub minute: u32, + pub second: u32, +} + +impl Debug for RtcTime { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{}-{}-{} {}:{}:{}", + self.year, self.month, self.day, self.hour, self.minute, self.second + ) + } +} + +impl ToString for RtcTime { + fn to_string(&self) -> String { + format!( + "{}:{}:{}\n{}-{}-{}", + self.hour, self.minute, self.second, self.year, self.month, self.day + ) + } +} + +/// 编译器会报出找不到bcmp的错误,这里将其实现为memcmp +#[no_mangle] +pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { + memcmp(s1, s2, n) +} + + +pub fn rtc_time_read() -> RtcTime { + let value = ls7a_read_w(LS7A_RTC_REG_BASE + RTC_TOYREAD0); + let sec = (value >> 4) & 0x3f; + let min = (value >> 10) & 0x3f; + let mut hour = (value >> 16) & 0x1f; + let day = (value >> 21) & 0x1f; + let mon = (value >> 26) & 0x3f; + let year = ls7a_read_w(LS7A_RTC_REG_BASE + RTC_YEAR) + 1900; + hour = (hour + 8) % 24; + return RtcTime { + year, + month: mon, + day, + hour, + minute: min, + second: sec, + }; +} +pub fn check_rtc() { + let val = ls7a_read_w(LS7A_RTC_REG_BASE + RTC_CTRL); + println!( + "RTC enable:{}, TOY enable:{}", + val.get_bit(13), + val.get_bit(11) + ); +} + +pub fn rtc_init() { + let mut val = ls7a_read_w(LS7A_RTC_REG_BASE + RTC_CTRL); + val.set_bit(13, true); + val.set_bit(11, true); + ls7a_write_w(LS7A_RTC_REG_BASE + RTC_CTRL, val); +} diff --git a/crates/loongarch64/src/tlb/asid.rs b/crates/loongarch64/src/tlb/asid.rs new file mode 100644 index 0000000000..92579fa8a8 --- /dev/null +++ b/crates/loongarch64/src/tlb/asid.rs @@ -0,0 +1,40 @@ +use super::super::register::csr::Register; +use super::super::register::csr::CSR_ASID; +use bit_field::BitField; +use core::arch::asm; + +// 该寄存器中包含了用于访存操作和 TLB 指令的地址空间标识符(ASID)信息。ASID 的位宽随着架构规 +// 范的演进可能进一步增加,为方便软件明确 ASID 的位宽,将直接给出这一信息 +pub struct Asid { + bits: u32, +} + +impl Register for Asid { + fn read() -> Self { + let bits: u32; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_ASID) } + unsafe { asm!("csrrd {},0x18",out(reg)bits) } + Self { bits } + } + fn write(&mut self) { + //unsafe { asm!("csrwr {},{}", in(reg)self.bits,const CSR_ASID) } + unsafe { asm!("csrwr {},0x18", in(reg)self.bits) } + } +} +impl Asid { + pub fn get_asid(&self) -> u32 { + self.bits.get_bits(0..10) + } + pub fn set_asid(&mut self, asid: u32) -> &mut Self { + self.bits.set_bits(0..10, asid); + self + } + + pub fn get_asid_width(&self) -> u32 { + self.bits.get_bits(16..=23) + } + pub fn set_asid_width(&mut self, asid_width: u32) -> &mut Self { + self.bits.set_bits(16..=23, asid_width); + self + } +} diff --git a/crates/loongarch64/src/tlb/mod.rs b/crates/loongarch64/src/tlb/mod.rs new file mode 100644 index 0000000000..7b60430cbd --- /dev/null +++ b/crates/loongarch64/src/tlb/mod.rs @@ -0,0 +1,35 @@ +//此模块负责管理LoongArch有关TLB和页表的寄存器与相关功能 +mod asid; +mod pgd; +mod pgdh; +mod pgdl; +pub mod pwch; +pub mod pwcl; +mod stlbps; +mod tlbehi; +mod tlbelo; +mod tlbentry; +mod tlbidx; +mod tlbrbadv; +mod tlbrehi; +mod tlbrelo; +mod tlbrera; +mod tlbrprmd; +mod tlbrsave; + +pub use asid::Asid; +pub use pgd::Pgd; +pub use pgdh::Pgdh; +pub use pgdl::Pgdl; +pub use pwch::Pwch; +pub use pwcl::Pwcl; +pub use stlbps::StlbPs; +pub use tlbehi::TlbEHi; +pub use tlbelo::{TLBEL, TLBELO}; +pub use tlbentry::TLBREntry; +pub use tlbidx::TlbIdx; +pub use tlbrbadv::TlbRBadv; +pub use tlbrehi::TlbREhi; +pub use tlbrelo::TlbRelo; +pub use tlbrera::TLBREra; +pub use tlbrprmd::TlbRPrmd; diff --git a/crates/loongarch64/src/tlb/pgd.rs b/crates/loongarch64/src/tlb/pgd.rs new file mode 100644 index 0000000000..6b57e9f10f --- /dev/null +++ b/crates/loongarch64/src/tlb/pgd.rs @@ -0,0 +1,28 @@ +// 该寄存器是一个只读寄存器,其内容是当前上下文中出错虚地址所对应的全局目录基址信息。该寄存 +// 器的只读信息,不仅用于 CSR 类指令的读返回值,也用于 LDDIR 指令访问全局目录时所需的基址信息 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_PGD; +use core::arch::asm; + +pub struct Pgd { + pub pgd: usize, +} + +impl Register for Pgd { + fn read() -> Self { + let bits: usize; + unsafe { + // asm!("csrrd {},{}",out(reg)bits,const CSR_PGD); + asm!("csrrd {},0x1b",out(reg)bits); + } + Self { pgd: bits } + } + fn write(&mut self) {} +} + +impl Pgd { + pub fn get_val(&self) -> usize { + self.pgd + } +} diff --git a/crates/loongarch64/src/tlb/pgdh.rs b/crates/loongarch64/src/tlb/pgdh.rs new file mode 100644 index 0000000000..8819d2224c --- /dev/null +++ b/crates/loongarch64/src/tlb/pgdh.rs @@ -0,0 +1,33 @@ +// 该寄存器用于配置高半地址空间的全局目录的基址。要求全局目录的基址一定是 4KB 边界地址对齐的, +// 所以该寄存器的最低 12 位软件不可配置,只读恒为 0。 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_PGDH; +use core::arch::asm; +pub struct Pgdh { + bits: usize, +} + +impl Register for Pgdh { + fn read() -> Self { + let bits: usize; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_PGDH) } + unsafe { asm!("csrrd {},0x1a",out(reg)bits) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg)self.bits,const CSR_PGDH) } + unsafe { asm!("csrwr {},0x1a",in(reg)self.bits) } + } +} +impl Pgdh { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + // 确保地址是 4KB 边界地址对齐的 + assert!(val & 0xFFF == 0); + self.bits = val; + self + } +} diff --git a/crates/loongarch64/src/tlb/pgdl.rs b/crates/loongarch64/src/tlb/pgdl.rs new file mode 100644 index 0000000000..3df901d941 --- /dev/null +++ b/crates/loongarch64/src/tlb/pgdl.rs @@ -0,0 +1,33 @@ +// 该寄存器用于配置低半地址空间的全局目录的基址。要求全局目录的基址一定是 4KB 边界地址对齐的, +// 所以该寄存器的最低 12 位软件不可配置,只读恒为 0 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_PGDL; +use core::arch::asm; +pub struct Pgdl { + bits: usize, +} + +impl Register for Pgdl { + fn read() -> Self { + let bits: usize; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_PGDL) } + unsafe { asm!("csrrd {},0x19",out(reg)bits) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg)self.bits,const CSR_PGDL) } + unsafe { asm!("csrwr {},0x19",in(reg)self.bits) } + } +} +impl Pgdl { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + // 确保地址是 4KB 边界地址对齐的 + assert!(val & 0xFFF == 0); + self.bits = val; + self + } +} diff --git a/crates/loongarch64/src/tlb/pwch.rs b/crates/loongarch64/src/tlb/pwch.rs new file mode 100644 index 0000000000..eb3d65ca8d --- /dev/null +++ b/crates/loongarch64/src/tlb/pwch.rs @@ -0,0 +1,51 @@ +use super::super::register::csr::Register; +use super::super::register::csr::CSR_PWCH; +use bit_field::BitField; +use core::arch::asm; +pub struct Pwch { + bits: u32, +} +impl Register for Pwch { + fn read() -> Self { + let bits: u32; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_PWCH) } + unsafe { asm!("csrrd {},0x1d",out(reg)bits) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg)self.bits,const CSR_PWCH) } + unsafe { asm!("csrwr {},0x1d",in(reg)self.bits) } + } +} +impl Pwch { + //次高一级目录的起始地址 + pub fn get_dir3_base(&self) -> u32 { + self.bits.get_bits(0..=5) + } + pub fn set_dir3_base(&mut self, dir2_base: u32) -> &mut Self { + self.bits.set_bits(0..=5, dir2_base); + self + } + // 次高一级目录的索引位数。0 表示没有这一级。 + pub fn get_dir3_width(&self) -> u32 { + self.bits.get_bits(6..=11) + } + pub fn set_dir3_width(&mut self, dir2_width: u32) -> &mut Self { + self.bits.set_bits(6..=11, dir2_width); + self + } + pub fn get_dir4_base(&self) -> u32 { + self.bits.get_bits(12..=17) + } + pub fn set_dir4_base(&mut self, dir3_base: u32) -> &mut Self { + self.bits.set_bits(12..=17, dir3_base); + self + } + pub fn get_dir4_width(&self) -> u32 { + self.bits.get_bits(18..=23) + } + pub fn set_dir4_width(&mut self, dir3_width: u32) -> &mut Self { + self.bits.set_bits(18..=23, dir3_width); + self + } +} diff --git a/crates/loongarch64/src/tlb/pwcl.rs b/crates/loongarch64/src/tlb/pwcl.rs new file mode 100644 index 0000000000..0b999e38c1 --- /dev/null +++ b/crates/loongarch64/src/tlb/pwcl.rs @@ -0,0 +1,99 @@ +// 该寄存器和 CSR.PWCH 寄存器中的信息在一起定义了操作系统中所采用的页表结构。这些信息将用于指 +// 示软件或硬件进行页表遍历 +// 在 LA32 架构下仅实现 CSR.PWCL。为此 PWCL 寄存器需包含刻画页表结构的所有信息,由此导致末级页 +// 表和最低两级目录的起始地址位置均不超过 32 位,该限制在 LA64 架构下依然存在 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_PWCL; +use bit_field::BitField; +use core::arch::asm; +pub struct Pwcl { + bits: u32, +} + +impl Register for Pwcl { + fn read() -> Self { + let bits: u32; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_PWCL) } + unsafe { asm!("csrrd {},0x1c",out(reg)bits) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg)self.bits,const CSR_PWCL) } + unsafe { asm!("csrwr {},0x1c",in(reg)self.bits) } + } +} +impl Pwcl { + // 末级页表的起始地址。 + pub fn get_ptbase(&self) -> u32 { + self.bits.get_bits(0..=4) + } + pub fn set_ptbase(&mut self, ptbase: u32) -> &mut Self { + self.bits.set_bits(0..=4, ptbase); + self + } + // 末级页表的索引位数 + pub fn get_ptwidth(&self) -> u32 { + self.bits.get_bits(5..=9) + } + pub fn set_ptwidth(&mut self, ptwidth: u32) -> &mut Self { + self.bits.set_bits(5..=9, ptwidth); + self + } + pub fn get_dir1_base(&self) -> u32 { + self.bits.get_bits(10..=14) + } + pub fn set_dir1_base(&mut self, dir1_base: u32) -> &mut Self { + self.bits.set_bits(10..=14, dir1_base); + self + } + // 最低一级目录的索引位数。0 表示没有这一级 + pub fn get_dir1_width(&self) -> u32 { + self.bits.get_bits(15..=19) + } + pub fn set_dir1_width(&mut self, dir1_width: u32) -> &mut Self { + self.bits.set_bits(15..=19, dir1_width); + self + } + pub fn get_dir2_base(&self) -> u32 { + self.bits.get_bits(20..=24) + } + pub fn set_dir2_base(&mut self, dir2_base: u32) -> &mut Self { + self.bits.set_bits(20..=24, dir2_base); + self + } + // 最低两级目录的索引位数。0 表示没有这一级 + pub fn get_dir2_width(&self) -> u32 { + self.bits.get_bits(25..=29) + } + pub fn set_dir2_width(&mut self, dir2_width: u32) -> &mut Self { + self.bits.set_bits(25..=29, dir2_width); + self + } + // 0 表示 64 比特,1 表示 128 比特,2 表示 192 比特,3 表示 256 比特。 + pub fn get_pte_width(&self) -> u32 { + let val = self.bits.get_bits(30..=31); + match val { + 0 => 64, + 1 => 128, + 2 => 192, + 3 => 256, + _ => panic!("invalid pte_width"), + } + } + pub fn set_pte_width(&mut self, pte_width: u32) -> &mut Self { + let val = match pte_width { + 64 => 0, + 128 => 1, + 192 => 2, + 256 => 3, + 0 => 0, + 1 => 1, + 2 => 2, + 3 => 3, + _ => panic!("invalid pte_width"), + }; + self.bits.set_bits(30..=31, val); + self + } +} diff --git a/crates/loongarch64/src/tlb/stlbps.rs b/crates/loongarch64/src/tlb/stlbps.rs new file mode 100644 index 0000000000..5825dfe976 --- /dev/null +++ b/crates/loongarch64/src/tlb/stlbps.rs @@ -0,0 +1,32 @@ +// 该寄存器用于配置 STLB 中页的大小 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_STLBPS; +use bit_field::BitField; +use core::arch::asm; +pub struct StlbPs { + bits: u32, +} + +impl Register for StlbPs { + fn read() -> Self { + let bits: u32; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_STLBPS) } + unsafe { asm!("csrrd {},0x1e",out(reg)bits) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg)self.bits,const CSR_STLBPS) } + unsafe { asm!("csrwr {},0x1e",in(reg)self.bits) } + } +} + +impl StlbPs { + pub fn get_page_size(&self) -> u32 { + self.bits.get_bits(0..=5) + } + pub fn set_page_size(&mut self, page_size: u32) -> &mut Self { + self.bits.set_bits(0..=5, page_size); + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbehi.rs b/crates/loongarch64/src/tlb/tlbehi.rs new file mode 100644 index 0000000000..5b81a36a63 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbehi.rs @@ -0,0 +1,37 @@ +// 该寄存器包含 TLB 指令操作时与 TLB 表项高位部分虚页号相关的信息。因 TLB 表项高位所含的 VPPN 域 +// 的位宽与实现所支持的有效虚地址范围相关,故有关寄存器域的定义分开表述 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_TLBEHI; +use bit_field::BitField; +use core::arch::asm; + +pub struct TlbEHi { + bits: usize, +} +impl Register for TlbEHi { + fn read() -> Self { + let bits: usize; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_TLBEHI) } + unsafe { asm!("csrrd {},0x11",out(reg)bits) } + TlbEHi { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg)self.bits,const CSR_TLBEHI) } + unsafe { asm!("csrwr {},0x11",in(reg)self.bits) } + } +} +impl TlbEHi { + // 执行 TLBRD 指令时,所读取 TLB 表项的 VPPN 域的值记录到这里。 + // 在 CSR.TLBRERA.IsTLBR=0 时,执行 TLBSRCH 指令时查询 TLB 所用 VPPN 值,以及执行 + // TLBWR 和 TLBFILL 指令时写入 TLB 表项的 VPPN 域的值来自于此。 + // 当触发 load 操作页无效例外、store 操作页无效例外、取指操作页无效例外、页修 + // 改例外、页不可读例外、页不可执行例外和页特权等级不合规例外时,触发例外的地址的[VALEN-1:13]位被记录到这里。 + pub fn get_vppn(&self, valen: usize) -> usize { + self.bits.get_bits(13..valen) + } + pub fn set_vppn(&mut self, valen: usize, vppn: usize) -> &mut Self { + self.bits.set_bits(13..valen, vppn); + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbelo.rs b/crates/loongarch64/src/tlb/tlbelo.rs new file mode 100644 index 0000000000..2a40d6b272 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbelo.rs @@ -0,0 +1,168 @@ +use super::super::register::csr::CSR_TLBELO; +use super::super::PALEN; +use bit_field::BitField; +use core::arch::asm; +use core::fmt; +// TLBELO0 和 TLBELO1 两个寄存器包含了 TLB 指令操作时 TLB 表项低位部分物理页号等相关的信息。因龙 +// 芯架构下 TLB 采用双页结构,所以 TLB 表项的低位信息对应奇偶两个物理页表项,其中偶数页信息在 TLBELO0 +// 中,奇数页信息在 TLBELO1 中。 +pub trait TLBEL { + fn get_valid(&self) -> bool; + fn set_valid(&mut self, valid: bool) -> &mut Self; + fn get_dirty(&self) -> bool; + fn set_dirty(&mut self, dirty: bool) -> &mut Self; + fn get_plv(&self) -> usize; + fn set_plv(&mut self, plv: usize) -> &mut Self; + fn get_mem_access_type(&self) -> usize; + fn set_mem_access_type(&mut self, mem_access_type: usize) -> &mut Self; + fn get_global_flag(&self) -> bool; + fn set_global_flag(&mut self, global_flag: bool) -> &mut Self; + fn get_ppn(&self, paleln: usize) -> usize; + fn set_ppn(&mut self, palen: usize, ppn: usize) -> &mut Self; + fn get_not_readable(&self) -> bool; + fn set_not_readable(&mut self, not_readable: bool) -> &mut Self; + fn get_not_executable(&self) -> bool; + fn set_not_executable(&mut self, not_executable: bool) -> &mut Self; + fn get_rplv(&self) -> bool; + fn set_rplv(&mut self, rplv: bool) -> &mut Self; +} +pub struct TLBELO { + bits: usize, + index: usize, +} + +impl fmt::Debug for TLBELO { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "TlbElo{}: RPLV:{},NX:{},NR:{},PPN:{:#x},G:{},MAT:{},PLV:{},D:{},V:{}", + self.index, + self.get_rplv(), + self.get_not_executable(), + self.get_not_readable(), + self.get_ppn(PALEN), + self.get_global_flag(), + self.get_mem_access_type(), + self.get_plv(), + self.get_dirty(), + self.get_valid() + ) + } +} + +impl TLBELO { + pub fn read(index: usize) -> Self { + let bits: usize; + unsafe { + match index { + // 0 => asm!("csrrd {},{}",out(reg)bits,const CSR_TLBELO), + // 1 => asm!("csrrd {},{}",out(reg)bits,const CSR_TLBELO+1), + 0 => asm!("csrrd {},0x12",out(reg)bits), + 1 => asm!("csrrd {},0x13",out(reg)bits), + _ => panic!("TLBELO index out of range"), + } + } + Self { bits, index } + } + pub fn write(&mut self) { + unsafe { + match self.index { + // 0 => asm!("csrwr {},{}",in(reg)self.bits,const CSR_TLBELO), + // 1 => asm!("csrwr {},{}",in(reg)self.bits,const CSR_TLBELO+1), + 0 => asm!("csrwr {},0x12",in(reg)self.bits), + 1 => asm!("csrwr {},0x13",in(reg)self.bits), + _ => panic!("TLBELO index out of range"), + } + } + } +} + +impl TLBELO { + pub fn set_val(&mut self, val: usize) -> &mut Self { + self.bits = val; + self + } +} +impl TLBEL for TLBELO { + // 页表项的有效位(V) + fn get_valid(&self) -> bool { + self.bits.get_bit(0) + } + + fn set_valid(&mut self, valid: bool) -> &mut Self { + self.bits.set_bit(0, valid); + self + } + + fn get_dirty(&self) -> bool { + self.bits.get_bit(1) + } + + fn set_dirty(&mut self, dirty: bool) -> &mut Self { + self.bits.set_bit(1, dirty); + self + } + + fn get_plv(&self) -> usize { + self.bits.get_bits(2..=3) + } + + fn set_plv(&mut self, plv: usize) -> &mut Self { + self.bits.set_bits(2..=3, plv); + self + } + + fn get_mem_access_type(&self) -> usize { + self.bits.get_bits(4..=5) + } + + fn set_mem_access_type(&mut self, mem_access_type: usize) -> &mut Self { + self.bits.set_bits(4..=5, mem_access_type); + self + } + + fn get_global_flag(&self) -> bool { + self.bits.get_bit(6) + } + + fn set_global_flag(&mut self, global_flag: bool) -> &mut Self { + self.bits.set_bit(6, global_flag); + self + } + + fn get_ppn(&self, palen: usize) -> usize { + self.bits.get_bits(12..palen) + } + + fn set_ppn(&mut self, palen: usize, ppn: usize) -> &mut Self { + self.bits.set_bits(12..palen, ppn); + self + } + + fn get_not_readable(&self) -> bool { + self.bits.get_bit(61) + } + + fn set_not_readable(&mut self, not_readable: bool) -> &mut Self { + self.bits.set_bit(61, not_readable); + self + } + + fn get_not_executable(&self) -> bool { + self.bits.get_bit(62) + } + + fn set_not_executable(&mut self, not_executable: bool) -> &mut Self { + self.bits.set_bit(62, not_executable); + self + } + + fn get_rplv(&self) -> bool { + self.bits.get_bit(63) + } + + fn set_rplv(&mut self, rplv: bool) -> &mut Self { + self.bits.set_bit(63, rplv); + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbentry.rs b/crates/loongarch64/src/tlb/tlbentry.rs new file mode 100644 index 0000000000..2c9130abc8 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbentry.rs @@ -0,0 +1,37 @@ +use super::super::register::csr::Register; +use super::super::register::csr::CSR_TLBRENTRY; +use core::arch::asm; + +// TLB重填例外入口地址 +pub struct TLBREntry { + bits: usize, +} + +impl Register for TLBREntry { + fn read() -> Self { + let bits: usize; + unsafe { + // asm!("csrrd {},{}", out(reg) bits,const CSR_TLBRENTRY); + asm!("csrrd {},0x88", out(reg) bits); + } + TLBREntry { bits } + } + fn write(&mut self) { + unsafe { + // asm!("csrwr {},{}", in(reg) self.bits,const CSR_TLBRENTRY); + asm!("csrwr {},0x88", in(reg) self.bits); + } + } +} + +impl TLBREntry { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + // 对齐到4kb + assert!(val & 0xFFF == 0); + self.bits = val; + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbidx.rs b/crates/loongarch64/src/tlb/tlbidx.rs new file mode 100644 index 0000000000..30f2d61032 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbidx.rs @@ -0,0 +1,58 @@ +// 该寄存器包含 TLB 指令操作 TLB 时相关的索引值等信息。Index 域的位宽与实现相关,不 +// 过本架构所允许的 Index 位宽不超过 16 比特。 +// 该寄存器还包含 TLB 指令操作时与 TLB 表项中 PS、E 域相关的信息 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_TLBIDX; +use bit_field::BitField; +use core::arch::asm; +pub struct TlbIdx { + bits: u32, +} +impl Register for TlbIdx { + fn read() -> Self { + let bits: u32; + // unsafe { asm!("csrrd {},{}",out(reg)bits,const CSR_TLBIDX) } + unsafe { asm!("csrrd {},0x10",out(reg)bits) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg)self.bits,const CSR_TLBIDX) } + unsafe { asm!("csrwr {},0x10",in(reg)self.bits) } + } +} +impl TlbIdx { + // 执行 TLBRD 和 TLBWR 指令时,访问 TLB 表项的索引值来自于此。 + // 执行 TLBSRCH 指令时,如果命中,则命中项的索引值记录到这里 + pub fn get_index(&self) -> u32 { + self.bits.get_bits(0..16) + } + pub fn set_index(&mut self, index: u32) -> &mut Self { + self.bits.set_bits(0..16, index); + self + } + // 执行 TLBRD 指令时,所读取 TLB 表项的 PS 域的值记录到这里。 + // 在 CSR.TLBRERA.IsTLBR=0 时,执行 TLBWR 和 TLBFILL 指令,写入的 TLB 表项的 PS + // 域的值来自于此。 + pub fn get_ps(&self) -> u32 { + self.bits.get_bits(24..=29) + } + pub fn set_ps(&mut self, ps: u32) -> &mut Self { + self.bits.set_bits(24..=29, ps); + self + } + // 该位为 1 表示该 TLB 表项为空(无效 TLB 表项),为 0 表示该 TLB 表项非空(有效 TLB + // 表项)。 + // 执行 TLBSRCH 时,如果有命中项该位记为 0,否则该位记为 1。 + // 执行 TLBRD 时,所读取 TLB 表项的 E 位信息取反后记录到这里。 + // 执行 TLBWR 或 TLBFILL 指令时,若 CSR.TLBRERA.IsTLBR=0,将该位的值取反后写入 + // 到被写 TLB 项的 E 位;若此时 CSR.TLBRERA.IsTLBR=1,那么被写入的 TLB 项的 E 位 + // 总是置为 1,与该位的值无关 + pub fn get_ne(&self) -> bool { + self.bits.get_bit(31) + } + pub fn set_ne(&mut self, ne: bool) -> &mut Self { + self.bits.set_bit(31, ne); + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbrbadv.rs b/crates/loongarch64/src/tlb/tlbrbadv.rs new file mode 100644 index 0000000000..6f3947e0f8 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbrbadv.rs @@ -0,0 +1,30 @@ +use super::super::register::csr::Register; +use super::super::register::csr::CSR_TLBRBADV; +use core::arch::asm; +// 该寄存器用于记录触发 TLB 重填例外的出错虚地址 +pub struct TlbRBadv { + bits: usize, +} + +impl Register for TlbRBadv { + fn read() -> Self { + let mut bits; + // unsafe { asm!("csrrd {},{}", out(reg) bits,const CSR_TLBRBADV ) } + unsafe { asm!("csrrd {},0x89", out(reg) bits ) } + Self { bits } + } + fn write(&mut self) { + // unsafe { asm!("csrwr {},{}",in(reg) self.bits, const CSR_TLBRBADV) } + unsafe { asm!("csrwr {},0x89",in(reg) self.bits) } + } +} + +impl TlbRBadv { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, value: usize) -> &mut Self { + self.bits = value; + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbrehi.rs b/crates/loongarch64/src/tlb/tlbrehi.rs new file mode 100644 index 0000000000..0130d47b2a --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbrehi.rs @@ -0,0 +1,46 @@ +// 无论 CSR.TLBRERA.IsTLBR 等于何值,执行 TLBRD 指令都只更新 TLBEHI 寄存器 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_TLBREHI; +use bit_field::BitField; +use core::arch::asm; + +pub struct TlbREhi { + bits: u64, +} + +impl Register for TlbREhi { + fn read() -> Self { + let bits: u64; + unsafe { + // asm!("csrrd {},{}",out(reg)bits,const CSR_TLBREHI); + asm!("csrrd {},0x8E",out(reg)bits); + } + Self { bits } + } + fn write(&mut self) { + unsafe { + // asm!("csrwr {},{}",in(reg)self.bits,const CSR_TLBREHI); + asm!("csrwr {},0x8E",in(reg)self.bits); + } + } +} + +impl TlbREhi { + // TLB 重填例外专用的页大小值。即在 CSR.TLBRERA.IsTLBR=1 时,执行 TLBWR 和 TLBFILL + // 指令,写入的 TLB 表项的 PS 域的值来自于此。 + pub fn get_page_size(&self) -> u64 { + self.bits.get_bits(0..=5) + } + pub fn set_page_size(&mut self, page_size: u64) -> &mut Self { + self.bits.set_bits(0..=5, page_size); + self + } + pub fn get_vppn(&self, valen: usize) -> u64 { + self.bits.get_bits(13..valen) + } + pub fn set_vppn(&mut self, valen: usize, vppn: u64) -> &mut Self { + self.bits.set_bits(13..valen, vppn); + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbrelo.rs b/crates/loongarch64/src/tlb/tlbrelo.rs new file mode 100644 index 0000000000..4f6def4857 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbrelo.rs @@ -0,0 +1,154 @@ +// TLBRELO0/1 两寄存器是处于 TLB 重填例外上下文时(此时 CSR.TLBRERA.IsTLBR=1),存放 TLB 指令操 +// 作时 TLB 表项低位部分物理页号等相关的信息。TLBRELO0/1 两寄存器的格式及各个域的含义分别与 +// TLBELO0/1 两寄存器一样 +// 无论 CSR.TLBRERA.IsTLBR 等于何值,执行 TLBRD 指令都只更新 TLBELO0/1 两寄存器。 +// 无论 CSR.TLBRERA.IsTLBR 等于何值,执行 LDPTE 指令都只更新 TLBRELO0/1 两寄存器 + +use super::super::register::csr::CSR_TLBRELO; +use super::super::PALEN; +use super::tlbelo::TLBEL; +use bit_field::BitField; +use core::arch::asm; +use core::fmt; +pub struct TlbRelo { + bits: usize, + index: usize, +} + +impl fmt::Debug for TlbRelo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "TlbRelo{}: RPLV:{},NX:{},NR:{},PPN:{:#x},G:{},MAT:{},PLV:{},D:{},V:{}", + self.index, + self.get_rplv(), + self.get_not_executable(), + self.get_not_readable(), + self.get_ppn(PALEN), + self.get_global_flag(), + self.get_mem_access_type(), + self.get_plv(), + self.get_dirty(), + self.get_valid() + ) + } +} +impl TlbRelo { + pub fn read(index: usize) -> Self { + let bits: usize; + unsafe { + match index { + // 0 => asm!("csrrd {},{}",out(reg)bits,const CSR_TLBRELO), + // 1 => asm!("csrrd {},{}",out(reg)bits,const CSR_TLBRELO+1), + 0 => asm!("csrrd {},0x8C",out(reg)bits), + 1 => asm!("csrrd {},0x8D",out(reg)bits), + _ => panic!("TLBELO index out of range"), + } + } + Self { bits, index } + } + pub fn write(&mut self) { + unsafe { + match self.index { + // 0 => asm!("csrwr {},{}",in(reg)self.bits,const CSR_TLBRELO), + // 1 => asm!("csrwr {},{}",in(reg)self.bits,const CSR_TLBRELO+1), + 0 => asm!("csrwr {},0x8C",in(reg)self.bits), + 1 => asm!("csrwr {},0x8D",in(reg)self.bits), + _ => panic!("TLBELO index out of range"), + } + } + } +} +impl TLBEL for TlbRelo { + // 页表项的有效位(V) + fn get_valid(&self) -> bool { + self.bits.get_bit(0) + } + + fn set_valid(&mut self, valid: bool) -> &mut Self { + self.bits.set_bit(0, valid); + self + } + + fn get_dirty(&self) -> bool { + self.bits.get_bit(1) + } + + fn set_dirty(&mut self, dirty: bool) -> &mut Self { + self.bits.set_bit(1, dirty); + self + } + + fn get_plv(&self) -> usize { + self.bits.get_bits(2..=3) + } + + fn set_plv(&mut self, plv: usize) -> &mut Self { + self.bits.set_bits(2..=3, plv); + self + } + + fn get_mem_access_type(&self) -> usize { + self.bits.get_bits(4..=5) + } + + fn set_mem_access_type(&mut self, mem_access_type: usize) -> &mut Self { + self.bits.set_bits(4..=5, mem_access_type); + self + } + + fn get_global_flag(&self) -> bool { + self.bits.get_bit(6) + } + + fn set_global_flag(&mut self, global_flag: bool) -> &mut Self { + self.bits.set_bit(6, global_flag); + self + } + + fn get_ppn(&self, palen: usize) -> usize { + self.bits.get_bits(12..palen) + } + + fn set_ppn(&mut self, palen: usize, ppn: usize) -> &mut Self { + self.bits.set_bits(12..palen, ppn); + self + } + + fn get_not_readable(&self) -> bool { + self.bits.get_bit(61) + } + + fn set_not_readable(&mut self, not_readable: bool) -> &mut Self { + self.bits.set_bit(61, not_readable); + self + } + + fn get_not_executable(&self) -> bool { + self.bits.get_bit(62) + } + + fn set_not_executable(&mut self, not_executable: bool) -> &mut Self { + self.bits.set_bit(62, not_executable); + self + } + + fn get_rplv(&self) -> bool { + self.bits.get_bit(63) + } + + fn set_rplv(&mut self, rplv: bool) -> &mut Self { + self.bits.set_bit(63, rplv); + self + } +} + +impl TlbRelo { + pub fn get_val(&self) -> usize { + self.bits + } + pub fn set_val(&mut self, val: usize) -> &mut Self { + self.bits = val; + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbrera.rs b/crates/loongarch64/src/tlb/tlbrera.rs new file mode 100644 index 0000000000..2b12a0b448 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbrera.rs @@ -0,0 +1,46 @@ +// 该寄存器保存 TLB 重填例外处理完毕之后的返回地址。除此之外,该寄存器还包含用于标识当前例外 +// 是 TLB 重填例外的标志位 + +use super::super::register::csr::Register; +use super::super::register::csr::CSR_TLBRERA; +use bit_field::BitField; +use core::arch::asm; +pub struct TLBREra { + bits: usize, +} + +impl Register for TLBREra { + fn read() -> Self { + let mut bits; + unsafe { + // asm!("csrrd {},{}", out(reg) bits,const CSR_TLBRERA); + asm!("csrrd {},0x8A", out(reg) bits); + } + TLBREra { bits } + } + fn write(&mut self) { + //写入era的内容 + unsafe { + // asm!("csrwr {},{}", in(reg) self.bits,const CSR_TLBRERA); + asm!("csrwr {},0x8A", in(reg) self.bits); + } + } +} + +impl TLBREra { + // 记录触发 TLB 重填例外的指令的 PC 的[GRLEN-1:2]位。当执行 ERTN 指令从 TLB 重填 + // 例外处理程序返回时(此时本寄存器 IsTLBR=1 且 CSR.ERRCTL.IsMERR=0),硬件自动 + // 将存放在此处的值最低位补上两比特 0 后作为最终的返回地址 + pub fn get_pc(&self) -> usize { + // 返回pc + self.bits.get_bits(2..) + } + pub fn get_is_tlbr(&self) -> bool { + // 返回是否是 TLB 重填例外 + self.bits.get_bit(0) + } + pub fn set_is_tlbr(&mut self, is_tlbr: bool) -> &mut Self { + self.bits.set_bit(0, is_tlbr); + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbrprmd.rs b/crates/loongarch64/src/tlb/tlbrprmd.rs new file mode 100644 index 0000000000..d54ef6c528 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbrprmd.rs @@ -0,0 +1,59 @@ +// 当触发 TLB 重填例外时,硬件会将此时处理器核的特权等级、客户机模式、全局中断使能和监视点使 +// 能位保存至该寄存器中,用于例外返回时恢复处理器核的现场 + +use super::super::cpu::CpuMode; +use super::super::register::csr::Register; +use super::super::register::csr::CSR_TLBRPRMD; +use bit_field::BitField; +use core::arch::asm; +pub struct TlbRPrmd { + bits: u32, +} + +impl Register for TlbRPrmd { + fn read() -> Self { + let bits: u32; + unsafe { + // asm!("csrrd {},{}", out(reg) bits,const CSR_TLBRPRMD); + asm!("csrrd {},0x8f", out(reg) bits); + } + Self { bits } + } + fn write(&mut self) { + //写入era的内容 + unsafe { + // asm!("csrwr {},{}", in(reg) self.bits,const CSR_TLBRPRMD); + asm!("csrwr {},0x8f", in(reg) self.bits); + } + } +} + +impl TlbRPrmd { + pub fn get_pplv(&self) -> u32 { + self.bits.get_bits(0..2) + } + pub fn set_pplv(&mut self, pplv: CpuMode) -> &mut Self { + //设置特权级 + // 用于在进入用户程序时设置特权级 + self.bits.set_bits(0..2, pplv as u32); + self + } + // 记录例外发生前的crmd.ie + pub fn get_pie(&self) -> bool { + self.bits.get_bit(2) + } + // 设置中断使能 + // 用于在进入用户程序时设置中断使能 + pub fn set_pie(&mut self, pie: bool) -> &mut Self { + self.bits.set_bit(2, pie); + self + } + + pub fn get_pwe(&self) -> bool { + self.bits.get_bit(4) + } + pub fn set_pwe(&mut self, pwe: bool) -> &mut Self { + self.bits.set_bit(4, pwe); + self + } +} diff --git a/crates/loongarch64/src/tlb/tlbrsave.rs b/crates/loongarch64/src/tlb/tlbrsave.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/loongarch64/src/tlb/tlbrsave.rs @@ -0,0 +1 @@ + diff --git a/crates/percpu/src/imp.rs b/crates/percpu/src/imp.rs index 322867b717..99ca47d976 100644 --- a/crates/percpu/src/imp.rs +++ b/crates/percpu/src/imp.rs @@ -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")] { + core::arch::asm!("move {}, $tp", 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 $tp, {}", in(reg) tp) } } } diff --git a/crates/percpu_macros/src/arch.rs b/crates/percpu_macros/src/arch.rs index 6d77eb6812..33c512bb82 100644 --- a/crates/percpu_macros/src/arch.rs +++ b/crates/percpu_macros/src/arch.rs @@ -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 } @@ -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 {}, $tp", out(reg) base); (base + self.offset()) as *const #ty } }) diff --git a/modules/axhal/Cargo.toml b/modules/axhal/Cargo.toml index f29ecde07d..bf8c148d33 100644 --- a/modules/axhal/Cargo.toml +++ b/modules/axhal/Cargo.toml @@ -54,5 +54,9 @@ 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] +bit_field = "0.10.1" +loongarch64 = { path = "../../crates/loongarch64" } + [build-dependencies] axconfig = { path = "../axconfig" } diff --git a/modules/axhal/linker.lds.S b/modules/axhal/linker.lds.S index 73b7a7884d..97bb9fb0fc 100644 --- a/modules/axhal/linker.lds.S +++ b/modules/axhal/linker.lds.S @@ -64,7 +64,7 @@ SECTIONS . = ALIGN(4K); _edata = .; - .bss : ALIGN(4K) { + .bss : AT(.) ALIGN(4K) { boot_stack = .; *(.bss.stack) . = ALIGN(4K); diff --git a/modules/axhal/src/arch/loongarch64/context.rs b/modules/axhal/src/arch/loongarch64/context.rs new file mode 100644 index 0000000000..d3ee92d24a --- /dev/null +++ b/modules/axhal/src/arch/loongarch64/context.rs @@ -0,0 +1,106 @@ +use core::arch::asm; +use memory_addr::VirtAddr; + +/// Saved registers when a trap (interrupt or exception) occurs. +#[repr(C)] +#[derive(Debug, Default, Clone)] +pub struct TrapFrame { + /// All general registers. + pub regs: [usize; 32], + /// Current Mode Information + pub crmd: usize, + /// Pre-exception Mode Information + pub prmd: usize, + /// Extended Component Unit Enable + pub euen: usize, + /// Exception Configuration + pub ecfg: usize, + /// Exception Status + pub estat: usize, + /// Exception Return Address + pub era: usize, + /// Bad Virtual Address + pub badv: usize, +} + +/// Saved hardware states of a task. +/// +/// The context usually includes: +/// +/// - Callee-saved registers +/// - Stack pointer register +/// - Thread pointer register (for thread-local storage, currently unsupported) +/// - FP/SIMD registers +/// +/// On context switch, current task saves its context from CPU to memory, +/// and the next task restores its context from memory to CPU. +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Default)] +pub struct TaskContext { + pub ra: usize, // return address + pub sp: usize, // stack pointer + pub s: [usize; 10], // loongArch need to save 10 static registers from $r22 to $r31 +} + +impl TaskContext { + /// Creates a new default context for a new task. + pub const fn new() -> Self { + unsafe { core::mem::MaybeUninit::zeroed().assume_init() } + } + + /// Initializes the context for a new task, with the given entry point and + /// kernel stack. + pub fn init(&mut self, entry: usize, kstack_top: VirtAddr) { + self.sp = kstack_top.as_usize(); + self.ra = entry; + } + + /// Switches to another task. + /// + /// It first saves the current task's context from CPU to this place, and then + /// restores the next task's context from `next_ctx` to CPU. + pub fn switch_to(&mut self, next_ctx: &Self) { + unsafe { + // TODO: switch TLS + context_switch(self, next_ctx) + } + } +} + +#[naked] +unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) { + asm!( + " + // save old context (callee-saved registers) + st.d $ra, $a0, 0 + st.d $sp, $a0, 1 * 8 + st.d $s0, $a0, 2 * 8 + st.d $s1, $a0, 3 * 8 + st.d $s2, $a0, 4 * 8 + st.d $s3, $a0, 5 * 8 + st.d $s4, $a0, 6 * 8 + st.d $s5, $a0, 7 * 8 + st.d $s6, $a0, 8 * 8 + st.d $s7, $a0, 9 * 8 + st.d $s8, $a0, 10 * 8 + st.d $fp, $a0, 11 * 8 + + // restore new context + ld.d $ra, $a1, 0 + ld.d $s0, $a1, 2 * 8 + ld.d $s1, $a1, 3 * 8 + ld.d $s2, $a1, 4 * 8 + ld.d $s3, $a1, 5 * 8 + ld.d $s4, $a1, 6 * 8 + ld.d $s5, $a1, 7 * 8 + ld.d $s6, $a1, 8 * 8 + ld.d $s7, $a1, 9 * 8 + ld.d $s8, $a1, 10 * 8 + ld.d $fp, $a1, 11 * 8 + ld.d $sp, $a1, 1 * 8 + + jr $ra", + options(noreturn), + ) +} diff --git a/modules/axhal/src/arch/loongarch64/mod.rs b/modules/axhal/src/arch/loongarch64/mod.rs new file mode 100644 index 0000000000..f6147379b7 --- /dev/null +++ b/modules/axhal/src/arch/loongarch64/mod.rs @@ -0,0 +1,117 @@ +#[macro_use] +//mod macros; + +mod context; +mod trap; + +use bit_field::BitField; +use core::arch::asm; +use loongarch64::register::{crmd::Crmd, csr::Register, eentry::Eentry}; + +use loongarch64::tlb::{Pgd, Pgdl, StlbPs, TLBREntry, TlbREhi}; +use memory_addr::{PhysAddr, VirtAddr}; + +pub use self::context::{TaskContext, TrapFrame}; + +/// Allows the current CPU to respond to interrupts. +#[inline] +pub fn enable_irqs() { + Crmd::read().set_ie(true).write() +} + +/// Makes the current CPU to ignore interrupts. +#[inline] +pub fn disable_irqs() { + Crmd::read().set_ie(false).write() +} + +/// Returns whether the current CPU is allowed to respond to interrupts. +#[inline] +pub fn irqs_enabled() -> bool { + Crmd::read().get_ie() +} + +/// Relaxes the current CPU and waits for interrupts. +/// +/// It must be called with interrupts enabled, otherwise it will never return. +#[inline] +pub fn wait_for_irqs() { + unsafe { loongarch64::asm::idle() } +} + +/// Halt the current CPU. +#[inline] +pub fn halt() { + unsafe { loongarch64::asm::idle() } // should never return + disable_irqs(); +} + +/// Reads the register that stores the current page table root. +/// +/// Returns the physical address of the page table root. +#[inline] +pub fn read_page_table_root() -> PhysAddr { + PhysAddr::from(Pgd::read().pgd) +} + +/// Writes the register to update the current page table root. +/// +/// # Safety +/// +/// This function is unsafe as it changes the virtual memory address space. +pub unsafe fn write_page_table_root(root_paddr: PhysAddr) { + let old_root = read_page_table_root(); + trace!("set page table root: {:#x} => {:#x}", old_root, root_paddr); + if old_root != root_paddr { + Pgdl::read().set_val(root_paddr.into()).write(); //设置新的页基址 + // Pgdh::read().set_val(root_paddr.into()).write(); //设置新的页基址 + } +} + +/// Flushes the TLB. +/// +/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB +/// entry that maps the given virtual address. +#[inline] +pub fn flush_tlb(_vaddr: Option) { + unsafe { + /* + if let Some(vaddr) = vaddr { + asm!("invtlb 0x6,$r0,{}", in(reg) vaddr.as_usize()); + } else { + asm!("invtlb 0,$r0,$r0"); + }*/ + asm!("tlbflush"); + } +} + +/// Writes Exception Entry Base Address Register (`eentry`). +#[inline] +pub fn set_trap_vector_base(eentry: usize) { + // TODO!(记录状态并恢复) + Crmd::read().set_ie(false).write(); //关闭全局中断 + Eentry::read().set_eentry(eentry).write(); //设置例外入口 + Crmd::read().set_ie(true).write(); //开启全局中断 +} + +core::arch::global_asm!(include_str!("tlb.S")); + +extern "C" { + fn tlb_refill_handler(); +} + +/// Writes TLB Refill Exception Entry Base Address (`tlbrentry`). +#[inline] +pub fn init_tlb() { + StlbPs::read().set_page_size(0xc).write(); //设置TLB的页面大小为4KiB + TlbREhi::read().set_page_size(0xc).write(); //设置TLB的页面大小为4KiB + set_tlb_handler(tlb_refill_handler as usize); +} + +/// Writes TLB Refill Exception Entry Base Address (`tlbrentry`). +#[inline] +pub fn set_tlb_handler(tlb_refill_entry: usize) { + TLBREntry::read() + .set_val((tlb_refill_entry).get_bits(0..32)) + .write(); +} diff --git a/modules/axhal/src/arch/loongarch64/tlb.S b/modules/axhal/src/arch/loongarch64/tlb.S new file mode 100644 index 0000000000..c09f8382d5 --- /dev/null +++ b/modules/axhal/src/arch/loongarch64/tlb.S @@ -0,0 +1,105 @@ +#define INVTLB_ADDR_GFALSE_AND_ASID 5 +#define PAGE_SHIFT 12 +#define PTRS_PER_PGD_BITS (PAGE_SHIFT - 3) +#define PTRS_PER_PUD_BITS (PAGE_SHIFT - 3) +#define PTRS_PER_PMD_BITS (PAGE_SHIFT - 3) +#define PTRS_PER_PTE_BITS (PAGE_SHIFT - 3) + +/* Page table bits */ +#define _PAGE_VALID_SHIFT 0 +#define _PAGE_ACCESSED_SHIFT 0 /* Reuse Valid for Accessed */ +#define _PAGE_DIRTY_SHIFT 1 +#define _PAGE_PLV_SHIFT 2 /* 2~3, two bits */ +#define _CACHE_SHIFT 4 /* 4~5, two bits */ +#define _PAGE_GLOBAL_SHIFT 6 +#define _PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */ +#define _PAGE_PRESENT_SHIFT 7 +#define _PAGE_WRITE_SHIFT 8 +#define _PAGE_MODIFIED_SHIFT 9 +#define _PAGE_PROTNONE_SHIFT 10 +#define _PAGE_SPECIAL_SHIFT 11 +#define _PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */ +#define _PAGE_PFN_SHIFT 12 +#define _PAGE_SWP_EXCLUSIVE_SHIFT 23 +#define _PAGE_PFN_END_SHIFT 48 +#define _PAGE_NO_READ_SHIFT 61 +#define _PAGE_NO_EXEC_SHIFT 62 +#define _PAGE_RPLV_SHIFT 63 + +/* Used by software */ +#define _PAGE_PRESENT (_ULCAST_(1) << _PAGE_PRESENT_SHIFT) +#define _PAGE_WRITE (_ULCAST_(1) << _PAGE_WRITE_SHIFT) +#define _PAGE_ACCESSED (_ULCAST_(1) << _PAGE_ACCESSED_SHIFT) +#define _PAGE_MODIFIED (_ULCAST_(1) << _PAGE_MODIFIED_SHIFT) +#define _PAGE_PROTNONE (_ULCAST_(1) << _PAGE_PROTNONE_SHIFT) +#define _PAGE_SPECIAL (_ULCAST_(1) << _PAGE_SPECIAL_SHIFT) + +/* We borrow bit 23 to store the exclusive marker in swap PTEs. */ +#define _PAGE_SWP_EXCLUSIVE (_ULCAST_(1) << _PAGE_SWP_EXCLUSIVE_SHIFT) + +/* Used by TLB hardware (placed in EntryLo*) */ +#define _PAGE_VALID (_ULCAST_(1) << _PAGE_VALID_SHIFT) +#define _PAGE_DIRTY (_ULCAST_(1) << _PAGE_DIRTY_SHIFT) +#define _PAGE_PLV (_ULCAST_(3) << _PAGE_PLV_SHIFT) +#define _PAGE_GLOBAL (_ULCAST_(1) << _PAGE_GLOBAL_SHIFT) +#define _PAGE_HUGE (_ULCAST_(1) << _PAGE_HUGE_SHIFT) +#define _PAGE_HGLOBAL (_ULCAST_(1) << _PAGE_HGLOBAL_SHIFT) +#define _PAGE_NO_READ (_ULCAST_(1) << _PAGE_NO_READ_SHIFT) +#define _PAGE_NO_EXEC (_ULCAST_(1) << _PAGE_NO_EXEC_SHIFT) +#define _PAGE_RPLV (_ULCAST_(1) << _PAGE_RPLV_SHIFT) +#define _CACHE_MASK (_ULCAST_(3) << _CACHE_SHIFT) +#define _PFN_SHIFT (PAGE_SHIFT - 12 + _PAGE_PFN_SHIFT) + +#define _PAGE_USER (PLV_USER << _PAGE_PLV_SHIFT) +#define _PAGE_KERN (PLV_KERN << _PAGE_PLV_SHIFT) + +/* +.macro tlb_do_page_fault, write + SAVE_REGS + + csrrd $a2, 0x7 + move $a0, $sp + st.d $a2, $sp, 8*38 + li.d $a1, \write + bl do_page_fault + + LOAD_REGS + + ertn +.endm +*/ + +.macro LOAD_PTE + csrrd $t0, 0x1B // pgd + //lddir $t0, $t0, 4 + //bstrpick.d $t0, $t0, 63, 12 + //slli.d $t0, $t0, 12 + lddir $t0, $t0, 3 + bstrpick.d $t0, $t0, 63, 12 + slli.d $t0, $t0, 12 + lddir $t0, $t0, 2 + bstrpick.d $t0, $t0, 63, 12 + slli.d $t0, $t0, 12 + lddir $t0, $t0, 1 + bstrpick.d $t0, $t0, 63, 12 + slli.d $t0, $t0, 12 + ldpte $t0, 0 #取回偶数号页表项 + csrrd $t1, 0x8c // tlbrelo0, used to debug + ldpte $t0, 1 #取回奇数号页表项 + csrrd $t1, 0x8d // tlbrelo1, used to debug +.endm + +.section .text.tlbrefill +.balign 4096 +.global tlb_refill_handler +tlb_refill_handler: + csrwr $t0, 0x8B // tlbrsave + csrwr $t1, 0x30 // save + + LOAD_PTE + + tlbfill + csrrd $t0, 0x8B // tlbrsave + csrrd $t1, 0x30 // save + + ertn diff --git a/modules/axhal/src/arch/loongarch64/trap.S b/modules/axhal/src/arch/loongarch64/trap.S new file mode 100644 index 0000000000..ed905724db --- /dev/null +++ b/modules/axhal/src/arch/loongarch64/trap.S @@ -0,0 +1,153 @@ +.comm kernelsp, 0x1000, 0x1000 + +.macro SAVE_STATIC_REGS + st.d $s0, $sp, 8*23 + st.d $s1, $sp, 8*24 + st.d $s2, $sp, 8*25 + st.d $s3, $sp, 8*26 + st.d $s4, $sp, 8*27 + st.d $s5, $sp, 8*28 + st.d $s6, $sp, 8*29 + st.d $s7, $sp, 8*30 + st.d $s8, $sp, 8*31 +.endm + +.macro LOAD_STATIC_REGS + ld.d $s0, $sp, 8*23 + ld.d $s1, $sp, 8*24 + ld.d $s2, $sp, 8*25 + ld.d $s3, $sp, 8*26 + ld.d $s4, $sp, 8*27 + ld.d $s5, $sp, 8*28 + ld.d $s6, $sp, 8*29 + ld.d $s7, $sp, 8*30 + ld.d $s8, $sp, 8*31 +.endm + +.macro SAVE_ARGUMENT_REGS + st.d $a0, $sp, 8*4 + st.d $a1, $sp, 8*5 + st.d $a2, $sp, 8*6 + st.d $a3, $sp, 8*7 + st.d $a4, $sp, 8*8 + st.d $a5, $sp, 8*9 + st.d $a6, $sp, 8*10 + st.d $a7, $sp, 8*11 +.endm + +.macro LOAD_ARGUMENT_REGS + ld.d $a0, $sp, 8*4 + ld.d $a1, $sp, 8*5 + ld.d $a2, $sp, 8*6 + ld.d $a3, $sp, 8*7 + ld.d $a4, $sp, 8*8 + ld.d $a5, $sp, 8*9 + ld.d $a6, $sp, 8*10 + ld.d $a7, $sp, 8*11 +.endm + +.macro SAVE_TEMP_REGS + st.d $t0, $sp, 8*12 + st.d $t1, $sp, 8*13 + st.d $t2, $sp, 8*14 + st.d $t3, $sp, 8*15 + st.d $t4, $sp, 8*16 + st.d $t5, $sp, 8*17 + st.d $t6, $sp, 8*18 + st.d $t7, $sp, 8*19 + st.d $t8, $sp, 8*20 +.endm + +.macro LOAD_TEMP_REGS + ld.d $t0, $sp, 8*12 + ld.d $t1, $sp, 8*13 + ld.d $t2, $sp, 8*14 + ld.d $t3, $sp, 8*15 + ld.d $t4, $sp, 8*16 + ld.d $t5, $sp, 8*17 + ld.d $t6, $sp, 8*18 + ld.d $t7, $sp, 8*19 + ld.d $t8, $sp, 8*20 +.endm + +.macro SAVE_CSR_REGS + csrrd $t2, 0x1 + st.d $t2, $sp, 8*33 // prmd + csrrd $t2, 0x0 + st.d $t2, $sp, 8*32 // crmd + csrrd $t2, 0x2 + st.d $t2, $sp, 8*34 // euen + csrrd $t2, 0x4 + st.d $t2, $sp, 8*35 // ecfg + csrrd $t2, 0x5 + st.d $t2, $sp, 8*36 // estat +.endm + +.macro LOAD_SOME_REGS + ld.d $a0, $sp, 8*33 // prmd + andi $a0, $a0, 0x3 // extract pplv bit (previous privilege level) + beqz $a0, 8f + ld.d $r21, $sp, 8*21 // reserved reg +8: + ld.d $a0, $sp, 8*37 // era + addi.d $a0, $a0, 0x4 // era + 4 + csrwr $a0, 0x6 + ld.d $a0, $sp, 8*33 // prmd + csrwr $a0, 0x1 + ld.d $ra, $sp, 8*1 // ra + + LOAD_ARGUMENT_REGS + + ld.d $tp, $sp, 8*2 // thread pointer + ld.d $fp, $sp, 8*22 // frame pointer +.endm + + +.macro SAVE_REGS + addi.d $sp, $sp, -{trapframe_size} // allocate space + st.d $sp, $sp, 8*3 // sp + st.d $ra, $sp, 8*1 // ra + + SAVE_ARGUMENT_REGS + SAVE_TEMP_REGS + SAVE_STATIC_REGS + SAVE_CSR_REGS + + csrrd $ra, 0x6 + st.d $ra, $sp, 8*37 // era + + st.d $tp, $sp, 8*2 // thread pointer + st.d $r21, $sp, 8*21 // reserved reg + st.d $fp, $sp, 8*22 // frame pointer + + move $a0, $sp +.endm + + +.macro LOAD_REGS + ld.d $sp, $sp, 8*3 + LOAD_STATIC_REGS + + LOAD_TEMP_REGS + + LOAD_SOME_REGS + + //ld.d $sp, $sp, 8*3 // sp + addi.d $sp, $sp, {trapframe_size} + +.endm + + +.section .text +.balign 4096 +.global trap_vector_base +trap_vector_base: + SAVE_REGS + + bl loongarch64_trap_handler + + LOAD_REGS + + ertn + + diff --git a/modules/axhal/src/arch/loongarch64/trap.rs b/modules/axhal/src/arch/loongarch64/trap.rs new file mode 100644 index 0000000000..5a5957e61d --- /dev/null +++ b/modules/axhal/src/arch/loongarch64/trap.rs @@ -0,0 +1,34 @@ +use super::context::TrapFrame; +use loongarch64::register::csr::Register; + +use loongarch64::register::estat::{Estat, Exception, Interrupt, Trap}; +use loongarch64::register::ticlr::Ticlr; + +core::arch::global_asm!( + include_str!("trap.S"), + trapframe_size = const core::mem::size_of::(), +); + +fn handle_breakpoint(era: &mut usize) { + debug!("Exception(Breakpoint) @ {:#x} ", era); +} + +#[no_mangle] +fn loongarch64_trap_handler(tf: &mut TrapFrame) { + let cause = Estat::read().cause(); + match cause { + Trap::Exception(Exception::Breakpoint) => handle_breakpoint(&mut tf.era), + Trap::Interrupt(Interrupt::Timer) => { + Ticlr::read().clear_timer().write(); + let irq_num: usize = tf.estat.trailing_zeros() as usize; + crate::trap::handle_irq_extern(irq_num) + } + Trap::Interrupt(_) => { + let irq_num: usize = tf.estat.trailing_zeros() as usize; + crate::trap::handle_irq_extern(irq_num) + } + _ => { + panic!("Unhandled trap {:?} @ {:#x}:\n{:#x?}", cause, tf.era, tf); + } + } +} diff --git a/modules/axhal/src/arch/mod.rs b/modules/axhal/src/arch/mod.rs index b8bc0af3d0..7220281628 100644 --- a/modules/axhal/src/arch/mod.rs +++ b/modules/axhal/src/arch/mod.rs @@ -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::*; } } diff --git a/modules/axhal/src/cpu.rs b/modules/axhal/src/cpu.rs index d0ee27a341..37c750329c 100644 --- a/modules/axhal/src/cpu.rs +++ b/modules/axhal/src/cpu.rs @@ -45,6 +45,10 @@ pub fn current_task_ptr() -> *const T { use tock_registers::interfaces::Readable; aarch64_cpu::registers::SP_EL0.get() as _ } + #[cfg(target_arch = "loongarch64")] + unsafe { + CURRENT_TASK_PTR.read_current_raw() as _ + } } /// Sets the pointer to the current task with preemption-safety. @@ -71,6 +75,10 @@ pub unsafe fn set_current_task_ptr(ptr: *const T) { use tock_registers::interfaces::Writeable; aarch64_cpu::registers::SP_EL0.set(ptr as u64) } + #[cfg(target_arch = "loongarch64")] + unsafe { + CURRENT_TASK_PTR.write_current_raw(ptr as usize) + } } #[allow(dead_code)] diff --git a/modules/axhal/src/platform/mod.rs b/modules/axhal/src/platform/mod.rs index a39151c47f..8437dcf623 100644 --- a/modules/axhal/src/platform/mod.rs +++ b/modules/axhal/src/platform/mod.rs @@ -22,7 +22,10 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-bsta1000b"))] { mod aarch64_bsta1000b; pub use self::aarch64_bsta1000b::*; - } else { + } else if #[cfg(all(target_arch = "loongarch64", platform_family = "loongarch64-qemu-virt"))] { + mod qemu_virt_loongarch64; + pub use self::qemu_virt_loongarch64::*; + }else { mod dummy; pub use self::dummy::*; } diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/boot.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/boot.rs new file mode 100644 index 0000000000..588cdfaf52 --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/boot.rs @@ -0,0 +1,96 @@ +use axconfig::TASK_STACK_SIZE; + +#[link_section = ".bss.stack"] +static mut BOOT_STACK: [u8; TASK_STACK_SIZE] = [0; TASK_STACK_SIZE]; +#[allow(unused)] +pub static mut SMP_BOOT_STACK_TOP: usize = 0; + +unsafe fn init_mmu() { + use loongarch64::register::csr::Register; + use loongarch64::tlb::Pwch; + use loongarch64::tlb::Pwcl; + + Pwcl::read() + .set_ptbase(12) //页表起始位置 + .set_ptwidth(9) //页表宽度为9位 + .set_dir1_base(21) //第一级页目录表起始位置 + .set_dir1_width(9) //第一级页目录表宽度为9位 + .set_dir2_base(30) //第二级页目录表起始位置 + .set_dir2_width(9) //第二级页目录表宽度为9位 + .write(); + Pwch::read() + .set_dir3_base(39) //第三级页目录表 + .set_dir3_width(8) //第三级页目录表宽度为9位 + //.set_dir4_base(48) //第四级页目录表 + .set_dir4_width(0) //第四级页目录表 + .write(); +} + +/// The earliest entry point for the primary CPU. +/// +/// We can't use bl to jump to higher address, so we use jirl to jump to higher address. +#[naked] +#[no_mangle] +#[link_section = ".text.boot"] +unsafe extern "C" fn _start() -> ! { + core::arch::asm!(" + ori $t0, $zero, 0x1 # CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -2048 # UC, PLV0, 0x8000 xxxx xxxx xxxx + csrwr $t0, 0x180 # LOONGARCH_CSR_DMWIN0 + ori $t0, $zero, 0x11 # CSR_DMW1_MAT | CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -1792 # CA, PLV0, 0x9000 xxxx xxxx xxxx + csrwr $t0, 0x181 # LOONGARCH_CSR_DMWIN1 + + bl {init_mmu} + + # Enable PG + li.w $t0, 0xb0 # PLV=0, IE=0, PG=1 + csrwr $t0, 0x0 # LOONGARCH_CSR_CRMD + li.w $t0, 0x00 # PLV=0, PIE=0, PWE=0 + csrwr $t0, 0x1 # LOONGARCH_CSR_PRMD + li.w $t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0 + csrwr $t0, 0x2 # LOONGARCH_CSR_EUEN + + bl {init_tlb} + + la.global $sp, {boot_stack} + li.d $t0, {boot_stack_size} + add.d $sp, $sp, $t0 # setup boot stack + csrrd $a0, 0x20 # cpuid + la.global $t0, {entry} + jirl $zero,$t0,0 + ", + boot_stack_size = const TASK_STACK_SIZE, + boot_stack = sym BOOT_STACK, + init_mmu = sym init_mmu, + init_tlb = sym crate::arch::init_tlb, + entry = sym super::rust_entry, + options(noreturn), + ) +} + +/// The earliest entry point for secondary CPUs. +#[cfg(feature = "smp")] +#[naked] +#[no_mangle] +#[link_section = ".text.boot"] +unsafe extern "C" fn _start_secondary() -> ! { + core::arch::asm!(" + ori $t0, $zero, 0x1 # CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -2048 # UC, PLV0, 0x8000 xxxx xxxx xxxx + csrwr $t0, 0x180 # LOONGARCH_CSR_DMWIN0 + ori $t0, $zero, 0x11 # CSR_DMW1_MAT | CSR_DMW1_PLV0 + lu52i.d $t0, $t0, -1792 # CA, PLV0, 0x9000 xxxx xxxx xxxx + csrwr $t0, 0x181 # LOONGARCH_CSR_DMWIN1 + la.abs $t0, {sm_boot_stack_top} + ld.d $sp, $t0,0 # read boot stack top + + csrrd $a0, 0x20 # cpuid + la.global $t0, {entry} + jirl $zero,$t0,0 + ", + sm_boot_stack_top = sym SMP_BOOT_STACK_TOP, + entry = sym super::rust_entry_secondary, + options(noreturn), + ) +} diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/console.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/console.rs new file mode 100644 index 0000000000..1176b86a9b --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/console.rs @@ -0,0 +1,77 @@ +//! Uart 16550. + +use core::fmt::Write; +use spinlock::SpinNoIrq; + +const UART_ADDR: usize = 0x900000001FE001E0; + +static COM1: SpinNoIrq = SpinNoIrq::new(Uart::new(UART_ADDR)); + +pub struct Uart { + base_address: usize, +} + +impl Uart { + pub const fn new(base_address: usize) -> Self { + Uart { base_address } + } + + pub fn putchar(&mut self, c: u8) { + let mut ptr = self.base_address as *mut u8; + loop { + unsafe { + let c = ptr.add(5).read_volatile(); + if c & (1 << 5) != 0 { + break; + } + } + } + ptr = self.base_address as *mut u8; + unsafe { + ptr.add(0).write_volatile(c); + } + } + + pub fn getchar(&mut self) -> Option { + let ptr = self.base_address as *mut u8; + unsafe { + if ptr.add(5).read_volatile() & 1 == 0 { + // The DR bit is 0, meaning no data + None + } else { + // The DR bit is 1, meaning data! + Some(ptr.add(0).read_volatile()) + } + } + } +} +impl Write for Uart { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for c in s.bytes() { + self.putchar(c); + } + Ok(()) + } +} + +/// Writes a byte to the console. +pub fn putchar(c: u8) { + let mut uart = COM1.lock(); + match c { + b'\n' => { + uart.putchar(b'\r'); + uart.putchar(b'\n'); + } + c => uart.putchar(c), + } +} + +pub fn write_fmt(args: core::fmt::Arguments) { + use core::fmt::Write; + COM1.lock().write_fmt(args).unwrap(); +} + +/// Reads a byte from the console, or returns [`None`] if no input is available. +pub fn getchar() -> Option { + COM1.lock().getchar() +} diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/irq.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/irq.rs new file mode 100644 index 0000000000..a3d95f18bf --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/irq.rs @@ -0,0 +1,64 @@ +use crate::irq::IrqHandler; +use lazy_init::LazyInit; +use loongarch64::register::csr::Register; +use loongarch64::register::tcfg::Tcfg; +pub(super) const CSR_ECFG_VS_SHIFT: usize = 16; +pub(super) const CSR_ECFG_LIE_TI_SHIFT: usize = 11; +pub(super) const TI_VEC: usize = 0x1 << CSR_ECFG_LIE_TI_SHIFT; +/// HWI mask +pub(super) const HWI_VEC: usize = 0x3fc; + +pub(super) const SWI_IRQ_NUM: usize = 0; + +/// The maximum number of IRQs. +pub const MAX_IRQ_COUNT: usize = 1024; + +/// The timer IRQ number +pub const TIMER_IRQ_NUM: usize = 11; + +static TIMER_HANDLER: LazyInit = LazyInit::new(); + +macro_rules! with_cause { + ($cause: expr, @TIMER => $timer_op: expr, @EXT => $ext_op: expr $(,)?) => { + match $cause { + TIMER_IRQ_NUM => $timer_op, + S_EXT => $ext_op, + _ => panic!("invalid trap cause: {:#x}", $cause), + } + }; +} +/// Enables or disables the given IRQ. +pub fn set_enable(vector: usize, enabled: bool) { + if vector == 11 { + if enabled { + Tcfg::read() + .set_enable(true) + .set_initval(800000000 as usize) + .set_loop(false) + .write(); + } + } +} + +/// Registers an IRQ handler for the given IRQ. +/// +/// It also enables the IRQ if the registration succeeds. It returns `false` if +/// the registration failed. +/// +pub fn register_handler(vector: usize, handler: IrqHandler) -> bool { + crate::irq::register_handler_common(vector, handler) +} + +/// Dispatches the IRQ. +/// +/// This function is called by the common interrupt handler. It looks +/// up in the IRQ handler table and calls the corresponding handler. If +/// necessary, it also acknowledges the interrupt controller after handling. +pub fn dispatch_irq(vector: usize) { + crate::irq::dispatch_irq_common(vector); +} + +pub(super) fn init_primary() { + // enable soft interrupts, timer interrupts, and external interrupts + // disable_irqs(); +} diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/mem.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/mem.rs new file mode 100644 index 0000000000..bad6113c42 --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/mem.rs @@ -0,0 +1,6 @@ +use crate::mem::MemRegion; + +/// Returns platform-specific memory regions. +pub(crate) fn platform_regions() -> impl Iterator { + crate::mem::default_free_regions().chain(crate::mem::default_mmio_regions()) +} diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/misc.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/misc.rs new file mode 100644 index 0000000000..2bda15cd4f --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/misc.rs @@ -0,0 +1,6 @@ +/// Shutdown the whole system, including all CPUs. +pub fn terminate() -> ! { + loop { + crate::arch::halt(); + } +} diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/mod.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/mod.rs new file mode 100644 index 0000000000..c41893ffab --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/mod.rs @@ -0,0 +1,51 @@ +mod boot; +pub mod console; +pub mod mem; +pub mod misc; +pub mod time; + +#[cfg(feature = "irq")] +pub mod irq; + +#[cfg(feature = "smp")] +pub mod mp; + +extern "C" { + fn trap_vector_base(); + fn rust_main(cpu_id: usize, dtb: usize); + fn _sbss(); + fn _ebss(); + #[cfg(feature = "smp")] + fn rust_main_secondary(cpu_id: usize); +} + +#[no_mangle] +unsafe extern "C" fn rust_entry(cpu_id: usize, _dtb: usize) { + crate::mem::clear_bss(); + crate::cpu::init_primary(cpu_id); + crate::arch::set_trap_vector_base(trap_vector_base as usize); + rust_main(cpu_id, 0); +} + +#[cfg(feature = "smp")] +unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { + crate::arch::set_trap_vector_base(trap_vector_base as usize); + crate::cpu::init_secondary(cpu_id); + rust_main_secondary(cpu_id); +} + +/// Initializes the platform devices for the primary CPU. +/// +/// For example, the interrupt controller and external interrupts. +pub fn platform_init() { + // use loongarch64::register::csr::Register; + #[cfg(feature = "irq")] + { + self::irq::init_primary(); + self::time::init_primary(); + } +} + +/// Initializes the platform devices for secondary CPUs. +#[cfg(feature = "smp")] +pub fn platform_init_secondary() {} diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/mp.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/mp.rs new file mode 100644 index 0000000000..c48fb4a49d --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/mp.rs @@ -0,0 +1,15 @@ +use crate::mem::{phys_to_virt, PhysAddr}; +use loongarch64::ipi::{csr_mail_send, send_ipi_single}; + +/// Starts the given secondary CPU with its boot stack. +pub fn start_secondary_cpu(hartid: usize, stack_top: PhysAddr) { + extern "C" { + fn _start_secondary(); + } + let stack_top_virt_addr = phys_to_virt(stack_top).as_usize(); + unsafe { + super::boot::SMP_BOOT_STACK_TOP = stack_top_virt_addr; + } + csr_mail_send(_start_secondary as u64, hartid, 0); + send_ipi_single(hartid, 1); +} diff --git a/modules/axhal/src/platform/qemu_virt_loongarch64/time.rs b/modules/axhal/src/platform/qemu_virt_loongarch64/time.rs new file mode 100644 index 0000000000..6398a3d168 --- /dev/null +++ b/modules/axhal/src/platform/qemu_virt_loongarch64/time.rs @@ -0,0 +1,45 @@ +// use loongarch64::register::csr::Register; +// use loongarch64::register::ticlr::Ticlr; +use loongarch64::register::time::Time; + +const NANOS_PER_TICK: u64 = crate::time::NANOS_PER_SEC / axconfig::TIMER_FREQUENCY as u64; + +/// Returns the current clock time in hardware ticks. +#[inline] +pub fn current_ticks() -> u64 { + Time::read() as u64 +} + +/// Converts hardware ticks to nanoseconds. +#[inline] +pub const fn ticks_to_nanos(ticks: u64) -> u64 { + ticks * NANOS_PER_TICK +} + +/// Converts nanoseconds to hardware ticks. +#[inline] +pub const fn nanos_to_ticks(nanos: u64) -> u64 { + nanos / NANOS_PER_TICK +} + +/// Set a one-shot timer. +/// +/// A timer interrupt will be triggered at the given deadline (in nanoseconds). +#[cfg(feature = "irq")] +pub fn set_oneshot_timer(deadline_ns: u64) { + use loongarch64::register::csr::Register; + use loongarch64::register::tcfg::Tcfg; + Tcfg::read() + .set_enable(true) + .set_loop(false) + .set_initval(nanos_to_ticks(deadline_ns) as usize) + .write(); //设置计时器的配置 +} +#[cfg(feature = "irq")] +pub(super) fn init_primary() { + { + use crate::arch::disable_irqs; + disable_irqs(); + Ticlr::read().clear_timer().write(); //清除时钟中断 + } +} diff --git a/platforms/loongarch64-qemu-virt.toml b/platforms/loongarch64-qemu-virt.toml new file mode 100644 index 0000000000..73474abbf5 --- /dev/null +++ b/platforms/loongarch64-qemu-virt.toml @@ -0,0 +1,35 @@ +# Architecture identifier. +arch = "loongarch64" +# Platform identifier. +platform = "loongarch64-qemu-virt" +# Platform family. +family = "loongarch64-qemu-virt" + +# Base address of the whole physical memory. +phys-memory-base = "0x0" +# Size of the whole physical memory. +phys-memory-size = "0x800_0000" # 128M +# Base physical address of the kernel image. +kernel-base-paddr = "0x000_1000" +# Base virtual address of the kernel image. +kernel-base-vaddr = "0x9000_0000_0000_1000" +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0x9000_0000_0000_0000" +# MMIO regions with format (`base_paddr`, `size`). +mmio-regions = [ + ["0xfec0_0000", "0x1000"], # IO APIC + ["0xfed0_0000", "0x1000"], # HPET + ["0xfee0_0000", "0x1000"], # Local APIC +] +# VirtIO MMIO regions with format (`base_paddr`, `size`). +virtio-mmio-regions = [ + ["0x4004_0000", "0x1000"], # virtio-pci-common-virtio-net + ["0x4004_1000", "0x1000"], # virtio-pci-isr-virtio-net + ["0x4004_2000", "0x1000"], # virtio-pci-device-virtio-net + ["0x4004_3000", "0x1000"], # virtio-pci-notify-virtio-net +] +# Timer interrupt frequency in Hz. +timer-frequency = "1_000_000_000" # 10MHz + + diff --git a/scripts/make/cargo.mk b/scripts/make/cargo.mk index fc07ea2dae..e4aff599d4 100644 --- a/scripts/make/cargo.mk +++ b/scripts/make/cargo.mk @@ -23,6 +23,10 @@ ifeq ($(ARCH), x86_64) RUSTFLAGS += -C link-arg=--no-relax endif +ifeq ($(ARCH),loongarch64) + build_args += -Z build-std +endif + ifeq ($(MAKECMDGOALS), doc_check_missing) RUSTDOCFLAGS += -D missing-docs endif diff --git a/scripts/make/qemu.mk b/scripts/make/qemu.mk index 3ed4326140..64d4dd4c97 100644 --- a/scripts/make/qemu.mk +++ b/scripts/make/qemu.mk @@ -24,7 +24,18 @@ qemu_args-aarch64 := \ -machine virt \ -kernel $(OUT_BIN) +LOONGARCH_BIOS = tools/la64/loongarch_bios_0310.bin +qemu_args-loongarch64 := \ + -bios $(LOONGARCH_BIOS) \ + -kernel $(OUT_ELF) \ + -vga none \ + + +ifeq ($(ARCH), loongarch64) +qemu_args-y := -m 1G -smp $(SMP) $(qemu_args-$(ARCH)) +else qemu_args-y := -m 128M -smp $(SMP) $(qemu_args-$(ARCH)) +endif qemu_args-$(BLK) += \ -device virtio-blk-$(vdev-suffix),drive=disk0 \ @@ -67,11 +78,25 @@ else endif define run_qemu + $(call before_run_qemu) @printf " $(CYAN_C)Running$(END_C) on qemu...\n" $(call run_cmd,$(QEMU),$(qemu_args-y)) + $(call after_run_qemu) endef define run_qemu_debug @printf " $(CYAN_C)Debugging$(END_C) on qemu...\n" $(call run_cmd,$(QEMU),$(qemu_args-debug)) endef + +define before_run_qemu + $(if $(filter $(ARCH), loongarch64), \ + @cp tools/la64/efi-virtio.rom . \ + ) +endef + +define after_run_qemu + $(if $(filter $(ARCH), loongarch64), \ + @rm efi-virtio.rom \ + ) +endef \ No newline at end of file diff --git a/tools/la64/efi-virtio.rom b/tools/la64/efi-virtio.rom new file mode 100644 index 0000000000000000000000000000000000000000..70e8588ccdc6e0e25eedfc8611f2183a55112ddb GIT binary patch literal 160768 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 z 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 literal 0 HcmV?d00001 diff --git a/tools/la64/la-gdb.sh b/tools/la64/la-gdb.sh new file mode 100755 index 0000000000..48b551354c --- /dev/null +++ b/tools/la64/la-gdb.sh @@ -0,0 +1,9 @@ +#!/bin/bash +git clone https://github.com/foxsen/binutils-gdb +git checkout loongarch-v2022-03-10 +cd binutils-gdb +mkdir "build" +cd "build" +../configure --target=loongarch64-unknown-linux-gnu --prefix=/opt/gdb +make -j$(nproc) +sudo make install \ No newline at end of file diff --git a/tools/la64/la-qemu.sh b/tools/la64/la-qemu.sh new file mode 100755 index 0000000000..8b6570fc70 --- /dev/null +++ b/tools/la64/la-qemu.sh @@ -0,0 +1,11 @@ +#!/bin/bash +sudo apt update +sudo apt install gcc cmake g++ build-essential pkg-config zlib1g-dev libglib2.0-dev meson libpixman-1-dev ninja-build libfdt-dev -y +git clone https://github.com/foxsen/qemu.git +cd qemu +git checkout loongarch +mkdir build +cd build +../configure --target-list=loongarch64-softmmu,loongarch64-linux-user --enable-kvm --enable-debug --disable-werror +make -j$(nproc) +#make install \ No newline at end of file diff --git a/tools/la64/loongarch_bios_0310.bin b/tools/la64/loongarch_bios_0310.bin new file mode 100644 index 0000000000000000000000000000000000000000..4f16623ba92b0437d9c8a9babc3f8dc0e07f0cec GIT binary patch literal 4190208 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%0Ap zW`A|>Cy=3BS}qmsH4Z$%v+s0-PpD(z*`$tr;`3Y5;TAcr`@i+~T0V$QweCHtdDZjT z2;+Ry3X5*)uBWZ=QO)b!f79(g_+N(g%?$V6ebuneKN`+Ojy%LXE!cjh8cw~O=wo_YN-^X`+L*Q0OlGschdO+mK=?rCOC>9Y%1pT}0-M*UuV-ui!FOyjHWJH(!t z%X}r)LpjQv<_oESuT*4+$VYWCeyco}W#1QGNzCTF0p3v&Ra#}*=Q=#geCUN9&@_MT zV@-4M)AhT==%wuoU$KhQpBGtUJ@v6(7tn2=X}2Bg?JE(PcQ$e<%o;&EawvA1ujEH( z5Oc?th;^VldN96kus)kMKJy}cstY-TJPkJMD!U)iuYGA-e1$WBQS|E#=-2Ize${a> znfIT58WvpXG1REgJAY&Si*cL4xcxC z{rmxB>UiXPVxkJ=^kmHuncIhR%Eq(K^$@v7(w6Y7$$F3aS{lyQ#SCdn)6_bU9K*j0 zytUr`OjFxu#TUNw+1N42sMdAtn>_fCQOWmu_O*HWtJaI3g|$43v}zf0jQqInV41b? zNOF(f%CF+XAWZ>dX-i=-PMq=)*bcO~zElenyFN@Q#ji@J>MTmU}SgXb<1rZoiVhJ;$HBSvBpp zim|5i^LR$$DEhgyam%^L4dAok!N0?k*hk^6_>>!`I;lMal{-cjJE<_hvflm%3lcZx-Ds{c;Y57Y_=( zhJcq$dzN(#-4}k55_5C+#K;=7&}=$6d4eN>Pvf>N^=xVQkFzILzSM%1XQeNBUO%fI zO5s<5M{31NoH5Be4j!s_U;2}NkLfcfwH@h`{&cMDm_7?rpY`gq2XkL&AXoSAfxxJV z6UUD(x*-@SyylwW!JxAL4XduLsT#Jpx_tJG>GK!PoIPxQ)%2Oesw!t)Hf%y=Rq3o5 z!^Y2?Hm7{fqG6>~GmC5IRE?fJZ_c99+L^QG9sA3r73%b&aCr2MlcwG{deTid-Y|9a zjW;r=t2>RWfl}4jQR8M;RxJef(m6A4E1y?YQa-PI=(S^RE3TbCd!D@IJsua|$AQypY3VpKI&<#4x#qO0>EOnkS5;G2 zD+D)hESg|e-Bw;PzkJ@z+SymybnAM)eEPhqIVXBtmCT%L_t%AwOJyikHMMgVjhj7p zUU@WHRcT&xjoFPuhj(#k$>h=IxYF^aW;;OOUFWT2E2iDpsHzz=XPbo!2algz;QTbc zYW9qI)%I^T_^S9uv$}k)IjX$U49}b~8@8NNC5Sm?y4al#vp>RBb8eeiQ8m}4j#8TO zuQa{DojKR6utyCJKsa;Htess^HAp~o_-5#}cEhFRGiWtDb8(e<^))V2!BBIms!FRD z&7Da@_JfmZ>ok3Ds9L}e`n6HzbF0j2ySeYiky$fy#vE9@(wtXo)>X}^DW6?6d!AXN zDSN4dZe^NdVEszx{p8R5ZknTtt{Gf7{2S4Qra9jE=Dw!yn`SpCbocZGvVaAMCJhw^ z4J?3~0+kC*(C(wScJ^&mbLJg00vCd!XtcHh==J!oWK1xFJPcvvcNkuVHMr9Jmr)v~ zl;_Rq