diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000000..a07cc5f67a --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,29 @@ +# Target Platform +[build] +target = 'riscv64gc-unknown-none-elf' +# target = 'x86_64-unknown-none' +# target = 'aarch64-unknown-none-softfloat' +# target = 'loongarch64-unknown-none' + +# This flags also can be set from every target. +rustflags = [ + '-Cforce-frame-pointers=yes', + '-Clink-arg=-no-pie', + '--cfg=board="qemu"', + '--cfg=driver="kvirtio,kgoldfish-rtc,ns16550a"', + # '-Zunstable-options', + # '--check-cfg=values(board, "qemu","k210","cv1811h", "knvme", "")', + # '--cfg=kernel_base="0xffffffc080200000"', # riscv64gc-unknown-none-elf + # '--cfg=kernel_base="0xffffff8000200000"', # x86_64-unknown-none +] + +[target.riscv64gc-unknown-none-elf] + +[target.x86_64-unknown-none] + +[target.aarch64-unknown-none-softfloat] + +[target.loongarch64-unknown-none] + +[unstable] +features = ['dev_dep','host_dep'] diff --git a/Cargo.lock b/Cargo.lock index d017b63e3d..5341f3711c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,6 +250,7 @@ dependencies = [ "allocator", "axerrno", "cfg-if", + "hal", "log", "memory_addr", "spinlock", @@ -385,6 +386,7 @@ dependencies = [ "crate_interface", "dw_apb_uart", "either", + "hal", "handler_table", "kernel_guard", "lazy_init", @@ -396,7 +398,7 @@ dependencies = [ "percpu", "ratio", "raw-cpuid 11.0.1", - "riscv", + "riscv 0.10.1", "sbi-rt", "spinlock", "static_assertions", @@ -449,7 +451,7 @@ dependencies = [ "elf_parser", "log", "page_table_entry", - "riscv", + "riscv 0.10.1", "spinlock", "xmas-elf", ] @@ -492,7 +494,7 @@ dependencies = [ "crate_interface", "elf_parser", "lazy_static", - "riscv", + "riscv 0.10.1", "spinlock", "xmas-elf", ] @@ -514,6 +516,7 @@ dependencies = [ "axtask", "cfg-if", "crate_interface", + "hal", "kernel_guard", "lazy_init", "percpu", @@ -609,6 +612,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version 0.2.3", +] + [[package]] name = "base64" version = "0.13.1" @@ -1169,6 +1181,33 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "hal" +version = "0.1.0" +dependencies = [ + "aarch64-cpu", + "allocator", + "arm_gic", + "arm_pl011", + "bitflags 2.4.0", + "cfg-if", + "crate_interface", + "fdt", + "irq_safety", + "log", + "loongarch64", + "memory_addr", + "multiboot", + "percpu", + "raw-cpuid 11.0.1", + "riscv 0.6.0", + "spin 0.9.8", + "tock-registers", + "x2apic", + "x86", + "x86_64", +] + [[package]] name = "half" version = "1.8.2" @@ -1202,7 +1241,7 @@ checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" dependencies = [ "atomic-polyfill", "hash32", - "rustc_version", + "rustc_version 0.4.0", "spin 0.9.8", "stable_deref_trait", ] @@ -1246,6 +1285,14 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "irq_safety" +version = "0.1.1" +source = "git+https://github.com/theseus-os/irq_safety.git#11bfab9f410a898df1e42ad6213488612e20c926" +dependencies = [ + "spin 0.9.8", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -1362,6 +1409,15 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +[[package]] +name = "loongarch64" +version = "0.2.3" +source = "git+https://github.com/Godones/loongArch64#096b2c32cdd0209bfc33c901c4a65705e1158b1d" +dependencies = [ + "bit_field", + "bitflags 1.3.2", +] + [[package]] name = "lwext4_rust" version = "0.1.0" @@ -1415,6 +1471,15 @@ dependencies = [ "axstarry", ] +[[package]] +name = "multiboot" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87ad3b7b7bcf5da525c22221e3eb3a020cd68b2d55ae62f629c15e8bc3bd56e" +dependencies = [ + "paste", +] + [[package]] name = "nb" version = "0.1.3" @@ -1744,6 +1809,18 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +[[package]] +name = "riscv" +version = "0.6.0" +source = "git+https://github.com/rcore-os/riscv#11d43cf7cccb3b62a3caaf3e07a1db7449588f9a" +dependencies = [ + "bare-metal", + "bit_field", + "bitflags 1.3.2", + "log", + "riscv-target", +] + [[package]] name = "riscv" version = "0.10.1" @@ -1755,6 +1832,16 @@ dependencies = [ "embedded-hal", ] +[[package]] +name = "riscv-target" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88aa938cda42a0cf62a20cfe8d139ff1af20c2e681212b5b34adb5a58333f222" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "rlsf" version = "0.2.1" @@ -1773,13 +1860,22 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.18", ] [[package]] @@ -1847,12 +1943,27 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.185" diff --git a/Cargo.toml b/Cargo.toml index 6be63c75d2..4b1806e1fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,9 @@ members = [ "crates/driver_net", "crates/driver_pci", "crates/driver_virtio", + "crates/elf_parser", "crates/flatten_objects", + "crates/hal", "crates/handler_table", "crates/kernel_guard", "crates/lazy_init", @@ -35,7 +37,6 @@ members = [ "crates/spinlock", "crates/timer_list", "crates/tuple_for_each", - "crates/elf_parser", "modules/axalloc", "modules/axconfig", diff --git a/Makefile b/Makefile index f457dacc47..79cdde97bc 100644 --- a/Makefile +++ b/Makefile @@ -177,7 +177,7 @@ debug: build sleep 1 $(GDB) $(OUT_ELF) \ -ex 'target remote localhost:1234' \ - -ex 'b rust_main' \ + -ex 'b rust_entry' \ -ex 'continue' \ -ex 'disp /16i $$pc' diff --git a/apps/monolithic_userboot/src/batch.rs b/apps/monolithic_userboot/src/batch.rs index 4173e1a232..a09d3fbaa6 100644 --- a/apps/monolithic_userboot/src/batch.rs +++ b/apps/monolithic_userboot/src/batch.rs @@ -10,8 +10,8 @@ pub const SDCARD_TESTCASES: &[&str] = &[ // "busybox sh ./test_all.sh", // "./riscv64-linux-musl-native/bin/riscv64-linux-musl-gcc ./hello.c -static", // "./a.out", - "./time-test", - "./interrupts-test-1", + // "./time-test", + // "./interrupts-test-1", // "./interrupts-test-2", // "./copy-file-range-test-1", // "./copy-file-range-test-2", @@ -56,7 +56,7 @@ pub const SDCARD_TESTCASES: &[&str] = &[ // "lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX", // "busybox echo context switch overhead", // "lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96", - // "busybox sh libctest_testcode.sh", + "busybox sh libctest_testcode.sh", // "busybox sh lua_testcode.sh", // "libc-bench", // "busybox sh ./netperf_testcode.sh", diff --git a/crates/hal/Cargo.toml b/crates/hal/Cargo.toml new file mode 100644 index 0000000000..7d2d12e6ca --- /dev/null +++ b/crates/hal/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "hal" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +# whether to use the stackful coroutine +stackful = [] +alloc = [] + +[dependencies] +log = "0.4" +fdt = "0.1.5" +bitflags = "2.0.2" +cfg-if = "1.0.0" +crate_interface = { path = "../crate_interface" } +allocator = { path = "../allocator" } +percpu = { path = "../percpu" } +memory_addr = { path = "../memory_addr" } + +[target.'cfg(target_arch = "riscv64")'.dependencies] +riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } + +[target.'cfg(target_arch = "x86_64")'.dependencies] +x86 = "0.52" +x86_64 = "0.14" +spin = { version = "0.9.8", features = ["mutex"] } +irq_safety = { git = "https://github.com/theseus-os/irq_safety.git"} +multiboot = "0.8.0" +x2apic = "0.4" +raw-cpuid = "11.0" + +[target.'cfg(target_arch = "aarch64")'.dependencies] +aarch64-cpu = "9.3" +arm_pl011 = { path = "../arm_pl011" } +tock-registers = "0.8" +irq_safety = { git = "https://github.com/theseus-os/irq_safety.git"} +arm_gic = { path = "../arm_gic" } + +[target.'cfg(target_arch = "loongarch64")'.dependencies] +spin = { version = "0.9.8", features = ["mutex"] } +loongarch64 = {git = "https://github.com/Godones/loongArch64",package = "loongarch64" } diff --git a/crates/hal/src/aarch64/boot.rs b/crates/hal/src/aarch64/boot.rs new file mode 100644 index 0000000000..d67c7ef98f --- /dev/null +++ b/crates/hal/src/aarch64/boot.rs @@ -0,0 +1,144 @@ +use crate::{PTEFlags, VirtAddr}; +use aarch64_cpu::{asm, asm::barrier, registers::*}; +use core::arch::asm; + +// use page_table_entry::aarch64::{MemAttr, A64PTE}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; + +#[link_section = ".data.prepage"] +static mut BOOT_PT_L1: [usize; 512] = [0; 512]; + +unsafe fn switch_to_el1() { + SPSel.write(SPSel::SP::ELx); + SP_EL0.set(0); + let current_el = CurrentEL.read(CurrentEL::EL); + if current_el >= 2 { + if current_el == 3 { + // Set EL2 to 64bit and enable the HVC instruction. + SCR_EL3.write( + SCR_EL3::NS::NonSecure + SCR_EL3::HCE::HvcEnabled + SCR_EL3::RW::NextELIsAarch64, + ); + // Set the return address and exception level. + SPSR_EL3.write( + SPSR_EL3::M::EL1h + + SPSR_EL3::D::Masked + + SPSR_EL3::A::Masked + + SPSR_EL3::I::Masked + + SPSR_EL3::F::Masked, + ); + ELR_EL3.set(LR.get()); + } + // Disable EL1 timer traps and the timer offset. + CNTHCTL_EL2.modify(CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET); + CNTVOFF_EL2.set(0); + // Set EL1 to 64bit. + HCR_EL2.write(HCR_EL2::RW::EL1IsAarch64); + // Set the return address and exception level. + SPSR_EL2.write( + SPSR_EL2::M::EL1h + + SPSR_EL2::D::Masked + + SPSR_EL2::A::Masked + + SPSR_EL2::I::Masked + + SPSR_EL2::F::Masked, + ); + core::arch::asm!( + " + mov x8, sp + msr sp_el1, x8" + ); + ELR_EL2.set(LR.get()); + asm::eret(); + } +} + +unsafe fn init_mmu() { + MAIR_EL1.set(0x44_ff_04); + + // Enable TTBR0 and TTBR1 walks, page size = 4K, vaddr size = 39 bits, paddr size = 40 bits. + let tcr_flags0 = TCR_EL1::EPD0::EnableTTBR0Walks + + TCR_EL1::TG0::KiB_4 + + TCR_EL1::SH0::Inner + + TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::T0SZ.val(25); + let tcr_flags1 = TCR_EL1::EPD1::EnableTTBR1Walks + + TCR_EL1::TG1::KiB_4 + + TCR_EL1::SH1::Inner + + TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable + + TCR_EL1::T1SZ.val(25); + TCR_EL1.write(TCR_EL1::IPS::Bits_48 + tcr_flags0 + tcr_flags1); + barrier::isb(barrier::SY); + + // Set both TTBR0 and TTBR1 + // let root_paddr = PhysAddr::from(BOOT_PT_L0.as_ptr() as usize).addr() as _; + let root_paddr = (BOOT_PT_L1.as_ptr() as usize & 0xFFFF_FFFF_F000) as _; + TTBR0_EL1.set(root_paddr); + TTBR1_EL1.set(root_paddr); + + // Flush the entire TLB + flush_tlb(None); + + // Enable the MMU and turn on I-cache and D-cache + SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); + barrier::isb(barrier::SY); +} + +unsafe fn init_boot_page_table() { + // Level 1 Entry for Huge Page + BOOT_PT_L1[0] = + 0 | (PTEFlags::VALID | PTEFlags::AF | PTEFlags::ATTR_INDX | PTEFlags::NG).bits(); + BOOT_PT_L1[1] = (0x4000_0000) + | (PTEFlags::VALID | PTEFlags::AF | PTEFlags::ATTR_INDX | PTEFlags::NG).bits(); +} +/// The earliest entry point for the primary CPU. +#[naked] +#[no_mangle] +#[link_section = ".text.entry"] +unsafe extern "C" fn _start() -> ! { + // PC = 0x8_0000 + // X0 = dtb + core::arch::asm!(" + mrs x19, mpidr_el1 + and x19, x19, #0xffffff // get current CPU id + mov x20, x0 // save DTB pointer + + adrp x8, {boot_stack} // setup boot stack + add x8, x8, {boot_stack_size} + mov sp, x8 + + bl {switch_to_el1} // switch to EL1 + bl {init_boot_page_table} + bl {init_mmu} // setup MMU + + mov x8, {phys_virt_offset} // set SP to the high address + add sp, sp, x8 + + mov x0, x19 // call rust_entry(cpu_id, dtb) + mov x1, x20 + ldr x8, ={entry} + blr x8 + b .", + switch_to_el1 = sym switch_to_el1, + init_boot_page_table = sym init_boot_page_table, + init_mmu = sym init_mmu, + boot_stack = sym crate::BOOT_STACK, + boot_stack_size = const crate::STACK_SIZE, + phys_virt_offset = const super::VIRT_ADDR_START, + entry = sym super::rust_tmp_main, + options(noreturn), + ) +} + +#[inline] +pub fn flush_tlb(vaddr: Option) { + unsafe { + if let Some(vaddr) = vaddr { + // TIPS: flush tlb, tlb addr: 0-47: ppn, otherwise tlb asid + asm!("tlbi vaale1is, {}; dsb sy; isb", in(reg) ((vaddr.0 >> 12) & 0xFFFF_FFFF_FFFF)) + } else { + // flush the entire TLB + asm!("tlbi vmalle1; dsb sy; isb") + } + } +} diff --git a/crates/hal/src/aarch64/consts.rs b/crates/hal/src/aarch64/consts.rs new file mode 100644 index 0000000000..b3e74aa14f --- /dev/null +++ b/crates/hal/src/aarch64/consts.rs @@ -0,0 +1,7 @@ +// pub const VIRT_ADDR_START: usize = 0xffff_0000_0000_0000; +pub const VIRT_ADDR_START: usize = 0xffff_ff80_0000_0000; +// pub const VIRT_ADDR_START: usize = 0; +pub const USER_ADDR_MAX: usize = 0x0000_ffff_ffff_ffff; +pub const PAGE_SIZE: usize = 4096; +pub const PAGE_ITEM_COUNT: usize = 512; +pub const SIG_RETURN_ADDR: usize = 0xFFFF_1000_0000_0000; diff --git a/crates/hal/src/aarch64/context.rs b/crates/hal/src/aarch64/context.rs new file mode 100644 index 0000000000..1998d6916f --- /dev/null +++ b/crates/hal/src/aarch64/context.rs @@ -0,0 +1,147 @@ +use core::ops::{Index, IndexMut}; + +use crate::ContextArgs; + +/// Saved registers when a trap (interrupt or exception) occurs.#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Default, Clone, Copy)] +pub struct Context { + pub regs: [usize; 31], + pub sp: usize, + pub elr: usize, + pub spsr: usize, + pub tpidr: usize, +} + +impl Context { + // 创建上下文信息 + #[inline] + pub fn new() -> Self { + Self { + ..Default::default() + } + } +} + +// impl ContextOps for Context { +// #[inline] +// fn set_sp(&mut self, sp: usize) { +// self.sp = sp +// } + +// #[inline] +// fn sp(&self) -> usize { +// self.sp +// } +// #[inline] +// fn set_ra(&mut self, ra: usize) { +// self.regs[30] = ra; +// } + +// #[inline] +// fn ra(&self) -> usize { +// self.regs[30] +// } + +// #[inline] +// fn set_sepc(&mut self, sepc: usize) { +// self.elr = sepc; +// } + +// #[inline] +// fn sepc(&self) -> usize { +// self.elr +// } + +// #[inline] +// fn syscall_number(&self) -> usize { +// self.regs[8] +// } + +// #[inline] +// fn args(&self) -> [usize; 6] { +// [ +// self.regs[0], +// self.regs[1], +// self.regs[2], +// self.regs[3], +// self.regs[4], +// self.regs[5], +// ] +// } + +// #[inline] +// fn syscall_ok(&mut self) {} + +// fn set_ret(&mut self, ret: usize) { +// self.regs[0] = ret; +// } + +// fn set_arg0(&mut self, ret: usize) { +// self.regs[0] = ret; +// } + +// fn set_arg1(&mut self, ret: usize) { +// self.regs[1] = ret; +// } + +// fn set_arg2(&mut self, ret: usize) { +// self.regs[2] = ret; +// } + +// #[inline] +// fn set_tls(&mut self, tls: usize) { +// self.tpidr = tls +// } +// } + +impl Context { + #[inline] + pub fn args(&self) -> [usize; 6] { + [ + self.regs[0], + self.regs[1], + self.regs[2], + self.regs[3], + self.regs[4], + self.regs[5], + ] + } + + #[inline] + pub fn syscall_ok(&mut self) {} +} + +impl Index for Context { + type Output = usize; + + fn index(&self, index: ContextArgs) -> &Self::Output { + match index { + ContextArgs::SEPC => &self.elr, + ContextArgs::RA => &self.regs[30], + ContextArgs::SP => &self.sp, + ContextArgs::RET => &self.regs[0], + ContextArgs::ARG0 => &self.regs[0], + ContextArgs::ARG1 => &self.regs[1], + ContextArgs::ARG2 => &self.regs[2], + ContextArgs::TLS => &self.tpidr, + ContextArgs::SYSCALL => &self.regs[8], + } + } +} + +impl IndexMut for Context { + fn index_mut(&mut self, index: ContextArgs) -> &mut Self::Output { + match index { + ContextArgs::SEPC => &mut self.elr, + ContextArgs::RA => &mut self.regs[30], + ContextArgs::SP => &mut self.sp, + ContextArgs::RET => &mut self.regs[0], + ContextArgs::ARG0 => &mut self.regs[0], + ContextArgs::ARG1 => &mut self.regs[1], + ContextArgs::ARG2 => &mut self.regs[2], + ContextArgs::TLS => &mut self.tpidr, + ContextArgs::SYSCALL => &mut self.regs[8], + } + } +} diff --git a/crates/hal/src/aarch64/gic.rs b/crates/hal/src/aarch64/gic.rs new file mode 100644 index 0000000000..977c3a7df7 --- /dev/null +++ b/crates/hal/src/aarch64/gic.rs @@ -0,0 +1,44 @@ +use arm_gic::gic_v2::{GicCpuInterface, GicDistributor}; +use arm_gic::{translate_irq, InterruptType}; +use irq_safety::MutexIrqSafe; + +use crate::PhysAddr; + +/// The maximum number of IRQs. +pub const MAX_IRQ_COUNT: usize = 1024; + +/// The timer IRQ number. +pub const TIMER_IRQ_NUM: usize = translate_irq(14, InterruptType::PPI).unwrap(); + +/// The UART IRQ number. +pub const UART_IRQ_NUM: usize = translate_irq(1, InterruptType::SPI).unwrap(); + +const GICD_BASE: PhysAddr = PhysAddr::new(0x0800_0000); +const GICC_BASE: PhysAddr = PhysAddr::new(0x0801_0000); + +static GICD: MutexIrqSafe = + MutexIrqSafe::new(GicDistributor::new(GICD_BASE.get_mut_ptr())); + +// per-CPU, no lock +static GICC: GicCpuInterface = GicCpuInterface::new(GICC_BASE.get_mut_ptr()); + +/// Enables or disables the given IRQ. +pub fn set_enable(irq_num: usize, enabled: bool) { + trace!("GICD set enable: {} {}", irq_num, enabled); + GICD.lock().set_enable(irq_num as _, enabled); +} + +/// Initializes GICD, GICC on the primary CPU. +pub(crate) fn init() { + info!("Initialize GICv2..."); + GICD.lock().init(); + GICC.init(); +} + +#[inline] +pub fn handle_irq(f: F) +where + F: FnOnce(u32), +{ + GICC.handle_irq(f) +} diff --git a/crates/hal/src/aarch64/mod.rs b/crates/hal/src/aarch64/mod.rs new file mode 100644 index 0000000000..63372ecf9f --- /dev/null +++ b/crates/hal/src/aarch64/mod.rs @@ -0,0 +1,83 @@ +mod boot; +mod consts; +mod context; +mod gic; +mod page_table; +mod pl011; +mod psci; +mod timer; +mod trap; + +use aarch64_cpu::registers::{Writeable, TTBR0_EL1}; +use aarch64_cpu::{asm::barrier, registers::CPACR_EL1}; +use alloc::vec::Vec; +pub use consts::*; +pub use context::Context; +use fdt::Fdt; +pub use page_table::*; +pub use pl011::{console_getchar, console_putchar}; +pub use psci::system_off as shutdown; +pub use timer::{get_time, time_to_usec}; +pub use trap::{enable_external_irq, enable_irq, init_interrupt, run_user_task}; + +use crate::{clear_bss, ArchInterface}; + +pub fn rust_tmp_main(hart_id: usize, device_tree: usize) { + clear_bss(); + pl011::init_early(); + ArchInterface::init_logging(); + trap::init(); + allocator::init(); + gic::init(); + + timer::init(); + + let mut dt_buf = Vec::new(); + + if device_tree != 0 { + let fdt = unsafe { Fdt::from_ptr(device_tree as *const u8).unwrap() }; + + dt_buf.extend_from_slice(unsafe { + core::slice::from_raw_parts(device_tree as *const u8, fdt.total_size()) + }); + + info!("There has {} CPU(s)", fdt.cpus().count()); + + fdt.memory() + .regions() + .for_each(|x: fdt::standard_nodes::MemoryRegion| { + info!( + "memory region {:#X} - {:#X}", + x.starting_address as usize, + x.starting_address as usize + x.size.unwrap() + ); + + ArchInterface::add_memory_region( + x.starting_address as usize | VIRT_ADDR_START, + (x.starting_address as usize + x.size.unwrap()) | VIRT_ADDR_START, + ); + }); + } + + ArchInterface::prepare_drivers(); + + if let Ok(fdt) = Fdt::new(&dt_buf) { + for node in fdt.all_nodes() { + ArchInterface::try_to_add_device(&node); + } + } + + drop(dt_buf); + + // enable fp + CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing); + barrier::isb(barrier::SY); + + ArchInterface::main(hart_id); + + shutdown(); +} + +pub fn switch_to_kernel_page_table() { + TTBR0_EL1.set_baddr(TTBR0_EL1.get_baddr()) +} diff --git a/crates/hal/src/aarch64/page_table.rs b/crates/hal/src/aarch64/page_table.rs new file mode 100644 index 0000000000..2f702e8a50 --- /dev/null +++ b/crates/hal/src/aarch64/page_table.rs @@ -0,0 +1,245 @@ +use core::arch::asm; + +use aarch64_cpu::registers::{Writeable, TTBR0_EL1}; +use alloc::sync::Arc; + +use crate::{ + ArchInterface, MappingFlags, PhysAddr, PhysPage, VirtAddr, VirtPage, PAGE_ITEM_COUNT, PAGE_SIZE, +}; + +use super::boot::flush_tlb; + +#[derive(Copy, Clone, Debug)] +pub struct PTE(usize); + +impl PTE { + #[inline] + pub const fn new() -> Self { + Self(0) + } + + #[inline] + pub const fn from_ppn(ppn: usize, flags: PTEFlags) -> Self { + PTE((ppn << 12) | flags.bits()) + } + + #[inline] + pub const fn from_addr(addr: usize, flags: PTEFlags) -> Self { + Self::from_ppn(addr >> 12, flags) + } + + #[inline] + pub const fn to_ppn(&self) -> PhysPage { + PhysPage((self.0 & 0xffff_ffff_ffff_f000) >> 12) + } + + #[inline] + pub fn set(&mut self, ppn: usize, flags: PTEFlags) { + self.0 = (ppn << 10) | flags.bits() as usize; + } + + #[inline] + pub const fn flags(&self) -> PTEFlags { + PTEFlags::from_bits_truncate(self.0) + } + + #[inline] + pub const fn is_valid(&self) -> bool { + self.flags().contains(PTEFlags::VALID) + } + + #[inline] + pub fn is_block(&self) -> bool { + self.flags().contains(PTEFlags::NON_BLOCK) + } + + #[inline] + pub fn get_next_ptr(&self) -> PhysAddr { + PhysAddr(self.0 & 0xffff_ffff_f000) + } + + #[inline] + pub fn is_leaf(&self) -> bool { + self.flags().contains(PTEFlags::VALID | PTEFlags::NON_BLOCK) + } +} + +impl From for PTEFlags { + fn from(value: MappingFlags) -> Self { + let mut flags = PTEFlags::VALID | PTEFlags::NON_BLOCK | PTEFlags::AF | PTEFlags::NG; + if !value.contains(MappingFlags::W) { + flags |= PTEFlags::AP_RO; + } + + if !value.contains(MappingFlags::X) { + flags |= PTEFlags::UXN | PTEFlags::PXN; + } + + if value.contains(MappingFlags::U) { + flags |= PTEFlags::AP_EL0; + } + flags + } +} + +bitflags::bitflags! { + /// Possible flags for a page table entry. + pub struct PTEFlags: usize { + // Attribute fields in stage 1 VMSAv8-64 Block and Page descriptors: + /// Whether the descriptor is valid. + const VALID = 1 << 0; + /// The descriptor gives the address of the next level of translation table or 4KB page. + /// (not a 2M, 1G block) + const NON_BLOCK = 1 << 1; + /// Memory attributes index field. + const ATTR_INDX = 0b111 << 2; + const NORMAL_NONCACHE = 0b010 << 2; + /// Non-secure bit. For memory accesses from Secure state, specifies whether the output + /// address is in Secure or Non-secure memory. + const NS = 1 << 5; + /// Access permission: accessable at EL0. + const AP_EL0 = 1 << 6; + /// Access permission: read-only. + const AP_RO = 1 << 7; + /// Shareability: Inner Shareable (otherwise Outer Shareable). + const INNER = 1 << 8; + /// Shareability: Inner or Outer Shareable (otherwise Non-shareable). + const SHAREABLE = 1 << 9; + /// The Access flag. + const AF = 1 << 10; + /// The not global bit. + const NG = 1 << 11; + /// Indicates that 16 adjacent translation table entries point to contiguous memory regions. + const CONTIGUOUS = 1 << 52; + /// The Privileged execute-never field. + const PXN = 1 << 53; + /// The Execute-never or Unprivileged execute-never field. + const UXN = 1 << 54; + + // Next-level attributes in stage 1 VMSAv8-64 Table descriptors: + + /// PXN limit for subsequent levels of lookup. + const PXN_TABLE = 1 << 59; + /// XN limit for subsequent levels of lookup. + const XN_TABLE = 1 << 60; + /// Access permissions limit for subsequent levels of lookup: access at EL0 not permitted. + const AP_NO_EL0_TABLE = 1 << 61; + /// Access permissions limit for subsequent levels of lookup: write access not permitted. + const AP_NO_WRITE_TABLE = 1 << 62; + /// For memory accesses from Secure state, specifies the Security state for subsequent + /// levels of lookup. + const NS_TABLE = 1 << 63; + } +} + +#[inline] +pub fn get_pte_list(paddr: PhysAddr) -> &'static mut [PTE] { + unsafe { core::slice::from_raw_parts_mut(paddr.get_mut_ptr::(), PAGE_ITEM_COUNT) } +} + +#[derive(Debug)] +pub struct PageTable(pub(crate) PhysAddr); + +impl PageTable { + pub fn alloc() -> Arc { + let addr = ArchInterface::frame_alloc_persist().into(); + let page_table = Self(addr); + page_table.restore(); + Arc::new(page_table) + } + + #[inline] + pub fn restore(&self) { + let drop_l3 = |l3: PhysAddr| { + l3.slice_mut_with_len::(0x200) + .iter_mut() + .for_each(|x| *x = PTE(0)); + }; + let drop_l2 = |l2: PhysAddr| { + l2.slice_mut_with_len::(0x200).iter().for_each(|x| { + if x.0 & 0b11 == 0b11 { + drop_l3(x.to_ppn().into()) + } + }) + }; + self.0 + .slice_mut_with_len::(0x200) + .iter() + .for_each(|x| { + if x.0 & 0b11 == 0b11 { + drop_l2(x.to_ppn().into()) + } + }); + flush_tlb(None) + } + + #[inline] + pub fn change(&self) { + debug!("change ttbr0 to :{:#x}", self.0.addr()); + TTBR0_EL1.set((self.0.addr() & 0xFFFF_FFFF_F000) as _); + flush_tlb(None) + } + + pub fn get_mut_entry(&self, vpn: VirtPage) -> &mut PTE { + let l1_list = self.0.slice_mut_with_len::(512); + let l1_index = (vpn.0 >> (9 * 2)) & 0x1ff; + + // l2 pte + let l2_pte = &mut l1_list[l1_index]; + if !l2_pte.is_valid() { + *l2_pte = PTE(ArchInterface::frame_alloc_persist().to_addr() | 0b11); + } + let l2_list = l2_pte.get_next_ptr().slice_mut_with_len::(512); + let l2_index = (vpn.0 >> 9) & 0x1ff; + + // l3 pte + let l3_pte = &mut l2_list[l2_index]; + if !l3_pte.is_valid() { + *l3_pte = PTE(ArchInterface::frame_alloc_persist().to_addr() | 0b11); + } + let l3_list = l3_pte.get_next_ptr().slice_mut_with_len::(512); + let l3_index = vpn.0 & 0x1ff; + &mut l3_list[l3_index] + } + + #[inline] + pub fn map(&self, ppn: PhysPage, vpn: VirtPage, flags: MappingFlags, _level: usize) { + *self.get_mut_entry(vpn) = PTE::from_ppn(ppn.0, flags.into()); + flush_tlb(Some(vpn.into())) + } + + #[inline] + pub fn unmap(&self, vpn: VirtPage) { + *self.get_mut_entry(vpn) = PTE(0); + flush_tlb(Some(vpn.into())); + } + + #[inline] + pub fn virt_to_phys(&self, vaddr: VirtAddr) -> Option { + let mut paddr = self.0; + for i in (0..3).rev() { + let value = (vaddr.0 >> (12 + 9 * i)) & 0x1ff; + let pte = &get_pte_list(paddr)[value]; + // 如果当前页是大页 返回相关的位置 + // vaddr.0 % (1 << (12 + 9 * i)) 是大页内偏移 + if !pte.is_valid() { + return None; + } + paddr = pte.to_ppn().into() + } + Some(PhysAddr(paddr.0 | vaddr.0 % PAGE_SIZE)) + } +} + +impl Drop for PageTable { + fn drop(&mut self) { + for root_pte in get_pte_list(self.0).iter().filter(|x| x.is_leaf()) { + get_pte_list(root_pte.to_ppn().into()) + .iter() + .filter(|x| x.is_leaf()) + .for_each(|x| ArchInterface::frame_unalloc(x.to_ppn())); + ArchInterface::frame_unalloc(root_pte.to_ppn()); + } + ArchInterface::frame_unalloc(self.0.into()); + } +} diff --git a/crates/hal/src/aarch64/pl011.rs b/crates/hal/src/aarch64/pl011.rs new file mode 100644 index 0000000000..7fe0f9eebe --- /dev/null +++ b/crates/hal/src/aarch64/pl011.rs @@ -0,0 +1,32 @@ +//! PL011 UART. + +use arm_pl011::pl011::Pl011Uart; +use irq_safety::MutexIrqSafe; + +use crate::PhysAddr; + +const UART_BASE: PhysAddr = PhysAddr(0x0900_0000); + +static UART: MutexIrqSafe = MutexIrqSafe::new(Pl011Uart::new(UART_BASE.get_mut_ptr())); + +/// Writes a byte to the console. +pub fn console_putchar(c: u8) { + let mut uart = UART.lock(); + match c { + b'\n' => { + uart.putchar(b'\r'); + uart.putchar(b'\n'); + } + c => uart.putchar(c), + } +} + +/// Reads a byte from the console, or returns [`None`] if no input is available. +pub fn console_getchar() -> Option { + UART.lock().getchar() +} + +/// Initialize the UART +pub fn init_early() { + UART.lock().init(); +} diff --git a/crates/hal/src/aarch64/psci.rs b/crates/hal/src/aarch64/psci.rs new file mode 100644 index 0000000000..8bd0b67a1d --- /dev/null +++ b/crates/hal/src/aarch64/psci.rs @@ -0,0 +1,130 @@ +//! ARM Power State Coordination Interface. + +#![allow(dead_code)] + +pub const PSCI_0_2_FN_BASE: u32 = 0x84000000; +pub const PSCI_0_2_64BIT: u32 = 0x40000000; +pub const PSCI_0_2_FN_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + 1; +pub const PSCI_0_2_FN_CPU_OFF: u32 = PSCI_0_2_FN_BASE + 2; +pub const PSCI_0_2_FN_CPU_ON: u32 = PSCI_0_2_FN_BASE + 3; +pub const PSCI_0_2_FN_MIGRATE: u32 = PSCI_0_2_FN_BASE + 5; +pub const PSCI_0_2_FN_SYSTEM_OFF: u32 = PSCI_0_2_FN_BASE + 8; +pub const PSCI_0_2_FN_SYSTEM_RESET: u32 = PSCI_0_2_FN_BASE + 9; +pub const PSCI_0_2_FN64_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 1; +pub const PSCI_0_2_FN64_CPU_ON: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 3; +pub const PSCI_0_2_FN64_MIGRATE: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 5; + +/// PSCI return values, inclusive of all PSCI versions. +#[derive(PartialEq, Debug)] +#[repr(i32)] +pub enum PsciError { + NotSupported = -1, + InvalidParams = -2, + Denied = -3, + AlreadyOn = -4, + OnPending = -5, + InternalFailure = -6, + NotPresent = -7, + Disabled = -8, + InvalidAddress = -9, +} + +impl From for PsciError { + fn from(code: i32) -> PsciError { + use PsciError::*; + match code { + -1 => NotSupported, + -2 => InvalidParams, + -3 => Denied, + -4 => AlreadyOn, + -5 => OnPending, + -6 => InternalFailure, + -7 => NotPresent, + -8 => Disabled, + -9 => InvalidAddress, + _ => panic!("Unknown PSCI error code: {}", code), + } + } +} + +/// arm,psci method: smc +/// when SMCCC_CONDUIT_SMC = 1 +fn arm_smccc_smc(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { + let mut ret; + unsafe { + core::arch::asm!( + "smc #0", + inlateout("x0") func as usize => ret, + in("x1") arg0, + in("x2") arg1, + in("x3") arg2, + ) + } + ret +} + +/// psci "hvc" method call +fn psci_hvc_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize { + let ret; + unsafe { + core::arch::asm!( + "hvc #0", + inlateout("x0") func as usize => ret, + in("x1") arg0, + in("x2") arg1, + in("x3") arg2, + ) + } + ret +} + +fn psci_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> Result<(), PsciError> { + // let ret = match axconfig::PSCI_METHOD { + // "smc" => arm_smccc_smc(func, arg0, arg1, arg2), + // "hvc" => psci_hvc_call(func, arg0, arg1, arg2), + // _ => panic!("Unknown PSCI method: {}", axconfig::PSCI_METHOD), + // }; + let ret = psci_hvc_call(func, arg0, arg1, arg2); + if ret == 0 { + Ok(()) + } else { + Err(PsciError::from(ret as i32)) + } +} + +/// Shutdown the whole system, including all CPUs. +pub fn system_off() -> ! { + info!("Shutting down..."); + psci_call(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0).ok(); + warn!("It should shutdown!"); + loop { + // crate::arch::halt(); + } +} + +/// Power up a core. This call is used to power up cores that either: +/// +/// * Have not yet been booted into the calling supervisory software. +/// * Have been previously powered down with a `cpu_off` call. +/// +/// `target_cpu` contains a copy of the affinity fields of the MPIDR register. +/// `entry_point` is the physical address of the secondary CPU's entry point. +/// `arg` will be passed to the `X0` register of the secondary CPU. +pub fn cpu_on(target_cpu: usize, entry_point: usize, arg: usize) { + info!("Starting CPU {:x} ON ...", target_cpu); + let res = psci_call(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_point, arg); + if let Err(e) = res { + error!("failed to boot CPU {:x} ({:?})", target_cpu, e); + } +} + +/// Power down the calling core. This call is intended for use in hotplug. A +/// core that is powered down by `cpu_off` can only be powered up again in +/// response to a `cpu_on`. +pub fn cpu_off() { + const PSCI_POWER_STATE_TYPE_STANDBY: u32 = 0; + const PSCI_POWER_STATE_TYPE_POWER_DOWN: u32 = 1; + const PSCI_0_2_POWER_STATE_TYPE_SHIFT: u32 = 16; + let state: u32 = PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT; + psci_call(PSCI_0_2_FN_CPU_OFF, state as usize, 0, 0).ok(); +} diff --git a/crates/hal/src/aarch64/timer.rs b/crates/hal/src/aarch64/timer.rs new file mode 100644 index 0000000000..bf67d95ebb --- /dev/null +++ b/crates/hal/src/aarch64/timer.rs @@ -0,0 +1,27 @@ +#![allow(unused_imports)] + +use aarch64_cpu::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0}; +use tock_registers::interfaces::{Readable, Writeable}; + +/// Returns the current clock time in hardware ticks. +#[inline] +pub fn get_time() -> usize { + CNTPCT_EL0.get() as _ +} +#[inline] +pub fn time_to_usec(ts: usize) -> usize { + ts * 1000_000 / CNTFRQ_EL0.get() as usize +} + +pub fn set_next_timer() { + CNTP_TVAL_EL0.set(CNTFRQ_EL0.get() / 1000); +} + +pub fn init() { + let freq = CNTFRQ_EL0.get(); + debug!("freq: {}", freq); + CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET); + CNTP_TVAL_EL0.set(0); + super::gic::set_enable(super::gic::TIMER_IRQ_NUM, true); + set_next_timer(); +} diff --git a/crates/hal/src/aarch64/trap.S b/crates/hal/src/aarch64/trap.S new file mode 100644 index 0000000000..82b66df535 --- /dev/null +++ b/crates/hal/src/aarch64/trap.S @@ -0,0 +1,139 @@ +.macro INVALID_EXCP, kind, source +.p2align 7 + msr daifset, #2 + sub sp, sp, 35 * 8 + stp x0, x1, [sp] + stp x2, x3, [sp, 2 * 8] + stp x4, x5, [sp, 4 * 8] + stp x6, x7, [sp, 6 * 8] + stp x8, x9, [sp, 8 * 8] + stp x10, x11, [sp, 10 * 8] + stp x12, x13, [sp, 12 * 8] + stp x14, x15, [sp, 14 * 8] + stp x16, x17, [sp, 16 * 8] + stp x18, x19, [sp, 18 * 8] + stp x20, x21, [sp, 20 * 8] + stp x22, x23, [sp, 22 * 8] + stp x24, x25, [sp, 24 * 8] + stp x26, x27, [sp, 26 * 8] + stp x28, x29, [sp, 28 * 8] + + mrs x9, sp_el0 + mrs x10, elr_el1 + mrs x11, spsr_el1 + mrs x12, tpidr_el0 + stp x30, x9, [sp, 30 * 8] + stp x10, x11, [sp, 32 * 8] + str x12, [sp, 34 * 8] + + mov x0, sp + mov x1, \kind + mov x2, \source + bl handle_exception + b .Lexception_return +.endm + +.macro USER_TRAP, kind +.p2align 7 + msr daifset, #2 + str x1, [sp, 17 * 8] + ldr x1, [sp, 16 * 8] + + stp x0, x1, [x1] + stp x2, x3, [x1, 2 * 8] + stp x4, x5, [x1, 4 * 8] + stp x6, x7, [x1, 6 * 8] + stp x8, x9, [x1, 8 * 8] + stp x10, x11, [x1, 10 * 8] + stp x12, x13, [x1, 12 * 8] + stp x14, x15, [x1, 14 * 8] + stp x16, x17, [x1, 16 * 8] + stp x18, x19, [x1, 18 * 8] + stp x20, x21, [x1, 20 * 8] + stp x22, x23, [x1, 22 * 8] + stp x24, x25, [x1, 24 * 8] + stp x26, x27, [x1, 26 * 8] + stp x28, x29, [x1, 28 * 8] + + mov x0, \kind + b .Luser_trap_external +.endm + +.section .text +.p2align 12 +.global exception_vector_base +exception_vector_base: + // current EL, with SP_EL0 + INVALID_EXCP 0 0 + INVALID_EXCP 1 0 + INVALID_EXCP 2 0 + INVALID_EXCP 3 0 + + // current EL, with SP_ELx + INVALID_EXCP 0 1 + INVALID_EXCP 1 1 + INVALID_EXCP 2 1 + INVALID_EXCP 3 1 + + // lower EL, aarch64 + USER_TRAP 0 + USER_TRAP 1 + USER_TRAP 2 + USER_TRAP 3 + + // lower EL, aarch32 + INVALID_EXCP 0 3 + INVALID_EXCP 1 3 + INVALID_EXCP 2 3 + INVALID_EXCP 3 3 + +.Luser_trap_external: + mrs x9, sp_el0 + mrs x10, elr_el1 + mrs x11, spsr_el1 + mrs x12, tpidr_el0 + stp x30, x9, [x1, 30 * 8] + stp x10, x11, [x1, 32 * 8] + str x12, [x1, 34 * 8] + + ldr x3, [sp, 17 * 8] + str x3, [x1, 1 * 8] + + ldp x8, x16, [sp] + ldp x17, x18, [sp, 2 * 8] + ldp x19, x20, [sp, 4 * 8] + ldp x21, x22, [sp, 6 * 8] + ldp x23, x24, [sp, 8 * 8] + ldp x25, x26, [sp, 10 * 8] + ldp x27, x28, [sp, 12 * 8] + ldp x29, x30, [sp, 14 * 8] + + add sp, sp, 18 * 8 + ret + +.Lexception_return: + ldr x12, [sp, 34 * 8] + ldp x10, x11, [sp, 32 * 8] + ldp x30, x9, [sp, 30 * 8] + msr sp_el0, x9 + msr elr_el1, x10 + msr spsr_el1, x11 + msr tpidr_el0, x12 + + ldp x28, x29, [sp, 28 * 8] + ldp x26, x27, [sp, 26 * 8] + ldp x24, x25, [sp, 24 * 8] + ldp x22, x23, [sp, 22 * 8] + ldp x20, x21, [sp, 20 * 8] + ldp x18, x19, [sp, 18 * 8] + ldp x16, x17, [sp, 16 * 8] + ldp x14, x15, [sp, 14 * 8] + ldp x12, x13, [sp, 12 * 8] + ldp x10, x11, [sp, 10 * 8] + ldp x8, x9, [sp, 8 * 8] + ldp x6, x7, [sp, 6 * 8] + ldp x4, x5, [sp, 4 * 8] + ldp x2, x3, [sp, 2 * 8] + ldp x0, x1, [sp] + add sp, sp, 35 * 8 + eret diff --git a/crates/hal/src/aarch64/trap.rs b/crates/hal/src/aarch64/trap.rs new file mode 100644 index 0000000000..229e90c5a3 --- /dev/null +++ b/crates/hal/src/aarch64/trap.rs @@ -0,0 +1,174 @@ +use core::arch::{asm, global_asm}; + +use aarch64_cpu::registers::{Writeable, ESR_EL1, FAR_EL1, VBAR_EL1}; +use tock_registers::interfaces::Readable; + +use crate::{ + aarch64::{gic::handle_irq, timer::set_next_timer}, + ArchInterface, TrapType, +}; + +use super::Context; + +global_asm!(include_str!("trap.S")); + +#[repr(u8)] +#[derive(Debug, PartialEq)] +#[allow(dead_code)] +enum TrapKind { + Synchronous = 0, + Irq = 1, + Fiq = 2, + SError = 3, +} + +#[repr(u8)] +#[derive(Debug)] +#[allow(dead_code)] +enum TrapSource { + CurrentSpEl0 = 0, + CurrentSpElx = 1, + LowerAArch64 = 2, + LowerAArch32 = 3, +} + +#[no_mangle] +fn handle_exception(tf: &mut Context, kind: TrapKind, source: TrapSource) -> TrapType { + if kind == TrapKind::Irq { + set_next_timer(); + handle_irq(|_irq| {}); + return TrapType::Time; + } + if kind != TrapKind::Synchronous { + panic!( + "Invalid exception {:?} from {:?}:\n{:#x?}", + kind, source, tf + ); + } + let esr = ESR_EL1.extract(); + let trap_type = match esr.read_as_enum(ESR_EL1::EC) { + Some(ESR_EL1::EC::Value::Brk64) => { + let iss = esr.read(ESR_EL1::ISS); + debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr); + tf.elr += 4; + TrapType::Breakpoint + } + Some(ESR_EL1::EC::Value::SVC64) => TrapType::UserEnvCall, + Some(ESR_EL1::EC::Value::DataAbortLowerEL) + | Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => { + let iss = esr.read(ESR_EL1::ISS); + warn!( + "EL0 Page Fault @ {:#x}, FAR={:#x}, ISS={:#x}", + tf.elr, + FAR_EL1.get(), + iss + ); + TrapType::InstructionPageFault(FAR_EL1.get() as _) + } + Some(ESR_EL1::EC::Value::DataAbortCurrentEL) + | Some(ESR_EL1::EC::Value::InstrAbortCurrentEL) => { + let iss = esr.read(ESR_EL1::ISS); + warn!( + "EL1 Page Fault @ {:#x}, FAR={:#x}, ISS={:#x}:\n{:#x?}", + tf.elr, + FAR_EL1.get(), + iss, + tf, + ); + TrapType::InstructionPageFault(FAR_EL1.get() as _) + } + _ => { + panic!( + "Unhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})", + tf.elr, + esr.get(), + esr.read(ESR_EL1::EC), + esr.read(ESR_EL1::ISS), + ); + } + }; + ArchInterface::kernel_interrupt(tf, trap_type); + trap_type +} + +pub fn init() { + extern "C" { + fn exception_vector_base(); + } + VBAR_EL1.set(exception_vector_base as _); +} + +// 设置中断 +pub fn init_interrupt() { + // unsafe { + // asm!("brk #0"); + // } + // enable_irq(); +} + +#[naked] +extern "C" fn user_restore(context: *mut Context) -> TrapKind { + unsafe { + asm!( + r" + sub sp, sp, 18 * 8 + stp x8, x16, [sp] + stp x17, x18, [sp, 2 * 8] + stp x19, x20, [sp, 4 * 8] + stp x21, x22, [sp, 6 * 8] + stp x23, x24, [sp, 8 * 8] + stp x25, x26, [sp, 10 * 8] + stp x27, x28, [sp, 12 * 8] + stp x29, x30, [sp, 14 * 8] + str x0, [sp, 16 * 8] + + ldr x12, [x0, 34 * 8] + ldp x10, x11, [x0, 32 * 8] + ldp x30, x9, [x0, 30 * 8] + msr sp_el0, x9 + msr elr_el1, x10 + msr spsr_el1, x11 + msr tpidr_el0, x12 + + ldp x28, x29, [x0, 28 * 8] + ldp x26, x27, [x0, 26 * 8] + ldp x24, x25, [x0, 24 * 8] + ldp x22, x23, [x0, 22 * 8] + ldp x20, x21, [x0, 20 * 8] + ldp x18, x19, [x0, 18 * 8] + ldp x16, x17, [x0, 16 * 8] + ldp x14, x15, [x0, 14 * 8] + ldp x12, x13, [x0, 12 * 8] + ldp x10, x11, [x0, 10 * 8] + ldp x8, x9, [x0, 8 * 8] + ldp x6, x7, [x0, 6 * 8] + ldp x4, x5, [x0, 4 * 8] + ldp x2, x3, [x0, 2 * 8] + ldp x0, x1, [x0] + eret + ", + options(noreturn) + ) + } +} + +pub fn run_user_task(cx: &mut Context) -> Option<()> { + let trap_kind = user_restore(cx); + match handle_exception(cx, trap_kind, TrapSource::LowerAArch64) { + TrapType::UserEnvCall => Some(()), + _ => None, + } +} + +#[allow(dead_code)] +#[inline(always)] +pub fn enable_irq() { + unsafe { asm!("msr daifclr, #2") }; +} + +#[inline(always)] +pub fn enable_external_irq() { + // unsafe { + // sie::set_sext(); + // } +} diff --git a/crates/hal/src/addr.rs b/crates/hal/src/addr.rs new file mode 100644 index 0000000000..9492de2ef9 --- /dev/null +++ b/crates/hal/src/addr.rs @@ -0,0 +1,175 @@ +use core::{ + fmt::{Debug, Display}, + mem::size_of, + ops::Add, +}; + +use memory_addr::{PhysAddr, VirtAddr, PAGE_SIZE_4K}; + +use crate::VIRT_ADDR_START; + +impl From for PhysAddr { + fn from(value: PhysPage) -> Self { + // Self(value.0 << 12) + PhysAddr::from(value.0 << 12) + } +} + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct PhysPage(pub(crate) usize); + +impl From for PhysPage { + fn from(value: usize) -> Self { + Self(value) + } +} + +impl From for PhysPage { + fn from(value: PhysAddr) -> Self { + Self(value.as_usize() >> 12) + } +} + +impl From for usize { + fn from(value: PhysPage) -> Self { + value.0 + } +} + +impl Add for PhysPage { + type Output = PhysPage; + + fn add(self, rhs: PhysPage) -> Self::Output { + PhysPage(self.0 + rhs.0) + } +} + +impl Add for PhysPage { + type Output = PhysPage; + + fn add(self, rhs: usize) -> Self::Output { + PhysPage(self.0 + rhs) + } +} + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct VirtPage(pub(crate) usize); +impl From for VirtPage { + fn from(value: VirtAddr) -> Self { + Self(value.as_usize() >> 12) + } +} +impl From for VirtPage { + fn from(value: usize) -> Self { + Self(value) + } +} + +impl PhysPage { + #[inline] + pub const fn new(ppn: usize) -> Self { + Self(ppn) + } + + #[inline] + pub const fn from_addr(addr: usize) -> Self { + Self(addr >> 12) + } + + #[inline] + pub const fn to_addr(&self) -> usize { + self.0 << 12 + } + + #[inline] + pub const fn get_buffer(&self) -> &'static mut [u8] { + unsafe { + core::slice::from_raw_parts_mut( + (self.0 << 12 | VIRT_ADDR_START) as *mut u8, + PAGE_SIZE_4K, + ) + } + } + + #[inline] + pub fn copy_value_from_another(&self, ppn: PhysPage) { + self.get_buffer().copy_from_slice(&ppn.get_buffer()); + #[cfg(c906)] + unsafe { + asm!(".long 0x0010000b"); // dcache.all + asm!(".long 0x01b0000b"); // sync.is + } + } + + #[inline] + pub fn drop_clear(&self) { + // self.get_buffer().fill(0); + unsafe { + core::slice::from_raw_parts_mut( + (self.0 << 12 | VIRT_ADDR_START) as *mut usize, + PAGE_SIZE_4K / size_of::(), + ) + .fill(0); + } + #[cfg(c906)] + unsafe { + asm!(".long 0x0010000b"); // dcache.all + asm!(".long 0x01b0000b"); // sync.is + } + } +} + +impl Add for VirtPage { + type Output = VirtPage; + + fn add(self, rhs: usize) -> Self::Output { + VirtPage(self.0 + rhs) + } +} + +impl From for VirtAddr { + fn from(value: VirtPage) -> Self { + // Self(value.to_addr()) + VirtAddr::from(value.to_addr()) + } +} + +impl VirtPage { + #[inline] + pub const fn new(vpn: usize) -> Self { + Self(vpn) + } + + #[inline] + pub const fn from_addr(addr: usize) -> Self { + Self(addr >> 12) + } + #[inline] + pub const fn to_addr(&self) -> usize { + self.0 << 12 + } +} + +impl Display for PhysPage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("{:#x}", self.0)) + } +} + +impl Display for VirtPage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("{:#x}", self.0)) + } +} + +impl Debug for PhysPage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("{:#x}", self.0)) + } +} + +impl Debug for VirtPage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("{:#x}", self.0)) + } +} diff --git a/crates/hal/src/api.rs b/crates/hal/src/api.rs new file mode 100644 index 0000000000..becf368ca9 --- /dev/null +++ b/crates/hal/src/api.rs @@ -0,0 +1,83 @@ +use crate_interface::call_interface; + +#[allow(unused_imports)] +use fdt::node::FdtNode; + +use crate::{TrapFrame, TrapType}; + +#[crate_interface::def_interface] +pub trait ArchInterface { + /// kernel interrupt + fn kernel_interrupt(ctx: &mut TrapFrame, from_user: bool, trap_type: TrapType); + /// init log + fn init_logging(); + /// add a memory region from start to end + fn add_memory_region(start: usize, end: usize); + /// init the allocator + fn init_allocator(); + /// kernel main function, entry point. + fn main(hartid: usize); + // /// Alloc a persistent memory page. + // fn frame_alloc_persist() -> PhysPage { + // unimplemented!() + // } + // /// Unalloc a persistent memory page + // fn frame_unalloc(_ppn: PhysPage) { + // unimplemented!() + // } + /// Preprare drivers. + fn prepare_drivers(); + /// Try to add device through FdtNode + fn try_to_add_device(fdt_node: &FdtNode); +} + +/// Kernel main function, entry point. +pub(crate) fn kernel_main(hartid: usize) { + call_interface!(ArchInterface::main, hartid); +} + +/// Kernel interrupt handler. +pub fn kernel_interrupt(ctx: &mut TrapFrame, from_user: bool, trap_type: TrapType) { + call_interface!(ArchInterface::kernel_interrupt, ctx, from_user, trap_type); +} + +/// Init logging. +pub fn init_logging() { + call_interface!(ArchInterface::init_logging); +} + +#[allow(dead_code)] +/// Add a memory region. +pub(crate) fn add_memory_region(start: usize, end: usize) { + call_interface!(ArchInterface::add_memory_region, start, end); +} + +#[allow(dead_code)] +/// Init the allocator. +pub(crate) fn init_allocator() { + call_interface!(ArchInterface::init_allocator); +} + +// #[allow(dead_code)] +// /// Alloc a persistent memory page. +// pub(crate) fn frame_alloc_persist() -> PhysPage { +// call_interface!(ArchInterface::frame_alloc_persist) +// } + +// #[allow(dead_code)] +// /// Unalloc a persistent memory page. +// pub(crate) fn frame_unalloc(ppn: PhysPage) { +// call_interface!(ArchInterface::frame_unalloc, ppn); +// } + +#[allow(dead_code)] +/// Prepare drivers. +pub(crate) fn prepare_drivers() { + call_interface!(ArchInterface::prepare_drivers); +} + +#[allow(dead_code)] +/// Try to add device through FdtNode. +pub(crate) fn try_to_add_device(fdt_node: &FdtNode) { + call_interface!(ArchInterface::try_to_add_device, fdt_node); +} diff --git a/crates/hal/src/lib.rs b/crates/hal/src/lib.rs new file mode 100644 index 0000000000..5ff43ada7a --- /dev/null +++ b/crates/hal/src/lib.rs @@ -0,0 +1,153 @@ +#![no_std] +#![no_main] +#![feature(naked_functions)] +#![feature(asm_const)] +#![feature(stdsimd)] +#![feature(const_mut_refs)] +#![feature(const_slice_from_raw_parts_mut)] +#![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] +#![cfg_attr(target_arch = "aarch64", feature(const_option))] + +extern crate alloc; + +#[macro_use] +extern crate log; + +// mod addr; +mod api; +pub use fdt::node::FdtNode; + +#[cfg(target_arch = "riscv64")] +mod riscv64; + +use core::mem::size_of; + +use alloc::vec::Vec; +#[cfg(target_arch = "riscv64")] +pub use riscv64::*; + +#[cfg(target_arch = "x86_64")] +mod x86_64; + +#[cfg(target_arch = "x86_64")] +pub use x86_64::*; + +// #[cfg(target_arch = "aarch64")] +// mod aarch64; + +// #[cfg(target_arch = "aarch64")] +// pub use aarch64::*; + +// #[cfg(target_arch = "loongarch64")] +// mod loongarch64; + +// #[cfg(target_arch = "loongarch64")] +// pub use loongarch64::*; + +// pub use addr::*; +pub use api::*; + +// pub trait ContextOps { +// fn set_sp(&mut self, sp: usize); +// fn sp(&self) -> usize; +// fn set_ra(&mut self, ra: usize); +// fn ra(&self) -> usize; +// fn set_sepc(&mut self, sepc: usize); +// fn sepc(&self) -> usize; + +// fn args(&self) -> [usize; 6]; +// fn set_arg0(&mut self, ret: usize); +// fn set_arg1(&mut self, ret: usize); +// fn set_arg2(&mut self, ret: usize); + +// fn syscall_number(&self) -> usize; +// fn syscall_ok(&mut self); + +// fn set_ret(&mut self, ret: usize); +// fn set_tls(&mut self, tls: usize); +// } + +#[derive(Debug)] +pub enum ContextArgs { + SEPC, + RA, + SP, + RET, + ARG0, + ARG1, + ARG2, + TLS, + SYSCALL, +} + +#[derive(Debug, Clone, Copy)] +pub enum TrapType { + Breakpoint, + UserEnvCall, + Time(usize), + Unknown, + SupervisorExternal, + StorePageFault(usize), + LoadPageFault(usize), + InstructionPageFault(usize), + IllegalInstruction(usize), +} + +pub enum MapPageSize { + Page4k, + Page2m, + Page1G, +} + +const STACK_SIZE: usize = 0x80000; + +#[link_section = ".bss.stack"] +static mut BOOT_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; + +static mut INT_RECORDS: Vec = Vec::new(); + +pub fn add_irq(irq: usize) { + unsafe { + while INT_RECORDS.len() < 256 { + INT_RECORDS.push(0); + } + INT_RECORDS[irq] += 1; + } +} + +pub fn get_int_records() -> Vec { + unsafe { INT_RECORDS.clone() } +} + +pub fn clear_bss() { + extern "C" { + fn _sbss(); + fn _ebss(); + } + unsafe { + core::slice::from_raw_parts_mut( + _sbss as usize as *mut u128, + (_ebss as usize - _sbss as usize) / size_of::(), + ) + .fill(0); + } +} + +bitflags::bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct MappingFlags: u64 { + const None = 0; + const U = 1 << 0; + const R = 1 << 1; + const W = 1 << 2; + const X = 1 << 3; + const A = 1 << 4; + const D = 1 << 5; + const Device = 1 << 6; + const Cache = 1 << 7; + + const URW = Self::U.bits() | Self::R.bits() | Self::W.bits(); + const URX = Self::U.bits() | Self::R.bits() | Self::X.bits(); + const URWX = Self::URW.bits() | Self::X.bits(); + } +} diff --git a/crates/hal/src/loongarch64/boot.rs b/crates/hal/src/loongarch64/boot.rs new file mode 100644 index 0000000000..706b188c01 --- /dev/null +++ b/crates/hal/src/loongarch64/boot.rs @@ -0,0 +1,37 @@ +/// 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.entry"] +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 + + # 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 + + + 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 crate::STACK_SIZE, + boot_stack = sym crate::BOOT_STACK, + entry = sym super::rust_tmp_main, + options(noreturn), + ) +} diff --git a/crates/hal/src/loongarch64/console.rs b/crates/hal/src/loongarch64/console.rs new file mode 100644 index 0000000000..0b512a056d --- /dev/null +++ b/crates/hal/src/loongarch64/console.rs @@ -0,0 +1,69 @@ +use core::fmt::Write; + +use spin::Mutex; + +use crate::VIRT_ADDR_START; + +const UART_ADDR: usize = 0x01FE001E0 | VIRT_ADDR_START; + +static COM1: Mutex = Mutex::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 ptr = self.base_address as *mut u8; + loop { + unsafe { + let c = ptr.add(5).read_volatile(); + if c & (1 << 5) != 0 { + break; + } + } + } + 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 console_putchar(c: u8) { + COM1.lock().putchar(c) +} + +pub fn write_fmt(args: core::fmt::Arguments) { + COM1.lock().write_fmt(args).unwrap(); +} + +/// read a byte, return -1 if nothing exists. +pub fn console_getchar() -> Option { + COM1.lock().getchar() +} diff --git a/crates/hal/src/loongarch64/consts.rs b/crates/hal/src/loongarch64/consts.rs new file mode 100644 index 0000000000..24e178e471 --- /dev/null +++ b/crates/hal/src/loongarch64/consts.rs @@ -0,0 +1,5 @@ +pub const VIRT_ADDR_START: usize = 0x9000_0000_0000_0000; +pub const USER_ADDR_MAX: usize = 0x0000_ffff_ffff_ffff; +pub const PAGE_SIZE: usize = 4096; +pub const PAGE_ITEM_COUNT: usize = 512; +pub const SIG_RETURN_ADDR: usize = 0x9000_1000_0000_0000; diff --git a/crates/hal/src/loongarch64/context.rs b/crates/hal/src/loongarch64/context.rs new file mode 100644 index 0000000000..78baf84641 --- /dev/null +++ b/crates/hal/src/loongarch64/context.rs @@ -0,0 +1,71 @@ +use core::ops::{Index, IndexMut}; + +use crate::ContextArgs; + +/// Saved registers when a trap (interrupt or exception) occurs. +#[allow(missing_docs)] +#[repr(C)] +#[derive(Debug, Default, Clone, Copy)] +pub struct Context { + /// General Registers + pub regs: [usize; 32], + /// Pre-exception Mode information + pub prmd: usize, + /// Exception Return Address + pub era: usize, +} + +impl Context { + // 创建上下文信息 + #[inline] + pub fn new() -> Self { + Self { + ..Default::default() + } + } +} + +impl Context { + pub fn syscall_ok(&self) { + todo!("syscall ok"); + } + + #[inline] + pub fn args(&self) -> [usize; 6] { + todo!("get args"); + } +} + +impl Index for Context { + type Output = usize; + + fn index(&self, index: ContextArgs) -> &Self::Output { + match index { + ContextArgs::SEPC => &self.era, + ContextArgs::RA => &self.regs[1], + ContextArgs::SP => &self.regs[3], + ContextArgs::RET => &self.regs[4], + ContextArgs::ARG0 => &self.regs[4], + ContextArgs::ARG1 => &self.regs[5], + ContextArgs::ARG2 => &self.regs[6], + ContextArgs::TLS => &self.regs[2], + ContextArgs::SYSCALL => &self.regs[7], + } + } +} + +impl IndexMut for Context { + fn index_mut(&mut self, index: ContextArgs) -> &mut Self::Output { + match index { + ContextArgs::SEPC => &mut self.era, + ContextArgs::RA => &mut self.regs[1], + ContextArgs::SP => &mut self.regs[3], + ContextArgs::RET => &mut self.regs[4], + ContextArgs::ARG0 => &mut self.regs[4], + ContextArgs::ARG1 => &mut self.regs[5], + ContextArgs::ARG2 => &mut self.regs[6], + ContextArgs::TLS => &mut self.regs[2], + ContextArgs::SYSCALL => &mut self.regs[7], + } + } +} diff --git a/crates/hal/src/loongarch64/mod.rs b/crates/hal/src/loongarch64/mod.rs new file mode 100644 index 0000000000..47378f35d1 --- /dev/null +++ b/crates/hal/src/loongarch64/mod.rs @@ -0,0 +1,50 @@ +mod boot; +mod console; +mod consts; +mod context; +mod page_table; +mod timer; +mod trap; + +pub use console::{console_getchar, console_putchar}; +pub use consts::*; +pub use context::Context; +pub use page_table::*; +pub use timer::get_time; +pub use trap::{enable_external_irq, enable_irq, init_interrupt, run_user_task}; + +use crate::{clear_bss, ArchInterface}; + +pub fn rust_tmp_main(hart_id: usize) { + clear_bss(); + ArchInterface::init_logging(); + allocator::init(); + trap::set_trap_vector_base(); + + ArchInterface::add_memory_region( + VIRT_ADDR_START | 0x9000_0000, + VIRT_ADDR_START | (0x9000_0000 + 0x2000_0000), + ); + info!("hart_id: {}", hart_id); + unsafe { + core::arch::asm!("break 2"); + } + ArchInterface::prepare_drivers(); + + shutdown(); +} + +pub fn time_to_usec(_t: usize) -> usize { + todo!("time to usec") +} + +pub fn switch_to_kernel_page_table() { + todo!("switch to kernel page table") +} + +pub fn shutdown() -> ! { + error!("shutdown!"); + loop { + unsafe { loongarch64::asm::idle() }; + } +} diff --git a/crates/hal/src/loongarch64/page_table.rs b/crates/hal/src/loongarch64/page_table.rs new file mode 100644 index 0000000000..380c2e6d2d --- /dev/null +++ b/crates/hal/src/loongarch64/page_table.rs @@ -0,0 +1,212 @@ +use alloc::sync::Arc; + +use crate::{ + ArchInterface, MappingFlags, PhysAddr, PhysPage, VirtAddr, VirtPage, PAGE_ITEM_COUNT, PAGE_SIZE, +}; + +#[derive(Copy, Clone, Debug)] +pub struct PTE(usize); + +impl PTE { + #[inline] + pub const fn new() -> Self { + Self(0) + } + + #[inline] + pub const fn from_ppn(ppn: usize, flags: PTEFlags) -> Self { + PTE((ppn << 12) | flags.bits()) + } + + #[inline] + pub const fn from_addr(addr: usize, flags: PTEFlags) -> Self { + Self::from_ppn(addr >> 12, flags) + } + + #[inline] + pub const fn to_ppn(&self) -> PhysPage { + PhysPage((self.0 & 0xffff_ffff_ffff_f000) >> 12) + } + + #[inline] + pub fn set(&mut self, ppn: usize, flags: PTEFlags) { + self.0 = (ppn << 10) | flags.bits() as usize; + } + + #[inline] + pub const fn flags(&self) -> PTEFlags { + PTEFlags::from_bits_truncate(self.0) + } + + #[inline] + pub const fn is_valid(&self) -> bool { + self.flags().contains(PTEFlags::VALID) + } + + #[inline] + pub fn is_block(&self) -> bool { + self.flags().contains(PTEFlags::NON_BLOCK) + } + + #[inline] + pub fn get_next_ptr(&self) -> PhysAddr { + PhysAddr(self.0 & 0xffff_ffff_f000) + } +} + +impl From for PTEFlags { + fn from(value: MappingFlags) -> Self { + let mut flags = PTEFlags::VALID | PTEFlags::NON_BLOCK | PTEFlags::AF | PTEFlags::NG; + if !value.contains(MappingFlags::W) { + flags |= PTEFlags::AP_RO; + } + + if !value.contains(MappingFlags::X) { + flags |= PTEFlags::UXN | PTEFlags::PXN; + } + + if value.contains(MappingFlags::U) { + flags |= PTEFlags::AP_EL0; + } + flags + } +} + +bitflags::bitflags! { + /// Possible flags for a page table entry. + pub struct PTEFlags: usize { + // Attribute fields in stage 1 VMSAv8-64 Block and Page descriptors: + /// Whether the descriptor is valid. + const VALID = 1 << 0; + /// The descriptor gives the address of the next level of translation table or 4KB page. + /// (not a 2M, 1G block) + const NON_BLOCK = 1 << 1; + /// Memory attributes index field. + const ATTR_INDX = 0b111 << 2; + const NORMAL_NONCACHE = 0b010 << 2; + /// Non-secure bit. For memory accesses from Secure state, specifies whether the output + /// address is in Secure or Non-secure memory. + const NS = 1 << 5; + /// Access permission: accessable at EL0. + const AP_EL0 = 1 << 6; + /// Access permission: read-only. + const AP_RO = 1 << 7; + /// Shareability: Inner Shareable (otherwise Outer Shareable). + const INNER = 1 << 8; + /// Shareability: Inner or Outer Shareable (otherwise Non-shareable). + const SHAREABLE = 1 << 9; + /// The Access flag. + const AF = 1 << 10; + /// The not global bit. + const NG = 1 << 11; + /// Indicates that 16 adjacent translation table entries point to contiguous memory regions. + const CONTIGUOUS = 1 << 52; + /// The Privileged execute-never field. + const PXN = 1 << 53; + /// The Execute-never or Unprivileged execute-never field. + const UXN = 1 << 54; + + // Next-level attributes in stage 1 VMSAv8-64 Table descriptors: + + /// PXN limit for subsequent levels of lookup. + const PXN_TABLE = 1 << 59; + /// XN limit for subsequent levels of lookup. + const XN_TABLE = 1 << 60; + /// Access permissions limit for subsequent levels of lookup: access at EL0 not permitted. + const AP_NO_EL0_TABLE = 1 << 61; + /// Access permissions limit for subsequent levels of lookup: write access not permitted. + const AP_NO_WRITE_TABLE = 1 << 62; + /// For memory accesses from Secure state, specifies the Security state for subsequent + /// levels of lookup. + const NS_TABLE = 1 << 63; + } +} + +#[inline] +pub fn get_pte_list(paddr: PhysAddr) -> &'static mut [PTE] { + unsafe { core::slice::from_raw_parts_mut(paddr.get_mut_ptr::(), PAGE_ITEM_COUNT) } +} + +#[derive(Debug)] +pub struct PageTable(pub(crate) PhysAddr); + +impl PageTable { + pub fn alloc() -> Arc { + let addr = ArchInterface::frame_alloc_persist().into(); + let page_table = Self(addr); + page_table.restore(); + Arc::new(page_table) + } + + #[inline] + pub fn restore(&self) { + warn!("doing nothing") + } + + #[inline] + pub fn change(&self) { + todo!("change pagetable") + } + + #[inline] + pub fn map(&self, ppn: PhysPage, vpn: VirtPage, flags: MappingFlags, _level: usize) { + let l1_list = self.0.slice_mut_with_len::(512); + let l1_index = (vpn.0 >> (9 * 2)) & 0x1ff; + + // l2 pte + let l2_pte = &mut l1_list[l1_index]; + if !l2_pte.is_valid() { + *l2_pte = PTE(ArchInterface::frame_alloc_persist().to_addr() | 0b11); + } + let l2_list = l2_pte.get_next_ptr().slice_mut_with_len::(512); + let l2_index = (vpn.0 >> 9) & 0x1ff; + + // l3 pte + let l3_pte = &mut l2_list[l2_index]; + if !l3_pte.is_valid() { + *l3_pte = PTE(ArchInterface::frame_alloc_persist().to_addr() | 0b11); + } + let l3_list = l3_pte.get_next_ptr().slice_mut_with_len::(512); + let l3_index = vpn.0 & 0x1ff; + l3_list[l3_index] = PTE::from_ppn(ppn.0, flags.into()); + } + + #[inline] + pub fn unmap(&self, _vpn: VirtPage) { + todo!("unmap pages"); + } + + #[inline] + pub fn virt_to_phys(&self, vaddr: VirtAddr) -> Option { + let mut paddr = self.0; + for i in (0..3).rev() { + let value = (vaddr.0 >> (12 + 9 * i)) & 0x1ff; + let pte = &get_pte_list(paddr)[value]; + // 如果当前页是大页 返回相关的位置 + // vaddr.0 % (1 << (12 + 9 * i)) 是大页内偏移 + if !pte.is_valid() { + return None; + } + paddr = pte.to_ppn().into() + } + Some(PhysAddr(paddr.0 | vaddr.0 % PAGE_SIZE)) + } +} + +// impl Drop for PageTable { +// fn drop(&mut self) { +// for root_pte in get_pte_list(self.0)[..0x100].iter().filter(|x| x.is_leaf()) { +// get_pte_list(root_pte.to_ppn().into()) +// .iter() +// .filter(|x| x.is_leaf()) +// .for_each(|x| ArchInterface::frame_unalloc(x.to_ppn())); +// ArchInterface::frame_unalloc(root_pte.to_ppn()); +// } +// ArchInterface::frame_unalloc(self.0.into()); +// } +// } + +#[inline] +pub fn flush_tlb(_vaddr: Option) { + todo!("flush_tlb") +} diff --git a/crates/hal/src/loongarch64/timer.rs b/crates/hal/src/loongarch64/timer.rs new file mode 100644 index 0000000000..e50c957265 --- /dev/null +++ b/crates/hal/src/loongarch64/timer.rs @@ -0,0 +1,5 @@ +/// Returns the current clock time in hardware ticks. +#[inline] +pub fn get_time() -> usize { + todo!("get_time") +} diff --git a/crates/hal/src/loongarch64/trap.rs b/crates/hal/src/loongarch64/trap.rs new file mode 100644 index 0000000000..e336d76b07 --- /dev/null +++ b/crates/hal/src/loongarch64/trap.rs @@ -0,0 +1,200 @@ +use core::arch::asm; + +use loongarch64::register::{ + ecfg, eentry, + estat::{self, Exception, Trap}, +}; + +use super::Context; + +pub fn init() { + todo!("init interrupt") +} + +// 设置中断 +pub fn init_interrupt() { + todo!("test brk"); + enable_irq(); +} + +#[naked] +#[no_mangle] +pub extern "C" fn user_restore(context: *mut Context) { + unsafe { + asm!( + r" + + ", + options(noreturn) + ) + } +} + +#[allow(dead_code)] +#[inline(always)] +pub fn enable_irq() { + todo!("enable_irq") +} + +#[inline(always)] +pub fn enable_external_irq() { + // unsafe { + // sie::set_sext(); + // } +} + +pub fn run_user_task(cx: &mut Context) -> Option<()> { + todo!("run_user_task"); +} + +#[naked] +pub unsafe extern "C" fn trap_vector_base() { + core::arch::asm!( + " + .balign 4096 + .equ KSAVE_KSP, 0x30 + .equ KSAVE_T0, 0x31 + .equ KSAVE_USP, 0x32 + // csrwr $t0, KSAVE_T0 + // csrrd $t0, 0x1 + // andi $t0, $t0, 0x3 + // bnez $t0, .Lfrom_userspace + + move $t0, $sp + addi.d $sp, $sp, -{trapframe_size} // allocate space + // save kernel sp + st.d $t0, $sp, 3*8 + + // save the registers. + st.d $ra, $sp, 8 + csrrd $t0, KSAVE_T0 + st.d $t0, $sp, 12*8 + + st.d $a0, $sp, 4*8 + st.d $a1, $sp, 5*8 + st.d $a2, $sp, 6*8 + st.d $a3, $sp, 7*8 + st.d $a4, $sp, 8*8 + st.d $a5, $sp, 9*8 + st.d $a6, $sp, 10*8 + st.d $a7, $sp, 11*8 + st.d $t1, $sp, 13*8 + st.d $t2, $sp, 14*8 + st.d $t3, $sp, 15*8 + st.d $t4, $sp, 16*8 + st.d $t5, $sp, 17*8 + st.d $t6, $sp, 18*8 + st.d $t7, $sp, 19*8 + st.d $t8, $sp, 20*8 + + st.d $fp, $sp, 22*8 + st.d $s0, $sp, 23*8 + st.d $s1, $sp, 24*8 + st.d $s2, $sp, 25*8 + st.d $s3, $sp, 26*8 + st.d $s4, $sp, 27*8 + st.d $s5, $sp, 28*8 + st.d $s6, $sp, 29*8 + st.d $s7, $sp, 30*8 + st.d $s8, $sp, 31*8 + + csrrd $t2, 0x1 + st.d $t2, $sp, 8*32 // prmd + csrrd $t1, 0x6 + st.d $t1, $sp, 8*33 // era + csrrd $t1, 0x7 + st.d $t1, $sp, 8*34 // badv + csrrd $t1, 0x0 + st.d $t1, $sp, 8*35 // crmd + + move $a0, $sp + csrrd $t0, 0x1 + andi $a1, $t0, 0x3 // if user or kernel + bl {trap_handler} + + // restore the registers. + ld.d $t1, $sp, 8*33 // era + csrwr $t1, 0x6 + ld.d $t2, $sp, 8*32 // prmd + csrwr $t2, 0x1 + + // Save kernel sp when exit kernel mode + addi.d $t1, $sp, {trapframe_size} + csrwr $t1, KSAVE_KSP + + ld.d $ra, $sp, 1*8 + ld.d $a0, $sp, 4*8 + ld.d $a1, $sp, 5*8 + ld.d $a2, $sp, 6*8 + ld.d $a3, $sp, 7*8 + ld.d $a4, $sp, 8*8 + ld.d $a5, $sp, 9*8 + ld.d $a6, $sp, 10*8 + ld.d $a7, $sp, 11*8 + ld.d $t0, $sp, 12*8 + ld.d $t1, $sp, 13*8 + ld.d $t2, $sp, 14*8 + ld.d $t3, $sp, 15*8 + ld.d $t4, $sp, 16*8 + ld.d $t5, $sp, 17*8 + ld.d $t6, $sp, 18*8 + ld.d $t7, $sp, 19*8 + ld.d $t8, $sp, 20*8 + + ld.d $fp, $sp, 22*8 + ld.d $s0, $sp, 23*8 + ld.d $s1, $sp, 24*8 + ld.d $s2, $sp, 25*8 + ld.d $s3, $sp, 26*8 + ld.d $s4, $sp, 27*8 + ld.d $s5, $sp, 28*8 + ld.d $s6, $sp, 29*8 + ld.d $s7, $sp, 30*8 + ld.d $s8, $sp, 31*8 + + // restore sp + ld.d $sp, $sp, 3*8 + ertn + ", + trapframe_size = const crate::CONTEXT_SIZE, + trap_handler = sym loongarch64_trap_handler, + options(noreturn) + ); +} + +#[inline] +pub fn set_trap_vector_base() { + ecfg::set_vs(0); + eentry::set_eentry(trap_vector_base as usize); +} + +fn handle_unaligned(tf: &mut Context) { + // unsafe { emulate_load_store_insn(tf) } + error!("address not aligned: {:#x?}", tf); +} + +fn handle_breakpoint(era: &mut usize) { + debug!("Exception(Breakpoint) @ {:#x} ", era); + *era += 4; +} + +fn loongarch64_trap_handler(tf: &mut Context) { + let estat = estat::read(); + + match estat.cause() { + Trap::Exception(Exception::Breakpoint) => handle_breakpoint(&mut tf.era), + Trap::Exception(Exception::AddressNotAligned) => handle_unaligned(tf), + Trap::Interrupt(_) => { + let irq_num: usize = estat.is().trailing_zeros() as usize; + info!("irq: {}", irq_num); + } + _ => { + panic!( + "Unhandled trap {:?} @ {:#x}:\n{:#x?}", + estat.cause(), + tf.era, + tf + ); + } + } +} diff --git a/crates/hal/src/riscv64/boards/cv1811h-fdt.dtb b/crates/hal/src/riscv64/boards/cv1811h-fdt.dtb new file mode 100644 index 0000000000..6b1439c131 Binary files /dev/null and b/crates/hal/src/riscv64/boards/cv1811h-fdt.dtb differ diff --git a/crates/hal/src/riscv64/boards/cv1811h-fdt.dts b/crates/hal/src/riscv64/boards/cv1811h-fdt.dts new file mode 100644 index 0000000000..6b76236302 --- /dev/null +++ b/crates/hal/src/riscv64/boards/cv1811h-fdt.dts @@ -0,0 +1,845 @@ +/dts-v1/; +// magic: 0xd00dfeed +// totalsize: 0x5000 (20480) +// off_dt_struct: 0x48 +// off_dt_strings: 0x4444 +// off_mem_rsvmap: 0x28 +// version: 17 +// last_comp_version: 16 +// boot_cpuid_phys: 0x0 +// size_dt_strings: 0x652 +// size_dt_struct: 0x43fc + +/memreserve/ 0x80000000 0x80000; +/ { + compatible = "cvitek,mars"; + #size-cells = <0x00000002>; + #address-cells = <0x00000002>; + model = "Cvitek. Mars ASIC. C906."; + top_misc_ctrl@3000000 { + compatible = "syscon"; + reg = <0x00000000 0x03000000 0x00000000 0x00008000>; + }; + clk-reset-controller { + #reset-cells = <0x00000001>; + compatible = "cvitek,clk-reset"; + reg = <0x00000000 0x03002000 0x00000000 0x00000008>; + }; + oscillator { + #clock-cells = <0x00000000>; + compatible = "fixed-clock"; + clock-frequency = <0x017d7840>; + clock-output-names = "osc"; + phandle = <0x00000001>; + }; + clock-controller { + compatible = "cvitek,mars-clk"; + reg = <0x00000000 0x03002000 0x00000000 0x00001000>; + clocks = <0x00000001>; + #clock-cells = <0x00000001>; + phandle = <0x00000002>; + }; + reset-controller { + #reset-cells = <0x00000001>; + compatible = "cvitek,reset"; + reg = <0x00000000 0x03003000 0x00000000 0x00000010>; + phandle = <0x00000003>; + }; + restart-controller { + compatible = "cvitek,restart"; + reg = <0x00000000 0x05025000 0x00000000 0x00002000>; + }; + tpu { + compatible = "cvitek,tpu"; + reg-names = "tdma", "tiu"; + reg = <0x00000000 0x0c100000 0x00000000 0x00001000 0x00000000 0x0c101000 0x00000000 0x00001000>; + clocks = <0x00000002 0x0000000f 0x00000002 0x00000010>; + clock-names = "clk_tpu_axi", "clk_tpu_fab"; + resets = <0x00000003 0x00000007 0x00000003 0x00000008 0x00000003 0x00000009>; + reset-names = "res_tdma", "res_tpu", "res_tpusys"; + interrupts = <0x0000004b 0x00000004 0x0000004c 0x00000004>; + interrupt-names = "tiu_irq", "tdma_irq"; + interrupt-parent = <0x00000004>; + }; + mon { + compatible = "cvitek,mon"; + reg-names = "pcmon", "ddr_ctrl", "ddr_phyd", "ddr_aximon", "ddr_top"; + reg = <0x00000000 0x01040000 0x00000000 0x00001000 0x00000000 0x08004000 0x00000000 0x00001000 0x00000000 0x08006000 0x00000000 0x00001000 0x00000000 0x08008000 0x00000000 0x00001000 0x00000000 0x0800a000 0x00000000 0x00001000>; + interrupts = <0x0000005d 0x00000004>; + interrupt-names = "mon_irq"; + interrupt-parent = <0x00000004>; + }; + wiegand0 { + compatible = "cvitek,wiegand"; + reg-names = "wiegand"; + reg = <0x00000000 0x03030000 0x00000000 0x00001000>; + clocks = <0x00000002 0x00000081 0x00000002 0x00000082>; + clock-names = "clk_wgn", "clk_wgn1"; + resets = <0x00000003 0x00000056>; + reset-names = "res_wgn"; + interrupts = <0x00000040 0x00000004>; + interrupt-parent = <0x00000004>; + }; + wiegand1 { + compatible = "cvitek,wiegand"; + reg-names = "wiegand"; + reg = <0x00000000 0x03031000 0x00000000 0x00001000>; + clocks = <0x00000002 0x00000081 0x00000002 0x00000083>; + clock-names = "clk_wgn", "clk_wgn1"; + resets = <0x00000003 0x00000057>; + reset-names = "res_wgn"; + interrupts = <0x00000041 0x00000004>; + interrupt-parent = <0x00000004>; + }; + wiegand2 { + compatible = "cvitek,wiegand"; + reg-names = "wiegand"; + reg = <0x00000000 0x03032000 0x00000000 0x00001000>; + clocks = <0x00000002 0x00000081 0x00000002 0x00000084>; + clock-names = "clk_wgn", "clk_wgn1"; + resets = <0x00000003 0x00000058>; + reset-names = "res_wgn"; + interrupts = <0x00000042 0x00000004>; + interrupt-parent = <0x00000004>; + }; + saradc { + compatible = "cvitek,saradc"; + reg-names = "top_domain_saradc", "rtc_domain_saradc"; + reg = <0x00000000 0x030f0000 0x00000000 0x00001000 0x00000000 0x0502c000 0x00000000 0x00001000>; + clocks = <0x00000002 0x00000015>; + clock-names = "clk_saradc"; + resets = <0x00000003 0x00000034>; + reset-names = "res_saradc"; + interrupts = <0x00000064 0x00000001>; + interrupt-parent = <0x00000004>; + }; + rtc { + compatible = "cvitek,rtc"; + reg = <0x00000000 0x05026000 0x00000000 0x00001000 0x00000000 0x05025000 0x00000000 0x00001000>; + clocks = <0x00000002 0x00000013>; + clock-names = "clk_rtc"; + interrupts = <0x00000011 0x00000004>; + interrupt-parent = <0x00000004>; + }; + cvitek-ion { + compatible = "cvitek,cvitek-ion"; + heap_carveout@0 { + compatible = "cvitek,carveout"; + memory-region = <0x00000005>; + }; + }; + sysdma_remap { + compatible = "cvitek,sysdma_remap"; + reg = <0x00000000 0x03000154 0x00000000 0x00000010>; + ch-remap = <0x00000000 0x00000005 0x00000002 0x00000003 0x00000026 0x00000026 0x00000004 0x00000007>; + int_mux_base = <0x03000298>; + int_mux = <0x0007fc00>; + }; + dma@0x4330000 { + compatible = "snps,dmac-bm"; + reg = <0x00000000 0x04330000 0x00000000 0x00001000>; + clock-names = "clk_sdma_axi"; + clocks = <0x00000002 0x0000002c>; + dma-channels = [08]; + #dma-cells = <0x00000003>; + dma-requests = [10]; + chan_allocation_order = [00]; + chan_priority = [01]; + block_size = <0x00000400>; + dma-masters = [02]; + data-width = <0x00000004 0x00000004>; + axi_tr_width = <0x00000004>; + block-ts = <0x0000000f>; + interrupts = <0x0000001d 0x00000004>; + interrupt-parent = <0x00000004>; + phandle = <0x0000000e>; + }; + cv-wd@0x3010000 { + compatible = "snps,dw-wdt"; + reg = <0x00000000 0x03010000 0x00000000 0x00001000>; + resets = <0x00000003 0x00000030>; + clocks = <0x00000006>; + }; + pclk { + #clock-cells = <0x00000000>; + compatible = "fixed-clock"; + clock-frequency = <0x017d7840>; + phandle = <0x00000006>; + }; + spi0@04180000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x00000000 0x04180000 0x00000000 0x00010000>; + clocks = <0x00000002 0x00000071>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + interrupts = <0x00000036 0x00000004>; + interrupt-parent = <0x00000004>; + }; + spi1@04190000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x00000000 0x04190000 0x00000000 0x00010000>; + clocks = <0x00000002 0x00000071>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + interrupts = <0x00000037 0x00000004>; + interrupt-parent = <0x00000004>; + }; + spi2@041A0000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x00000000 0x041a0000 0x00000000 0x00010000>; + clocks = <0x00000002 0x00000071>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + interrupts = <0x00000038 0x00000004>; + interrupt-parent = <0x00000004>; + }; + spi3@041B0000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x00000000 0x041b0000 0x00000000 0x00010000>; + clocks = <0x00000002 0x00000071>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + interrupts = <0x00000039 0x00000004>; + interrupt-parent = <0x00000004>; + }; + serial@04140000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00000000 0x04140000 0x00000000 0x00001000>; + clock-frequency = <0x017d7840>; + reg-shift = <0x00000002>; + reg-io-width = <0x00000004>; + status = "okay"; + interrupts = <0x0000002c 0x00000004>; + interrupt-parent = <0x00000004>; + }; + serial@04150000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00000000 0x04150000 0x00000000 0x00001000>; + clock-frequency = <0x017d7840>; + reg-shift = <0x00000002>; + reg-io-width = <0x00000004>; + status = "okay"; + interrupts = <0x0000002d 0x00000004>; + interrupt-parent = <0x00000004>; + }; + serial@04160000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00000000 0x04160000 0x00000000 0x00001000>; + clock-frequency = <0x017d7840>; + reg-shift = <0x00000002>; + reg-io-width = <0x00000004>; + status = "okay"; + interrupts = <0x0000002e 0x00000004>; + interrupt-parent = <0x00000004>; + }; + serial@04170000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00000000 0x04170000 0x00000000 0x00001000>; + clock-frequency = <0x017d7840>; + reg-shift = <0x00000002>; + reg-io-width = <0x00000004>; + status = "okay"; + interrupts = <0x0000002f 0x00000004>; + interrupt-parent = <0x00000004>; + }; + serial@041C0000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00000000 0x041c0000 0x00000000 0x00001000>; + clock-frequency = <0x017d7840>; + reg-shift = <0x00000002>; + reg-io-width = <0x00000004>; + status = "disabled"; + interrupts = <0x00000030 0x00000004>; + interrupt-parent = <0x00000004>; + }; + gpio@03020000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00000000 0x03020000 0x00000000 0x00001000>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + bank-name = "porta"; + gpio-controller; + #gpio-cells = <0x00000002>; + snps,nr-gpios = <0x00000020>; + reg = <0x00000000>; + interrupt-controller; + interrupts = <0x0000003c 0x00000004>; + interrupt-parent = <0x00000004>; + phandle = <0x0000000c>; + }; + }; + gpio@03021000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00000000 0x03021000 0x00000000 0x00001000>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + gpio-controller@1 { + compatible = "snps,dw-apb-gpio-port"; + bank-name = "portb"; + gpio-controller; + #gpio-cells = <0x00000002>; + snps,nr-gpios = <0x00000020>; + reg = <0x00000000>; + interrupt-controller; + interrupts = <0x0000003d 0x00000004>; + interrupt-parent = <0x00000004>; + phandle = <0x00000011>; + }; + }; + gpio@03022000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00000000 0x03022000 0x00000000 0x00001000>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + gpio-controller@2 { + compatible = "snps,dw-apb-gpio-port"; + bank-name = "portc"; + gpio-controller; + #gpio-cells = <0x00000002>; + snps,nr-gpios = <0x00000020>; + reg = <0x00000000>; + interrupt-controller; + interrupts = <0x0000003e 0x00000004>; + interrupt-parent = <0x00000004>; + }; + }; + gpio@03023000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00000000 0x03023000 0x00000000 0x00001000>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + gpio-controller@3 { + compatible = "snps,dw-apb-gpio-port"; + bank-name = "portd"; + gpio-controller; + #gpio-cells = <0x00000002>; + snps,nr-gpios = <0x0000000c>; + reg = <0x00000000>; + interrupt-controller; + interrupts = <0x0000003f 0x00000004>; + interrupt-parent = <0x00000004>; + }; + }; + gpio@05021000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00000000 0x05021000 0x00000000 0x00001000>; + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + gpio-controller@4 { + compatible = "snps,dw-apb-gpio-port"; + bank-name = "porte"; + gpio-controller; + #gpio-cells = <0x00000002>; + snps,nr-gpios = <0x00000018>; + reg = <0x00000000>; + interrupt-controller; + interrupts = <0x00000046 0x00000004>; + interrupt-parent = <0x00000004>; + phandle = <0x0000000f>; + }; + }; + i2c@04000000 { + compatible = "snps,designware-i2c"; + clocks = <0x00000002 0x00000072>; + reg = <0x00000000 0x04000000 0x00000000 0x00001000>; + clock-frequency = <0x00061a80>; + #size-cells = <0x00000000>; + #address-cells = <0x00000001>; + resets = <0x00000003 0x0000001b>; + reset-names = "i2c0"; + interrupts = <0x00000031 0x00000004>; + interrupt-parent = <0x00000004>; + }; + i2c@04020000 { + compatible = "snps,designware-i2c"; + clocks = <0x00000002 0x00000072>; + reg = <0x00000000 0x04020000 0x00000000 0x00001000>; + clock-frequency = <0x000186a0>; + resets = <0x00000003 0x0000001d>; + reset-names = "i2c2"; + interrupts = <0x00000033 0x00000004>; + interrupt-parent = <0x00000004>; + }; + i2c@04030000 { + compatible = "snps,designware-i2c"; + clocks = <0x00000002 0x00000072>; + reg = <0x00000000 0x04030000 0x00000000 0x00001000>; + clock-frequency = <0x00061a80>; + resets = <0x00000003 0x0000001e>; + reset-names = "i2c3"; + interrupts = <0x00000034 0x00000004>; + interrupt-parent = <0x00000004>; + }; + i2c@04040000 { + compatible = "snps,designware-i2c"; + clocks = <0x00000002 0x00000072>; + reg = <0x00000000 0x04040000 0x00000000 0x00001000>; + clock-frequency = <0x00061a80>; + resets = <0x00000003 0x0000001f>; + reset-names = "i2c4"; + interrupts = <0x00000035 0x00000004>; + interrupt-parent = <0x00000004>; + }; + eth_csrclk { + clock-output-names = "eth_csrclk"; + clock-frequency = <0x0ee6b280>; + #clock-cells = <0x00000000>; + compatible = "fixed-clock"; + phandle = <0x00000007>; + }; + eth_ptpclk { + clock-output-names = "eth_ptpclk"; + clock-frequency = <0x02faf080>; + #clock-cells = <0x00000000>; + compatible = "fixed-clock"; + phandle = <0x00000008>; + }; + stmmac-axi-config { + snps,wr_osr_lmt = <0x00000001>; + snps,rd_osr_lmt = <0x00000002>; + snps,blen = <0x00000004 0x00000008 0x00000010 0x00000000 0x00000000 0x00000000 0x00000000>; + phandle = <0x00000009>; + }; + rx-queues-config { + snps,rx-queues-to-use = <0x00000001>; + phandle = <0x0000000a>; + queue0 { + }; + }; + tx-queues-config { + snps,tx-queues-to-use = <0x00000001>; + phandle = <0x0000000b>; + queue0 { + }; + }; + ethernet@4070000 { + compatible = "cvitek,ethernet"; + reg = <0x00000000 0x04070000 0x00000000 0x00010000>; + clock-names = "stmmaceth", "ptp_ref"; + clocks = <0x00000007 0x00000008>; + tx-fifo-depth = <0x00002000>; + rx-fifo-depth = <0x00002000>; + snps,multicast-filter-bins = <0x00000000>; + snps,perfect-filter-entries = <0x00000001>; + snps,txpbl = <0x00000008>; + snps,rxpbl = <0x00000008>; + snps,aal; + snps,axi-config = <0x00000009>; + snps,mtl-rx-config = <0x0000000a>; + snps,mtl-tx-config = <0x0000000b>; + phy-mode = "rmii"; + interrupt-names = "macirq"; + interrupts = <0x0000001f 0x00000004>; + interrupt-parent = <0x00000004>; + }; + cv-emmc@4300000 { + compatible = "cvitek,mars-emmc"; + reg = <0x00000000 0x04300000 0x00000000 0x00001000>; + reg-names = "core_mem"; + bus-width = <0x00000004>; + non-removable; + no-sdio; + no-sd; + src-frequency = <0x165a0bc0>; + min-frequency = <0x00061a80>; + max-frequency = <0x0bebc200>; + 64_addressing; + reset_tx_rx_phy; + pll_index = <0x00000005>; + pll_reg = <0x03002064>; + interrupts = <0x00000022 0x00000004>; + interrupt-parent = <0x00000004>; + }; + cv-sd@4310000 { + compatible = "cvitek,mars-sd"; + reg = <0x00000000 0x04310000 0x00000000 0x00001000>; + reg-names = "core_mem"; + bus-width = <0x00000004>; + cap-sd-highspeed; + cap-mmc-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + no-sdio; + no-mmc; + src-frequency = <0x165a0bc0>; + min-frequency = <0x00061a80>; + max-frequency = <0x0bebc200>; + 64_addressing; + reset_tx_rx_phy; + reset-names = "sdhci"; + pll_index = <0x00000006>; + pll_reg = <0x03002070>; + cvi-cd-gpios = <0x0000000c 0x0000000d 0x00000001>; + interrupts = <0x00000024 0x00000004>; + interrupt-parent = <0x00000004>; + }; + wifi-sd@4320000 { + compatible = "cvitek,mars-sdio"; + bus-width = <0x00000004>; + reg = <0x00000000 0x04320000 0x00000000 0x00001000>; + reg_names = "core_mem"; + src-frequency = <0x165a0bc0>; + min-frequency = <0x00061a80>; + max-frequency = <0x02faf080>; + 64_addressing; + reset_tx_rx_phy; + non-removable; + pll_index = <0x00000007>; + pll_reg = <0x0300207c>; + no-mmc; + no-sd; + status = "okay"; + interrupts = <0x00000026 0x00000004>; + interrupt-parent = <0x00000004>; + }; + i2s_mclk { + clock-output-names = "i2s_mclk"; + clock-frequency = <0x01770000>; + #clock-cells = <0x00000000>; + compatible = "fixed-clock"; + phandle = <0x0000000d>; + }; + i2s_subsys { + compatible = "cvitek,i2s_tdm_subsys"; + reg = <0x00000000 0x04108000 0x00000000 0x00000100>; + clocks = <0x0000000d 0x00000002 0x00000004 0x00000002 0x0000002d 0x00000002 0x0000002e 0x00000002 0x0000002f 0x00000002 0x00000030>; + clock-names = "i2sclk", "clk_a0pll", "clk_sdma_aud0", "clk_sdma_aud1", "clk_sdma_aud2", "clk_sdma_aud3"; + master_base = <0x04110000>; + }; + i2s@04100000 { + compatible = "cvitek,cv1835-i2s"; + reg = <0x00000000 0x04100000 0x00000000 0x00002000>; + clocks = <0x0000000d 0x00000000>; + clock-names = "i2sclk"; + dev-id = <0x00000000>; + #sound-dai-cells = <0x00000000>; + dmas = <0x0000000e 0x00000000 0x00000001 0x00000001>; + dma-names = "rx"; + capability = "rx"; + mclk_out = "false"; + interrupts = <0x00000028 0x00000004>; + interrupt-parent = <0x00000004>; + }; + i2s@04130000 { + compatible = "cvitek,cv1835-i2s"; + reg = <0x00000000 0x04130000 0x00000000 0x00002000>; + clocks = <0x0000000d 0x00000000>; + clock-names = "i2sclk"; + dev-id = <0x00000003>; + #sound-dai-cells = <0x00000000>; + dmas = <0x0000000e 0x00000007 0x00000001 0x00000001>; + dma-names = "tx"; + capability = "tx"; + mclk_out = "true"; + interrupts = <0x0000002b 0x00000004>; + interrupt-parent = <0x00000004>; + }; + adc@0300A100 { + compatible = "cvitek,cv182xaadc"; + reg = <0x00000000 0x0300a100 0x00000000 0x00000100>; + clocks = <0x0000000d 0x00000000>; + clock-names = "i2sclk"; + clk_source = <0x04130000>; + }; + dac@0300A000 { + compatible = "cvitek,cv182xadac"; + reg = <0x00000000 0x0300a000 0x00000000 0x00000100>; + clocks = <0x0000000d 0x00000000>; + clock-names = "i2sclk"; + }; + pdm@0x041D0C00 { + compatible = "cvitek,cv1835pdm"; + reg = <0x00000000 0x041d0c00 0x00000000 0x00000100>; + clocks = <0x0000000d 0x00000000>; + clock-names = "i2sclk"; + }; + sound_adc { + compatible = "cvitek,cv182xa-adc"; + cvi,model = "CV182XA"; + cvi,card_name = "cv182xa_adc"; + }; + sound_dac { + compatible = "cvitek,cv182xa-dac"; + cvi,model = "CV182XA"; + cvi,card_name = "cv182xa_dac"; + }; + wifi_pin { + compatible = "cvitek,wifi-pin"; + poweron-gpio = <0x0000000c 0x00000012 0x00000000>; + wakeup-gpio = <0x0000000f 0x00000007 0x00000000>; + }; + bt_pin { + compatible = "cvitek,bt-pin"; + poweron-gpio = <0x0000000f 0x00000009 0x00000000>; + }; + cif { + compatible = "cvitek,cif"; + reg = <0x00000000 0x0a0c2000 0x00000000 0x00002000 0x00000000 0x0a0d0000 0x00000000 0x00001000 0x00000000 0x0a0c4000 0x00000000 0x00002000 0x00000000 0x0a0c6000 0x00000000 0x00002000 0x00000000 0x03001c30 0x00000000 0x00000030>; + reg-names = "csi_mac0", "csi_wrap0", "csi_mac1", "csi_mac2", "pad_ctrl"; + snsr-reset = <0x0000000c 0x00000002 0x00000001 0x0000000c 0x00000006 0x00000001 0x0000000c 0x00000002 0x00000001>; + resets = <0x00000003 0x00000046 0x00000003 0x00000048 0x00000003 0x00000047 0x00000003 0x00000049>; + reset-names = "phy0", "phy1", "phy-apb0", "phy-apb1"; + clocks = <0x00000002 0x0000005b 0x00000002 0x0000005c 0x00000002 0x00000088 0x00000002 0x00000003 0x00000002 0x00000005 0x00000002 0x00000002>; + clock-names = "clk_cam0", "clk_cam1", "clk_sys_2", "clk_mipimpll", "clk_disppll", "clk_fpll"; + interrupts = <0x0000001a 0x00000004 0x0000001b 0x00000004>; + interrupt-names = "csi0", "csi1"; + interrupt-parent = <0x00000004>; + }; + mipi_tx { + compatible = "cvitek,mipi_tx"; + reset-gpio = <0x0000000f 0x00000002 0x00000001>; + pwm-gpio = <0x0000000f 0x00000000 0x00000000>; + power-ct-gpio = <0x0000000f 0x00000001 0x00000000>; + clocks = <0x00000002 0x00000069 0x00000002 0x0000006a>; + clock-names = "clk_disp", "clk_dsi"; + }; + sys { + compatible = "cvitek,sys"; + }; + base { + compatible = "cvitek,base"; + reg = <0x00000000 0x0a0c8000 0x00000000 0x00000020>; + reg-names = "vip_sys"; + }; + vi { + compatible = "cvitek,vi"; + reg = <0x00000000 0x0a000000 0x00000000 0x00080000>; + clocks = <0x00000002 0x00000050 0x00000002 0x00000051 0x00000002 0x00000088 0x00000002 0x0000009a 0x00000002 0x0000004f 0x00000002 0x00000093 0x00000002 0x0000009d 0x00000002 0x0000005f 0x00000002 0x0000005d 0x00000002 0x0000005e 0x00000002 0x0000009f>; + clock-names = "clk_sys_0", "clk_sys_1", "clk_sys_2", "clk_sys_3", "clk_axi", "clk_csi_be", "clk_raw", "clk_isp_top", "clk_csi_mac0", "clk_csi_mac1", "clk_csi_mac2"; + clock-freq-vip-sys1 = <0x11e1a300>; + interrupts = <0x00000018 0x00000004>; + interrupt-parent = <0x00000004>; + interrupt-names = "isp"; + }; + vpss { + compatible = "cvitek,vpss"; + reg = <0x00000000 0x0a080000 0x00000000 0x00010000 0x00000000 0x0a0d1000 0x00000000 0x00000100>; + reg-names = "sc"; + clocks = <0x00000002 0x00000050 0x00000002 0x00000051 0x00000002 0x00000088 0x00000002 0x00000060 0x00000002 0x00000061 0x00000002 0x00000062 0x00000002 0x00000063 0x00000002 0x00000064 0x00000002 0x00000065 0x00000002 0x00000066>; + clock-names = "clk_sys_0", "clk_sys_1", "clk_sys_2", "clk_img_d", "clk_img_v", "clk_sc_top", "clk_sc_d", "clk_sc_v1", "clk_sc_v2", "clk_sc_v3"; + clock-freq-vip-sys1 = <0x11e1a300>; + interrupts = <0x00000019 0x00000004>; + interrupt-names = "sc"; + interrupt-parent = <0x00000004>; + }; + ive { + compatible = "cvitek,ive"; + reg = <0x00000000 0x0a0a0000 0x00000000 0x00003100>; + reg-names = "ive_base"; + interrupt-names = "ive_irq"; + interrupt-parent = <0x00000004>; + interrupts = <0x00000061 0x00000004>; + }; + vo { + compatible = "cvitek,vo"; + reg = <0x00000000 0x0a080000 0x00000000 0x00010000 0x00000000 0x0a0c8000 0x00000000 0x000000a0 0x00000000 0x0a0d1000 0x00000000 0x00000100>; + reg-names = "sc", "vip_sys", "dphy"; + clocks = <0x00000002 0x00000069 0x00000002 0x0000006a 0x00000002 0x00000068>; + reset-gpio = <0x0000000f 0x00000002 0x00000001>; + pwm-gpio = <0x0000000f 0x00000000 0x00000000>; + power-ct-gpio = <0x0000000f 0x00000001 0x00000000>; + clock-names = "clk_disp", "clk_dsi", "clk_bt"; + }; + reserved-memory { + #size-cells = <0x00000002>; + #address-cells = <0x00000002>; + ranges; + mmode_resv0@80000000 { + reg = <0x00000000 0x80000000 0x00000000 0x00040000>; + phandle = <0x00000014>; + }; + cvifb { + alloc-ranges = <0x00000000 0x8377e000 0x00000000 0x001c2000>; + size = <0x00000000 0x001c2000>; + phandle = <0x00000010>; + }; + ion { + compatible = "ion-region"; + alloc-ranges = <0x00000000 0x83940000 0x00000000 0x04600000>; + size = <0x00000000 0x04600000>; + phandle = <0x00000005>; + }; + }; + cvifb { + compatible = "cvitek,fb"; + memory-region = <0x00000010>; + reg = <0x00000000 0x0a088000 0x00000000 0x00001000>; + reg-names = "disp"; + }; + dwa { + compatible = "cvitek,dwa"; + reg = <0x00000000 0x0a0c0000 0x00000000 0x00001000>; + reg-names = "dwa"; + clocks = <0x00000002 0x00000050 0x00000002 0x00000051 0x00000002 0x00000088 0x00000002 0x0000009a 0x00000002 0x0000009b 0x00000002 0x00000067>; + clock-names = "clk_sys_0", "clk_sys_1", "clk_sys_2", "clk_sys_3", "clk_sys_4", "clk_dwa"; + clock-freq-vip-sys1 = <0x11e1a300>; + interrupts = <0x0000001c 0x00000004>; + interrupt-names = "dwa"; + interrupt-parent = <0x00000004>; + }; + rgn { + compatible = "cvitek,rgn"; + }; + vcodec { + compatible = "cvitek,asic-vcodec"; + reg = <0x00000000 0x0b020000 0x00000000 0x00010000 0x00000000 0x0b010000 0x00000000 0x00010000 0x00000000 0x0b030000 0x00000000 0x00000100 0x00000000 0x0b058000 0x00000000 0x00000100 0x00000000 0x0b050000 0x00000000 0x00000400>; + reg-names = "h265", "h264", "vc_ctrl", "vc_sbm", "vc_addr_remap"; + clocks = <0x00000002 0x00000053 0x00000002 0x00000055 0x00000002 0x00000059 0x00000002 0x00000056 0x00000002 0x0000005a 0x00000002 0x00000054 0x00000002 0x00000087 0x00000002 0x0000008e 0x00000002 0x0000008b>; + clock-names = "clk_axi_video_codec", "clk_h264c", "clk_apb_h264c", "clk_h265c", "clk_apb_h265c", "clk_vc_src0", "clk_vc_src1", "clk_vc_src2", "clk_cfg_reg_vc"; + interrupts = <0x00000016 0x00000004 0x00000015 0x00000004 0x00000017 0x00000004>; + interrupt-names = "h265", "h264", "sbm"; + interrupt-parent = <0x00000004>; + }; + cvi_vc_drv { + compatible = "cvitek,cvi_vc_drv"; + reg = <0x00000000 0x0b030000 0x00000000 0x00000100 0x00000000 0x0b058000 0x00000000 0x00000100 0x00000000 0x0b050000 0x00000000 0x00000400>; + reg-names = "vc_ctrl", "vc_sbm", "vc_addr_remap"; + }; + rtos_cmdqu { + compatible = "cvitek,rtos_cmdqu"; + reg = <0x00000000 0x01900000 0x00000000 0x00001000>; + reg-names = "mailbox"; + interrupts = <0x00000065 0x00000004>; + interrupt-names = "mailbox"; + interrupt-parent = <0x00000004>; + }; + usb@04340000 { + compatible = "cvitek,cv182x-usb"; + reg = <0x00000000 0x04340000 0x00000000 0x00010000 0x00000000 0x03006000 0x00000000 0x00000058>; + dr_mode = "otg"; + g-use-dma; + g-rx-fifo-size = <0x00000218>; + g-np-tx-fifo-size = <0x00000020>; + g-tx-fifo-size = <0x00000300 0x00000200 0x00000200 0x00000180 0x00000080 0x00000080>; + clocks = <0x00000002 0x00000047 0x00000002 0x00000048 0x00000002 0x00000049 0x00000002 0x0000004a 0x00000002 0x0000004b>; + clock-names = "clk_axi", "clk_apb", "clk_125m", "clk_33k", "clk_12m"; + vbus-gpio = <0x00000011 0x00000006 0x00000000>; + status = "okay"; + interrupts = <0x0000001e 0x00000004>; + interrupt-parent = <0x00000004>; + }; + thermal@030E0000 { + compatible = "cvitek,mars-thermal"; + reg = <0x00000000 0x030e0000 0x00000000 0x00010000>; + clocks = <0x00000002 0x00000014>; + clock-names = "clk_tempsen"; + reset-names = "tempsen"; + #thermal-sensor-cells = <0x00000001>; + interrupts = <0x00000010 0x00000004>; + interrupt-names = "tempsen"; + phandle = <0x00000012>; + }; + thermal-zones { + soc_thermal_0 { + polling-delay-passive = <0x000003e8>; + polling-delay = <0x000003e8>; + thermal-sensors = <0x00000012 0x00000000>; + trips { + soc_thermal_trip_0 { + temperature = <0x00015f90>; + hysteresis = <0x00001388>; + type = "passive"; + }; + soc_thermal_trip_1 { + temperature = <0x000186a0>; + hysteresis = <0x00001388>; + type = "passive"; + }; + soc_thermal_crtical_0 { + temperature = <0x0001d4c0>; + hysteresis = <0x00000000>; + type = "critical"; + }; + }; + }; + }; + cviaudio_core { + compatible = "cvitek,audio"; + }; + audio_clock { + compatible = "fixed-clock"; + #clock-cells = <0x00000000>; + clock-frequency = <0x01770000>; + }; + aliases { + serial0 = "/serial@04140000"; + ethernet0 = "/ethernet@4070000"; + }; + chosen { + boot-hartid = <0x00000000>; + bootargs = "rootfstype=squashfs rootwait ro root=/dev/mmcblk0p4 blkdevparts=mmcblk0:8192K(BOOT),512K(MISC),128K(ENV),70656K(ROOTFS),40960K(SYSTEM),15240K(CFG),3145728K(DATA);mmcblk0boot0:1M(fip),1M(fip_bak); console=ttyS0,115200 earlycon=sbi loglevel=9 riscv.fwsz=0x80000"; + stdout-path = "serial0"; + }; + cpus { + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + timebase-frequency = <0x017d7840>; + cpu-map { + cluster0 { + core0 { + cpu = <0x00000001>; + }; + }; + }; + cpu@0 { + device_type = "cpu"; + reg = <0x00000000>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdvcsu"; + mmu-type = "riscv,sv39"; + clock-frequency = <0x017d7840>; + interrupt-controller { + #interrupt-cells = <0x00000001>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + phandle = <0x00000013>; + }; + }; + }; + soc { + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + compatible = "simple-bus"; + ranges; + interrupt-controller@70000000 { + riscv,ndev = <0x00000065>; + riscv,max-priority = <0x00000007>; + reg-names = "control"; + reg = <0x00000000 0x70000000 0x00000000 0x04000000>; + interrupts-extended = <0x00000013 0xffffffff 0x00000013 0x00000009>; + interrupt-controller; + compatible = "riscv,plic0"; + #interrupt-cells = <0x00000002>; + #address-cells = <0x00000000>; + phandle = <0x00000004>; + }; + clint@74000000 { + interrupts-extended = <0x00000013 0x00000003 0x00000013 0x00000007>; + reg = <0x00000000 0x74000000 0x00000000 0x00010000>; + compatible = "riscv,clint0"; + clint,has-no-64bit-mmio; + }; + }; + mars_cooling { + clocks = <0x00000002 0x00000098 0x00000002 0x0000000f>; + clock-names = "clk_cpu", "clk_tpu_axi"; + dev-freqs = <0x32a9f880 0x1dcd6500 0x1954fc40 0x165a0bc0 0x1954fc40 0x11e1a300>; + compatible = "cvitek,mars-cooling"; + #cooling-cells = <0x00000002>; + }; + memory@80000000 { + device_type = "memory"; + reg = <0x00000000 0x80000000 0x00000000 0x07f40000>; + }; + fast_image { + compatible = "cvitek,rtos_image"; + reg-names = "rtos_region"; + reg = <0x00000000 0x87f40000 0x00000000 0x000c0000>; + ion-size = <0x01600000>; + }; +}; diff --git a/crates/hal/src/riscv64/boards/cv1811h.rs b/crates/hal/src/riscv64/boards/cv1811h.rs new file mode 100644 index 0000000000..c41c60568d --- /dev/null +++ b/crates/hal/src/riscv64/boards/cv1811h.rs @@ -0,0 +1,15 @@ +use riscv::register::sstatus; + +pub const CLOCK_FREQ: usize = 25000000; + +static DEVICE_TREE: &[u8] = include_bytes!("cv1811h-fdt.dtb"); + +pub fn init_device(hartid: usize, _device_tree: usize) -> (usize, usize) { + // 开启SUM位 让内核可以访问用户空间 踩坑: + // only in qemu. eg: qemu is riscv 1.10 NOTE: k210 is riscv 1.9.1 + // in 1.10 is SUM but in 1.9.1 is PUM which is the opposite meaning with SUM + unsafe { + sstatus::set_sum(); + } + (hartid, DEVICE_TREE.as_ptr() as usize) +} diff --git a/crates/hal/src/riscv64/boards/k210.rs b/crates/hal/src/riscv64/boards/k210.rs new file mode 100644 index 0000000000..4a1d6a9e85 --- /dev/null +++ b/crates/hal/src/riscv64/boards/k210.rs @@ -0,0 +1,5 @@ +pub const CLOCK_FREQ: usize = 403000000 / 62; + +pub fn init_device(hartid: usize, device_tree: usize) -> (usize, usize) { + (hartid, device_tree) +} diff --git a/crates/hal/src/riscv64/boards/mod.rs b/crates/hal/src/riscv64/boards/mod.rs new file mode 100644 index 0000000000..00dd77429b --- /dev/null +++ b/crates/hal/src/riscv64/boards/mod.rs @@ -0,0 +1,20 @@ +// cfg_if::cfg_if! { +// if #[cfg(board = "k210")] { +// mod k210; +// pub use k210::*; +// } else if #[cfg(board = "qemu")] { +mod qemu; +pub use qemu::*; +// } else if #[cfg(board = "cv1811h")] { +// mod cv1811h; +// pub use cv1811h::*; +// } else { +// compile_error!("not support this board"); +// pub const CLOCK_FREQ: usize = 12500000; + +// pub fn init_device(hartid: usize, device_tree: usize) -> (usize, usize) { +// // warn!("use default board config"); +// (hartid, device_tree) +// } +// } +// } diff --git a/crates/hal/src/riscv64/boards/qemu.rs b/crates/hal/src/riscv64/boards/qemu.rs new file mode 100644 index 0000000000..f730acccd3 --- /dev/null +++ b/crates/hal/src/riscv64/boards/qemu.rs @@ -0,0 +1,13 @@ +use riscv::register::sstatus; + +pub const CLOCK_FREQ: usize = 12500000; + +pub fn init_device(hartid: usize, device_tree: usize) -> (usize, usize) { + // 开启SUM位 让内核可以访问用户空间 踩坑: + // only in qemu. eg: qemu is riscv 1.10 NOTE: k210 is riscv 1.9.1 + // in 1.10 is SUM but in 1.9.1 is PUM which is the opposite meaning with SUM + unsafe { + sstatus::set_sum(); + } + (hartid, device_tree) +} diff --git a/crates/hal/src/riscv64/consts.rs b/crates/hal/src/riscv64/consts.rs new file mode 100644 index 0000000000..dedace1163 --- /dev/null +++ b/crates/hal/src/riscv64/consts.rs @@ -0,0 +1,4 @@ +pub const VIRT_ADDR_START: usize = 0xffff_ffc0_0000_0000; +pub const USER_ADDR_MAX: usize = 0xbf_ffff_ffff; +pub const PAGE_ITEM_COUNT: usize = 512; +pub const SIG_RETURN_ADDR: usize = 0xFFFF_FFC1_0000_0000; diff --git a/crates/hal/src/riscv64/entry.rs b/crates/hal/src/riscv64/entry.rs new file mode 100644 index 0000000000..e8fdc57b89 --- /dev/null +++ b/crates/hal/src/riscv64/entry.rs @@ -0,0 +1,65 @@ +use crate::PAGE_ITEM_COUNT; +use crate::VIRT_ADDR_START; + +#[link_section = ".data.boot_page_table"] +static mut PAGE_TABLE: [u64; PAGE_ITEM_COUNT] = { + let mut arr: [u64; PAGE_ITEM_COUNT] = [0; PAGE_ITEM_COUNT]; + // 初始化页表信息 + // 0x00000000_80000000 -> 0x80000000 (1G) + // 高半核 + // 0xffffffc0_00000000 -> 0x00000000 (1G) + // 0xffffffc0_80000000 -> 0x80000000 (1G) + + // arr[0] = PTE::from_addr(0x0000_0000, PTEFlags::VRWX); + // arr[1] = PTE::from_addr(0x4000_0000, PTEFlags::VRWX); + arr[2] = (0x80000 << 10) | 0xef; + arr[0x100] = (0x00000 << 10) | 0xef; + arr[0x101] = (0x40000 << 10) | 0xef; + arr[0x102] = (0x80000 << 10) | 0xef; + arr[0x106] = (0x80000 << 10) | 0xef; + arr +}; + +/// 汇编入口函数 +/// +/// 分配栈 初始化页表信息 并调到rust入口函数 +#[naked] +#[no_mangle] +#[link_section = ".text.entry"] +unsafe extern "C" fn _start() -> ! { + core::arch::asm!( + // 1. 设置栈信息 + // sp = bootstack + (hartid + 1) * 0x10000 + " + la sp, {boot_stack} + li t0, {stack_size} + add sp, sp, t0 // set boot stack + + li s0, {virt_addr_start} // add virtual address + or sp, sp, s0 + ", + // 2. 开启分页模式 + // satp = (8 << 60) | PPN(page_table) + " + la t0, {page_table} + srli t0, t0, 12 + li t1, 8 << 60 + or t0, t0, t1 + csrw satp, t0 + sfence.vma + ", + // 3. 跳到 rust_entry 函数,绝对路径 + " + + la a2, {entry} + or a2, a2, s0 + jalr a2 // call rust_entry + ", + stack_size = const crate::STACK_SIZE, + boot_stack = sym crate::BOOT_STACK, + page_table = sym PAGE_TABLE, + virt_addr_start = const VIRT_ADDR_START, + entry = sym super::rust_entry, + options(noreturn), + ) +} diff --git a/crates/hal/src/riscv64/interrupt/frame.rs b/crates/hal/src/riscv64/interrupt/frame.rs new file mode 100644 index 0000000000..32f5834eb8 --- /dev/null +++ b/crates/hal/src/riscv64/interrupt/frame.rs @@ -0,0 +1,145 @@ +use core::{ + fmt::Debug, + ops::{Index, IndexMut}, +}; + +use riscv::register::sstatus::{self, Sstatus}; + +use crate::ContextArgs; + +/// Saved registers when a trap (interrupt or exception) occurs. +#[repr(C)] +#[derive(Clone, Copy)] +// 上下文 +pub struct TrapFrame { + /// All general registers including x0 + pub x: [usize; 32], + /// Supervisor Status Register. + pub sstatus: Sstatus, + /// Supervisor Exception Program Counter. + pub sepc: usize, + /// 浮点数寄存器 + pub fsx: [usize; 2], +} + +impl Debug for TrapFrame { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("TrapFrame") + .field("ra", &self.x[1]) + .field("sp", &self.x[2]) + .field("gp", &self.x[3]) + .field("tp", &self.x[4]) + .field("t0", &self.x[5]) + .field("t1", &self.x[6]) + .field("t2", &self.x[7]) + .field("s0", &self.x[8]) + .field("s1", &self.x[9]) + .field("a0", &self.x[10]) + .field("a1", &self.x[11]) + .field("a2", &self.x[12]) + .field("a3", &self.x[13]) + .field("a4", &self.x[14]) + .field("a5", &self.x[15]) + .field("a6", &self.x[16]) + .field("a7", &self.x[17]) + .field("s2", &self.x[18]) + .field("s3", &self.x[19]) + .field("s4", &self.x[20]) + .field("s5", &self.x[21]) + .field("s6", &self.x[22]) + .field("s7", &self.x[23]) + .field("s8", &self.x[24]) + .field("s9", &self.x[25]) + .field("s10", &self.x[26]) + .field("s11", &self.x[27]) + .field("t3", &self.x[28]) + .field("t4", &self.x[29]) + .field("t5", &self.x[30]) + .field("t6", &self.x[31]) + .field("sstatus", &self.sstatus) + .field("sepc", &self.sepc) + .field("fsx", &self.fsx) + .finish() + } +} + +impl TrapFrame { + // 创建上下文信息 + #[inline] + pub fn new() -> Self { + TrapFrame { + x: [0usize; 32], + sstatus: sstatus::read(), + sepc: 0, + fsx: [0; 2], + } + } + + /// 用于第一次进入应用程序时的初始化 + pub fn app_init_context(app_entry: usize, user_sp: usize) -> Self { + // 当前版本的riscv不支持使用set_spp函数,需要手动修改 + // 修改当前的sstatus为User,即是第8位置0 + let mut trap_frame = TrapFrame::new(); + trap_frame[ContextArgs::SP] = user_sp; + // info!("app_entry: {:#x}", app_entry); + trap_frame[ContextArgs::SEPC] = app_entry; + trap_frame.sstatus.set_spp(sstatus::SPP::User); + // When modifying the CSR, the SIE bit must be cleared + trap_frame.sstatus.set_sie(false); + // trap_frame.sstatus = + // unsafe { (*(&sstatus as *const Sstatus as *const usize) & !(1 << 8)) & !(1 << 1) }; + unsafe { + // a0为参数个数 + // a1存储的是用户栈底,即argv + trap_frame[ContextArgs::ARG0] = *(user_sp as *const usize); + trap_frame[ContextArgs::ARG1] = *(user_sp as *const usize).add(1); + } + trap_frame + } +} + +impl TrapFrame { + #[inline] + pub fn args(&self) -> [usize; 6] { + self.x[10..16].try_into().expect("args slice force convert") + } + + #[inline] + pub fn syscall_ok(&mut self) { + self.sepc += 4; + } +} + +impl Index for TrapFrame { + type Output = usize; + + fn index(&self, index: ContextArgs) -> &Self::Output { + match index { + ContextArgs::SEPC => &self.sepc, + ContextArgs::RA => &self.x[1], + ContextArgs::SP => &self.x[2], + ContextArgs::RET => &self.x[10], + ContextArgs::ARG0 => &self.x[10], + ContextArgs::ARG1 => &self.x[11], + ContextArgs::ARG2 => &self.x[12], + ContextArgs::TLS => &self.x[4], + ContextArgs::SYSCALL => &self.x[17], + } + } +} + +impl IndexMut for TrapFrame { + fn index_mut(&mut self, index: ContextArgs) -> &mut Self::Output { + match index { + ContextArgs::SEPC => &mut self.sepc, + ContextArgs::RA => &mut self.x[1], + ContextArgs::SP => &mut self.x[2], + ContextArgs::RET => &mut self.x[10], + ContextArgs::ARG0 => &mut self.x[10], + ContextArgs::ARG1 => &mut self.x[11], + ContextArgs::ARG2 => &mut self.x[12], + ContextArgs::TLS => &mut self.x[4], + ContextArgs::SYSCALL => &mut self.x[17], + } + } +} diff --git a/crates/hal/src/riscv64/interrupt/macros.rs b/crates/hal/src/riscv64/interrupt/macros.rs new file mode 100644 index 0000000000..d87d9a8870 --- /dev/null +++ b/crates/hal/src/riscv64/interrupt/macros.rs @@ -0,0 +1,134 @@ +/// define the macro for the assembly code + +macro_rules! include_asm_marcos { + () => { + #[cfg(target_arch = "riscv32")] + core::arch::global_asm!( + r" + .ifndef XLENB + .equ XLENB, 4 + + .macro LDR rd, rs, off + lw \rd, \off*XLENB(\rs) + .endm + .macro STR rs2, rs1, off + sw \rs2, \off*XLENB(\rs1) + .endm + + .endif" + ); + + #[cfg(target_arch = "riscv64")] + core::arch::global_asm!( + r" + .ifndef XLENB + .equ XLENB, 8 + + .macro LDR rd, rs, off + ld \rd, \off*XLENB(\rs) + .endm + .macro STR rs2, rs1, off + sd \rs2, \off*XLENB(\rs1) + .endm + + .endif", + ); + + #[cfg(feature = "stackful")] + core::arch::global_asm!( + r" + .ifndef .LPUSH_POP_GENERAL_REGS + .equ .LPUSH_POP_GENERAL_REGS, 0 + + .macro PUSH_POP_GENERAL_REGS, op + \op ra, sp, 1 + \op t0, sp, 5 + \op t1, sp, 6 + \op t2, sp, 7 + \op s0, sp, 8 + \op s1, sp, 9 + \op a0, sp, 10 + \op a1, sp, 11 + \op a2, sp, 12 + \op a3, sp, 13 + \op a4, sp, 14 + \op a5, sp, 15 + \op a6, sp, 16 + \op a7, sp, 17 + \op s2, sp, 18 + \op s3, sp, 19 + \op s4, sp, 20 + \op s5, sp, 21 + \op s6, sp, 22 + \op s7, sp, 23 + \op s8, sp, 24 + \op s9, sp, 25 + \op s10, sp, 26 + \op s11, sp, 27 + \op t3, sp, 28 + \op t4, sp, 29 + \op t5, sp, 30 + \op t6, sp, 31 + .endm + + .macro PUSH_GENERAL_REGS + PUSH_POP_GENERAL_REGS STR + .endm + .macro POP_GENERAL_REGS + PUSH_POP_GENERAL_REGS LDR + .endm + + .endif" + ); + + #[cfg(not(feature = "stackful"))] + // need to save the gp and the tp register + core::arch::global_asm!( + r" + .ifndef .LPUSH_POP_GENERAL_REGS + .equ .LPUSH_POP_GENERAL_REGS, 0 + + .macro PUSH_POP_GENERAL_REGS, op + \op ra, sp, 1 + \op gp, sp, 3 + \op tp, sp, 4 + \op t0, sp, 5 + \op t1, sp, 6 + \op t2, sp, 7 + \op s0, sp, 8 + \op s1, sp, 9 + \op a0, sp, 10 + \op a1, sp, 11 + \op a2, sp, 12 + \op a3, sp, 13 + \op a4, sp, 14 + \op a5, sp, 15 + \op a6, sp, 16 + \op a7, sp, 17 + \op s2, sp, 18 + \op s3, sp, 19 + \op s4, sp, 20 + \op s5, sp, 21 + \op s6, sp, 22 + \op s7, sp, 23 + \op s8, sp, 24 + \op s9, sp, 25 + \op s10, sp, 26 + \op s11, sp, 27 + \op t3, sp, 28 + \op t4, sp, 29 + \op t5, sp, 30 + \op t6, sp, 31 + .endm + + .macro PUSH_GENERAL_REGS + PUSH_POP_GENERAL_REGS STR + .endm + .macro POP_GENERAL_REGS + PUSH_POP_GENERAL_REGS LDR + .endm + + .endif" + ); + }; +} diff --git a/crates/hal/src/riscv64/interrupt/mod.rs b/crates/hal/src/riscv64/interrupt/mod.rs new file mode 100644 index 0000000000..b5033e4471 --- /dev/null +++ b/crates/hal/src/riscv64/interrupt/mod.rs @@ -0,0 +1,135 @@ +#[macro_use] +mod macros; +mod frame; +cfg_if::cfg_if! { + if #[cfg(feature = "stackful")] { + mod stackful; + } else { + mod stackless; + pub use stackless::*; + } +} + +pub use frame::TrapFrame; + +use crate::{kernel_interrupt, TrapType, VIRT_ADDR_START}; +use riscv::register::{ + scause::{self, Exception, Interrupt, Trap}, + sie, stval, +}; +/// 内核中断回调 +#[no_mangle] +fn kernel_callback(context: &mut TrapFrame, from_user: bool) -> TrapType { + let scause = scause::read(); + let stval = stval::read(); + debug!( + "中断发生: {:#x} {:?} stval {:#x} sepc: {:#x}", + scause.bits(), + scause.cause(), + stval, + context.sepc + ); + let trap_type = match scause.cause() { + // 中断异常 + Trap::Exception(Exception::Breakpoint) => { + // QUESTION: Why do we need to add 2 to sepc? + context.sepc += 2; + TrapType::Breakpoint + } + Trap::Exception(Exception::LoadFault) => { + if stval > VIRT_ADDR_START { + panic!("kernel error: {:#x}", stval); + } + TrapType::Unknown + } + Trap::Exception(Exception::UserEnvCall) => TrapType::UserEnvCall, + // 时钟中断 + Trap::Interrupt(Interrupt::SupervisorTimer) => TrapType::Time(scause.bits()), + Trap::Exception(Exception::StorePageFault) => TrapType::StorePageFault(stval), + Trap::Exception(Exception::InstructionPageFault) => TrapType::InstructionPageFault(stval), + Trap::Exception(Exception::IllegalInstruction) => TrapType::IllegalInstruction(stval), + Trap::Exception(Exception::LoadPageFault) => TrapType::LoadPageFault(stval), + Trap::Interrupt(Interrupt::SupervisorExternal) => TrapType::SupervisorExternal, + _ => { + error!( + "内核态中断发生: {:#x} {:?} stval {:#x} sepc: {:#x}", + scause.bits(), + scause.cause(), + stval, + context.sepc + ); + panic!("未知中断: {:#x?}", context); + } + }; + kernel_interrupt(context, from_user, trap_type); + // crate::api::ArchInterface::kernel_interrupt(context, from_user, trap_type); + trap_type +} + +#[allow(dead_code)] +#[inline(always)] +pub fn enable_irq() { + unsafe { + sie::set_sext(); + sie::set_ssoft(); + } +} + +#[inline(always)] +pub fn enable_external_irq() { + unsafe { + sie::set_sext(); + } +} + +/// 设置中断 +pub fn init_interrupt() { + // crate::riscv64::page_table::sigtrx::init(); + // 输出内核信息 + + extern "C" { + fn trap_vector_base(); + } + unsafe { + core::arch::asm!("csrw stvec, a0", in("a0") trap_vector_base as usize); + + // 测试 + info!("测试 ebreak exception"); + core::arch::asm!("ebreak"); + } + + // // 初始化定时器 + // crate::riscv64::timer::init(); +} + +/// Create a trampoline for sigreturn +/// +/// This page can be accessed by user space +/// +/// To use this function, you need to add the page to the linker script like this after the text section: +/// ``` +/// . = ALIGN(4K); +/// *(.text.signal_trampoline) +/// . = ALIGN(4K); +/// ``` +/// +#[naked] +#[no_mangle] +#[link_section = ".text.signal_trampoline"] +unsafe extern "C" fn _sigreturn() -> ! { + core::arch::asm!( + // 1. 设置栈信息 + // sp = bootstack + (hartid + 1) * 0x10000 + " + li a7, 139 + ecall + ", + options(noreturn) + ) +} + +/// To get the address of sigreturn trampoline +#[allow(dead_code)] +pub fn get_sigreturn() -> usize { + _sigreturn as usize +} diff --git a/crates/hal/src/riscv64/interrupt/stackful.rs b/crates/hal/src/riscv64/interrupt/stackful.rs new file mode 100644 index 0000000000..659704a266 --- /dev/null +++ b/crates/hal/src/riscv64/interrupt/stackful.rs @@ -0,0 +1,6 @@ +use super::frame::TrapFrame; +include_asm_marcos!(); +core::arch::global_asm!( + include_str!("stackful_trap.S"), + trapframe_size = const core::mem::size_of::(), +); diff --git a/crates/hal/src/riscv64/interrupt/stackful_trap.S b/crates/hal/src/riscv64/interrupt/stackful_trap.S new file mode 100644 index 0000000000..cbe98c2790 --- /dev/null +++ b/crates/hal/src/riscv64/interrupt/stackful_trap.S @@ -0,0 +1,72 @@ +.macro SAVE_REGS, from_user + addi sp, sp, -{trapframe_size} + PUSH_GENERAL_REGS + + csrr t0, sepc + csrr t1, sstatus + csrrw t2, sscratch, zero // save sscratch (sp) and zero it + STR t0, sp, 33 // tf.sepc + STR t1, sp, 32 // tf.sstatus + STR t2, sp, 2 // tf.regs.sp + .word 0x10813827 // fsd fs0, 272(sp). Warn! it is only used in riscv64 + .word 0x10913c27 // fsd fs1, 280(sp). Warn! it is only used in riscv64 + +.if \from_user == 1 + LDR t1, sp, 3 // load supervisor gp + LDR t0, sp, 4 // load supervisor tp + STR gp, sp, 3 // save user gp and tp + STR tp, sp, 4 + mv gp, t1 + mv tp, t0 +.endif +.endm + +.macro RESTORE_REGS, from_user +.if \from_user == 1 + LDR t1, sp, 3 // load user gp and tp + LDR t0, sp, 4 + STR gp, sp, 3 // save supervisor tp + STR tp, sp, 4 + mv gp, t1 + mv tp, t0 + addi t0, sp, {trapframe_size} // put supervisor sp to scratch + csrw sscratch, t0 +.endif + + LDR t0, sp, 33 + LDR t1, sp, 32 + csrw sepc, t0 + csrw sstatus, t1 + .short 0x2452 // fld fs0, 272(sp). Warn! it is only used in riscv64 + .short 0x24f2 // fld fs1, 280(sp). Warn! it is only used in riscv64 + POP_GENERAL_REGS + LDR sp, sp, 2 // load sp from tf.regs.sp +.endm + +.section .text +.balign 4 +.global trap_vector_base +trap_vector_base: + // sscratch == 0: trap from S mode + // sscratch != 0: trap from U mode + csrrw sp, sscratch, sp // switch sscratch and sp + bnez sp, .Ltrap_entry_u + + csrr sp, sscratch // put supervisor sp back + j .Ltrap_entry_s + +.Ltrap_entry_s: + SAVE_REGS 0 + mv a0, sp + li a1, 0 + call kernel_callback + RESTORE_REGS 0 + sret + +.Ltrap_entry_u: + SAVE_REGS 1 + mv a0, sp + li a1, 1 + call kernel_callback + RESTORE_REGS 1 + sret diff --git a/crates/hal/src/riscv64/interrupt/stackless.rs b/crates/hal/src/riscv64/interrupt/stackless.rs new file mode 100644 index 0000000000..b1902a366a --- /dev/null +++ b/crates/hal/src/riscv64/interrupt/stackless.rs @@ -0,0 +1,194 @@ +use core::arch::asm; + +use riscv::register::sie; + +use super::{kernel_callback, TrapFrame}; + +use crate::TrapType; + +#[no_mangle] +#[percpu::def_percpu] +static KERNEL_RSP: usize = 0; + +#[no_mangle] +#[percpu::def_percpu] +static USER_RSP: usize = 0; + +include_asm_marcos!(); + +#[naked] +pub unsafe extern "C" fn trap_vector_base() { + asm!( + // 宏定义 + r" + .align 4 + .altmacro + + csrrw sp, sscratch, sp + bnez sp, uservec + csrr sp, sscratch + + addi sp, sp, -{cx_size} + + PUSH_GENERAL_REGS + csrr t0, sscratch + SDR t0, sp, 2 + csrr t0, sstatus + SDR t0, sp, 32 + csrr t0, sepc + SDR t0, sp, 33 + + + csrw sscratch, x0 + + mv a0, sp + mv a1, 0 + call kernel_callback + + LDR t0, sp, 33 + csrw sepc, t0 + LDR t0, sp, 32 + csrw sstatus, t0 + POP_GENERAL_REGS + LDR sp, sp, 2 + sret + ", + cx_size = const core::mem::size_of::(), + options(noreturn) + ) +} + +#[naked] +#[no_mangle] +extern "C" fn user_restore(context: *mut TrapFrame) { + unsafe { + asm!( + r" + .align 4 + .altmacro + ", + // 在内核态栈中开一个空间来存储内核态信息 + // 下次发生中断必然会进入中断入口然后恢复这个上下文. + // 仅保存 Callee-saved regs、gp、tp、ra. + " addi sp, sp, -18*8 + + sd sp, 8*1(sp) + sd gp, 8*2(sp) + sd tp, 8*3(sp) + sd s0, 8*4(sp) + sd s1, 8*5(sp) + sd s2, 8*6(sp) + sd s3, 8*7(sp) + sd s4, 8*8(sp) + sd s5, 8*9(sp) + sd s6, 8*10(sp) + sd s7, 8*11(sp) + sd s8, 8*12(sp) + sd s9, 8*13(sp) + sd s10, 8*14(sp) + sd s11, 8*15(sp) + sd a0, 8*16(sp) + sd ra, 8*17(sp) + ", + // 将栈信息保存到用户栈. + // a0 是传入的Context, 然后下面会再次恢复 sp 地址. + " sd sp, 8*0(a0) + csrw sscratch, a0 + mv sp, a0 + + .short 0x2452 # fld fs0, 272(sp). Warn! it is only used in riscv64 + .short 0x24f2 # fld fs1, 280(sp). Warn! it is only used in riscv64 + + LDR t0, sp, 33 + csrw sepc, t0 + LDR t0, sp, 32 + csrw sstatus, t0 + POP_GENERAL_REGS + LDR sp, sp, 2 + sret + ", + options(noreturn) + ) + } +} + +#[naked] +#[no_mangle] +#[allow(named_asm_labels)] +pub unsafe extern "C" fn uservec() { + asm!( + r" + .altmacro + ", + // 保存 general registers, 除了 sp + " + PUSH_GENERAL_REGS + csrr t0, sscratch + SDR t0, sp, 2 + csrr t0, sstatus + SDR t0, sp, 32 + csrr t0, sepc + SDR t0, sp, 33 + + + csrw sscratch, x0 + + .word 0x10813827 # fsd fs0, 272(sp). Warn! it is only used in riscv64 + .word 0x10913c27 # fsd fs1, 280(sp). Warn! it is only used in riscv64 + + mv a0, sp + ld sp, 0*8(a0) + sd x0, 0*8(a0) + ", + // 恢复内核上下文信息, 仅恢复 callee-saved 寄存器和 ra、gp、tp + " + ld gp, 8*2(sp) + ld tp, 8*3(sp) + ld s0, 8*4(sp) + ld s1, 8*5(sp) + ld s2, 8*6(sp) + ld s3, 8*7(sp) + ld s4, 8*8(sp) + ld s5, 8*9(sp) + ld s6, 8*10(sp) + ld s7, 8*11(sp) + ld s8, 8*12(sp) + ld s9, 8*13(sp) + ld s10, 8*14(sp) + ld s11, 8*15(sp) + ld ra, 8*17(sp) + + ld sp, 8(sp) + ", + // 回收栈 + " addi sp, sp, 18*8 + ret + ", + options(noreturn) + ); +} + +/// Return Some(()) if it was interrupt by syscall, otherwise None. +pub fn run_user_task(context: &mut TrapFrame) -> Option<()> { + user_restore(context); + match kernel_callback(context, true) { + TrapType::UserEnvCall => Some(()), + _ => None, + } +} + +#[allow(dead_code)] +#[inline(always)] +pub fn enable_irq() { + unsafe { + sie::set_sext(); + sie::set_ssoft(); + } +} + +#[inline(always)] +pub fn enable_external_irq() { + unsafe { + sie::set_sext(); + } +} diff --git a/crates/hal/src/riscv64/mod.rs b/crates/hal/src/riscv64/mod.rs new file mode 100644 index 0000000000..7ed8974cdf --- /dev/null +++ b/crates/hal/src/riscv64/mod.rs @@ -0,0 +1,93 @@ +mod boards; +mod consts; +mod entry; +mod interrupt; +// mod page_table; + +mod sbi; +mod timer; +// use alloc::vec::Vec; +pub use boards::*; +pub use consts::*; + +// use fdt::Fdt; +pub use interrupt::*; +// pub use page_table::*; + +use riscv::register::sstatus; +pub use sbi::*; +pub use timer::*; + +#[no_mangle] +extern "C" fn rust_entry(hartid: usize, device_tree: usize) { + crate::clear_bss(); + // ArchInterface::init_logging(); + crate::init_logging(); + // Init allocator + + #[cfg(feature = "alloc")] + crate::init_allocator(); + + // allocator::init(); + let smp: usize = option_env!("AX_SMP").unwrap_or("").parse().unwrap_or(1); + percpu::init(smp); + percpu::set_local_thread_pointer(hartid); + + let (hartid, _device_tree) = boards::init_device(hartid, device_tree); + + // let mut dt_buf = Vec::new(); + + // if device_tree != 0 { + // let fdt = unsafe { Fdt::from_ptr(device_tree as *const u8).unwrap() }; + + // dt_buf.extend_from_slice(unsafe { + // core::slice::from_raw_parts(device_tree as *const u8, fdt.total_size()) + // }); + + // info!("There has {} CPU(s)", fdt.cpus().count()); + + // fdt.memory().regions().for_each(|x| { + // info!( + // "memory region {:#X} - {:#X}", + // x.starting_address as usize, + // x.starting_address as usize + x.size.unwrap() + // ); + + // crate::add_memory_region( + // x.starting_address as usize | VIRT_ADDR_START, + // (x.starting_address as usize + x.size.unwrap()) | VIRT_ADDR_START, + // ); + // }); + // } + + crate::prepare_drivers(); + + // if let Ok(fdt) = Fdt::new(&dt_buf) { + // for node in fdt.all_nodes() { + // crate::try_to_add_device(&node); + // } + // } + + // 开启 SUM + unsafe { + // 开启浮点运算 + sstatus::set_fs(sstatus::FS::Dirty); + } + + // drop(dt_buf); + + // To enable the interrupt + init_interrupt(); + // crate::ArchInterface::main(hartid); + crate::kernel_main(hartid); + shutdown(); +} + +#[inline] +pub fn wfi() { + unsafe { + riscv::register::sstatus::clear_sie(); + riscv::asm::wfi(); + riscv::register::sstatus::set_sie(); + } +} diff --git a/crates/hal/src/riscv64/page_table/mod.rs b/crates/hal/src/riscv64/page_table/mod.rs new file mode 100644 index 0000000000..cd694fc5aa --- /dev/null +++ b/crates/hal/src/riscv64/page_table/mod.rs @@ -0,0 +1,4 @@ +pub mod sigtrx; +mod sv39; + +pub use sv39::*; diff --git a/crates/hal/src/riscv64/page_table/sigtrx.rs b/crates/hal/src/riscv64/page_table/sigtrx.rs new file mode 100644 index 0000000000..b092a23230 --- /dev/null +++ b/crates/hal/src/riscv64/page_table/sigtrx.rs @@ -0,0 +1,39 @@ +use crate::{PTEFlags, PAGE_ITEM_COUNT, PTE, VIRT_ADDR_START}; + +/// 汇编入口函数 +/// +/// 分配栈 初始化页表信息 并调到rust入口函数 +#[naked] +#[no_mangle] +#[link_section = ".sigtrx.sigreturn"] +unsafe extern "C" fn _sigreturn() -> ! { + core::arch::asm!( + // 1. 设置栈信息 + // sp = bootstack + (hartid + 1) * 0x10000 + " + li a7, 139 + ecall + ", + options(noreturn) + ) +} + +#[link_section = ".data.prepage.trx1"] +static mut TRX_STEP1: [PTE; PAGE_ITEM_COUNT] = [PTE::new(); PAGE_ITEM_COUNT]; + +#[link_section = ".data.prepage.trx2"] +static mut TRX_STEP2: [PTE; PAGE_ITEM_COUNT] = [PTE::new(); PAGE_ITEM_COUNT]; + +pub fn init() { + unsafe { + TRX_STEP1[0] = PTE::from_addr( + _sigreturn as usize & !VIRT_ADDR_START, + PTEFlags::ADUVRX.union(PTEFlags::G), + ); + TRX_STEP2[0] = PTE::from_addr(TRX_STEP1.as_ptr() as usize & !VIRT_ADDR_START, PTEFlags::V); + } +} + +pub fn get_trx_mapping() -> usize { + unsafe { TRX_STEP2.as_ptr() as usize & !VIRT_ADDR_START } +} diff --git a/crates/hal/src/riscv64/page_table/sv39.rs b/crates/hal/src/riscv64/page_table/sv39.rs new file mode 100644 index 0000000000..18eae65b07 --- /dev/null +++ b/crates/hal/src/riscv64/page_table/sv39.rs @@ -0,0 +1,273 @@ +use core::arch::{asm, riscv64::sfence_vma}; + +use alloc::sync::Arc; +use bitflags::bitflags; + +use crate::{ + sigtrx::get_trx_mapping, ArchInterface, MappingFlags, PhysAddr, PhysPage, VirtAddr, VirtPage, + PAGE_ITEM_COUNT, PAGE_SIZE, +}; + +#[derive(Copy, Clone, Debug)] +pub struct PTE(usize); + +impl PTE { + #[inline] + pub const fn new() -> Self { + Self(0) + } + + #[inline] + pub const fn from_ppn(ppn: usize, flags: PTEFlags) -> Self { + // let flags = flags.union(PTEFlags::D); + let mut flags = flags; + if flags.contains(PTEFlags::R) | flags.contains(PTEFlags::X) { + flags = flags.union(PTEFlags::A) + } + if flags.contains(PTEFlags::W) { + flags = flags.union(PTEFlags::D) + } + // TIPS: This is prepare for the extend bits of T-HEAD C906 + #[cfg(c906)] + if flags.contains(PTEFlags::G) && ppn == 0x8_0000 { + Self( + ppn << 10 + | flags + .union(PTEFlags::C) + .union(PTEFlags::B) + .union(PTEFlags::K) + .bits() as usize, + ) + } else if flags.contains(PTEFlags::G) && ppn == 0 { + Self(ppn << 10 | flags.union(PTEFlags::SE).union(PTEFlags::SO).bits() as usize) + } else { + Self(ppn << 10 | flags.union(PTEFlags::C).bits() as usize) + } + + #[cfg(not(c906))] + Self(ppn << 10 | flags.bits() as usize) + } + + #[inline] + pub const fn from_addr(addr: usize, flags: PTEFlags) -> Self { + Self::from_ppn(addr >> 12, flags) + } + + #[inline] + pub const fn to_ppn(&self) -> PhysPage { + PhysPage((self.0 >> 10) & ((1 << 29) - 1)) + } + + #[inline] + pub fn set(&mut self, ppn: usize, flags: PTEFlags) { + self.0 = (ppn << 10) | flags.bits() as usize; + } + + #[inline] + pub const fn flags(&self) -> PTEFlags { + PTEFlags::from_bits_truncate((self.0 & 0xff) as u64) + } + + #[inline] + pub const fn is_valid(&self) -> bool { + self.flags().contains(PTEFlags::V) && self.0 > u8::MAX as usize + } + + /// 判断是否是大页 + /// + /// 大页判断条件 V 位为 1, R/W/X 位至少有一个不为 0 + /// PTE 页表范围 1G(0x4000_0000) 2M(0x20_0000) 4K(0x1000) + #[inline] + pub fn is_huge(&self) -> bool { + return self.flags().contains(PTEFlags::V) + && (self.flags().contains(PTEFlags::R) + || self.flags().contains(PTEFlags::W) + || self.flags().contains(PTEFlags::X)); + } + + #[inline] + pub fn is_leaf(&self) -> bool { + return self.flags().contains(PTEFlags::V) + && !(self.flags().contains(PTEFlags::R) + || self.flags().contains(PTEFlags::W) + || self.flags().contains(PTEFlags::X)); + } +} + +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct PTEFlags: u64 { + const NONE = 0; + const V = 1 << 0; + const R = 1 << 1; + const W = 1 << 2; + const X = 1 << 3; + const U = 1 << 4; + const G = 1 << 5; + const A = 1 << 6; + const D = 1 << 7; + + #[cfg(c906)] + const SO = 1 << 63; + #[cfg(c906)] + const C = 1 << 62; + #[cfg(c906)] + const B = 1 << 61; + #[cfg(c906)] + const K = 1 << 60; + #[cfg(c906)] + const SE = 1 << 59; + + const VRWX = Self::V.bits() | Self::R.bits() | Self::W.bits() | Self::X.bits(); + const ADUVRX = Self::A.bits() | Self::D.bits() | Self::U.bits() | Self::V.bits() | Self::R.bits() | Self::X.bits(); + const ADVRWX = Self::A.bits() | Self::D.bits() | Self::VRWX.bits(); + const ADGVRWX = Self::G.bits() | Self::ADVRWX.bits(); + } +} + +impl From for PTEFlags { + fn from(flags: MappingFlags) -> Self { + if flags == MappingFlags::None { + Self::NONE + } else { + let mut res = Self::V; + if flags.contains(MappingFlags::R) { + res |= PTEFlags::R; + } + if flags.contains(MappingFlags::W) { + res |= PTEFlags::W; + } + if flags.contains(MappingFlags::X) { + res |= PTEFlags::X; + } + if flags.contains(MappingFlags::U) { + res |= PTEFlags::U; + } + if flags.contains(MappingFlags::A) { + res |= PTEFlags::A; + } + if flags.contains(MappingFlags::D) { + res |= PTEFlags::D; + } + res + } + } +} + +#[inline] +pub fn get_pte_list(paddr: PhysAddr) -> &'static mut [PTE] { + unsafe { core::slice::from_raw_parts_mut(paddr.get_mut_ptr::(), PAGE_ITEM_COUNT) } +} + +#[derive(Debug)] +pub struct PageTable(pub(crate) PhysAddr); + +impl PageTable { + pub fn alloc() -> Arc { + let addr = ArchInterface::frame_alloc_persist().into(); + let page_table = Self(addr); + page_table.restore(); + Arc::new(page_table) + } + + #[inline] + pub fn restore(&self) { + let arr = get_pte_list(self.0); + arr[0x100] = PTE::from_addr(0x0000_0000, PTEFlags::ADGVRWX); + arr[0x101] = PTE::from_addr(0x4000_0000, PTEFlags::ADGVRWX); + arr[0x102] = PTE::from_addr(0x8000_0000, PTEFlags::ADGVRWX); + arr[0x104] = PTE::from_addr(get_trx_mapping(), PTEFlags::V); + arr[0x106] = PTE::from_addr(0x8000_0000, PTEFlags::ADGVRWX); + arr[0..0x100].fill(PTE::from_addr(0, PTEFlags::NONE)); + } + + #[inline] + pub const fn get_satp(&self) -> usize { + (8 << 60) | (self.0 .0 >> 12) + } + + #[inline] + pub fn change(&self) { + unsafe { + asm!("csrw satp, {0}", in(reg) self.get_satp()); + riscv::asm::sfence_vma_all(); + } + } + + #[inline] + pub fn map(&self, ppn: PhysPage, vpn: VirtPage, flags: MappingFlags, level: usize) { + // TODO: Add huge page support. + let mut pte_list = get_pte_list(self.0); + for i in (1..level).rev() { + let value = (vpn.0 >> 9 * i) & 0x1ff; + let pte = &mut pte_list[value]; + if i == 0 { + break; + } + if !pte.is_valid() { + *pte = PTE::from_ppn(ArchInterface::frame_alloc_persist().0, PTEFlags::V); + } + + // page_table = PageTable(pte.to_ppn().into()); + pte_list = get_pte_list(pte.to_ppn().into()); + } + + pte_list[vpn.0 & 0x1ff] = PTE::from_ppn(ppn.0, flags.into()); + unsafe { + sfence_vma(vpn.to_addr(), 0); + } + } + + #[inline] + pub fn unmap(&self, vpn: VirtPage) { + // TODO: Add huge page support. + let mut pte_list = get_pte_list(self.0); + for i in (1..3).rev() { + let value = (vpn.0 >> 9 * i) & 0x1ff; + let pte = &mut pte_list[value]; + if !pte.is_valid() { + return; + } + pte_list = get_pte_list(pte.to_ppn().into()); + } + + pte_list[vpn.0 & 0x1ff] = PTE::new(); + unsafe { + sfence_vma(vpn.to_addr(), 0); + } + } + + #[inline] + pub fn virt_to_phys(&self, vaddr: VirtAddr) -> Option { + let mut paddr = self.0; + for i in (0..3).rev() { + let value = (vaddr.0 >> 12 + 9 * i) & 0x1ff; + let pte = &get_pte_list(paddr)[value]; + // 如果当前页是大页 返回相关的位置 + // vaddr.0 % (1 << (12 + 9 * i)) 是大页内偏移 + if !pte.flags().contains(PTEFlags::V) { + return None; + } + if pte.is_huge() { + return Some(PhysAddr( + pte.to_ppn().0 << 12 | vaddr.0 % (1 << (12 + 9 * i)), + )); + } + paddr = pte.to_ppn().into() + } + Some(PhysAddr(paddr.0 | vaddr.0 % PAGE_SIZE)) + } +} + +impl Drop for PageTable { + fn drop(&mut self) { + for root_pte in get_pte_list(self.0)[..0x100].iter().filter(|x| x.is_leaf()) { + get_pte_list(root_pte.to_ppn().into()) + .iter() + .filter(|x| x.is_leaf()) + .for_each(|x| ArchInterface::frame_unalloc(x.to_ppn())); + ArchInterface::frame_unalloc(root_pte.to_ppn()); + } + ArchInterface::frame_unalloc(self.0.into()); + } +} diff --git a/crates/hal/src/riscv64/sbi.rs b/crates/hal/src/riscv64/sbi.rs new file mode 100644 index 0000000000..2beea9de39 --- /dev/null +++ b/crates/hal/src/riscv64/sbi.rs @@ -0,0 +1,58 @@ +//! 调用 Machine 层的操作 +// 目前还不会用到全部的 SBI 调用,暂时允许未使用的变量或函数 +#![allow(unused)] + +use core::arch::asm; + +const SBI_SET_TIMER: usize = 0; +const SBI_CONSOLE_PUT_CHAR: usize = 1; +const SBI_CONSOLE_GET_CHAR: usize = 2; +const SBI_CLEAR_IPI: usize = 3; +const SBI_SEND_IPI: usize = 4; +const SBI_REMOTE_FENCE_I: usize = 5; +const SBI_REMOTE_SFENCE_VMA: usize = 6; +const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; +const SBI_SHUTDOWN: usize = 8; + +// SBI 调用 +fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { + let mut ret; + unsafe { + asm!("ecall", + in("a7") which, + inlateout("a0") arg0 => ret, + in("a1") arg1, + in("a2") arg2); + } + ret +} + +/// 设置定时器 +#[inline] +pub fn set_timer(time: usize) { + sbi_call(SBI_SET_TIMER, time, 0, 0); +} + +/// 输出一个字符到屏幕 +#[inline] +pub fn console_putchar(ch: u8) { + sbi_call(SBI_CONSOLE_PUT_CHAR, ch as usize, 0, 0); +} + +/// 获取输入 +#[inline] +pub fn console_getchar() -> Option { + let c = sbi_call(SBI_CONSOLE_GET_CHAR, 0, 0, 0) as u8; + if c == u8::MAX { + None + } else { + Some(c) + } +} + +/// 调用 SBI_SHUTDOWN 来关闭操作系统(直接退出 QEMU) +#[inline] +pub fn shutdown() -> ! { + sbi_call(SBI_SHUTDOWN, 0, 0, 0); + unreachable!() +} diff --git a/crates/hal/src/riscv64/timer.rs b/crates/hal/src/riscv64/timer.rs new file mode 100644 index 0000000000..9909795686 --- /dev/null +++ b/crates/hal/src/riscv64/timer.rs @@ -0,0 +1,40 @@ +use riscv::register::{sie, time}; + +use crate::set_timer; + +pub use crate::riscv64::boards::CLOCK_FREQ; +const TICKS_PER_SEC: usize = 100; +#[allow(dead_code)] +const MSEC_PER_SEC: usize = 1000; +const USEC_PER_SEC: usize = 1000_000; +const NSEC_PER_SEC: usize = 1000_000_000; + +#[inline] +pub fn get_time() -> usize { + time::read() +} + +#[inline] +pub fn time_to_usec(t: usize) -> usize { + t / (CLOCK_FREQ / USEC_PER_SEC) +} + +#[inline] +pub fn time_to_nsec(t: usize) -> usize { + t * NSEC_PER_SEC / CLOCK_FREQ +} + +// 设置下一次时钟中断触发时间 +#[inline] +pub fn set_next_timeout() { + // 调用sbi设置定时器 + set_timer(time::read() + CLOCK_FREQ / TICKS_PER_SEC); +} + +pub fn init() { + unsafe { + sie::set_stimer(); + } + set_next_timeout(); + info!("initialize timer interrupt"); +} diff --git a/crates/hal/src/x86_64/apic.rs b/crates/hal/src/x86_64/apic.rs new file mode 100644 index 0000000000..04cb4a4852 --- /dev/null +++ b/crates/hal/src/x86_64/apic.rs @@ -0,0 +1,114 @@ +#![allow(dead_code)] + +use irq_safety::MutexIrqSafe; +use spin::Once; +use x2apic::ioapic::IoApic; +use x2apic::lapic::{xapic_base, LocalApic, LocalApicBuilder}; +use x86_64::instructions::port::Port; + +use self::vectors::*; +use crate::VIRT_ADDR_START; + +pub(super) mod vectors { + pub const APIC_TIMER_VECTOR: u8 = 0xf0; + pub const APIC_SPURIOUS_VECTOR: u8 = 0xf1; + pub const APIC_ERROR_VECTOR: u8 = 0xf2; +} + +/// The maximum number of IRQs. +pub const MAX_IRQ_COUNT: usize = 256; + +/// The timer IRQ number. +pub const TIMER_IRQ_NUM: usize = APIC_TIMER_VECTOR as usize; + +const IO_APIC_BASE: u64 = 0xFEC0_0000; + +static mut LOCAL_APIC: Option = None; +static mut IS_X2APIC: bool = false; +static IO_APIC: Once> = Once::new(); + +/// Enables or disables the given IRQ. +pub fn set_enable(vector: usize, enabled: bool) { + // should not affect LAPIC interrupts + if vector < APIC_TIMER_VECTOR as _ { + unsafe { + if enabled { + IO_APIC.get_unchecked().lock().enable_irq(vector as u8); + } else { + IO_APIC.get_unchecked().lock().disable_irq(vector as u8); + } + } + } +} + +/// 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: crate::irq::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); +// unsafe { local_apic().end_of_interrupt() }; +// } + +pub(super) fn local_apic<'a>() -> &'a mut LocalApic { + // It's safe as LAPIC is per-cpu. + unsafe { LOCAL_APIC.as_mut().unwrap() } +} + +pub(super) fn raw_apic_id(id_u8: u8) -> u32 { + if unsafe { IS_X2APIC } { + id_u8 as u32 + } else { + (id_u8 as u32) << 24 + } +} + +fn cpu_has_x2apic() -> bool { + match raw_cpuid::CpuId::new().get_feature_info() { + Some(finfo) => finfo.has_x2apic(), + None => false, + } +} + +pub(super) fn init() { + info!("Initialize Local APIC..."); + + unsafe { + // Disable 8259A interrupt controllers + Port::::new(0x21).write(0xff); + Port::::new(0xA1).write(0xff); + } + + let mut builder = LocalApicBuilder::new(); + builder + .timer_vector(APIC_TIMER_VECTOR as _) + .error_vector(APIC_ERROR_VECTOR as _) + .spurious_vector(APIC_SPURIOUS_VECTOR as _); + + if cpu_has_x2apic() { + info!("Using x2APIC."); + unsafe { IS_X2APIC = true }; + } else { + info!("Using xAPIC."); + builder.set_xapic_base(unsafe { xapic_base() } | VIRT_ADDR_START as u64); + } + + let mut lapic = builder.build().unwrap(); + unsafe { + lapic.enable(); + LOCAL_APIC = Some(lapic); + } + + info!("Initialize IO APIC..."); + let io_apic = unsafe { IoApic::new(IO_APIC_BASE) }; + IO_APIC.call_once(|| MutexIrqSafe::new(io_apic)); +} diff --git a/crates/hal/src/x86_64/consts.rs b/crates/hal/src/x86_64/consts.rs new file mode 100644 index 0000000000..18a0296c05 --- /dev/null +++ b/crates/hal/src/x86_64/consts.rs @@ -0,0 +1,7 @@ +pub const VIRT_ADDR_START: usize = 0xffff_ff80_0000_0000; +pub const USER_ADDR_MAX: usize = 0xbf_ffff_ffff; +pub const PAGE_SIZE: usize = 4096; +pub const PAGE_ITEM_COUNT: usize = 512; +pub const SIG_RETURN_ADDR: usize = 0xFFFF_FF80_0000_0000; + +pub const SYSCALL_VECTOR: usize = 0x33445566; diff --git a/crates/hal/src/x86_64/context.rs b/crates/hal/src/x86_64/context.rs new file mode 100644 index 0000000000..2bc1e8aef0 --- /dev/null +++ b/crates/hal/src/x86_64/context.rs @@ -0,0 +1,242 @@ +use core::{ + fmt::Debug, + ops::{Index, IndexMut}, +}; + +use x86_64::registers::rflags::RFlags; + +use crate::ContextArgs; + +use super::gdt::GdtStruct; + +#[repr(C, align(16))] +#[derive(Clone)] +pub struct FxsaveArea { + pub fcw: u16, + pub fsw: u16, + pub ftw: u16, + pub fop: u16, + pub fip: u64, + pub fdp: u64, + pub mxcsr: u32, + pub mxcsr_mask: u32, + pub st: [u64; 16], + pub xmm: [u64; 32], + _padding: [u64; 12], +} + +impl FxsaveArea { + #[inline] + pub(crate) fn save(&mut self) { + unsafe { core::arch::x86_64::_fxsave64(self as *mut _ as *mut u8) } + } + + #[inline] + pub(crate) fn restore(&self) { + unsafe { core::arch::x86_64::_fxrstor64(self as *const _ as *const u8) } + } +} + +impl Default for FxsaveArea { + fn default() -> Self { + let mut area: FxsaveArea = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; + area.fcw = 0x37f; + area.ftw = 0xffff; + area.mxcsr = 0x1f80; + area + } +} + +impl Debug for FxsaveArea { + fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + Ok(()) + } +} + +/// Saved registers when a trap (interrupt or exception) occurs. +/// This is need be align 16, because tss trap ptr should be align 16? I think it is. +#[allow(missing_docs)] +#[repr(C, align(16))] +#[derive(Debug, Default, Clone)] +pub struct Context { + pub rax: usize, + pub rcx: usize, + pub rdx: usize, + pub rbx: usize, + pub rbp: usize, + pub rsi: usize, + pub rdi: usize, + pub r8: usize, + pub r9: usize, + pub r10: usize, + pub r11: usize, + pub r12: usize, + pub r13: usize, + pub r14: usize, + pub r15: usize, + + pub fs_base: usize, + pub gs_base: usize, + + // Pushed by `trap.S` + pub vector: usize, + pub error_code: usize, + + // Pushed by CPU + pub rip: usize, + pub cs: usize, + pub rflags: usize, + pub rsp: usize, + pub ss: usize, + + // save fx area + pub fx_area: FxsaveArea, +} + +impl Context { + // 创建上下文信息 + #[inline] + pub fn new() -> Self { + debug!( + "new_user cs: {:#x}, ss: {:#x}", + GdtStruct::UCODE64_SELECTOR.0, + GdtStruct::UDATA_SELECTOR.0 + ); + Self { + cs: GdtStruct::UCODE64_SELECTOR.0 as _, + ss: GdtStruct::UDATA_SELECTOR.0 as _, + rflags: RFlags::INTERRUPT_FLAG.bits() as _, + ..Default::default() + } + } +} + +impl Context { + #[inline] + pub fn args(&self) -> [usize; 6] { + [self.rdi, self.rsi, self.rdx, self.r10, self.r8, self.r9] + } + + #[inline] + pub fn syscall_ok(&mut self) { + // self.sepc += 4; + } +} + +// impl ContextOps for Context { +// #[inline] +// fn set_sp(&mut self, sp: usize) { +// self.rsp = sp; +// } + +// #[inline] +// fn sp(&self) -> usize { +// self.rsp +// } +// #[inline] +// fn set_ra(&mut self, ra: usize) { +// warn!("set_ra in x86_64 is push return address to rsp, shoule be execute at end"); +// self.rsp -= 8; +// unsafe { +// *(self.rsp as *mut usize) = ra; +// } +// // unimplemented!("set ra in x86_64 is not implemented") +// } + +// #[inline] +// fn ra(&self) -> usize { +// unimplemented!("get ra in x86_64 is not implemented") +// } + +// #[inline] +// fn set_sepc(&mut self, sepc: usize) { +// self.rip = sepc; +// } + +// #[inline] +// fn sepc(&self) -> usize { +// self.rip +// } + +// #[inline] +// fn syscall_number(&self) -> usize { +// self.rax +// } + +// #[inline] +// fn args(&self) -> [usize; 6] { +// [self.rdi, self.rsi, self.rdx, self.r10, self.r8, self.r9] +// } + +// #[inline] +// fn syscall_ok(&mut self) { +// // self.sepc += 4; +// } + +// fn set_ret(&mut self, ret: usize) { +// self.rax = ret; +// } + +// fn set_arg0(&mut self, ret: usize) { +// self.rdi = ret; +// } + +// fn set_arg1(&mut self, ret: usize) { +// self.rsi = ret; +// } + +// fn set_arg2(&mut self, ret: usize) { +// self.rdx = ret; +// } + +// #[inline] +// fn set_tls(&mut self, tls: usize) { +// self.fs_base = tls; +// } +// } + +impl Context { + #[inline] + pub fn is_user(&self) -> bool { + self.cs == GdtStruct::UCODE64_SELECTOR.0 as _ + } +} + +impl Index for Context { + type Output = usize; + + fn index(&self, index: ContextArgs) -> &Self::Output { + match index { + ContextArgs::SEPC => &self.rip, + ContextArgs::RA => unimplemented!("Can't get return address in x86_64"), + ContextArgs::ARG0 => &self.rdi, + ContextArgs::ARG1 => &self.rsi, + ContextArgs::ARG2 => &self.rdx, + ContextArgs::TLS => &self.fs_base, + ContextArgs::SP => &self.rsp, + ContextArgs::RET => &self.rax, + ContextArgs::SYSCALL => &self.rax, + } + } +} + +impl IndexMut for Context { + fn index_mut(&mut self, index: ContextArgs) -> &mut Self::Output { + match index { + ContextArgs::SEPC => &mut self.rip, + ContextArgs::RA => { + // set return address, at x86_64 is push return address to rsp, shoule be execute at end. + warn!("set_ra in x86_64 is push return address to rsp, shoule be execute at end"); + self.rsp -= 8; + unsafe { (self.rsp as *mut usize).as_mut().unwrap() } + } + ContextArgs::ARG0 => &mut self.rdi, + ContextArgs::ARG1 => &mut self.rsi, + ContextArgs::ARG2 => &mut self.rdx, + ContextArgs::TLS => &mut self.fs_base, + ContextArgs::SP => &mut self.rsp, + ContextArgs::RET => &mut self.rax, + ContextArgs::SYSCALL => unreachable!("can't set syscall number"), + } + } +} diff --git a/crates/hal/src/x86_64/gdt.rs b/crates/hal/src/x86_64/gdt.rs new file mode 100644 index 0000000000..306c48cc5d --- /dev/null +++ b/crates/hal/src/x86_64/gdt.rs @@ -0,0 +1,117 @@ +use core::fmt; + +use spin::Once; +use x86_64::instructions::tables::{lgdt, load_tss}; +use x86_64::registers::segmentation::{Segment, SegmentSelector, CS}; +use x86_64::structures::gdt::{Descriptor, DescriptorFlags}; +use x86_64::structures::{tss::TaskStateSegment, DescriptorTablePointer}; +use x86_64::{addr::VirtAddr, PrivilegeLevel}; + +#[percpu::def_percpu] +pub(super) static GDT: Once = Once::new(); + +#[percpu::def_percpu] +pub(super) static TSS: Once = Once::new(); + +/// A wrapper of the Global Descriptor Table (GDT) with maximum 16 entries. +#[repr(align(16))] +pub struct GdtStruct { + table: [u64; 16], +} + +#[allow(dead_code)] +impl GdtStruct { + /// Kernel code segment for 32-bit mode. + pub const KCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0); + /// Kernel code segment for 64-bit mode. + pub const KCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring0); + /// Kernel data segment. + pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0); + /// User code segment for 32-bit mode. + pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3); + /// User data segment. + pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3); + /// User code segment for 64-bit mode. + pub const UCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring3); + /// TSS segment. + pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(7, PrivilegeLevel::Ring0); + + /// Constructs a new GDT struct that filled with the default segment + /// descriptors, including the given TSS segment. + pub fn new(tss: &'static TaskStateSegment) -> Self { + let mut table = [0; 16]; + // first 3 entries are the same as in multiboot.S + table[1] = DescriptorFlags::KERNEL_CODE32.bits(); // 0x00cf9b000000ffff + table[2] = DescriptorFlags::KERNEL_CODE64.bits(); // 0x00af9b000000ffff + table[3] = DescriptorFlags::KERNEL_DATA.bits(); // 0x00cf93000000ffff + table[4] = DescriptorFlags::USER_CODE32.bits(); // 0x00cffb000000ffff + table[5] = DescriptorFlags::USER_DATA.bits(); // 0x00cff3000000ffff + table[6] = DescriptorFlags::USER_CODE64.bits(); // 0x00affb000000ffff + if let Descriptor::SystemSegment(low, high) = Descriptor::tss_segment(tss) { + table[7] = low; + table[8] = high; + } + Self { table } + } + + /// Returns the GDT pointer (base and limit) that can be used in `lgdt` + /// instruction. + pub fn pointer(&self) -> DescriptorTablePointer { + DescriptorTablePointer { + base: VirtAddr::new(self.table.as_ptr() as u64), + limit: (core::mem::size_of_val(&self.table) - 1) as u16, + } + } + + /// Loads the GDT into the CPU (executes the `lgdt` instruction), and + /// updates the code segment register (`CS`). + /// + /// # Safety + /// + /// This function is unsafe because it manipulates the CPU's privileged + /// states. + pub unsafe fn load(&'static self) { + lgdt(&self.pointer()); + CS::set_reg(Self::KCODE64_SELECTOR); + } + + /// Loads the TSS into the CPU (executes the `ltr` instruction). + /// + /// # Safety + /// + /// This function is unsafe because it manipulates the CPU's privileged + /// states. + pub unsafe fn load_tss(&'static self) { + load_tss(Self::TSS_SELECTOR); + } +} + +impl fmt::Debug for GdtStruct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("GdtStruct") + .field("pointer", &self.pointer()) + .field("table", &self.table) + .finish() + } +} + +pub fn init() { + unsafe { + let tss = TSS.current_ref_raw(); + let gdt = GDT.current_ref_mut_raw(); + tss.call_once(|| TaskStateSegment::new()); + gdt.call_once(|| GdtStruct::new(tss.get_unchecked())); + let gdt = gdt.get_unchecked(); + gdt.load(); + gdt.load_tss(); + } +} + +#[inline] +pub fn set_tss_kernel_sp(addr: usize) { + unsafe { + TSS.with_current(|tss| { + tss.get_mut_unchecked().privilege_stack_table[0] = VirtAddr::new(addr as _); + }); + } +} diff --git a/crates/hal/src/x86_64/idt.rs b/crates/hal/src/x86_64/idt.rs new file mode 100644 index 0000000000..071ea378f7 --- /dev/null +++ b/crates/hal/src/x86_64/idt.rs @@ -0,0 +1,53 @@ +use spin::Once; +use x86_64::structures::idt::{Entry, HandlerFunc, InterruptDescriptorTable}; + +const NUM_INT: usize = 256; + +pub(super) static IDT: Once = Once::new(); + +/// A wrapper of the Interrupt Descriptor Table (IDT). +#[repr(transparent)] +pub struct IdtStruct(InterruptDescriptorTable); + +impl IdtStruct { + /// Constructs a new IDT struct that filled with entries from + /// `trap_handler_table`. + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + extern "C" { + #[link_name = "trap_handler_table"] + static ENTRIES: [extern "C" fn(); NUM_INT]; + } + let mut idt = Self(InterruptDescriptorTable::new()); + + let entries = unsafe { + core::slice::from_raw_parts_mut( + &mut idt.0 as *mut _ as *mut Entry, + NUM_INT, + ) + }; + for i in 0..NUM_INT { + entries[i].set_handler_fn(unsafe { core::mem::transmute(ENTRIES[i]) }); + } + idt + } + + /// Loads the IDT into the CPU (executes the `lidt` instruction). + /// + /// # Safety + /// + /// This function is unsafe because it manipulates the CPU's privileged + /// states. + pub unsafe fn load(&'static self) { + self.0.load(); + } +} + +pub fn init() { + info!("Initializing IDT..."); + let idt = IdtStruct::new(); + IDT.call_once(|| idt); + unsafe { + IDT.get().unwrap().load(); + } +} diff --git a/crates/hal/src/x86_64/interrupt.rs b/crates/hal/src/x86_64/interrupt.rs new file mode 100644 index 0000000000..8af2b4508a --- /dev/null +++ b/crates/hal/src/x86_64/interrupt.rs @@ -0,0 +1,427 @@ +use core::arch::{asm, global_asm}; +use core::mem::size_of; + +use bitflags::bitflags; +use x86_64::registers::model_specific::{Efer, EferFlags, KernelGsBase, LStar, SFMask, Star}; +use x86_64::registers::rflags::RFlags; +use x86_64::VirtAddr; + +use x86::{controlregs::cr2, irq::*}; + +use crate::x86_64::gdt::set_tss_kernel_sp; +use crate::{x86_64::gdt::GdtStruct, Context, TrapType}; +use crate::{ArchInterface, CONTEXT_SIZE, SYSCALL_VECTOR}; + +use super::apic::vectors::APIC_TIMER_VECTOR; +use super::context::FxsaveArea; +use super::time::ticks_to_nanos; + +global_asm!( + r" + .altmacro + .macro LOAD reg, offset + ld \reg, \offset*8(sp) + .endm + + .macro SAVE reg, offset + sd \reg, \offset*8(sp) + .endm + + .macro LOAD_N n + ld x\n, \n*8(sp) + .endm + + .macro SAVE_N n + sd x\n, \n*8(sp) + .endm + + .macro SAVE_TP_N n + sd x\n, \n*8(tp) + .endm +" +); + +global_asm!(include_str!("trap.S")); + +#[no_mangle] +#[percpu::def_percpu] +static USER_RSP: usize = 0; + +#[no_mangle] +#[percpu::def_percpu] +static KERNEL_RSP: usize = 0; + +#[no_mangle] +#[percpu::def_percpu] +static USER_CONTEXT: usize = 0; + +bitflags! { + // https://wiki.osdev.org/Exceptions#Page_Fault + #[derive(Debug)] + struct PageFaultFlags: u32 { + const P = 1; + const W = 1 << 1; + const U = 1 << 2; + const R = 1 << 3; + const I = 1 << 4; + const PK = 1 << 5; + const SS = 1 << 6; + const SGX = 1 << 15; + } +} + +// 内核中断回调 +#[no_mangle] +fn kernel_callback(context: &mut Context) { + let trap_type = match context.vector as u8 { + PAGE_FAULT_VECTOR => { + let pflags = PageFaultFlags::from_bits_truncate(context.rflags as _); + // debug!("flags: {:#x?} cx_ref: {:#x?}", pflags, context); + if pflags.contains(PageFaultFlags::I) { + TrapType::InstructionPageFault(unsafe { cr2() }) + } else if pflags.contains(PageFaultFlags::W) { + TrapType::StorePageFault(unsafe { cr2() }) + } else { + TrapType::LoadPageFault(unsafe { cr2() }) + } + } + BREAKPOINT_VECTOR => { + debug!("#BP @ {:#x} ", context.rip); + TrapType::Breakpoint + } + GENERAL_PROTECTION_FAULT_VECTOR => { + panic!( + "#GP @ {:#x}, fault_vaddr={:#x} error_code={:#x}:\n{:#x?}", + context.rip, + unsafe { cr2() }, + context.error_code, + context + ); + } + APIC_TIMER_VECTOR => TrapType::Time, + // IRQ_VECTOR_START..=IRQ_VECTOR_END => crate::trap::handle_irq_extern(tf.vector as _), + _ => { + panic!( + "Unhandled exception {} (error_code = {:#x}) @ {:#x}:\n{:#x?}", + context.vector, context.error_code, context.rip, context + ); + } + }; + ArchInterface::kernel_interrupt(context, trap_type); + unsafe { super::apic::local_apic().end_of_interrupt() }; +} + +#[naked] +#[no_mangle] +pub unsafe extern "C" fn kernelvec() { + asm!( + r" + sub rsp, 16 # push fs_base, gs_base + + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rdi + push rsi + push rbp + push rbx + push rdx + push rcx + push rax + + mov rdi, rsp + call {trap_handler} + + pop rax + pop rcx + pop rdx + pop rbx + pop rbp + pop rsi + pop rdi + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + add rsp, 32 # pop fs_base, gs_base, vector, error_code + iretq + ", + trap_handler = sym kernel_callback, + options(noreturn) + ) +} + +#[naked] +#[no_mangle] +pub unsafe extern "C" fn uservec() { + asm!( + r" + sub rsp, 16 + + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rdi + push rsi + push rbp + push rbx + push rdx + push rcx + push rax + + swapgs + + mov rdi, rsp + mov rsp, gs:[offset __PERCPU_KERNEL_RSP] // kernel rsp + + pop r15 + pop r14 + pop r13 + pop r12 + pop rbx + pop rbp + pop rax + + mov ecx, 0xC0000100 + mov rdx, rax + shr rdx, 32 + wrmsr # pop fsbase + + ret + ", + options(noreturn) + ); +} + +#[naked] +#[no_mangle] +pub extern "C" fn user_restore(context: *mut Context) { + unsafe { + asm!( + // Save callee saved registers and cs and others. + r" + mov ecx, 0xC0000100 + rdmsr + shl rdx, 32 + or rax, rdx + push rax # push fsbase + + push rbp + push rbx + push r12 + push r13 + push r14 + push r15 + + mov gs:[offset __PERCPU_KERNEL_RSP], rsp + ", + // Write fs_base and gs_base + " + mov ecx, 0xC0000100 + mov edx, [rdi + 15*8+4] + mov eax, [rdi + 15*8] + wrmsr # pop fsbase + mov ecx, 0xC0000102 + mov edx, [rdi + 16*8+4] + mov eax, [rdi + 16*8] + wrmsr # pop gsbase to kernel_gsbase + ", + // push fs_base + " + mov rsp, rdi + pop rax + pop rcx + pop rdx + pop rbx + pop rbp + pop rsi + pop rdi + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + add rsp, 32 # pop fs_base,gs_base,vector,error_code + cmp DWORD PTR [rsp - 8*2], {syscall_vector} + je {sysretq} + + swapgs + iretq + ", + syscall_vector = const SYSCALL_VECTOR, + sysretq = sym sysretq, + options(noreturn) + ) + } +} + +#[naked] +unsafe extern "C" fn sysretq() { + asm!( + " + pop rcx + add rsp, 8 + pop r11 + pop rsp + swapgs + + sysretq + ", + options(noreturn) + ) +} + +pub fn init_syscall() { + LStar::write(VirtAddr::new(syscall_entry as usize as _)); + Star::write( + GdtStruct::UCODE64_SELECTOR, + GdtStruct::UDATA_SELECTOR, + GdtStruct::KCODE64_SELECTOR, + GdtStruct::KDATA_SELECTOR, + ) + .unwrap(); + SFMask::write( + RFlags::TRAP_FLAG + | RFlags::INTERRUPT_FLAG + | RFlags::DIRECTION_FLAG + | RFlags::IOPL_LOW + | RFlags::IOPL_HIGH + | RFlags::NESTED_TASK + | RFlags::ALIGNMENT_CHECK, + ); // TF | IF | DF | IOPL | AC | NT (0x47700) + unsafe { + Efer::update(|efer| *efer |= EferFlags::SYSTEM_CALL_EXTENSIONS); + } + KernelGsBase::write(VirtAddr::new(0)); +} + +#[naked] +unsafe extern "C" fn syscall_entry() { + asm!( + r" + swapgs + mov gs:[offset __PERCPU_USER_RSP], rsp + mov rsp, gs:[offset __PERCPU_USER_CONTEXT] + + sub rsp, 8 // skip user_ss + push gs:[offset __PERCPU_USER_RSP] // user_rsp + push r11 // rflags + mov [rsp - 2 * 8], rcx // rip + mov r11, {syscall_vector} + mov [rsp - 4 * 8], r11 // vector + sub rsp, 6 * 8 // skip until general registers + + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rdi + push rsi + push rbp + push rbx + push rdx + push rcx + push rax + + mov ecx, 0xC0000100 + rdmsr + mov [rsp + 15*8+4], edx + mov [rsp + 15*8], eax # push fabase + + mov ecx, 0xC0000102 + rdmsr + mov [rsp + 16*8+4], edx + mov [rsp + 16*8], eax # push gs_base + + mov rsp, gs:[offset __PERCPU_KERNEL_RSP] // kernel rsp + pop r15 + pop r14 + pop r13 + pop r12 + pop rbx + pop rbp + pop rax + + mov ecx, 0xC0000100 + mov rdx, rax + shr rdx, 32 + wrmsr # pop fsbase + ret + ", + syscall_vector = const SYSCALL_VECTOR, + options(noreturn) + ) +} + +/// Return Some(()) if it was interrupt by syscall, otherwise None. +pub fn run_user_task(context: &mut Context) -> Option<()> { + // TODO: set tss kernel sp just once, before task run. + let cx_general_top = context as *mut Context as usize + CONTEXT_SIZE - size_of::(); + set_tss_kernel_sp(cx_general_top); + USER_CONTEXT.write_current(cx_general_top); + context.fx_area.restore(); + user_restore(context); + context.fx_area.save(); + + match context.vector { + SYSCALL_VECTOR => Some(()), + _ => { + kernel_callback(context); + None + } + } +} + +#[allow(dead_code)] +#[inline(always)] +pub fn enable_irq() { + unsafe { asm!("sti") } +} + +pub fn close_irq() { + unsafe { asm!("cli") } +} + +#[inline(always)] +pub fn enable_external_irq() { + // unsafe { + + // } +} + +pub fn init_interrupt() { + // Test break point. + unsafe { core::arch::asm!("int 3") } + enable_irq() +} + +pub fn time_to_usec(ticks: usize) -> usize { + (ticks_to_nanos(ticks as _) / 1000) as _ +} + +pub fn get_time() -> usize { + unsafe { core::arch::x86_64::_rdtsc() as _ } +} diff --git a/crates/hal/src/x86_64/mod.rs b/crates/hal/src/x86_64/mod.rs new file mode 100644 index 0000000000..1ad4a20536 --- /dev/null +++ b/crates/hal/src/x86_64/mod.rs @@ -0,0 +1,119 @@ +mod apic; +mod consts; +mod context; +mod gdt; +mod idt; +mod interrupt; +mod multiboot; +mod page_table; +mod sigtrx; +mod time; +mod uart; + +use ::multiboot::information::MemoryType; +pub use consts::*; +pub use context::Context; +pub use interrupt::*; +pub use multiboot::switch_to_kernel_page_table; +pub use page_table::*; +use raw_cpuid::CpuId; +pub use uart::*; + +use x86::tlb; +use x86_64::{ + instructions::port::PortWriteOnly, + registers::{ + control::{Cr4, Cr4Flags}, + xcontrol::{XCr0, XCr0Flags}, + }, +}; + +use crate::{x86_64::multiboot::use_multiboot, ArchInterface, VirtAddr}; + +#[percpu::def_percpu] +static CPU_ID: usize = 1; + +pub fn shutdown() -> ! { + unsafe { PortWriteOnly::new(0x604).write(0x2000u16) }; + + loop {} +} + +fn rust_tmp_main(magic: usize, mboot_ptr: usize) { + crate::clear_bss(); + idt::init(); + apic::init(); + sigtrx::init(); + ArchInterface::init_logging(); + // Init allocator + allocator::init(); + percpu::init(1); + percpu::set_local_thread_pointer(0); + gdt::init(); + interrupt::init_syscall(); + time::init_early(); + + // enable avx extend instruction set and sse if support avx + // TIPS: QEMU not support avx, so we can't enable avx here + // IF you want to use avx in the qemu, you can use -cpu IvyBridge-v2 to + // select a cpu with avx support + CpuId::new().get_feature_info().map(|features| { + info!("is there a avx feature: {}", features.has_avx()); + info!("is there a xsave feature: {}", features.has_xsave()); + info!("cr4 has OSXSAVE feature: {:?}", Cr4::read()); + if features.has_avx() && features.has_xsave() && Cr4::read().contains(Cr4Flags::OSXSAVE) { + unsafe { + XCr0::write(XCr0::read() | XCr0Flags::AVX | XCr0Flags::SSE | XCr0Flags::X87); + } + } + }); + + info!( + "TEST CPU ID: {} ptr: {:#x}", + CPU_ID.read_current(), + unsafe { CPU_ID.current_ptr() } as usize + ); + CPU_ID.write_current(345); + info!( + "TEST CPU ID: {} ptr: {:#x}", + CPU_ID.read_current(), + unsafe { CPU_ID.current_ptr() } as usize + ); + + info!("magic: {:#x}, mboot_ptr: {:#x}", magic, mboot_ptr); + + if let Some(mboot) = use_multiboot(mboot_ptr as _) { + mboot + .boot_loader_name() + .inspect(|x| info!("bootloader: {}", x)); + mboot + .command_line() + .inspect(|x| info!("command_line: {}", x)); + if mboot.has_memory_map() { + mboot + .memory_regions() + .unwrap() + .filter(|x| x.memory_type() == MemoryType::Available) + .for_each(|x| { + let start = x.base_address() as usize | VIRT_ADDR_START; + let end = x.length() as usize | VIRT_ADDR_START; + crate::ArchInterface::add_memory_region(start, end); + }); + } + } + + ArchInterface::prepare_drivers(); + + crate::ArchInterface::main(0); + + shutdown() +} + +#[inline] +pub fn flush_tlb(vaddr: Option) { + if let Some(vaddr) = vaddr { + unsafe { tlb::flush(vaddr.into()) } + } else { + unsafe { tlb::flush_all() } + } +} diff --git a/crates/hal/src/x86_64/multiboot.S b/crates/hal/src/x86_64/multiboot.S new file mode 100644 index 0000000000..e73b35db29 --- /dev/null +++ b/crates/hal/src/x86_64/multiboot.S @@ -0,0 +1,109 @@ +# Bootstrapping from 32-bit with the Multiboot specification. +# See https://www.gnu.org/software/grub/manual/multiboot/multiboot.html + +.section .text.entry +.code32 +.global _start +_start: + mov edi, eax # arg1: magic: 0x2BADB002 + mov esi, ebx # arg2: multiboot info + jmp bsp_entry32 + +.balign 4 +.type multiboot_header, STT_OBJECT +multiboot_header: + .int {mb_hdr_magic} # magic: 0x1BADB002 + .int {mb_hdr_flags} # flags + .int -({mb_hdr_magic} + {mb_hdr_flags}) # checksum + .int multiboot_header - {offset} # header_addr + .int _skernel - {offset} # load_addr + .int _load_end - {offset} # load_end + .int end - {offset} # bss_end_addr + .int _start - {offset} # entry_addr + +# Common code in 32-bit, prepare states to enter 64-bit. +.code32 +bsp_entry32: + lgdt [.Ltmp_gdt_desc - {offset}] # load the temporary GDT + # set data segment selectors + mov ax, 0x18 + mov ss, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + # set PAE, PGE bit in CR4 + mov eax, {cr4} + mov cr4, eax + + # load the temporary page table + lea eax, [kernel_page_table - {offset}] + mov cr3, eax + + # set LME, NXE bit in IA32_EFER + mov ecx, {efer_msr} + mov edx, 0 + mov eax, {efer} + wrmsr + + # set protected mode, write protect, paging bit in CR0 + mov eax, {cr0} + mov cr0, eax + ljmp 0x10, offset bsp_entry64 - {offset} # 0x10 is code64 segment + +.code64 +bsp_entry64: + # clear segment selectors + xor ax, ax + mov ss, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + # set RSP to boot stack + movabs rsp, offset {boot_stack} + add rsp, {boot_stack_size} + + # call rust_entry(magic, mbi) + movabs rax, offset {entry} + call rax + jmp .Lhlt + +.Lhlt: + hlt + jmp .Lhlt + +.section .rodata +.balign 8 +.Ltmp_gdt_desc: + .short .Ltmp_gdt_end - .Ltmp_gdt - 1 # limit + .long .Ltmp_gdt - {offset} # base + +.section .data +.balign 16 +.Ltmp_gdt: + .quad 0x0000000000000000 # 0x00: null + .quad 0x00cf9b000000ffff # 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) + .quad 0x00af9b000000ffff # 0x10: code segment (base=0, limit=0xfffff, type=64bit code exec/read, DPL=0, 4k) + .quad 0x00cf93000000ffff # 0x18: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) +.Ltmp_gdt_end: + +.balign 4096 +.global kernel_page_table +kernel_page_table: + # 0x0000_0000 ~ 0xffff_ffff + .quad kernel_mapping_pdpt - {offset} + 0x3 # PRESENT | WRITABLE | paddr(tmp_pdpt) + .zero 8 * 510 + # 0xffff_ff80_0000_0000 ~ 0xffff_ff80_ffff_ffff + .quad kernel_mapping_pdpt - {offset} + 0x3 # PRESENT | WRITABLE | paddr(tmp_pdpt) + +.global kernel_mapping_pdpt +# FIXME: may not work on macOS using hvf as the CPU does not support 1GB page (pdpe1gb) +kernel_mapping_pdpt: + .quad 0x0000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x0) + .quad 0x40000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x4000_0000) + .quad 0x80000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0x8000_0000) + .quad 0xc0000000 | 0x83 # PRESENT | WRITABLE | HUGE_PAGE | paddr(0xc000_0000) + .zero 8 * 508 diff --git a/crates/hal/src/x86_64/multiboot.rs b/crates/hal/src/x86_64/multiboot.rs new file mode 100644 index 0000000000..5e003fd1f0 --- /dev/null +++ b/crates/hal/src/x86_64/multiboot.rs @@ -0,0 +1,89 @@ +extern crate core; + +use crate::x86_64::rust_tmp_main; +use crate::{BOOT_STACK, STACK_SIZE}; +use core::arch::global_asm; +use core::{mem, slice}; +use multiboot::information::{MemoryManagement, Multiboot, PAddr}; +use x86_64::registers::control::{Cr0Flags, Cr4Flags}; +use x86_64::registers::model_specific::EferFlags; + +use crate::VIRT_ADDR_START; + +/// Flags set in the 'flags' member of the multiboot header. +/// +/// (bits 1, 16: memory information, address fields in header) +const MULTIBOOT_HEADER_FLAGS: usize = 0x0001_0002; + +/// The magic field should contain this. +const MULTIBOOT_HEADER_MAGIC: usize = 0x1BADB002; + +const CR0: u64 = Cr0Flags::PROTECTED_MODE_ENABLE.bits() + | Cr0Flags::MONITOR_COPROCESSOR.bits() + | Cr0Flags::NUMERIC_ERROR.bits() + | Cr0Flags::WRITE_PROTECT.bits() + | Cr0Flags::PAGING.bits(); + +const CR4: u64 = Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits() + | Cr4Flags::PAGE_GLOBAL.bits() + | Cr4Flags::OSFXSR.bits() + | Cr4Flags::OSXSAVE.bits() + | Cr4Flags::OSXMMEXCPT_ENABLE.bits(); +const EFER: u64 = EferFlags::LONG_MODE_ENABLE.bits() | EferFlags::NO_EXECUTE_ENABLE.bits(); + +static mut MEM: Mem = Mem; + +struct Mem; + +impl MemoryManagement for Mem { + unsafe fn paddr_to_slice(&self, addr: PAddr, size: usize) -> Option<&'static [u8]> { + let ptr = mem::transmute(addr | VIRT_ADDR_START as u64); + Some(slice::from_raw_parts(ptr, size)) + } + + // If you only want to read fields, you can simply return `None`. + unsafe fn allocate(&mut self, _length: usize) -> Option<(PAddr, &mut [u8])> { + None + } + + unsafe fn deallocate(&mut self, addr: PAddr) { + if addr != 0 { + unimplemented!() + } + } +} + +/// mboot_ptr is the initial pointer to the multiboot structure +/// provided in %ebx on start-up. +pub fn use_multiboot(mboot_ptr: PAddr) -> Option> { + unsafe { Multiboot::from_ptr(mboot_ptr, &mut MEM) } +} + +global_asm!( + include_str!("multiboot.S"), + mb_hdr_magic = const MULTIBOOT_HEADER_MAGIC, + mb_hdr_flags = const MULTIBOOT_HEADER_FLAGS, + entry = sym rust_tmp_main, + + offset = const VIRT_ADDR_START, + boot_stack_size = const STACK_SIZE, + boot_stack = sym BOOT_STACK, + + cr0 = const CR0, + cr4 = const CR4, + efer_msr = const x86::msr::IA32_EFER, + efer = const EFER, +); + +#[no_mangle] +pub fn switch_to_kernel_page_table() { + unsafe { + core::arch::asm!( + " + lea rax, [kernel_page_table - {offset}] + mov cr3, rax + ", + offset = const VIRT_ADDR_START + ); + } +} diff --git a/crates/hal/src/x86_64/page_table.rs b/crates/hal/src/x86_64/page_table.rs new file mode 100644 index 0000000000..e8bb64c4b1 --- /dev/null +++ b/crates/hal/src/x86_64/page_table.rs @@ -0,0 +1,166 @@ +use alloc::sync::Arc; +use x86::bits64::paging::{ + pd_index, pdpt_index, pml4_index, pt_index, PDEntry, PDFlags, PDPTEntry, PDPTFlags, PML4Entry, + PML4Flags, PTEntry, PTFlags, PAGE_SIZE_ENTRIES, +}; + +use crate::{ + flush_tlb, ArchInterface, MappingFlags, PhysAddr, PhysPage, VirtAddr, VirtPage, PAGE_SIZE, + VIRT_ADDR_START, +}; + +impl From for PTFlags { + fn from(flags: MappingFlags) -> Self { + let mut res = Self::P; + if flags.contains(MappingFlags::W) { + res |= Self::RW; + } + if flags.contains(MappingFlags::U) { + res |= Self::US; + } + if flags.contains(MappingFlags::A) { + res |= Self::A; + } + if flags.contains(MappingFlags::D) { + res |= Self::D; + } + if flags.contains(MappingFlags::X) { + res.remove(Self::XD); + } + res + } +} + +#[derive(Debug)] +pub struct PageTable(pub(crate) PhysAddr); + +impl PageTable { + pub fn alloc() -> Arc { + let addr = ArchInterface::frame_alloc_persist().into(); + let page_table = Self(addr); + page_table.restore(); + Arc::new(page_table) + } + + #[inline] + pub fn restore(&self) { + let map_pd = |pd_entry: &PDEntry| { + if !pd_entry.is_present() || pd_entry.is_page() { + return; + } + PhysAddr::new(pd_entry.address().as_usize()) + .slice_mut_with_len::(PAGE_SIZE_ENTRIES) + .iter_mut() + .for_each(|x| *x = PTEntry(0)); + }; + + let map_pdpt = |pdpt_entry: &PDPTEntry| { + if !pdpt_entry.is_present() || pdpt_entry.is_page() { + return; + } + PhysAddr::new(pdpt_entry.address().as_usize()) + .slice_mut_with_len::(PAGE_SIZE_ENTRIES) + .iter() + .for_each(map_pd); + }; + + let map_pml4 = |pml4_entry: &mut PML4Entry| { + if !pml4_entry.is_present() { + return; + } + PhysAddr::new(pml4_entry.address().as_usize()) + .slice_mut_with_len::(PAGE_SIZE_ENTRIES) + .iter() + .for_each(map_pdpt); + }; + + self.0.slice_mut_with_len::(PAGE_SIZE_ENTRIES)[..0x100] + .iter_mut() + .for_each(map_pml4); + + extern "C" { + fn kernel_mapping_pdpt(); + } + let pml4 = self.0.slice_mut_with_len::(PAGE_SIZE_ENTRIES); + pml4[0x1ff] = PML4Entry((kernel_mapping_pdpt as u64 - VIRT_ADDR_START as u64) | 0x3); + // mfence(); + flush_tlb(None); + } + + #[inline] + pub fn change(&self) { + unsafe { + core::arch::asm!("mov cr3, {}", in(reg) self.0.0); + } + } + + #[inline] + pub fn get_entry(&self, vpn: VirtPage) -> &mut PTEntry { + let vaddr = vpn.to_addr().into(); + + let pml4 = self.0.slice_mut_with_len::(PAGE_SIZE_ENTRIES); + let pml4_index = pml4_index(vaddr); + if !pml4[pml4_index].is_present() { + pml4[pml4_index] = PML4Entry::new( + ArchInterface::frame_alloc_persist().to_addr().into(), + PML4Flags::P | PML4Flags::RW | PML4Flags::US, + ); + } + + let pdpt = PhysAddr::new(pml4[pml4_index].address().into()) + .slice_mut_with_len::(PAGE_SIZE_ENTRIES); + let pdpt_index = pdpt_index(vaddr); + if !pdpt[pdpt_index].is_present() { + pdpt[pdpt_index] = PDPTEntry::new( + ArchInterface::frame_alloc_persist().to_addr().into(), + PDPTFlags::P | PDPTFlags::RW | PDPTFlags::US, + ); + } + + let pd = PhysAddr::new(pdpt[pdpt_index].address().into()) + .slice_mut_with_len::(PAGE_SIZE_ENTRIES); + let pd_index = pd_index(vaddr); + if !pd[pd_index].is_present() { + pd[pd_index] = PDEntry::new( + ArchInterface::frame_alloc_persist().to_addr().into(), + PDFlags::P | PDFlags::RW | PDFlags::US, + ); + } + + let pte = PhysAddr::new(pd[pd_index].address().into()) + .slice_mut_with_len::(PAGE_SIZE_ENTRIES); + let pte_index = pt_index(vaddr); + &mut pte[pte_index] + } + + #[inline] + pub fn map(&self, ppn: PhysPage, vpn: VirtPage, flags: MappingFlags, _level: usize) { + *self.get_entry(vpn) = PTEntry::new(ppn.to_addr().into(), flags.into()); + flush_tlb(Some(vpn.into())) + } + + #[inline] + pub fn unmap(&self, vpn: VirtPage) { + *self.get_entry(vpn) = PTEntry(0); + flush_tlb(Some(vpn.into())) + } + + #[inline] + pub fn virt_to_phys(&self, vaddr: VirtAddr) -> Option { + let pte = self.get_entry(vaddr.into()); + if !pte.is_present() { + None + } else { + Some(PhysAddr::new( + pte.address().as_usize() + vaddr.0 % PAGE_SIZE, + )) + } + } +} + +impl Drop for PageTable { + fn drop(&mut self) { + self.restore(); + ArchInterface::frame_unalloc(self.0.into()); + } +} diff --git a/crates/hal/src/x86_64/sigtrx.rs b/crates/hal/src/x86_64/sigtrx.rs new file mode 100644 index 0000000000..2a432b3699 --- /dev/null +++ b/crates/hal/src/x86_64/sigtrx.rs @@ -0,0 +1,40 @@ +use x86::bits64::paging::{PDEntry, PDFlags, PTEntry, PTFlags, PAGE_SIZE_ENTRIES, PD, PT}; + +use crate::VIRT_ADDR_START; + +/// 汇编入口函数 +/// +/// 分配栈 初始化页表信息 并调到rust入口函数 +#[naked] +#[no_mangle] +#[link_section = ".sigtrx.sigreturn"] +unsafe extern "C" fn _sigreturn() -> ! { + core::arch::asm!( + // 1. 设置栈信息 + // sp = bootstack + (hartid + 1) * 0x10000 + " + mov rax, 15 + syscall + ", + options(noreturn) + ) +} + +#[link_section = ".data.prepage"] +static mut TRX_STEP1: PD = [PDEntry(0); PAGE_SIZE_ENTRIES]; + +#[link_section = ".data.prepage"] +static mut TRX_STEP2: PT = [PTEntry(0); PAGE_SIZE_ENTRIES]; + +pub fn init() { + unsafe { + TRX_STEP1[0] = PDEntry::new( + (TRX_STEP2.as_ptr() as usize & !VIRT_ADDR_START).into(), + PDFlags::P | PDFlags::RW, + ); + TRX_STEP2[0] = PTEntry::new( + (_sigreturn as usize & !VIRT_ADDR_START).into(), + PTFlags::P | PTFlags::US, + ); + } +} diff --git a/crates/hal/src/x86_64/time.rs b/crates/hal/src/x86_64/time.rs new file mode 100644 index 0000000000..e5d1d5b725 --- /dev/null +++ b/crates/hal/src/x86_64/time.rs @@ -0,0 +1,39 @@ +use raw_cpuid::CpuId; + +static mut INIT_TICK: u64 = 0; +static mut CPU_FREQ_MHZ: u64 = 4000; + +/// Converts hardware ticks to nanoseconds. +pub fn ticks_to_nanos(ticks: u64) -> u64 { + ticks * 1_000 / unsafe { CPU_FREQ_MHZ } +} + +pub(super) fn init_early() { + info!("freq1: {:#x?}", CpuId::new().get_tsc_info()); + debug!("cpuid: {:#x?}", CpuId::new().get_vendor_info()); + if let Some(freq) = CpuId::new() + .get_processor_frequency_info() + .map(|info| info.processor_base_frequency()) + { + debug!("freq: {}", freq); + if freq > 0 { + info!("Got TSC frequency by CPUID: {} MHz", freq); + unsafe { CPU_FREQ_MHZ = freq as u64 } + } + } + + unsafe { INIT_TICK = core::arch::x86_64::_rdtsc() }; + debug!("INIT_TICK: {}", unsafe { INIT_TICK }); + + unsafe { + use x2apic::lapic::{TimerDivide, TimerMode}; + let lapic = super::apic::local_apic(); + lapic.set_timer_mode(TimerMode::Periodic); + lapic.set_timer_divide(TimerDivide::Div256); // indeed it is Div1, the name is confusing. + lapic.enable_timer(); + + lapic.set_timer_initial(0x20_0000); + debug!("count: {}", lapic.timer_current()); + // set_oneshot_timer(2000); + } +} diff --git a/crates/hal/src/x86_64/trap.S b/crates/hal/src/x86_64/trap.S new file mode 100644 index 0000000000..81c4511098 --- /dev/null +++ b/crates/hal/src/x86_64/trap.S @@ -0,0 +1,42 @@ +.equ NUM_INT, 256 + +.altmacro +.macro DEF_HANDLER, i +.Ltrap_handler_\i: +.if \i == 8 || (\i >= 10 && \i <= 14) || \i == 17 + # error code pushed by CPU + push \i # interrupt vector + jmp .Ltrap_common +.else + push 0 # fill in error code in TrapFrame + push \i # interrupt vector + jmp .Ltrap_common +.endif +.endm + +.macro DEF_TABLE_ENTRY, i + .quad .Ltrap_handler_\i +.endm + +.section .text +.code64 +_trap_handlers: +.set i, 0 +.rept NUM_INT + DEF_HANDLER %i + .set i, i + 1 +.endr + +.Ltrap_common: + test byte ptr [rsp + 3 * 8], 3 + jnz uservec + jmp kernelvec + +.section .rodata +.global trap_handler_table +trap_handler_table: +.set i, 0 +.rept NUM_INT + DEF_TABLE_ENTRY %i + .set i, i + 1 +.endr diff --git a/crates/hal/src/x86_64/uart.rs b/crates/hal/src/x86_64/uart.rs new file mode 100644 index 0000000000..e1bee6967f --- /dev/null +++ b/crates/hal/src/x86_64/uart.rs @@ -0,0 +1,101 @@ +//! Uart 16550. + +use irq_safety::MutexIrqSafe; +use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly}; + +const UART_CLOCK_FACTOR: usize = 16; +const OSC_FREQ: usize = 1_843_200; + +static COM1: MutexIrqSafe = MutexIrqSafe::new(Uart16550::new(0x3f8)); + +bitflags::bitflags! { + /// Line status flags + struct LineStsFlags: u8 { + const INPUT_FULL = 1; + // 1 to 4 unknown + const OUTPUT_EMPTY = 1 << 5; + // 6 and 7 unknown + } +} + +struct Uart16550 { + data: Port, + int_en: PortWriteOnly, + fifo_ctrl: PortWriteOnly, + line_ctrl: PortWriteOnly, + modem_ctrl: PortWriteOnly, + line_sts: PortReadOnly, +} + +impl Uart16550 { + const fn new(port: u16) -> Self { + Self { + data: Port::new(port), + int_en: PortWriteOnly::new(port + 1), + fifo_ctrl: PortWriteOnly::new(port + 2), + line_ctrl: PortWriteOnly::new(port + 3), + modem_ctrl: PortWriteOnly::new(port + 4), + line_sts: PortReadOnly::new(port + 5), + } + } + + fn init(&mut self, baud_rate: usize) { + unsafe { + // Disable interrupts + self.int_en.write(0x00); + + // Enable DLAB + self.line_ctrl.write(0x80); + + // Set maximum speed according the input baud rate by configuring DLL and DLM + let divisor = OSC_FREQ / (baud_rate * UART_CLOCK_FACTOR); + self.data.write((divisor & 0xff) as u8); + self.int_en.write((divisor >> 8) as u8); + + // Disable DLAB and set data word length to 8 bits + self.line_ctrl.write(0x03); + + // Enable FIFO, clear TX/RX queues and + // set interrupt watermark at 14 bytes + self.fifo_ctrl.write(0xC7); + + // Mark data terminal ready, signal request to send + // and enable auxilliary output #2 (used as interrupt line for CPU) + self.modem_ctrl.write(0x0B); + + // Enable interrupts + self.int_en.write(0x00); + } + } + + fn line_sts(&mut self) -> LineStsFlags { + unsafe { LineStsFlags::from_bits_truncate(self.line_sts.read()) } + } + + fn putchar(&mut self, c: u8) { + while !self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {} + unsafe { self.data.write(c) }; + } + + fn getchar(&mut self) -> Option { + if self.line_sts().contains(LineStsFlags::INPUT_FULL) { + unsafe { Some(self.data.read()) } + } else { + None + } + } +} + +pub fn console_putchar(c: u8) { + COM1.lock().putchar(c); +} + +pub fn console_getchar() -> Option { + COM1.lock().getchar() +} + +pub fn init_early() { + COM1.lock().init(115200); +} + +pub fn init() {} diff --git a/crates/page_table/src/bits64.rs b/crates/page_table/src/bits64.rs index a7c3966f97..04d8c51580 100644 --- a/crates/page_table/src/bits64.rs +++ b/crates/page_table/src/bits64.rs @@ -88,11 +88,11 @@ impl PageTable64 { ) -> PagingResult { let entry = self.get_entry_mut_or_create(vaddr, page_size)?; - // FIXME: return already mapped if it was unused? if entry.is_unused() { - return Err(PagingError::AlreadyMapped); + return Err(PagingError::NotMapped); } *entry = GenericPTE::new_page(target.align_down(page_size), flags, page_size.is_huge()); + IF::flush_tlb(Some(vaddr)); Ok(()) } @@ -100,7 +100,7 @@ impl PageTable64 { /// /// Returns [`Err(PagingError::NotMapped)`](PagingError::NotMapped) if the /// mapping is not present. - pub fn unmap(&mut self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, PageSize)> { + fn unmap(&mut self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, PageSize)> { let (entry, size) = self.get_entry_mut(vaddr)?; if entry.is_unused() { return Err(PagingError::NotMapped); @@ -111,7 +111,7 @@ impl PageTable64 { } /// Maps a fault page starts with `vaddr`. - pub fn map_fault( + fn map_fault( &mut self, vaddr: VirtAddr, page_size: PageSize, @@ -148,7 +148,7 @@ impl PageTable64 { /// /// Returns [`Err(PagingError::NotMapped)`](PagingError::NotMapped) if the /// mapping is not present. - pub fn update( + fn update( &mut self, vaddr: VirtAddr, paddr: Option, @@ -225,6 +225,7 @@ impl PageTable64 { vaddr, page_size, paddr, e ) })?; + IF::flush_tlb(Some(vaddr)); vaddr += page_size as usize; paddr += page_size as usize; size -= page_size as usize; @@ -262,6 +263,7 @@ impl PageTable64 { e ) })?; + IF::flush_tlb(Some(vaddr)); vaddr += PageSize::Size4K as usize; size -= PageSize::Size4K as usize; } @@ -288,6 +290,7 @@ impl PageTable64 { .inspect_err(|e| error!("failed to unmap page: {:#x?}, {:?}", vaddr, e))?; assert!(vaddr.is_aligned(page_size)); assert!(page_size as usize <= size); + IF::flush_tlb(Some(vaddr)); vaddr += page_size as usize; size -= page_size as usize; } @@ -305,6 +308,7 @@ impl PageTable64 { let end = vaddr + size; while vaddr < end { let page_size = self.update(vaddr, None, Some(flags))?; + IF::flush_tlb(Some(vaddr)); vaddr += page_size as usize; } Ok(()) diff --git a/crates/page_table/src/lib.rs b/crates/page_table/src/lib.rs index 79c62dfb64..15f5e46f48 100644 --- a/crates/page_table/src/lib.rs +++ b/crates/page_table/src/lib.rs @@ -94,6 +94,8 @@ pub trait PagingIf: Sized { /// /// Used to access the physical memory directly in page table implementation. fn phys_to_virt(paddr: PhysAddr) -> VirtAddr; + /// To update the TLB after the page table is modified. + fn flush_tlb(vaddr: Option); } /// The page sizes supported by the hardware page table. diff --git a/doc/build.md b/doc/build.md index 8cc302a654..31ded56ade 100644 --- a/doc/build.md +++ b/doc/build.md @@ -42,7 +42,7 @@ What happens when "make A=apps/net/httpserver ARCH=aarch64 LOG=info NET=y SMP=1 ```rust #[naked] #[no_mangle] - #[link_section = ".text.boot"] + #[link_section = ".text.entry"] unsafe extern "C" fn _start() -> ! { extern "C" { fn rust_main(); diff --git a/modules/axalloc/Cargo.toml b/modules/axalloc/Cargo.toml index 40eedf404f..44e9bf99a5 100644 --- a/modules/axalloc/Cargo.toml +++ b/modules/axalloc/Cargo.toml @@ -22,3 +22,4 @@ spinlock = { path = "../../crates/spinlock" } memory_addr = { path = "../../crates/memory_addr" } allocator = { path = "../../crates/allocator", features = ["bitmap"] } axerrno = { path = "../../crates/axerrno" } +hal = { path = "../../crates/hal", features = ["alloc"]} diff --git a/modules/axhal/Cargo.toml b/modules/axhal/Cargo.toml index 632b2b9063..8632cddd1a 100644 --- a/modules/axhal/Cargo.toml +++ b/modules/axhal/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://rcore-os.github.io/arceos/axhal/index.html" [features] smp = [] -alloc = [] +alloc = ["hal/alloc"] fp_simd = [] paging = ["axalloc", "page_table"] irq = [] @@ -39,7 +39,8 @@ memory_addr = { path = "../../crates/memory_addr" } handler_table = { path = "../../crates/handler_table" } crate_interface = { path = "../../crates/crate_interface" } axfs_ramfs = { path = "../../crates/axfs_ramfs", optional = true } -riscv = "0.10" +hal = { path = "../../crates/hal", features = ["stackful"] } + [target.'cfg(target_arch = "x86_64")'.dependencies] x86 = "0.52" x86_64 = "0.14" diff --git a/modules/axhal/linker.lds.S b/modules/axhal/linker.lds.S index 7d25f2bfa2..2cf09dcb48 100644 --- a/modules/axhal/linker.lds.S +++ b/modules/axhal/linker.lds.S @@ -10,7 +10,7 @@ SECTIONS .text : ALIGN(4K) { _stext = .; - *(.text.boot) + *(.text.entry) . = ALIGN(4K); *(.text.signal_trampoline) . = ALIGN(4K); diff --git a/modules/axhal/src/arch/mod.rs b/modules/axhal/src/arch/mod.rs index b8bc0af3d0..cdf657d244 100644 --- a/modules/axhal/src/arch/mod.rs +++ b/modules/axhal/src/arch/mod.rs @@ -12,3 +12,5 @@ cfg_if::cfg_if! { pub use self::aarch64::*; } } + +pub use hal::{get_sigreturn, ContextArgs, TrapFrame}; diff --git a/modules/axhal/src/arch/riscv/context.rs b/modules/axhal/src/arch/riscv/context.rs index a3686688c0..03c31e78d9 100644 --- a/modules/axhal/src/arch/riscv/context.rs +++ b/modules/axhal/src/arch/riscv/context.rs @@ -1,151 +1,7 @@ use core::arch::asm; use memory_addr::VirtAddr; -use riscv::register::sstatus::{self, Sstatus}; -include_asm_marcos!(); -/// General registers of RISC-V. -#[allow(missing_docs)] -#[repr(C)] -#[derive(Debug, Default, Clone, Copy)] -pub struct GeneralRegisters { - pub ra: usize, - pub sp: usize, - pub gp: usize, // only valid for user traps - pub tp: usize, // only valid for user traps - pub t0: usize, - pub t1: usize, - pub t2: usize, - pub s0: usize, - pub s1: usize, - pub a0: usize, - pub a1: usize, - pub a2: usize, - pub a3: usize, - pub a4: usize, - pub a5: usize, - pub a6: usize, - pub a7: usize, - pub s2: usize, - pub s3: usize, - pub s4: usize, - pub s5: usize, - pub s6: usize, - pub s7: usize, - pub s8: usize, - pub s9: usize, - pub s10: usize, - pub s11: usize, - pub t3: usize, - pub t4: usize, - pub t5: usize, - pub t6: usize, -} - -/// Saved registers when a trap (interrupt or exception) occurs. -#[repr(C)] -#[derive(Debug, Default, Clone, Copy)] -pub struct TrapFrame { - /// All general registers. - pub regs: GeneralRegisters, - /// Supervisor Exception Program Counter. - pub sepc: usize, - /// Supervisor Status Register. - pub sstatus: usize, - /// 浮点数寄存器 - pub fs: [usize; 2], -} - -impl TrapFrame { - pub fn set_user_sp(&mut self, user_sp: usize) { - self.regs.sp = user_sp; - } - - /// 用于第一次进入应用程序时的初始化 - pub fn app_init_context(app_entry: usize, user_sp: usize) -> Self { - let sstatus = sstatus::read(); - // 当前版本的riscv不支持使用set_spp函数,需要手动修改 - // 修改当前的sstatus为User,即是第8位置0 - let mut trap_frame = TrapFrame::default(); - trap_frame.set_user_sp(user_sp); - trap_frame.sepc = app_entry; - trap_frame.sstatus = - unsafe { (*(&sstatus as *const Sstatus as *const usize) & !(1 << 8)) & !(1 << 1) }; - unsafe { - // a0为参数个数 - // a1存储的是用户栈底,即argv - trap_frame.regs.a0 = *(user_sp as *const usize); - trap_frame.regs.a1 = *(user_sp as *const usize).add(1); - } - trap_frame - } - - /// 设置返回值 - pub fn set_ret_code(&mut self, ret_value: usize) { - self.regs.a0 = ret_value; - } - - /// 设置TLS - pub fn set_tls(&mut self, tls_value: usize) { - self.regs.tp = tls_value; - } - - /// 获取 sp - pub fn get_sp(&self) -> usize { - self.regs.sp - } - - /// 设置 pc - pub fn set_pc(&mut self, pc: usize) { - self.sepc = pc; - } - - /// 设置 arg0 - pub fn set_arg0(&mut self, arg: usize) { - self.regs.a0 = arg; - } - - /// 设置 arg1 - pub fn set_arg1(&mut self, arg: usize) { - self.regs.a1 = arg; - } - - /// 设置 arg2 - pub fn set_arg2(&mut self, arg: usize) { - self.regs.a2 = arg; - } - - /// 获取 pc - pub fn get_pc(&self) -> usize { - self.sepc - } - - /// 获取 ret - pub fn get_ret_code(&self) -> usize { - self.regs.a0 - } - - /// 设置返回地址 - pub fn set_ra(&mut self, ra: usize) { - self.regs.ra = ra; - } - - /// 获取所有 syscall 参数 - pub fn get_syscall_args(&self) -> [usize; 6] { - [ - self.regs.a0, - self.regs.a1, - self.regs.a2, - self.regs.a3, - self.regs.a4, - self.regs.a5, - ] - } - - /// 获取 syscall id - pub fn get_syscall_num(&self) -> usize { - self.regs.a7 as _ - } -} +include_asm_marcos!(); /// Saved hardware states of a task. /// diff --git a/modules/axhal/src/arch/riscv/macros.rs b/modules/axhal/src/arch/riscv/macros.rs index c36c4da80f..0e0daf71ca 100644 --- a/modules/axhal/src/arch/riscv/macros.rs +++ b/modules/axhal/src/arch/riscv/macros.rs @@ -31,51 +31,5 @@ macro_rules! include_asm_marcos { .endif", ); - - core::arch::global_asm!( - r" - .ifndef .LPUSH_POP_GENERAL_REGS - .equ .LPUSH_POP_GENERAL_REGS, 0 - - .macro PUSH_POP_GENERAL_REGS, op - \op ra, sp, 0 - \op t0, sp, 4 - \op t1, sp, 5 - \op t2, sp, 6 - \op s0, sp, 7 - \op s1, sp, 8 - \op a0, sp, 9 - \op a1, sp, 10 - \op a2, sp, 11 - \op a3, sp, 12 - \op a4, sp, 13 - \op a5, sp, 14 - \op a6, sp, 15 - \op a7, sp, 16 - \op s2, sp, 17 - \op s3, sp, 18 - \op s4, sp, 19 - \op s5, sp, 20 - \op s6, sp, 21 - \op s7, sp, 22 - \op s8, sp, 23 - \op s9, sp, 24 - \op s10, sp, 25 - \op s11, sp, 26 - \op t3, sp, 27 - \op t4, sp, 28 - \op t5, sp, 29 - \op t6, sp, 30 - .endm - - .macro PUSH_GENERAL_REGS - PUSH_POP_GENERAL_REGS STR - .endm - .macro POP_GENERAL_REGS - PUSH_POP_GENERAL_REGS LDR - .endm - - .endif" - ); }; } diff --git a/modules/axhal/src/arch/riscv/mod.rs b/modules/axhal/src/arch/riscv/mod.rs index dcbbd683ac..b8152cf6a7 100644 --- a/modules/axhal/src/arch/riscv/mod.rs +++ b/modules/axhal/src/arch/riscv/mod.rs @@ -3,10 +3,13 @@ mod macros; mod context; mod trap; +pub use trap::riscv_trap_handler as trap_handler; + #[cfg(feature = "monolithic")] pub use trap::first_into_user; -pub use self::context::{GeneralRegisters, TaskContext, TrapFrame}; +pub use self::context::TaskContext; + use memory_addr::{PhysAddr, VirtAddr}; use riscv::asm; use riscv::register::{satp, sstatus, stvec}; @@ -109,8 +112,3 @@ pub fn read_thread_pointer() -> usize { pub unsafe fn write_thread_pointer(tp: usize) { core::arch::asm!("mv tp, {}", in(reg) tp) } - -include_asm_marcos!(); - -#[cfg(feature = "signal")] -core::arch::global_asm!(include_str!("signal.S")); diff --git a/modules/axhal/src/arch/riscv/signal.S b/modules/axhal/src/arch/riscv/signal.S deleted file mode 100644 index c9d6259af4..0000000000 --- a/modules/axhal/src/arch/riscv/signal.S +++ /dev/null @@ -1,9 +0,0 @@ -# To create the sigreturn trampoline -.equ __NR_sigreturn, 139 -.section .text.signal_trampoline -.balign 4 -.global start_signal_trampoline -start_signal_trampoline: - li a7, __NR_sigreturn - li a0, 0 - ecall \ No newline at end of file diff --git a/modules/axhal/src/arch/riscv/trap.S b/modules/axhal/src/arch/riscv/trap.S deleted file mode 100644 index 852dd841f7..0000000000 --- a/modules/axhal/src/arch/riscv/trap.S +++ /dev/null @@ -1,91 +0,0 @@ -.macro SAVE_REGS, from_user - addi sp, sp, -{trapframe_size} - PUSH_GENERAL_REGS - - csrr t0, sepc - csrr t1, sstatus - csrrw t2, sscratch, zero // save sscratch (sp) and zero it - STR t0, sp, 31 // tf.sepc - STR t1, sp, 32 // tf.sstatus - STR t2, sp, 1 // tf.regs.sp - .short 0xa622 // fsd fs0,264(sp) - .short 0xaa26 // fsd fs1,272(sp) -.if \from_user == 1 - LDR t1, sp, 2 // load user gp with CPU ID - LDR t0, sp, 3 // load supervisor tp - STR gp, sp, 2 // save user gp and tp - STR tp, sp, 3 - mv gp, t1 - mv tp, t0 -.endif -.endm - -.macro RESTORE_REGS, from_user -.if \from_user == 1 - LDR t1, sp, 2 - LDR t0, sp, 3 - STR gp, sp, 2 // load user gp and tp - STR tp, sp, 3 // save supervisor tp - mv gp, t1 - mv tp, t0 - addi t0, sp, {trapframe_size} // put supervisor sp to scratch - csrw sscratch, t0 -.endif - - LDR t0, sp, 31 - LDR t1, sp, 32 - csrw sepc, t0 - csrw sstatus, t1 - .short 0x2432 // fld fs0,264(sp) - .short 0x24d2 // fld fs1,272(sp) - POP_GENERAL_REGS - LDR sp, sp, 1 // load sp from tf.regs.sp -.endm - -.section .text -.balign 4 -.global trap_vector_base -trap_vector_base: - // sscratch == 0: trap from S mode - // sscratch != 0: trap from U mode - csrrw sp, sscratch, sp // switch sscratch and sp - bnez sp, .Ltrap_entry_u - - csrr sp, sscratch // put supervisor sp back - j .Ltrap_entry_s - -.Ltrap_entry_s: - SAVE_REGS 0 - mv a0, sp - li a1, 0 - call riscv_trap_handler - RESTORE_REGS 0 - sret - -.Ltrap_entry_u: - SAVE_REGS 1 - mv a0, sp - li a1, 1 - call riscv_trap_handler - RESTORE_REGS 1 - sret - -.altmacro -.macro COPY n - ld t2, (\n)*8(a0) - sd t2, (\n)*8(a1) -.endm - -.section .text -.globl __copy -__copy: - # __copy( - # frame_address: *const TrapFrame, - # kernel_base: *mut T - # ) - .set n, 0 - .rept 33 - COPY %n - .set n, n + 1 - .endr - ret diff --git a/modules/axhal/src/arch/riscv/trap.rs b/modules/axhal/src/arch/riscv/trap.rs index cd796ed4b4..4b46f2c4c9 100644 --- a/modules/axhal/src/arch/riscv/trap.rs +++ b/modules/axhal/src/arch/riscv/trap.rs @@ -1,11 +1,7 @@ +use hal::{ContextArgs, TrapFrame, TrapType}; #[cfg(feature = "monolithic")] use page_table_entry::MappingFlags; -#[cfg(feature = "monolithic")] -use riscv::register::{sepc, stval}; - -use riscv::register::scause::{self, Exception as E, Trap}; - #[cfg(feature = "monolithic")] use crate::trap::handle_page_fault; @@ -13,7 +9,7 @@ use crate::trap::handle_page_fault; use crate::trap::handle_signal; #[allow(unused)] -use super::{disable_irqs, TrapFrame}; +use super::disable_irqs; #[cfg(feature = "monolithic")] use super::enable_irqs; @@ -21,76 +17,65 @@ use super::enable_irqs; #[cfg(feature = "monolithic")] use crate::trap::handle_syscall; -include_asm_marcos!(); - -core::arch::global_asm!( - include_str!("trap.S"), - trapframe_size = const core::mem::size_of::(), -); - fn handle_breakpoint(sepc: &mut usize) { - debug!("Exception(Breakpoint) @ {:#x} ", sepc); - *sepc += 2 + // The sepc has been modified in the kernel callback function + info!("Exception(Breakpoint) @ {:#x} ", sepc); } #[no_mangle] #[allow(unused)] -fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool) { - let scause = scause::read(); +pub fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool, trap_type: TrapType) { + let scause = riscv::register::scause::read(); #[cfg(feature = "monolithic")] + // 这里是测例 interrupt 的对应代码,需要记录中断号 axfs_ramfs::INTERRUPT.lock().record(scause.code()); - match scause.cause() { - Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc), - Trap::Interrupt(_) => crate::trap::handle_irq_extern(scause.bits(), from_user), + match trap_type { + TrapType::Breakpoint => handle_breakpoint(&mut tf.sepc), + TrapType::Time(irq_num) => crate::trap::handle_irq_extern(irq_num, from_user), #[cfg(feature = "monolithic")] - Trap::Exception(E::UserEnvCall) => { + TrapType::UserEnvCall => { enable_irqs(); - // jump to next instruction anyway - tf.sepc += 4; // get system call return value - let result = handle_syscall( - tf.regs.a7, - [ - tf.regs.a0, tf.regs.a1, tf.regs.a2, tf.regs.a3, tf.regs.a4, tf.regs.a5, - ], - ); + // If it call syscall ok after the handle syscall, then the execve and clone syscall need to add or sub 4 to the sepc for the new task manually. + // So it doesn't call tf.syscall_ok() here. + tf[ContextArgs::SEPC] += 4; + let result = handle_syscall(tf[ContextArgs::SYSCALL], tf.args()); // cx is changed during sys_exec, so we have to call it again - tf.regs.a0 = result as usize; + tf[ContextArgs::RET] = result as usize; } #[cfg(feature = "monolithic")] - Trap::Exception(E::InstructionPageFault) => { - let addr = stval::read(); + TrapType::InstructionPageFault(addr) => { + info!( + "I page fault from kernel, addr: {:#x} sepc:{:#x} from user: {}", + addr, tf.sepc, from_user + ); if !from_user { - unimplemented!( - "I page fault from kernel, addr: {:X}, sepc: {:X}", - addr, - tf.sepc - ); + unimplemented!("I page fault from kernel"); } handle_page_fault(addr.into(), MappingFlags::USER | MappingFlags::EXECUTE); } #[cfg(feature = "monolithic")] - Trap::Exception(E::LoadPageFault) => { - let addr = stval::read(); + TrapType::LoadPageFault(addr) => { + info!( + "L page fault from kernel, addr: {:#x} sepc:{:#x}", + addr, tf.sepc + ); if !from_user { - error!("L page fault from kernel, addr: {:#x}", addr); unimplemented!("L page fault from kernel"); } handle_page_fault(addr.into(), MappingFlags::USER | MappingFlags::READ); } #[cfg(feature = "monolithic")] - Trap::Exception(E::StorePageFault) => { + TrapType::StorePageFault(addr) => { + info!( + "S page fault from kernel, addr: {:#x} sepc:{:#x}", + addr, tf.sepc + ); if !from_user { - error!( - "S page fault from kernel, addr: {:#x} sepc:{:X}", - stval::read(), - sepc::read() - ); unimplemented!("S page fault from kernel"); } - let addr = stval::read(); handle_page_fault(addr.into(), MappingFlags::USER | MappingFlags::WRITE); } @@ -129,10 +114,8 @@ fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool) { /// 2. frame_base: the address of the trap frame which will be pushed into the kernel stack pub fn first_into_user(kernel_sp: usize, frame_base: usize) { // Make sure that all csr registers are stored before enable the interrupt - use crate::arch::flush_tlb; - disable_irqs(); - flush_tlb(None); + super::flush_tlb(None); let trap_frame_size = core::mem::size_of::(); let kernel_base = kernel_sp - trap_frame_size; @@ -140,22 +123,23 @@ pub fn first_into_user(kernel_sp: usize, frame_base: usize) { core::arch::asm!( r" mv sp, {frame_base} - .short 0x2432 // fld fs0,264(sp) - .short 0x24d2 // fld fs1,272(sp) + .short 0x2452 # fld fs0, 272(sp). Warn! it is only used in riscv64 + .short 0x24f2 # fld fs1, 280(sp). Warn! it is only used in riscv64 + mv t1, {kernel_base} - LDR t0, sp, 2 - STR gp, t1, 2 - mv gp, t0 LDR t0, sp, 3 - STR tp, t1, 3 // save supervisor tp. Note that it is stored on the kernel stack rather than in sp, in which case the ID of the currently running CPU should be stored + STR gp, t1, 3 + mv gp, t0 + LDR t0, sp, 4 + STR tp, t1, 4 // save supervisor tp. Note that it is stored on the kernel stack rather than in sp, in which case the ID of the currently running CPU should be stored mv tp, t0 // tp: now it stores the TLS pointer to the corresponding thread csrw sscratch, {kernel_sp} // put supervisor sp to scratch - LDR t0, sp, 31 + LDR t0, sp, 33 LDR t1, sp, 32 csrw sepc, t0 csrw sstatus, t1 POP_GENERAL_REGS - LDR sp, sp, 1 + LDR sp, sp, 2 sret ", frame_base = in(reg) frame_base, diff --git a/modules/axhal/src/cpu.rs b/modules/axhal/src/cpu.rs index d0ee27a341..784f80d6c4 100644 --- a/modules/axhal/src/cpu.rs +++ b/modules/axhal/src/cpu.rs @@ -74,9 +74,11 @@ pub unsafe fn set_current_task_ptr(ptr: *const T) { } #[allow(dead_code)] -pub(crate) fn init_primary(cpu_id: usize) { - percpu::init(axconfig::SMP); - percpu::set_local_thread_pointer(cpu_id); +/// To init the primary CPU ID and IS_BSP. +pub fn init_primary(cpu_id: usize) { + // It has been set in hal crate. + // percpu::init(axconfig::SMP); + // percpu::set_local_thread_pointer(cpu_id); unsafe { CPU_ID.write_current_raw(cpu_id); IS_BSP.write_current_raw(true); diff --git a/modules/axhal/src/paging.rs b/modules/axhal/src/paging.rs index 2d035e5c62..c892acd2cb 100644 --- a/modules/axhal/src/paging.rs +++ b/modules/axhal/src/paging.rs @@ -50,6 +50,10 @@ impl PagingIf for PagingIfImpl { fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { phys_to_virt(paddr) } + + fn flush_tlb(vaddr: Option) { + crate::arch::flush_tlb(vaddr) + } } cfg_if::cfg_if! { diff --git a/modules/axhal/src/platform/aarch64_common/boot.rs b/modules/axhal/src/platform/aarch64_common/boot.rs index ae9d23e4ef..cfc5517b23 100644 --- a/modules/axhal/src/platform/aarch64_common/boot.rs +++ b/modules/axhal/src/platform/aarch64_common/boot.rs @@ -59,7 +59,7 @@ unsafe fn enable_fp() { /// The earliest entry point for the primary CPU. #[naked] #[no_mangle] -#[link_section = ".text.boot"] +#[link_section = ".text.entry"] unsafe extern "C" fn _start() -> ! { // PC = 0x8_0000 // X0 = dtb @@ -105,7 +105,7 @@ unsafe extern "C" fn _start() -> ! { #[cfg(feature = "smp")] #[naked] #[no_mangle] -#[link_section = ".text.boot"] +#[link_section = ".text.entry"] unsafe extern "C" fn _start_secondary() -> ! { core::arch::asm!(" mrs x19, mpidr_el1 diff --git a/modules/axhal/src/platform/aarch64_raspi/mp.rs b/modules/axhal/src/platform/aarch64_raspi/mp.rs index 23549c01f1..dd693e4b61 100644 --- a/modules/axhal/src/platform/aarch64_raspi/mp.rs +++ b/modules/axhal/src/platform/aarch64_raspi/mp.rs @@ -7,7 +7,7 @@ extern "C" { } #[naked] -#[link_section = ".text.boot"] +#[link_section = ".text.entry"] unsafe extern "C" fn modify_stack_and_start() { core::arch::asm!(" ldr x21, ={secondary_boot_stack} // the secondary CPU hasn't set the TTBR1 diff --git a/modules/axhal/src/platform/mod.rs b/modules/axhal/src/platform/mod.rs index 3a5ed4561d..da5903043f 100644 --- a/modules/axhal/src/platform/mod.rs +++ b/modules/axhal/src/platform/mod.rs @@ -1,30 +1,30 @@ //! Platform-specific operations. -cfg_if::cfg_if! { - if #[cfg(target_arch = "aarch64")]{ - mod aarch64_common; - pub use self::aarch64_common::*; - } -} +// cfg_if::cfg_if! { +// if #[cfg(target_arch = "aarch64")]{ +// mod aarch64_common; +// pub use self::aarch64_common::*; +// } +// } -cfg_if::cfg_if! { - if #[cfg(all(target_arch = "x86_64", platform_family = "x86-pc"))] { - mod x86_pc; - pub use self::x86_pc::*; - } else if #[cfg(all(target_arch = "riscv64", platform_family = "riscv64-qemu-virt"))] { - mod riscv64_qemu_virt; - pub use self::riscv64_qemu_virt::*; - } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-qemu-virt"))] { - mod aarch64_qemu_virt; - pub use self::aarch64_qemu_virt::*; - } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-raspi"))] { - mod aarch64_raspi; - pub use self::aarch64_raspi::*; - } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-bsta1000b"))] { - mod aarch64_bsta1000b; - pub use self::aarch64_bsta1000b::*; - } else { - mod dummy; - pub use self::dummy::*; - } -} +// cfg_if::cfg_if! { +// if #[cfg(all(target_arch = "x86_64", platform_family = "x86-pc"))] { +// mod x86_pc; +// pub use self::x86_pc::*; +// } else if #[cfg(all(target_arch = "riscv64", platform_family = "riscv64-qemu-virt"))] { +mod riscv64_qemu_virt; +pub use self::riscv64_qemu_virt::*; +// } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-qemu-virt"))] { +// mod aarch64_qemu_virt; +// pub use self::aarch64_qemu_virt::*; +// } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-raspi"))] { +// mod aarch64_raspi; +// pub use self::aarch64_raspi::*; +// } else if #[cfg(all(target_arch = "aarch64", platform_family = "aarch64-bsta1000b"))] { +// mod aarch64_bsta1000b; +// pub use self::aarch64_bsta1000b::*; +// } else { +// mod dummy; +// pub use self::dummy::*; +// } +// } diff --git a/modules/axhal/src/platform/riscv64_qemu_virt/boot.rs b/modules/axhal/src/platform/riscv64_qemu_virt/boot.rs index eb293133d0..ffd606b39f 100644 --- a/modules/axhal/src/platform/riscv64_qemu_virt/boot.rs +++ b/modules/axhal/src/platform/riscv64_qemu_virt/boot.rs @@ -1,68 +1,67 @@ -use riscv::register::satp; - +#[allow(unused_imports)] use axconfig::{PHYS_VIRT_OFFSET, TASK_STACK_SIZE}; -#[link_section = ".bss.stack"] -static mut BOOT_STACK: [u8; TASK_STACK_SIZE] = [0; TASK_STACK_SIZE]; +// #[link_section = ".bss.stack"] +// static mut BOOT_STACK: [u8; TASK_STACK_SIZE] = [0; TASK_STACK_SIZE]; -#[link_section = ".data.boot_page_table"] -static mut BOOT_PT_SV39: [u64; 512] = [0; 512]; +// #[link_section = ".data.boot_page_table"] +// static mut BOOT_PT_SV39: [u64; 512] = [0; 512]; -unsafe fn init_boot_page_table() { - // 0x8000_0000..0xc000_0000, VRWX_GAD, 1G block - BOOT_PT_SV39[2] = (0x80000 << 10) | 0xef; - // 0xffff_ffc0_8000_0000..0xffff_ffc0_c000_0000, VRWX_GAD, 1G block - BOOT_PT_SV39[0x102] = (0x80000 << 10) | 0xef; -} +// unsafe fn init_boot_page_table() { +// // 0x8000_0000..0xc000_0000, VRWX_GAD, 1G block +// BOOT_PT_SV39[2] = (0x80000 << 10) | 0xef; +// // 0xffff_ffc0_8000_0000..0xffff_ffc0_c000_0000, VRWX_GAD, 1G block +// BOOT_PT_SV39[0x102] = (0x80000 << 10) | 0xef; +// } -unsafe fn init_mmu() { - let page_table_root = BOOT_PT_SV39.as_ptr() as usize; - satp::set(satp::Mode::Sv39, 0, page_table_root >> 12); - riscv::asm::sfence_vma_all(); -} +// unsafe fn init_mmu() { +// let page_table_root = BOOT_PT_SV39.as_ptr() as usize; +// satp::set(satp::Mode::Sv39, 0, page_table_root >> 12); +// riscv::asm::sfence_vma_all(); +// } -/// The earliest entry point for the primary CPU. -#[naked] -#[no_mangle] -#[link_section = ".text.boot"] -unsafe extern "C" fn _start() -> ! { - // PC = 0x8020_0000 - // a0 = hartid - // a1 = dtb - core::arch::asm!(" - mv s0, a0 // save hartid - mv s1, a1 // save DTB pointer - la sp, {boot_stack} - li t0, {boot_stack_size} - add sp, sp, t0 // setup boot stack +// /// The earliest entry point for the primary CPU. +// #[naked] +// #[no_mangle] +// #[link_section = ".text.entry"] +// unsafe extern "C" fn _start() -> ! { +// // PC = 0x8020_0000 +// // a0 = hartid +// // a1 = dtb +// core::arch::asm!(" +// mv s0, a0 // save hartid +// mv s1, a1 // save DTB pointer +// la sp, {boot_stack} +// li t0, {boot_stack_size} +// add sp, sp, t0 // setup boot stack - call {init_boot_page_table} - call {init_mmu} // setup boot page table and enabel MMU +// call {init_boot_page_table} +// call {init_mmu} // setup boot page table and enabel MMU - li s2, {phys_virt_offset} // fix up virtual high address - add sp, sp, s2 +// li s2, {phys_virt_offset} // fix up virtual high address +// add sp, sp, s2 - mv a0, s0 - mv a1, s1 - la a2, {entry} - add a2, a2, s2 - jalr a2 // call rust_entry(hartid, dtb) - j .", - phys_virt_offset = const PHYS_VIRT_OFFSET, - boot_stack_size = const TASK_STACK_SIZE, - boot_stack = sym BOOT_STACK, - init_boot_page_table = sym init_boot_page_table, - init_mmu = sym init_mmu, - entry = sym super::rust_entry, - options(noreturn), - ) -} +// mv a0, s0 +// mv a1, s1 +// la a2, {entry} +// add a2, a2, s2 +// jalr a2 // call rust_entry(hartid, dtb) +// j .", +// phys_virt_offset = const PHYS_VIRT_OFFSET, +// boot_stack_size = const TASK_STACK_SIZE, +// boot_stack = sym BOOT_STACK, +// init_boot_page_table = sym init_boot_page_table, +// init_mmu = sym init_mmu, +// entry = sym super::rust_entry, +// options(noreturn), +// ) +// } /// The earliest entry point for secondary CPUs. #[cfg(feature = "smp")] #[naked] #[no_mangle] -#[link_section = ".text.boot"] +#[link_section = ".text.entry"] unsafe extern "C" fn _start_secondary() -> ! { // a0 = hartid // a1 = SP diff --git a/modules/axhal/src/platform/riscv64_qemu_virt/console.rs b/modules/axhal/src/platform/riscv64_qemu_virt/console.rs index a7ec3e6465..4a78fe9a88 100644 --- a/modules/axhal/src/platform/riscv64_qemu_virt/console.rs +++ b/modules/axhal/src/platform/riscv64_qemu_virt/console.rs @@ -1,14 +1,9 @@ /// Writes a byte to the console. pub fn putchar(c: u8) { - #[allow(deprecated)] - sbi_rt::legacy::console_putchar(c as usize); + hal::console_putchar(c); } /// Reads a byte from the console, or returns [`None`] if no input is available. pub fn getchar() -> Option { - #[allow(deprecated)] - match sbi_rt::legacy::console_getchar() as isize { - -1 => None, - c => Some(c as u8), - } + hal::console_getchar() } diff --git a/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs b/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs index 24c14e5b38..7c7fe1b1c5 100644 --- a/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs +++ b/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs @@ -12,22 +12,23 @@ pub mod irq; pub mod mp; extern "C" { - fn trap_vector_base(); - fn rust_main(cpu_id: usize, dtb: usize); + // fn rust_main(cpu_id: usize, dtb: usize); #[cfg(feature = "smp")] fn rust_main_secondary(cpu_id: usize); } -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, dtb); -} +// unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { +// crate::mem::clear_bss(); +// crate::cpu::init_primary(cpu_id); +// // It has been initialized in the hal crates. +// // hal::init_interrupt(); +// rust_main(cpu_id, dtb); +// } +// TODO: It needed to be moved to the hal crate #[cfg(feature = "smp")] unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { - crate::arch::set_trap_vector_base(trap_vector_base as usize); + hal::init_interrupt(); crate::cpu::init_secondary(cpu_id); rust_main_secondary(cpu_id); } diff --git a/modules/axhal/src/platform/x86_pc/multiboot.S b/modules/axhal/src/platform/x86_pc/multiboot.S index b18103b1af..844c5f4f5d 100644 --- a/modules/axhal/src/platform/x86_pc/multiboot.S +++ b/modules/axhal/src/platform/x86_pc/multiboot.S @@ -1,7 +1,7 @@ # Bootstrapping from 32-bit with the Multiboot specification. # See https://www.gnu.org/software/grub/manual/multiboot/multiboot.html -.section .text.boot +.section .text.entry .code32 .global _start _start: diff --git a/modules/axmem/src/area.rs b/modules/axmem/src/area.rs index ebfffd71be..8d92b5b2d8 100644 --- a/modules/axmem/src/area.rs +++ b/modules/axmem/src/area.rs @@ -472,7 +472,7 @@ impl MapArea { } None => { page_table - .map_fault(vaddr, PageSize::Size4K, self.flags) + .map_fault_region(vaddr, PAGE_SIZE_4K, self.flags) .unwrap(); None } diff --git a/modules/axprocess/src/lib.rs b/modules/axprocess/src/lib.rs index bd2508b64e..d200d166c6 100644 --- a/modules/axprocess/src/lib.rs +++ b/modules/axprocess/src/lib.rs @@ -1,5 +1,5 @@ //! This module provides the process management API for the operating system. - +#![feature(stmt_expr_attributes)] #![cfg_attr(not(test), no_std)] mod api; pub use api::*; diff --git a/modules/axprocess/src/process.rs b/modules/axprocess/src/process.rs index 0cb39d623a..0b5b6c2bf9 100644 --- a/modules/axprocess/src/process.rs +++ b/modules/axprocess/src/process.rs @@ -6,7 +6,7 @@ use alloc::vec::Vec; use alloc::{collections::BTreeMap, string::String}; use axerrno::{AxError, AxResult}; use axfs::api::{FileIO, OpenFlags}; -use axhal::arch::{write_page_table_root0, TrapFrame}; +use axhal::arch::{get_sigreturn, write_page_table_root0, ContextArgs, TrapFrame}; use axhal::mem::{phys_to_virt, VirtAddr}; use axhal::KERNEL_PROCESS_ID; @@ -31,11 +31,6 @@ pub static TID2TASK: Mutex> = Mutex::new(BTreeMap::new( pub static PID2PC: Mutex>> = Mutex::new(BTreeMap::new()); const FD_LIMIT_ORIGIN: usize = 1025; -#[cfg(feature = "signal")] -extern "C" { - fn start_signal_trampoline(); -} - /// The process control block pub struct Process { /// 进程号 @@ -204,7 +199,7 @@ impl Process { use axhal::paging::MappingFlags; // 生成信号跳板 let signal_trampoline_vaddr: VirtAddr = (axconfig::SIGNAL_TRAMPOLINE).into(); - let signal_trampoline_paddr = virt_to_phys((start_signal_trampoline as usize).into()); + let signal_trampoline_paddr = virt_to_phys(get_sigreturn().into()); memory_set.map_page_without_alloc( signal_trampoline_vaddr, signal_trampoline_paddr, @@ -218,8 +213,6 @@ impl Process { if page_table_token != 0 { unsafe { write_page_table_root0(page_table_token.into()); - #[cfg(target_arch = "riscv64")] - riscv::register::sstatus::set_sum(); }; } @@ -410,7 +403,7 @@ impl Process { // 生成信号跳板 let signal_trampoline_vaddr: VirtAddr = (axconfig::SIGNAL_TRAMPOLINE).into(); - let signal_trampoline_paddr = virt_to_phys((start_signal_trampoline as usize).into()); + let signal_trampoline_paddr = virt_to_phys(get_sigreturn().into()); let mut memory_set = self.memory_set.lock(); if memory_set.query(signal_trampoline_vaddr).is_err() { let _ = memory_set.map_page_without_alloc( @@ -461,8 +454,7 @@ impl Process { use axhal::paging::MappingFlags; // 生成信号跳板 let signal_trampoline_vaddr: VirtAddr = (axconfig::SIGNAL_TRAMPOLINE).into(); - let signal_trampoline_paddr = - virt_to_phys((start_signal_trampoline as usize).into()); + let signal_trampoline_paddr = virt_to_phys(get_sigreturn().into()); memory_set.lock().map_page_without_alloc( signal_trampoline_vaddr, signal_trampoline_paddr, @@ -653,10 +645,10 @@ impl Process { let mut trap_frame = unsafe { *(current_task.get_first_trap_frame()) }; // drop(current_task); // 新开的进程/线程返回值为0 - trap_frame.set_ret_code(0); + trap_frame[ContextArgs::RET] = 0; if flags.contains(CloneFlags::CLONE_SETTLS) { #[cfg(not(target_arch = "x86_64"))] - trap_frame.set_tls(tls); + trap_frame[ContextArgs::TLS] = tls; #[cfg(target_arch = "x86_64")] unsafe { new_task.set_tls_force(tls); @@ -668,11 +660,7 @@ impl Process { // 若没有给定用户栈,则使用当前用户栈 // 没有给定用户栈的时候,只能是共享了地址空间,且原先调用clone的有用户栈,此时已经在之前的trap clone时复制了 if let Some(stack) = stack { - trap_frame.set_user_sp(stack); - // info!( - // "New user stack: sepc:{:X}, stack:{:X}", - // trap_frame.sepc, trap_frame.regs.sp - // ); + trap_frame[ContextArgs::SP] = stack; } new_task.set_trap_context(trap_frame); new_task.set_trap_in_kernel_stack(); diff --git a/modules/axprocess/src/signal.rs b/modules/axprocess/src/signal.rs index 44a3796634..974a0447ef 100644 --- a/modules/axprocess/src/signal.rs +++ b/modules/axprocess/src/signal.rs @@ -2,7 +2,11 @@ extern crate alloc; use alloc::sync::Arc; use axerrno::{AxError, AxResult}; -use axhal::{arch::TrapFrame, cpu::this_cpu_id, KERNEL_PROCESS_ID}; +use axhal::{ + arch::{ContextArgs, TrapFrame}, + cpu::this_cpu_id, + KERNEL_PROCESS_ID, +}; use axlog::{info, warn}; use axsignal::{ action::{SigActionFlags, SignalDefault, SIG_IGN}, @@ -68,11 +72,11 @@ pub fn load_trap_for_signal() -> bool { // 考虑当时调用信号处理函数时,sp对应的地址上的内容即是SignalUserContext // 此时认为一定通过sig_return调用这个函数 // 所以此时sp的位置应该是SignalUserContext的位置 - let sp = (*now_trap_frame).get_sp(); + let sp = (*now_trap_frame)[ContextArgs::SP]; *now_trap_frame = old_trap_frame; if signal_module.sig_info { let pc = (*(sp as *const SignalUserContext)).get_pc(); - (*now_trap_frame).set_pc(pc); + (*now_trap_frame)[ContextArgs::SEPC] = pc; } } true @@ -191,7 +195,7 @@ pub fn handle_signals() { let trap_frame = unsafe { &mut *(current_task.get_first_trap_frame()) }; // // 新的trap上下文的sp指针位置,由于SIGINFO会存放内容,所以需要开个保护区域 - let mut sp = trap_frame.get_sp() - USER_SIGNAL_PROTECT; + let mut sp = trap_frame[ContextArgs::SP] - USER_SIGNAL_PROTECT; let restorer = if let Some(addr) = action.get_storer() { addr } else { @@ -203,13 +207,13 @@ pub fn handle_signals() { restorer, action.sa_handler ); #[cfg(not(target_arch = "x86_64"))] - trap_frame.set_ra(restorer); + trap_frame[ContextArgs::RA] = restorer; - let old_pc = trap_frame.get_pc(); + let old_pc = trap_frame[ContextArgs::SEPC]; - trap_frame.set_pc(action.sa_handler); + trap_frame[ContextArgs::SEPC] = action.sa_handler; // 传参 - trap_frame.set_arg0(sig_num); + trap_frame[ContextArgs::ARG0] = sig_num; // 若带有SIG_INFO参数,则函数原型为fn(sig: SignalNo, info: &SigInfo, ucontext: &mut UContext) if action.sa_flags.contains(SigActionFlags::SA_SIGINFO) { // current_task.set_siginfo(true); @@ -223,7 +227,7 @@ pub fn handle_signals() { unsafe { *(sp as *mut SigInfo) = info; } - trap_frame.set_arg1(sp); + trap_frame[ContextArgs::ARG1] = sp; // 接下来存储ucontext sp = (sp - core::mem::size_of::()) & !0xf; @@ -232,7 +236,7 @@ pub fn handle_signals() { unsafe { *(sp as *mut SignalUserContext) = ucontext; } - trap_frame.set_arg2(sp); + trap_frame[ContextArgs::ARG2] = sp; } #[cfg(target_arch = "x86_64")] @@ -242,7 +246,8 @@ pub fn handle_signals() { *(sp as *mut usize) = restorer; } - trap_frame.set_user_sp(sp); + // trap_frame.set_user_sp(sp); + trap_frame[ContextArgs::SP] = sp; drop(signal_handler); drop(signal_modules); } @@ -255,7 +260,7 @@ pub fn signal_return() -> isize { // 说明确实存在着信号处理函数的trap上下文 // 此时内核栈上存储的是调用信号处理前的trap上下文 let trap_frame = current_task().get_first_trap_frame(); - unsafe { (*trap_frame).get_ret_code() as isize } + unsafe { (*trap_frame)[ContextArgs::RET] as isize } } else { // 没有进行信号处理,但是调用了sig_return // 此时直接返回-1 diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index b5fd550f17..1d622bac5d 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -42,4 +42,5 @@ axmem = { path = "../axmem", optional = true } crate_interface = { path = "../../crates/crate_interface" } percpu = { path = "../../crates/percpu", optional = true } kernel_guard = { path = "../../crates/kernel_guard", optional = true } -lazy_init = { path = "../../crates/lazy_init", optional = true } \ No newline at end of file +lazy_init = { path = "../../crates/lazy_init", optional = true } +hal = { path = "../../crates/hal", features = ["stackful"] } diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index abfbf8bd4e..ad4cc51cc0 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -106,7 +106,7 @@ fn is_init_ok() -> bool { /// In multi-core environment, this function is called on the primary CPU, /// and the secondary CPUs call [`rust_main_secondary`]. #[cfg_attr(not(test), no_mangle)] -pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { +pub extern "C" fn rust_main(cpu_id: usize) -> ! { ax_println!("{}", LOGO); ax_println!( "\ @@ -125,10 +125,8 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { option_env!("AX_LOG").unwrap_or(""), ); - axlog::init(); - axlog::set_max_level(option_env!("AX_LOG").unwrap_or("")); // no effect if set `log-level-*` features - info!("Logging is enabled."); - info!("Primary CPU {} started, dtb = {:#x}.", cpu_id, dtb); + info!("Primary CPU {} started.", cpu_id); + axhal::cpu::init_primary(cpu_id); info!("Platform name {}.", axhal::platform_name()); info!("Found physcial memory regions:"); @@ -142,8 +140,8 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { ); } - #[cfg(feature = "alloc")] - init_allocator(); + // #[cfg(feature = "alloc")] + // init_allocator(); #[cfg(feature = "paging")] { @@ -326,3 +324,34 @@ fn init_tls() { unsafe { axhal::arch::write_thread_pointer(main_tls.tls_ptr() as usize) }; core::mem::forget(main_tls); } + +struct ArchInterfaceImpl; + +#[crate_interface::impl_interface] +impl hal::ArchInterface for ArchInterfaceImpl { + fn init_logging() { + axlog::init(); + axlog::set_max_level(option_env!("AX_LOG").unwrap_or("")); // no effect if set `log-level-*` features + info!("Logging is enabled."); + } + + fn main(hartid: usize) { + rust_main(hartid) + } + + fn kernel_interrupt(ctx: &mut hal::TrapFrame, from_user: bool, trap_type: hal::TrapType) { + axhal::arch::trap_handler(ctx, from_user, trap_type) + } + + fn add_memory_region(start: usize, end: usize) { + axalloc::global_add_memory(start, end - start).unwrap() + } + + fn prepare_drivers() {} + + fn try_to_add_device(_fdt_node: &hal::FdtNode) {} + + fn init_allocator() { + init_allocator() + } +} diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index 7fe05c6f3e..8d1ca4f8e1 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -497,7 +497,7 @@ impl TaskInner { #[cfg(feature = "monolithic")] // 初始化的trap上下文 - trap_frame: UnsafeCell::new(TrapFrame::default()), + trap_frame: UnsafeCell::new(TrapFrame::new()), #[cfg(feature = "monolithic")] page_table_token: 0, diff --git a/ulib/axstarry/src/ctypes.rs b/ulib/axstarry/src/ctypes.rs index f084b65655..391108d14c 100644 --- a/ulib/axstarry/src/ctypes.rs +++ b/ulib/axstarry/src/ctypes.rs @@ -547,6 +547,7 @@ pub fn normal_file_mode(file_type: StMode) -> StMode { } /// prctl 中 PR_NAME_SIZE 要求的缓冲区长度 +#[allow(dead_code)] pub const PR_NAME_SIZE: usize = 16; numeric_enum_macro::numeric_enum! { diff --git a/ulib/axstarry/src/syscall_fs/imp/ctl.rs b/ulib/axstarry/src/syscall_fs/imp/ctl.rs index ca7dd916f0..3ac28067e2 100644 --- a/ulib/axstarry/src/syscall_fs/imp/ctl.rs +++ b/ulib/axstarry/src/syscall_fs/imp/ctl.rs @@ -13,8 +13,6 @@ use axprocess::{ link::{deal_with_path, FilePath, AT_FDCWD}, }; -use super::{syscall_unlinkat, AT_REMOVEDIR}; - extern crate alloc; use alloc::string::ToString; @@ -102,6 +100,7 @@ pub fn syscall_mkdirat(args: [usize; 6]) -> SyscallResult { /// * `mode`: u32, 文件的所有权描述。详见`man 7 inode `。 /// # Return /// 成功执行,返回0。失败,返回-1。 +#[cfg(feature = "x86_64")] pub fn syscall_mkdir(args: [usize; 6]) -> SyscallResult { let path = args[0]; let mode = args[1]; @@ -341,6 +340,7 @@ pub fn syscall_renameat2(args: [usize; 6]) -> SyscallResult { /// * `old_path`: *const u8 /// * `new_path`: *const u8 /// To rename the file from old_path to new_path +#[cfg(feature = "x86_64")] pub fn syscall_rename(args: [usize; 6]) -> SyscallResult { let old_path = args[0]; let new_path = args[1]; @@ -536,6 +536,7 @@ pub fn syscall_faccessat(args: [usize; 6]) -> SyscallResult { /// # Arguments /// * `path`: *const u8, 文件的路径 /// * `mode`: usize, 文件的权限 +#[cfg(feature = "x86_64")] pub fn syscall_access(args: [usize; 6]) -> SyscallResult { let path = args[0]; let mode = args[1]; @@ -548,7 +549,10 @@ pub fn syscall_access(args: [usize; 6]) -> SyscallResult { /// 删除目录 /// # Arguments /// * `path`: *const u8, 文件的路径 +#[cfg(feature = "x86_64")] pub fn syscall_rmdir(args: [usize; 6]) -> SyscallResult { + use super::{syscall_unlinkat, AT_REMOVEDIR}; + let path = args[0]; let temp_args = [AT_FDCWD, path, AT_REMOVEDIR, 0, 0, 0]; syscall_unlinkat(temp_args) diff --git a/ulib/axstarry/src/syscall_fs/imp/io.rs b/ulib/axstarry/src/syscall_fs/imp/io.rs index 5f254c4656..58c26c141f 100644 --- a/ulib/axstarry/src/syscall_fs/imp/io.rs +++ b/ulib/axstarry/src/syscall_fs/imp/io.rs @@ -10,7 +10,7 @@ use axfs::api::{FileIOType, OpenFlags, SeekFrom}; use axlog::{debug, info}; use axprocess::current_process; -use axprocess::link::{create_link, deal_with_path, real_path, AT_FDCWD}; +use axprocess::link::{create_link, deal_with_path, real_path}; use crate::syscall_fs::ctype::{ dir::new_dir, @@ -255,6 +255,7 @@ pub fn syscall_pipe2(args: [usize; 6]) -> SyscallResult { /// 返回值:成功执行,返回0。失败,返回-1。 /// /// 注意:`fd[2]`是32位数组,所以这里的 fd 是 u32 类型的指针,而不是 usize 类型的指针。 +#[cfg(feature = "x86_64")] pub fn syscall_pipe(mut args: [usize; 6]) -> SyscallResult { args[1] = 0; syscall_pipe2(args) @@ -293,6 +294,7 @@ pub fn syscall_dup(args: [usize; 6]) -> SyscallResult { /// * fd: usize, 原文件所在的文件描述符 /// * new_fd: usize, 新的文件描述符 /// 返回值:成功执行,返回新的文件描述符。失败,返回-1。 +#[cfg(feature = "x86_64")] pub fn syscall_dup2(args: [usize; 6]) -> SyscallResult { syscall_dup3(args) } @@ -402,7 +404,10 @@ pub fn syscall_openat(args: [usize; 6]) -> SyscallResult { /// /// 说明:如果打开的是一个目录,那么返回的文件描述符指向的是该目录的描述符。(后面会用到针对目录的文件描述符) /// flags: O_RDONLY: 0, O_WRONLY: 1, O_RDWR: 2, O_CREAT: 64, O_DIRECTORY: 65536 +#[cfg(feature = "x86_64")] pub fn syscall_open(args: [usize; 6]) -> SyscallResult { + use axprocess::link::AT_FDCWD; + let temp_args = [AT_FDCWD, args[0], args[1], args[2], 0, 0]; syscall_openat(temp_args) } @@ -615,7 +620,10 @@ pub fn syscall_readlinkat(args: [usize; 6]) -> SyscallResult { /// * `path`: *const u8 /// * `buf`: *mut u8 /// * `bufsiz`: usize +#[cfg(feature = "x86_64")] pub fn syscall_readlink(args: [usize; 6]) -> SyscallResult { + use axprocess::link::AT_FDCWD; + let temp_args = [AT_FDCWD, args[0], args[1], args[2], 0, 0]; syscall_readlinkat(temp_args) } diff --git a/ulib/axstarry/src/syscall_fs/imp/link.rs b/ulib/axstarry/src/syscall_fs/imp/link.rs index 2eddc97d0e..7cd9b0a774 100644 --- a/ulib/axstarry/src/syscall_fs/imp/link.rs +++ b/ulib/axstarry/src/syscall_fs/imp/link.rs @@ -49,6 +49,7 @@ pub fn sys_linkat(args: [usize; 6]) -> SyscallResult { /// * `path`: *const u8, 要删除的链接的名字。 /// # Return /// 成功执行,返回0。失败,返回-1。 +#[cfg(feature = "x86_64")] pub fn syscall_unlink(args: [usize; 6]) -> SyscallResult { let path = args[0] as *const u8; let temp_args = [axprocess::link::AT_FDCWD, path as usize, 0, 0, 0, 0]; diff --git a/ulib/axstarry/src/syscall_fs/imp/poll.rs b/ulib/axstarry/src/syscall_fs/imp/poll.rs index 5c03a6347e..2a022427d8 100644 --- a/ulib/axstarry/src/syscall_fs/imp/poll.rs +++ b/ulib/axstarry/src/syscall_fs/imp/poll.rs @@ -3,7 +3,7 @@ use axhal::{mem::VirtAddr, time::current_ticks}; use axprocess::{current_process, yield_now_task}; use bitflags::bitflags; extern crate alloc; -use crate::{SyscallError, SyscallResult, TimeSecs, TimeVal}; +use crate::{SyscallError, SyscallResult, TimeSecs}; use alloc::{sync::Arc, vec::Vec}; bitflags! { /// 在文件上等待或者发生过的事件 @@ -214,7 +214,10 @@ pub fn syscall_ppoll(args: [usize; 6]) -> SyscallResult { /// * `ufds` - *mut PollFd /// * `nfds` - usize /// * `timeout_msecs` - usize +#[cfg(feature = "x86_64")] pub fn syscall_poll(args: [usize; 6]) -> SyscallResult { + use crate::TimeVal; + let ufds = args[0] as *mut PollFd; let nfds = args[1]; let timeout_msecs = args[2]; @@ -302,6 +305,7 @@ fn init_fd_set(addr: *mut usize, len: usize) -> Result /// * `writefds` - *mut usize /// * `exceptfds` - *mut usize /// * `timeout` - *const TimeSecs +#[cfg(feature = "x86_64")] pub fn syscall_select(mut args: [usize; 6]) -> SyscallResult { args[5] = 0; syscall_pselect6(args) diff --git a/ulib/axstarry/src/syscall_fs/imp/stat.rs b/ulib/axstarry/src/syscall_fs/imp/stat.rs index 348adf8f5a..5a6fd9d011 100644 --- a/ulib/axstarry/src/syscall_fs/imp/stat.rs +++ b/ulib/axstarry/src/syscall_fs/imp/stat.rs @@ -94,6 +94,7 @@ pub fn syscall_fstatat(args: [usize; 6]) -> SyscallResult { /// # Arguments /// * `path` - *const u8 /// * `kst` - *mut Kstat +#[cfg(feature = "x86_64")] pub fn syscall_lstat(args: [usize; 6]) -> SyscallResult { let path = args[0]; let kst = args[1]; @@ -105,6 +106,7 @@ pub fn syscall_lstat(args: [usize; 6]) -> SyscallResult { /// # Arguments /// * `path` - *const u8 /// * `stat_ptr` - *mut Kstat +#[cfg(feature = "x86_64")] pub fn syscall_stat(args: [usize; 6]) -> SyscallResult { let path = args[0]; let stat_ptr = args[1]; diff --git a/ulib/axstarry/src/syscall_task/imp/task.rs b/ulib/axstarry/src/syscall_task/imp/task.rs index 281dec0c25..8e0b54c385 100644 --- a/ulib/axstarry/src/syscall_task/imp/task.rs +++ b/ulib/axstarry/src/syscall_task/imp/task.rs @@ -1,7 +1,6 @@ -use axtask::current; +use core::mem::size_of; /// 处理与任务(线程)有关的系统调用 use core::time::Duration; -use core::{mem::size_of, ptr::slice_from_raw_parts_mut}; use axconfig::TASK_STACK_SIZE; use axhal::time::current_time; @@ -18,8 +17,8 @@ use axprocess::{ // AxTaskRef, // }; use crate::{ - CloneArgs, PrctlOption, RLimit, SyscallError, SyscallResult, TimeSecs, WaitFlags, PR_NAME_SIZE, - RLIMIT_AS, RLIMIT_NOFILE, RLIMIT_STACK, + CloneArgs, RLimit, SyscallError, SyscallResult, TimeSecs, WaitFlags, RLIMIT_AS, RLIMIT_NOFILE, + RLIMIT_STACK, }; use axlog::{info, warn}; use axtask::TaskId; @@ -251,6 +250,7 @@ pub fn syscall_clone3(args: [usize; 6]) -> SyscallResult { } /// 创建一个子进程,挂起父进程,直到子进程exec或者exit,父进程才继续执行 +#[cfg(feature = "x86_64")] pub fn syscall_vfork() -> SyscallResult { let args: [usize; 6] = [0x4011, 0, 0, 0, 0, 0]; syscall_clone(args) @@ -552,6 +552,7 @@ pub fn syscall_arch_prctl(args: [usize; 6]) -> SyscallResult { } /// To implement the fork syscall for x86_64 +#[cfg(feature = "x86_64")] pub fn syscall_fork() -> SyscallResult { warn!("transfer syscall_fork to syscall_clone"); let args = [1, 0, 0, 0, 0, 0]; @@ -562,13 +563,18 @@ pub fn syscall_fork() -> SyscallResult { /// # Arguments /// * `option` - usize /// * `arg2` - *mut u8 +#[cfg(feature = "x86_64")] pub fn syscall_prctl(args: [usize; 6]) -> SyscallResult { + use core::ptr::slice_from_raw_parts_mut; + + use crate::{PrctlOption, PR_NAME_SIZE}; + let option = args[0]; let arg2 = args[1] as *mut u8; match PrctlOption::try_from(option) { Ok(PrctlOption::PR_GET_NAME) => { // 获取进程名称。 - let mut process_name = current().name().to_string(); + let mut process_name = current_task().name().to_string(); process_name += "\0"; // [syscall 定义](https://man7.org/linux/man-pages/man2/prctl.2.html)要求 NAME 应该不超过 16 Byte process_name.truncate(PR_NAME_SIZE);