diff --git a/Cargo.lock b/Cargo.lock index 95ad03b9b8..0a142db4f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,10 +172,12 @@ dependencies = [ "axio", "axlog", "axnet", + "axns", "axruntime", "axsync", "axtask", "bindgen", + "ctor_bare", "flatten_objects", "lazy_static", "spin", @@ -400,6 +402,7 @@ dependencies = [ "axfs_ramfs", "axfs_vfs", "axio", + "axns", "axsync", "axtask", "cap_access", @@ -545,6 +548,15 @@ dependencies = [ "spin", ] +[[package]] +name = "axns" +version = "0.1.0" +dependencies = [ + "axns", + "crate_interface", + "lazyinit", +] + [[package]] name = "axruntime" version = "0.1.0" @@ -561,6 +573,7 @@ dependencies = [ "axtask", "chrono", "crate_interface", + "ctor_bare", "kernel_guard", "percpu", ] @@ -852,6 +865,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "ctor_bare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e5ae3c454dc1efb0e5821dc17344539849391b2de18c89596ea563f1909f93" +dependencies = [ + "ctor_bare_macros", +] + +[[package]] +name = "ctor_bare_macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49d5cd78b1c748184d41407b14a58af8403c13328ff2b9f49b0a418c24e3ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "defmt" version = "0.3.10" diff --git a/Cargo.toml b/Cargo.toml index 2924a174af..dfc0a37bda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "modules/axmm", "modules/axdma", "modules/axnet", + "modules/axns", "modules/axruntime", "modules/axsync", "modules/axtask", @@ -58,6 +59,7 @@ axhal = { path = "modules/axhal" } axlog = { path = "modules/axlog" } axmm = { path = "modules/axmm" } axnet = { path = "modules/axnet" } +axns = { path = "modules/axns" } axruntime = { path = "modules/axruntime" } axsync = { path = "modules/axsync" } axtask = { path = "modules/axtask" } diff --git a/api/arceos_posix_api/Cargo.toml b/api/arceos_posix_api/Cargo.toml index 681b6aeb71..2794bda372 100644 --- a/api/arceos_posix_api/Cargo.toml +++ b/api/arceos_posix_api/Cargo.toml @@ -23,12 +23,13 @@ smp = ["axfeat/smp"] irq = ["axfeat/irq"] alloc = ["dep:axalloc", "axfeat/alloc"] multitask = ["axtask/multitask", "axfeat/multitask", "axsync/multitask"] -fd = ["alloc"] +fd = ["alloc", "dep:axns"] fs = ["dep:axfs", "axfeat/fs", "fd"] net = ["dep:axnet", "axfeat/net", "fd"] pipe = ["fd"] select = ["fd"] epoll = ["fd"] +uspace = ["axns/thread-local"] [dependencies] # ArceOS modules @@ -42,6 +43,7 @@ axalloc = { workspace = true, optional = true } axtask = { workspace = true, optional = true } axfs = { workspace = true, optional = true } axnet = { workspace = true, optional = true } +axns = { workspace = true, optional = true } # Other crates axio = "0.1" @@ -50,6 +52,7 @@ flatten_objects = "0.2" static_assertions = "1.1.0" spin = { version = "0.9" } lazy_static = { version = "1.5", features = ["spin_no_std"] } +ctor_bare = "0.2" [build-dependencies] bindgen ={ version = "0.69" } diff --git a/api/arceos_posix_api/src/imp/fd_ops.rs b/api/arceos_posix_api/src/imp/fd_ops.rs index 53663c584a..7274b4cb13 100644 --- a/api/arceos_posix_api/src/imp/fd_ops.rs +++ b/api/arceos_posix_api/src/imp/fd_ops.rs @@ -3,11 +3,12 @@ use core::ffi::c_int; use axerrno::{LinuxError, LinuxResult}; use axio::PollState; +use axns::{ResArc, def_resource}; use flatten_objects::FlattenObjects; use spin::RwLock; -use super::stdio::{stdin, stdout}; use crate::ctypes; +use crate::imp::stdio::{stdin, stdout}; pub const AX_FILE_LIMIT: usize = 1024; @@ -21,14 +22,8 @@ pub trait FileLike: Send + Sync { fn set_nonblocking(&self, nonblocking: bool) -> LinuxResult; } -lazy_static::lazy_static! { - static ref FD_TABLE: RwLock, AX_FILE_LIMIT>> = { - let mut fd_table = FlattenObjects::new(); - fd_table.add_at(0, Arc::new(stdin()) as _).unwrap_or_else(|_| panic!()); // stdin - fd_table.add_at(1, Arc::new(stdout()) as _).unwrap_or_else(|_| panic!()); // stdout - fd_table.add_at(2, Arc::new(stdout()) as _).unwrap_or_else(|_| panic!()); // stderr - RwLock::new(fd_table) - }; +def_resource! { + pub(crate) static FD_TABLE: ResArc, AX_FILE_LIMIT>>> = ResArc::new(); } pub fn get_file_like(fd: c_int) -> LinuxResult> { @@ -127,3 +122,18 @@ pub fn sys_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int { } }) } + +#[ctor_bare::register_ctor] +fn init_stdio() { + let mut fd_table = flatten_objects::FlattenObjects::new(); + fd_table + .add_at(0, Arc::new(stdin()) as _) + .unwrap_or_else(|_| panic!()); // stdin + fd_table + .add_at(1, Arc::new(stdout()) as _) + .unwrap_or_else(|_| panic!()); // stdout + fd_table + .add_at(2, Arc::new(stdout()) as _) + .unwrap_or_else(|_| panic!()); // stderr + FD_TABLE.init_new(spin::RwLock::new(fd_table)); +} diff --git a/api/arceos_posix_api/src/imp/io_mpx/select.rs b/api/arceos_posix_api/src/imp/io_mpx/select.rs index 8a3471a672..c51d1f0513 100644 --- a/api/arceos_posix_api/src/imp/io_mpx/select.rs +++ b/api/arceos_posix_api/src/imp/io_mpx/select.rs @@ -153,13 +153,13 @@ pub unsafe fn sys_select( unsafe fn zero_fd_set(fds: *mut ctypes::fd_set, nfds: usize) { if !fds.is_null() { let nfds_usizes = nfds.div_ceil(BITS_PER_USIZE); - let dst = &mut (*fds).fds_bits[..nfds_usizes]; + let dst = &mut unsafe { *fds }.fds_bits[..nfds_usizes]; dst.fill(0); } } unsafe fn set_fd_set(fds: *mut ctypes::fd_set, fd: usize) { if !fds.is_null() { - (*fds).fds_bits[fd / BITS_PER_USIZE] |= 1 << (fd % BITS_PER_USIZE); + unsafe { *fds }.fds_bits[fd / BITS_PER_USIZE] |= 1 << (fd % BITS_PER_USIZE); } } diff --git a/api/arceos_posix_api/src/imp/net.rs b/api/arceos_posix_api/src/imp/net.rs index 861e4737bb..3c43430e3c 100644 --- a/api/arceos_posix_api/src/imp/net.rs +++ b/api/arceos_posix_api/src/imp/net.rs @@ -525,10 +525,10 @@ pub unsafe fn sys_freeaddrinfo(res: *mut ctypes::addrinfo) { return; } let aibuf_ptr = res as *mut ctypes::aibuf; - let len = (*aibuf_ptr).ref_ as usize; - assert!((*aibuf_ptr).slot == 0); + let len = unsafe { *aibuf_ptr }.ref_ as usize; + assert!(unsafe { *aibuf_ptr }.slot == 0); assert!(len > 0); - let vec = Vec::from_raw_parts(aibuf_ptr, len, len); // TODO: lock + let vec = unsafe { Vec::from_raw_parts(aibuf_ptr, len, len) }; // TODO: lock drop(vec); } diff --git a/modules/axfs/Cargo.toml b/modules/axfs/Cargo.toml index 13d2e141fe..441a923817 100644 --- a/modules/axfs/Cargo.toml +++ b/modules/axfs/Cargo.toml @@ -34,6 +34,7 @@ crate_interface = { version = "0.1", optional = true } axsync = { workspace = true } axdriver = { workspace = true, features = ["block"] } axdriver_block = { git = "https://github.com/arceos-org/axdriver_crates.git", tag = "v0.1.0" } +axns = { workspace = true } [dependencies.fatfs] git = "https://github.com/rafalh/rust-fatfs" diff --git a/modules/axfs/src/root.rs b/modules/axfs/src/root.rs index 83de70ef63..afa3f937a2 100644 --- a/modules/axfs/src/root.rs +++ b/modules/axfs/src/root.rs @@ -5,13 +5,16 @@ use alloc::{string::String, sync::Arc, vec::Vec}; use axerrno::{AxError, AxResult, ax_err}; use axfs_vfs::{VfsNodeAttr, VfsNodeOps, VfsNodeRef, VfsNodeType, VfsOps, VfsResult}; +use axns::{ResArc, def_resource}; use axsync::Mutex; use lazyinit::LazyInit; use crate::{api::FileType, fs, mounts}; -static CURRENT_DIR_PATH: Mutex = Mutex::new(String::new()); -static CURRENT_DIR: LazyInit> = LazyInit::new(); +def_resource! { + static CURRENT_DIR_PATH: ResArc> = ResArc::new(); + static CURRENT_DIR: ResArc> = ResArc::new(); +} struct MountPoint { path: &'static str, @@ -180,8 +183,8 @@ pub(crate) fn init_rootfs(disk: crate::dev::Disk) { .expect("fail to mount sysfs at /sys"); ROOT_DIR.init_once(Arc::new(root_dir)); - CURRENT_DIR.init_once(Mutex::new(ROOT_DIR.clone())); - *CURRENT_DIR_PATH.lock() = "/".into(); + CURRENT_DIR.init_new(Mutex::new(ROOT_DIR.clone())); + CURRENT_DIR_PATH.init_new(Mutex::new("/".into())); } fn parent_node_of(dir: Option<&VfsNodeRef>, path: &str) -> VfsNodeRef { diff --git a/modules/axhal/linker.lds.S b/modules/axhal/linker.lds.S index b8d42ee770..aa3b3c9ca3 100644 --- a/modules/axhal/linker.lds.S +++ b/modules/axhal/linker.lds.S @@ -16,15 +16,22 @@ SECTIONS _etext = .; } + _srodata = .; .rodata : ALIGN(4K) { - _srodata = .; *(.rodata .rodata.*) *(.srodata .srodata.*) *(.sdata2 .sdata2.*) - . = ALIGN(4K); - _erodata = .; } + .init_array : ALIGN(0x10) { + __init_array_start = .; + *(.init_array .init_array.*) + __init_array_end = .; + } + + . = ALIGN(4K); + _erodata = .; + .data : ALIGN(4K) { _sdata = .; *(.data.boot_page_table) @@ -89,5 +96,6 @@ SECTIONS { linkm2_PAGE_FAULT : { *(linkm2_PAGE_FAULT) } linkme_SYSCALL : { *(linkme_SYSCALL) } linkm2_SYSCALL : { *(linkm2_SYSCALL) } + axns_resource : { *(axns_resource) } } INSERT AFTER .tbss; diff --git a/modules/axhal/src/arch/aarch64/context.rs b/modules/axhal/src/arch/aarch64/context.rs index 23a4fe5a48..ddd39f2fa2 100644 --- a/modules/axhal/src/arch/aarch64/context.rs +++ b/modules/axhal/src/arch/aarch64/context.rs @@ -118,41 +118,43 @@ impl UspaceContext { /// /// This function is unsafe because it changes processor mode and the stack. #[inline(never)] - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! { super::disable_irqs(); // We do not handle traps that occur at the current exception level, // so the kstack ptr(`sp_el1`) will not change during running in user space. // Then we don't need to save the `sp_el1` to the taskctx. - asm!( - " - mov sp, x1 - ldp x30, x9, [x0, 30 * 8] - ldp x10, x11, [x0, 32 * 8] - msr sp_el0, x9 - msr elr_el1, x10 - msr spsr_el1, x11 + unsafe { + core::arch::asm!( + " + mov sp, x1 + ldp x30, x9, [x0, 30 * 8] + ldp x10, x11, [x0, 32 * 8] + msr sp_el0, x9 + msr elr_el1, x10 + msr spsr_el1, x11 - 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", - in("x0") &self.0, - in("x1") kstack_top.as_usize() , - options(noreturn), - ) + 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", + in("x0") &self.0, + in("x1") kstack_top.as_usize() , + options(noreturn), + ) + } } } diff --git a/modules/axhal/src/arch/aarch64/mod.rs b/modules/axhal/src/arch/aarch64/mod.rs index 9e56602b2c..2d99acad8c 100644 --- a/modules/axhal/src/arch/aarch64/mod.rs +++ b/modules/axhal/src/arch/aarch64/mod.rs @@ -144,7 +144,7 @@ pub unsafe fn write_thread_pointer(tpidr_el0: usize) { /// /// On AArch64, it sets the exception vector base address (`VBAR_EL1`) and `TTBR0_EL1`. pub fn cpu_init() { - extern "C" { + unsafe extern "C" { fn exception_vector_base(); } set_exception_vector_base(exception_vector_base as usize); diff --git a/modules/axhal/src/arch/riscv/context.rs b/modules/axhal/src/arch/riscv/context.rs index b92a24754f..5efd89d923 100644 --- a/modules/axhal/src/arch/riscv/context.rs +++ b/modules/axhal/src/arch/riscv/context.rs @@ -150,8 +150,7 @@ impl UspaceContext { /// # Safety /// /// This function is unsafe because it changes processor mode and the stack. - #[inline(never)] - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! { use riscv::register::{sepc, sscratch}; @@ -160,24 +159,28 @@ impl UspaceContext { sepc::write(self.0.sepc); // Address of the top of the kernel stack after saving the trap frame. let kernel_trap_addr = kstack_top.as_usize() - core::mem::size_of::(); - asm!(" - mv sp, {tf} - - STR gp, {kernel_trap_addr}, 2 - LDR gp, sp, 2 - - STR tp, {kernel_trap_addr}, 3 - LDR tp, sp, 3 - - LDR t0, sp, 32 - csrw sstatus, t0 - POP_GENERAL_REGS - LDR sp, sp, 1 - sret", - tf = in(reg) &(self.0), - kernel_trap_addr = in(reg) kernel_trap_addr, - options(noreturn), - ) + unsafe { + core::arch::asm!( + include_asm_macros!(), + " + mv sp, {tf} + + STR gp, {kernel_trap_addr}, 2 + LDR gp, sp, 2 + + STR tp, {kernel_trap_addr}, 3 + LDR tp, sp, 3 + + LDR t0, sp, 32 + csrw sstatus, t0 + POP_GENERAL_REGS + LDR sp, sp, 1 + sret", + tf = in(reg) &(self.0), + kernel_trap_addr = in(reg) kernel_trap_addr, + options(noreturn), + ) + } } } @@ -281,7 +284,7 @@ impl TaskContext { #[naked] unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) { naked_asm!( - include_asm_marcos!(), + include_asm_macros!(), " // save old context (callee-saved registers) STR ra, a0, 0 diff --git a/modules/axhal/src/arch/riscv/macros.rs b/modules/axhal/src/arch/riscv/macros.rs index a793036774..6377a2ec20 100644 --- a/modules/axhal/src/arch/riscv/macros.rs +++ b/modules/axhal/src/arch/riscv/macros.rs @@ -1,5 +1,5 @@ #[cfg(target_arch = "riscv32")] -macro_rules! include_asm_marcos { +macro_rules! __asm_macros { () => { r" .ifndef XLENB @@ -17,7 +17,7 @@ macro_rules! include_asm_marcos { } #[cfg(target_arch = "riscv64")] -macro_rules! include_asm_marcos { +macro_rules! __asm_macros { () => { r" .ifndef XLENB @@ -33,3 +33,54 @@ macro_rules! include_asm_marcos { .endif" }; } + +macro_rules! include_asm_macros { + () => { + concat!( + __asm_macros!(), + r" + .ifndef REGS_MACROS_FLAG + .equ REGS_MACROS_FLAG, 1 + + .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 36ce91da41..07caf58643 100644 --- a/modules/axhal/src/arch/riscv/mod.rs +++ b/modules/axhal/src/arch/riscv/mod.rs @@ -114,7 +114,7 @@ pub unsafe fn write_thread_pointer(tp: usize) { /// /// On RISC-V, it sets the trap vector base address. pub fn cpu_init() { - extern "C" { + unsafe extern "C" { fn trap_vector_base(); } set_trap_vector_base(trap_vector_base as usize); diff --git a/modules/axhal/src/arch/riscv/trap.S b/modules/axhal/src/arch/riscv/trap.S index c42780a6f7..8a594b8ada 100644 --- a/modules/axhal/src/arch/riscv/trap.S +++ b/modules/axhal/src/arch/riscv/trap.S @@ -1,42 +1,3 @@ -.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 - .macro SAVE_REGS, from_user addi sp, sp, -{trapframe_size} PUSH_GENERAL_REGS diff --git a/modules/axhal/src/arch/riscv/trap.rs b/modules/axhal/src/arch/riscv/trap.rs index 3867f778d4..febf88e572 100644 --- a/modules/axhal/src/arch/riscv/trap.rs +++ b/modules/axhal/src/arch/riscv/trap.rs @@ -6,7 +6,7 @@ use riscv::register::{scause, stval}; use super::TrapFrame; core::arch::global_asm!( - include_asm_marcos!(), + include_asm_macros!(), include_str!("trap.S"), trapframe_size = const core::mem::size_of::(), ); diff --git a/modules/axhal/src/arch/x86_64/context.rs b/modules/axhal/src/arch/x86_64/context.rs index 8eedec44a7..ccec7e4c9d 100644 --- a/modules/axhal/src/arch/x86_64/context.rs +++ b/modules/axhal/src/arch/x86_64/context.rs @@ -1,6 +1,5 @@ use core::{arch::naked_asm, fmt}; use memory_addr::VirtAddr; - /// Saved registers when a trap (interrupt or exception) occurs. #[allow(missing_docs)] #[repr(C)] @@ -85,6 +84,8 @@ impl UspaceContext { /// Creates a new context with the given entry point, user stack pointer, /// and the argument. pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self { + use crate::arch::GdtStruct; + use x86_64::registers::rflags::RFlags; Self(TrapFrame { rdi: arg0 as _, rip: entry as _, @@ -102,6 +103,7 @@ impl UspaceContext { /// It copies almost all registers except `CS` and `SS` which need to be /// set to the user segment selectors. pub const fn from(tf: &TrapFrame) -> Self { + use crate::arch::GdtStruct; let mut tf = *tf; tf.cs = GdtStruct::UCODE64_SELECTOR.0 as _; tf.ss = GdtStruct::UDATA_SELECTOR.0 as _; @@ -146,29 +148,31 @@ impl UspaceContext { pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! { super::disable_irqs(); assert_eq!(super::tss_get_rsp0(), kstack_top); - core::arch::asm!(" - mov rsp, {tf} - 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, 16 // skip vector, error_code - swapgs - iretq", - tf = in(reg) &self.0, - options(noreturn), - ) + unsafe { + core::arch::asm!(" + mov rsp, {tf} + 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, 16 // skip vector, error_code + swapgs + iretq", + tf = in(reg) &self.0, + options(noreturn), + ) + } } } @@ -277,7 +281,7 @@ pub struct TaskContext { pub ext_state: ExtendedState, /// The `CR3` register value, i.e., the page table root. #[cfg(feature = "uspace")] - pub cr3: PhysAddr, + pub cr3: memory_addr::PhysAddr, } impl TaskContext { @@ -311,13 +315,10 @@ impl TaskContext { // is executed), (stack pointer + 8) should be 16-byte aligned. let frame_ptr = (kstack_top.as_mut_ptr() as *mut u64).sub(1); let frame_ptr = (frame_ptr as *mut ContextSwitchFrame).sub(1); - core::ptr::write( - frame_ptr, - ContextSwitchFrame { - rip: entry as _, - ..Default::default() - }, - ); + core::ptr::write(frame_ptr, ContextSwitchFrame { + rip: entry as _, + ..Default::default() + }); self.rsp = frame_ptr as u64; } self.kstack_top = kstack_top; @@ -331,7 +332,7 @@ impl TaskContext { /// /// [1]: crate::paging::kernel_page_table_root #[cfg(feature = "uspace")] - pub fn set_page_table_root(&mut self, cr3: PhysAddr) { + pub fn set_page_table_root(&mut self, cr3: memory_addr::PhysAddr) { self.cr3 = cr3; } @@ -368,23 +369,24 @@ impl TaskContext { unsafe extern "C" fn context_switch(_current_stack: &mut u64, _next_stack: &u64) { unsafe { naked_asm!( - ".code64 - push rbp - push rbx - push r12 - push r13 - push r14 - push r15 - mov [rdi], rsp - - mov rsp, [rsi] - pop r15 - pop r14 - pop r13 - pop r12 - pop rbx - pop rbp - ret", + " + .code64 + push rbp + push rbx + push r12 + push r13 + push r14 + push r15 + mov [rdi], rsp + + mov rsp, [rsi] + pop r15 + pop r14 + pop r13 + pop r12 + pop rbx + pop rbp + ret", ) } } diff --git a/modules/axhal/src/arch/x86_64/mod.rs b/modules/axhal/src/arch/x86_64/mod.rs index a3b7d81156..e1b348da1c 100644 --- a/modules/axhal/src/arch/x86_64/mod.rs +++ b/modules/axhal/src/arch/x86_64/mod.rs @@ -15,8 +15,8 @@ use x86::{controlregs, msr, tlb}; use x86_64::instructions::interrupts; pub use self::context::{ExtendedState, FxsaveArea, TaskContext, TrapFrame}; -pub use self::gdt::{init_gdt, tss_get_rsp0, tss_set_rsp0, GdtStruct}; -pub use self::idt::{init_idt, IdtStruct}; +pub use self::gdt::{GdtStruct, init_gdt, tss_get_rsp0, tss_set_rsp0}; +pub use self::idt::{IdtStruct, init_idt}; #[cfg(feature = "uspace")] pub use self::{context::UspaceContext, syscall::init_syscall}; diff --git a/modules/axhal/src/arch/x86_64/syscall.S b/modules/axhal/src/arch/x86_64/syscall.S index 08ac99995d..61c511ec85 100644 --- a/modules/axhal/src/arch/x86_64/syscall.S +++ b/modules/axhal/src/arch/x86_64/syscall.S @@ -1,4 +1,5 @@ .section .text +.code64 syscall_entry: swapgs // switch to kernel gs mov gs:[offset __PERCPU_USER_RSP_OFFSET], rsp // save user rsp diff --git a/modules/axhal/src/arch/x86_64/syscall.rs b/modules/axhal/src/arch/x86_64/syscall.rs index 941ccd9ab3..92dcf130a8 100644 --- a/modules/axhal/src/arch/x86_64/syscall.rs +++ b/modules/axhal/src/arch/x86_64/syscall.rs @@ -5,7 +5,7 @@ use x86_64::structures::tss::TaskStateSegment; use super::{GdtStruct, TrapFrame}; -#[no_mangle] +#[unsafe(no_mangle)] #[percpu::def_percpu] static USER_RSP_OFFSET: usize = 0; @@ -14,14 +14,14 @@ core::arch::global_asm!( tss_rsp0_offset = const core::mem::offset_of!(TaskStateSegment, privilege_stack_table), ); -#[no_mangle] +#[unsafe(no_mangle)] pub(super) fn x86_syscall_handler(tf: &mut TrapFrame) { tf.rax = crate::trap::handle_syscall(tf, tf.rax as usize) as u64; } /// Initializes syscall support and setups the syscall handler. pub fn init_syscall() { - extern "C" { + unsafe extern "C" { fn syscall_entry(); } unsafe { diff --git a/modules/axhal/src/arch/x86_64/trap.rs b/modules/axhal/src/arch/x86_64/trap.rs index ae92f68a1b..7c44b60370 100644 --- a/modules/axhal/src/arch/x86_64/trap.rs +++ b/modules/axhal/src/arch/x86_64/trap.rs @@ -29,7 +29,7 @@ fn handle_page_fault(tf: &TrapFrame) { } } -#[no_mangle] +#[unsafe(no_mangle)] fn x86_trap_handler(tf: &mut TrapFrame) { match tf.vector as u8 { PAGE_FAULT_VECTOR => handle_page_fault(tf), diff --git a/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs b/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs index a50b2d5550..6dddea80b7 100644 --- a/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs +++ b/modules/axhal/src/platform/aarch64_bsta1000b/mod.rs @@ -20,7 +20,6 @@ pub mod time { } unsafe extern "C" { - fn exception_vector_base(); fn rust_main(cpu_id: usize, dtb: usize); #[cfg(feature = "smp")] fn rust_main_secondary(cpu_id: usize); diff --git a/modules/axhal/src/platform/aarch64_phytium_pi/mod.rs b/modules/axhal/src/platform/aarch64_phytium_pi/mod.rs index 546b703345..73199fb121 100644 --- a/modules/axhal/src/platform/aarch64_phytium_pi/mod.rs +++ b/modules/axhal/src/platform/aarch64_phytium_pi/mod.rs @@ -26,7 +26,6 @@ pub mod misc { } unsafe extern "C" { - fn exception_vector_base(); fn rust_main(cpu_id: usize, dtb: usize); #[cfg(feature = "smp")] fn rust_main_secondary(cpu_id: usize); @@ -35,7 +34,6 @@ unsafe extern "C" { pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { crate::mem::clear_bss(); let cpu_id = cpu_hard_id_to_logic_id(cpu_id); - crate::arch::set_exception_vector_base(exception_vector_base as usize); crate::arch::write_page_table_root0(0.into()); // disable low address access crate::cpu::init_primary(cpu_id); super::aarch64_common::pl011::init_early(); @@ -46,7 +44,6 @@ pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { #[cfg(feature = "smp")] pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { let cpu_id = cpu_hard_id_to_logic_id(cpu_id); - crate::arch::set_exception_vector_base(exception_vector_base as usize); crate::arch::write_page_table_root0(0.into()); // disable low address access crate::cpu::init_secondary(cpu_id); rust_main_secondary(cpu_id); diff --git a/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs b/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs index f1d3a570eb..a074c8b102 100644 --- a/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs +++ b/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs @@ -21,7 +21,6 @@ pub mod misc { } unsafe extern "C" { - fn exception_vector_base(); fn rust_main(cpu_id: usize, dtb: usize); #[cfg(feature = "smp")] fn rust_main_secondary(cpu_id: usize); diff --git a/modules/axhal/src/platform/aarch64_raspi/mod.rs b/modules/axhal/src/platform/aarch64_raspi/mod.rs index 2357eb16ad..f6f4113e1e 100644 --- a/modules/axhal/src/platform/aarch64_raspi/mod.rs +++ b/modules/axhal/src/platform/aarch64_raspi/mod.rs @@ -26,7 +26,6 @@ pub mod misc { } unsafe extern "C" { - fn exception_vector_base(); fn rust_main(cpu_id: usize, dtb: usize); #[cfg(feature = "smp")] fn rust_main_secondary(cpu_id: usize); @@ -34,7 +33,6 @@ unsafe extern "C" { pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { crate::mem::clear_bss(); - crate::arch::set_exception_vector_base(exception_vector_base as usize); crate::cpu::init_primary(cpu_id); super::aarch64_common::pl011::init_early(); super::aarch64_common::generic_timer::init_early(); @@ -43,7 +41,6 @@ pub(crate) unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) { #[cfg(feature = "smp")] pub(crate) unsafe extern "C" fn rust_entry_secondary(cpu_id: usize) { - crate::arch::set_exception_vector_base(exception_vector_base as usize); crate::cpu::init_secondary(cpu_id); rust_main_secondary(cpu_id); } diff --git a/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs b/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs index 4ab5d50bd9..e599e22e64 100644 --- a/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs +++ b/modules/axhal/src/platform/riscv64_qemu_virt/mod.rs @@ -12,7 +12,6 @@ pub mod irq; pub mod mp; unsafe extern "C" { - fn trap_vector_base(); fn rust_main(cpu_id: usize, dtb: usize); #[cfg(feature = "smp")] fn rust_main_secondary(cpu_id: usize); diff --git a/modules/axmm/src/backend/alloc.rs b/modules/axmm/src/backend/alloc.rs index e404d718a8..cce416ee0e 100644 --- a/modules/axmm/src/backend/alloc.rs +++ b/modules/axmm/src/backend/alloc.rs @@ -1,7 +1,7 @@ use axalloc::global_allocator; use axhal::mem::{phys_to_virt, virt_to_phys}; use axhal::paging::{MappingFlags, PageSize, PageTable}; -use memory_addr::{PageIter4K, PhysAddr, VirtAddr, PAGE_SIZE_4K}; +use memory_addr::{PAGE_SIZE_4K, PageIter4K, PhysAddr, VirtAddr}; use super::Backend; diff --git a/modules/axns/Cargo.toml b/modules/axns/Cargo.toml new file mode 100644 index 0000000000..7200734ac0 --- /dev/null +++ b/modules/axns/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "axns" +version.workspace = true +edition.workspace = true +authors = ["Yuekai Jia "] +description = "ArceOS namespaces to control system resource sharing between threads" +license.workspace = true +homepage.workspace = true +repository = "https://github.com/arceos-org/arceos/tree/main/modules/axns" +documentation = "https://arceos-org.github.io/arceos/axns/index.html" + +[features] +default = [] + +# Each thread has its individual namespace field, instead of using the global +# namespace. +thread-local = [] + +[dependencies] +lazyinit = "0.2" +crate_interface = "0.1" + +[dev-dependencies] +axns = { workspace = true, features = ["thread-local"] } diff --git a/modules/axns/src/lib.rs b/modules/axns/src/lib.rs new file mode 100644 index 0000000000..16158ad915 --- /dev/null +++ b/modules/axns/src/lib.rs @@ -0,0 +1,280 @@ +//! [ArceOS](https://github.com/arceos-org/arceos) namespaces module. +//! +//! Namespaces are used to control system resource sharing between threads. This +//! module provides a unified interface to access system resources in different +//! scenarios. +//! +//! For a unikernel, there is only one global namespace, so all threads share +//! the same system resources, such as virtual address space, working directory, +//! and file descriptors, etc. +//! +//! For a monolithic kernel, each process corresponds to a namespace, all +//! threads in the same process share the same system resources. Different +//! processes have different namespaces and isolated resources. +//! +//! For further container support, some global system resources can also be +//! grouped into a namespace. +//! +//! See the examples of [`def_resource!`] for more usage. + +#![cfg_attr(not(test), no_std)] + +extern crate alloc; + +use alloc::sync::Arc; +use core::{alloc::Layout, fmt, ops::Deref}; + +use lazyinit::LazyInit; + +unsafe extern "C" { + fn __start_axns_resource(); + fn __stop_axns_resource(); +} + +/// A namespace that contains all user-defined resources. +/// +/// There are two types of namespaces: +/// +/// - Global namespace: this namespace is globally unique and all threads share +/// the resources in it. Resources are statically collected into the +/// `axns_resource` section, and the global namespace is constructed by the base +/// address of the section ([`AxNamespace::global`]). +/// - Thread-local namespace: this namespace is per-thread, each thread should +/// call [`AxNamespace::new_thread_local()`] to allocate a memory area as its +/// namespace. Layout of resources in global and thread-local namespaces is +/// consistent. Each namespace has its own resources, which may be unique or +/// shared between threads by the [`Arc`] wrapper. +pub struct AxNamespace { + base: *mut u8, + alloc: bool, +} + +impl AxNamespace { + /// Returns the base address of the namespace, which points to the start of + /// all resources. + pub const fn base(&self) -> *mut u8 { + self.base + } + + /// Returns the size of the namespace (size of all resources). + pub fn size(&self) -> usize { + Self::section_size() + } + + /// Returns the size of the `axns_resource` section. + fn section_size() -> usize { + __stop_axns_resource as usize - __start_axns_resource as usize + } + + /// Returns the global namespace. + pub fn global() -> Self { + Self { + base: __start_axns_resource as *mut u8, + alloc: false, + } + } + + /// Constructs a new thread-local namespace. + /// + /// Each thread can have its own namespace instead of the global one, to + /// isolate resources between threads. + /// + /// This function allocates a memory area to store the thread-local resources, + /// and copies from the global namespace as the initial value. + #[cfg(feature = "thread-local")] + pub fn new_thread_local() -> Self { + let size = Self::section_size(); + let base = if size == 0 { + core::ptr::null_mut() + } else { + let layout = Layout::from_size_align(size, 64).unwrap(); + let dst = unsafe { alloc::alloc::alloc(layout) }; + let src = __start_axns_resource as *const u8; + unsafe { core::ptr::copy_nonoverlapping(src, dst, size) }; + dst + }; + Self { base, alloc: true } + } +} + +impl Drop for AxNamespace { + fn drop(&mut self) { + if self.alloc { + let size = Self::section_size(); + if size != 0 && !self.base.is_null() { + let layout = Layout::from_size_align(size, 64).unwrap(); + unsafe { alloc::alloc::dealloc(self.base, layout) }; + } + } + } +} + +/// A helper type to easily manage shared resources. +/// +/// It provides methods to lazily initialize the resource of the current thread, +/// or to share the resource with other threads. +pub struct ResArc(LazyInit>); + +impl ResArc { + /// Creates a new uninitialized resource. + pub const fn new() -> Self { + Self(LazyInit::new()) + } + + /// Returns a shared reference to the resource. + pub fn share(&self) -> Arc { + self.0.deref().clone() + } + + /// Initializes the resource and does not share with others. + pub fn init_new(&self, data: T) { + self.0.init_once(Arc::new(data)); + } + + /// Initializes the resource with the shared data. + pub fn init_shared(&self, data: Arc) { + self.0.init_once(data); + } + + /// Checks whether the value is initialized. + pub fn is_inited(&self) -> bool { + self.0.is_inited() + } +} + +impl Deref for ResArc { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl fmt::Debug for ResArc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +/// The interfaces need to be implemented when enable thread-local namespaces. +#[cfg(feature = "thread-local")] +#[crate_interface::def_interface] +pub trait AxNamespaceIf { + /// Returns the pointer to the current namespace. + /// + /// It usually needs to be obtained from the thread local storage. + fn current_namespace_base() -> *mut u8; +} + +/// Returns the pointer to the current namespace. +/// +/// When `thread-local` feature is enabled, it returns the thread-local namespace +/// of the current thread. Otherwise, it returns the global namespace. +/// +/// # Safety +/// +/// This function is unsafe, the returned pointer should not outlive the current +/// thread. +pub unsafe fn current_namespace_base() -> *mut u8 { + #[cfg(feature = "thread-local")] + { + crate_interface::call_interface!(AxNamespaceIf::current_namespace_base) + } + #[cfg(not(feature = "thread-local"))] + { + AxNamespace::global().base() + } +} + +/// Defines a resource that managed by [`AxNamespace`]. +/// +/// Each resource will be collected into the `axns_resource` section. When +/// accessed, it is either dereferenced from the global namespace or the +/// thread-local namespace according to the `thread-local` feature. +/// +/// # Example +/// +/// ``` +/// use axns::ResArc; +/// +/// axns::def_resource! { +/// static FOO: u32 = 42; +/// static BAR: ResArc = ResArc::new(); +/// } +/// +/// BAR.init_new("hello world".to_string()); +/// assert_eq!(*FOO, 42); +/// assert_eq!(BAR.as_str(), "hello world"); +/// +/// mod imp { +/// use axns::{AxNamespace, AxNamespaceIf}; +/// +/// struct ResArcImpl; +/// +/// #[crate_interface::impl_interface] +/// impl AxNamespaceIf for ResArcImpl { +/// fn current_namespace_base() -> *mut u8 { +/// AxNamespace::global().base() +/// } +/// } +/// } +/// ``` +#[macro_export] +macro_rules! def_resource { + ( $( $(#[$attr:meta])* $vis:vis static $name:ident: $ty:ty = $default:expr; )+ ) => { + $( + #[doc = concat!("Wrapper struct for the namespace resource [`", stringify!($name), "`]")] + #[allow(non_camel_case_types)] + $vis struct $name { __value: () } + + impl $name { + unsafe fn deref_from_base(&self, ns_base: *mut u8) -> &$ty { + unsafe extern { + fn __start_axns_resource(); + } + + #[unsafe(link_section = "axns_resource")] + static RES: $ty = $default; + + let offset = &RES as *const _ as usize - __start_axns_resource as usize; + let ptr = unsafe{ ns_base.add(offset) } as *const _; + unsafe{ &*ptr } + } + + /// Dereference the resource from the given namespace. + pub fn deref_from(&self, ns: &$crate::AxNamespace) -> &$ty { + unsafe { self.deref_from_base(ns.base()) } + } + + /// Dereference the resource from the global namespace. + pub fn deref_global(&self) -> &$ty { + self.deref_from(&$crate::AxNamespace::global()) + } + + /// Dereference the resource automatically, according whether the + /// `thread-local` feature of the `axns` crate is enabled or not. + /// + /// When the feature is enabled, it dereferences from the + /// thread-local namespace of the current thread. Otherwise, it + /// dereferences from the global namespace. + pub fn deref_auto(&self) -> &$ty { + unsafe { self.deref_from_base($crate::current_namespace_base()) } + } + } + + impl core::ops::Deref for $name { + type Target = $ty; + + #[inline(never)] + fn deref(&self) -> &Self::Target { + self.deref_auto() + } + } + + #[used] + #[doc(hidden)] + $(#[$attr])* + $vis static $name: $name = $name { __value: () }; + )+ + }; +} diff --git a/modules/axns/tests/test_global.rs b/modules/axns/tests/test_global.rs new file mode 100644 index 0000000000..00aaf4e430 --- /dev/null +++ b/modules/axns/tests/test_global.rs @@ -0,0 +1,71 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Barrier, Mutex}; +use std::thread; + +use axns::{ResArc, def_resource}; + +use self::imp::thread_init_namespace; + +def_resource! { + static FOO: ResArc = ResArc::new(); + static BAR: ResArc> = ResArc::new(); +} + +static BARRIER: Barrier = Barrier::new(3); + +fn thread_fn() { + FOO.fetch_add(1, Ordering::SeqCst); + BAR.lock().unwrap().push_str(" hello"); + + BARRIER.wait(); + println!("{:?} FOO: {:?}", std::thread::current().id(), *FOO); + println!("{:?} BAR: {:?}", std::thread::current().id(), BAR.lock()); + + // all threads share the same namespace + assert_eq!(FOO.load(Ordering::SeqCst), 103); + assert_eq!(BAR.lock().unwrap().as_str(), "one hello hello hello"); +} + +#[test] +fn test_namespace() { + thread_init_namespace(); + FOO.init_new(100.into()); + BAR.init_new(Mutex::new(String::from("one"))); + + let t1 = thread::spawn(|| { + thread_init_namespace(); + thread_fn(); + }); + let t2 = thread::spawn(|| { + thread_init_namespace(); + thread_fn(); + }); + + thread_fn(); + t1.join().unwrap(); + t2.join().unwrap(); +} + +mod imp { + use axns::{AxNamespace, AxNamespaceIf}; + use lazyinit::LazyInit; + + thread_local! { + static NS: LazyInit = LazyInit::new(); + } + + struct AxNamespaceImpl; + + #[crate_interface::impl_interface] + impl AxNamespaceIf for AxNamespaceImpl { + fn current_namespace_base() -> *mut u8 { + NS.with(|ns| ns.base()) + } + } + + pub fn thread_init_namespace() { + NS.with(|ns| { + ns.init_once(AxNamespace::global()); + }); + } +} diff --git a/modules/axns/tests/test_thread_local.rs b/modules/axns/tests/test_thread_local.rs new file mode 100644 index 0000000000..0b8eff465b --- /dev/null +++ b/modules/axns/tests/test_thread_local.rs @@ -0,0 +1,85 @@ +#![feature(thread_id_value)] + +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Barrier, Mutex}; +use std::thread; + +use axns::{ResArc, def_resource}; + +use self::imp::thread_init_namespace; + +def_resource! { + static FOO: ResArc = ResArc::new(); + static BAR: ResArc> = ResArc::new(); +} + +static BARRIER: Barrier = Barrier::new(3); + +fn thread_fn() { + FOO.fetch_add(1, Ordering::SeqCst); + BAR.lock().unwrap().push_str(" hello"); + + BARRIER.wait(); + println!("{:?} FOO: {:?}", std::thread::current().id(), *FOO); + println!("{:?} BAR: {:?}", std::thread::current().id(), BAR.lock()); + + let id: u64 = thread::current().id().as_u64().into(); + if id == 2 || id == 4 { + assert_eq!(FOO.load(Ordering::SeqCst), 102); + assert_eq!(BAR.lock().unwrap().as_str(), "one hello hello"); + } else if id == 3 { + assert_eq!(FOO.load(Ordering::SeqCst), 201); + assert_eq!(BAR.lock().unwrap().as_str(), "two hello"); + } +} + +#[test] +fn test_namespace() { + thread_init_namespace(); + FOO.init_new(100.into()); + BAR.init_new(Mutex::new(String::from("one"))); + + let t0_foo = FOO.share(); + let t0_bar = BAR.share(); + + let t1 = thread::spawn(|| { + thread_init_namespace(); + FOO.init_new(200.into()); // isolated from t0 + BAR.init_new(Mutex::new(String::from("two"))); // isolated from t0 + thread_fn(); + }); + let t2 = thread::spawn(|| { + thread_init_namespace(); + FOO.init_shared(t0_foo); // shared with t0 + BAR.init_shared(t0_bar); // shared with t0 + thread_fn(); + }); + + thread_fn(); + t1.join().unwrap(); + t2.join().unwrap(); +} + +mod imp { + use axns::{AxNamespace, AxNamespaceIf}; + use lazyinit::LazyInit; + + thread_local! { + static NS: LazyInit = LazyInit::new(); + } + + struct AxNamespaceImpl; + + #[crate_interface::impl_interface] + impl AxNamespaceIf for AxNamespaceImpl { + fn current_namespace_base() -> *mut u8 { + NS.with(|ns| ns.base()) + } + } + + pub fn thread_init_namespace() { + NS.with(|ns| { + ns.init_once(AxNamespace::new_thread_local()); + }); + } +} diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index 770b85dc74..8209722d1d 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -39,5 +39,6 @@ axtask = { workspace = true, optional = true } crate_interface = "0.1" percpu = { version = "0.2", optional = true } kernel_guard = { version = "0.1", optional = true } +ctor_bare = "0.2" chrono = { version = "0.4.38", default-features = false } diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 114db35cc0..1261f95116 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -183,6 +183,8 @@ pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! { init_tls(); } + ctor_bare::call_ctors(); + info!("Primary CPU {} init OK.", cpu_id); INITED_CPUS.fetch_add(1, Ordering::Relaxed); diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index 0c5873ca73..2e68bc1559 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -613,13 +613,14 @@ pub(crate) fn migrate_entry(migrated_task: AxTaskRef) { /// Clear the `on_cpu` field of previous task running on this CPU. #[cfg(feature = "smp")] pub(crate) unsafe fn clear_prev_task_on_cpu() { - PREV_TASK - .current_ref_raw() - .upgrade() - .expect("Invalid prev_task pointer or prev_task has been dropped") - .set_on_cpu(false); + unsafe { + PREV_TASK + .current_ref_raw() + .upgrade() + .expect("Invalid prev_task pointer or prev_task has been dropped") + .set_on_cpu(false); + } } - pub(crate) fn init() { let cpu_id = this_cpu_id(); diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index 2b9a5bfd8c..dfb2a844c0 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -498,14 +498,18 @@ impl CurrentTask { #[cfg(feature = "tls")] axhal::arch::write_thread_pointer(init_task.tls.tls_ptr() as usize); let ptr = Arc::into_raw(init_task); - axhal::cpu::set_current_task_ptr(ptr); + unsafe { + axhal::cpu::set_current_task_ptr(ptr); + } } pub(crate) unsafe fn set_current(prev: Self, next: AxTaskRef) { let Self(arc) = prev; ManuallyDrop::into_inner(arc); // `call Arc::drop()` to decrease prev task reference count. let ptr = Arc::into_raw(next); - axhal::cpu::set_current_task_ptr(ptr); + unsafe { + axhal::cpu::set_current_task_ptr(ptr); + } } } diff --git a/scripts/make/cargo.mk b/scripts/make/cargo.mk index 030d26c586..97e985ff8b 100644 --- a/scripts/make/cargo.mk +++ b/scripts/make/cargo.mk @@ -49,6 +49,7 @@ define cargo_doc endef define unit_test + $(call run_cmd,cargo test,-p axfs $(1) $(verbose) -- --nocapture) $(call run_cmd,cargo test,-p axfs $(1) --features "myfs" $(verbose) -- --nocapture) - $(call run_cmd,cargo test,--workspace $(1) $(verbose) -- --nocapture) + $(call run_cmd,cargo test,--workspace --exclude axfs $(1) $(verbose) -- --nocapture) endef