Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
75bb6f0
tmp: disable vendor source temporary
muou000 Jul 18, 2026
45d0489
feat(smp): harden CPU startup and interrupt routing
muou000 Jul 18, 2026
ea36d8f
fix(smp): harden task wakeups and futex waits
muou000 Jul 18, 2026
83df1af
fix(smp): stabilize task stacks and ext4 mutations
muou000 Jul 18, 2026
2d2ee48
fix(loongarch64): harden secondary CPU boot protocol
muou000 Jul 18, 2026
f1f3e8f
fix(loongarch64): separate local and external IRQ IDs
muou000 Jul 18, 2026
2be3595
fix(loongarch64): serialize EIOINTC enable updates
muou000 Jul 18, 2026
9d3c576
fix(loongarch64): program one-shot timers safely
muou000 Jul 18, 2026
ce377b9
fix(loongarch64): serialize UART writes
muou000 Jul 18, 2026
73e560b
fix(loongarch64): map all high RAM during boot
muou000 Jul 18, 2026
e16f752
fix(memory): support 8G RAM on RISC-V and LoongArch
muou000 Jul 18, 2026
b7b41ff
fix(loongarch64): clamp one-shot timer intervals
muou000 Jul 18, 2026
a815a4b
fix(mm): synchronize COW mappings across CPUs
muou000 Jul 18, 2026
9d961af
fix(axtask): harden task switching and interruptions
muou000 Jul 18, 2026
9b80727
fix(task): close process lifecycle and futex races
muou000 Jul 18, 2026
508bf12
fix(smp): harden CPU boot and online sequencing
muou000 Jul 18, 2026
697ff73
fix(loongarch64): harden SMP platform handling
muou000 Jul 18, 2026
8c4ff3e
fix(riscv64): fail closed on reserved memory overflow
muou000 Jul 18, 2026
ff54fc9
fix(task): preserve exit and futex cleanup semantics
muou000 Jul 18, 2026
8e68dbe
fix(syscall): preserve concurrent interrupt state
muou000 Jul 18, 2026
ae63075
fix(axtask): guard timer insertion against local IRQs
muou000 Jul 19, 2026
1417b49
fix(loongarch64): enable eight CPUs for QEMU virt
muou000 Jul 19, 2026
db6a7d2
fix(mm): avoid address-space deadlocks during COW faults
muou000 Jul 19, 2026
088bd90
fix(axipi): handle partial TLB shootdown failures
muou000 Jul 19, 2026
18f794b
fix(mm): propagate TLB shootdown failures safely
muou000 Jul 19, 2026
c2e719c
fix(mm): defer reclamation until TLB shootdown
muou000 Jul 19, 2026
9950c83
chore: enable vendor and update vendor sources
muou000 Jul 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
### RISC-V 64

```bash
timeout 360 qemu-system-riscv64 -machine virt -kernel kernel-rv -m 1G -nographic -smp 1 -bios default -drive file=sdcard-rv.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 -no-reboot -device virtio-net-device,netdev=net -netdev user,id=net -rtc base=utc -drive file=disk.img,if=none,format=raw,id=x1 -device virtio-blk-device,drive=x1,bus=virtio-mmio-bus.1
timeout 360 qemu-system-riscv64 -machine virt -kernel kernel-rv -m 8G -nographic -smp 8 -bios default -drive file=sdcard-rv.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 -no-reboot -device virtio-net-device,netdev=net -netdev user,id=net -rtc base=utc -drive file=disk.img,if=none,format=raw,id=x1 -device virtio-blk-device,drive=x1,bus=virtio-mmio-bus.1
```

### LoongArch64

```bash
timeout 360 qemu-system-loongarch64 -machine virt -kernel kernel-la -m 1G -nographic -smp 1 -drive file=sdcard-la.img,if=none,format=raw,id=x0 -device virtio-blk-pci,drive=x0 -no-reboot -device virtio-net-pci,netdev=net0 -netdev user,id=net0 -rtc base=utc -drive file=disk-la.img,if=none,format=raw,id=x1 -device virtio-blk-pci,drive=x1
timeout 360 qemu-system-loongarch64 -machine virt -kernel kernel-la -m 8G -nographic -smp 8 -drive file=sdcard-la.img,if=none,format=raw,id=x0 -device virtio-blk-pci,drive=x0 -no-reboot -device virtio-net-pci,netdev=net0 -netdev user,id=net0 -rtc base=utc -drive file=disk-la.img,if=none,format=raw,id=x1 -device virtio-blk-pci,drive=x1
```

## 任务执行约定
Expand All @@ -46,4 +46,4 @@ timeout 360 qemu-system-loongarch64 -machine virt -kernel kernel-la -m 1G -nogra
- 保持改动最小且可审查,不要顺手做无关重构。
- 如果遇到权限问题,必须立即停止任务,并提示用户先修复权限后再继续。
- 一旦出现权限不足、只读文件系统、无法写入产物目录等情况,不要尝试绕过限制或改用破坏性手段。
- 制订计划时必须先考虑制订功能的测试
- 制订计划时必须先考虑制订功能的测试
29 changes: 29 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pulse_syscalls = { path = "pulse_syscalls" }

axfeat = { path = "arceos/api/axfeat", features = [
"alloc-tlsf",
"page-alloc-4g",
"page-alloc-64g",
"multitask",
"sched-rr",
"fs",
Expand Down Expand Up @@ -109,6 +109,7 @@ repository.workspace = true
[features]
default = []
qemu = []
smp = ["axfeat/smp", "axfeat/ipi"]
testcode = []

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export AX_LIB := axfeat
export APP_FEATURES := qemu
export BLK := y

export MEM := 1G
export MEM := 8G
export ARCH ?= riscv64
export LOG ?= info

Expand Down
2 changes: 1 addition & 1 deletion arceos/api/axfeat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fp-simd = ["axhal/fp-simd"]

# Interrupts
irq = ["axhal/irq", "axruntime/irq", "axtask?/irq"]
ipi = ["irq", "dep:axipi", "axhal/ipi", "axruntime/ipi"]
ipi = ["irq", "dep:axipi", "axhal/ipi", "axruntime/ipi", "axtask?/ipi"]

# Custom or default platforms
myplat = ["axhal/myplat"]
Expand Down
35 changes: 22 additions & 13 deletions arceos/modules/axdma/src/dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,26 +92,35 @@ impl DmaAllocator {
flags: MappingFlags,
) -> AllocResult<()> {
let expand_size = num_pages * PAGE_SIZE_4K;
axmm::kernel_aspace()
.lock()
.protect(vaddr, expand_size, flags)
.map_err(|e| {
error!("change table flag fail: {e:?}");
AllocError::NoMemory
})
let mutation = {
let mut aspace = axmm::kernel_aspace().lock();
aspace.protect(vaddr, expand_size, flags)
};
mutation.complete_after_unlock().map_err(|e| {
error!("change table flag fail: {e:?}");
AllocError::NoMemory
})
}

/// Gives back the allocated region to the byte allocator.
pub unsafe fn dealloc_coherent(&mut self, dma: DMAInfo, layout: Layout) {
if layout.size() >= PAGE_SIZE_4K {
let num_pages = layout_pages(&layout);
let virt_raw = dma.cpu_addr.as_ptr() as usize;
global_allocator().dealloc_pages(virt_raw, num_pages);
let _ = self.update_flags(
va!(virt_raw),
num_pages,
MappingFlags::READ | MappingFlags::WRITE,
);
if self
.update_flags(
va!(virt_raw),
num_pages,
MappingFlags::READ | MappingFlags::WRITE,
)
.is_ok()
{
global_allocator().dealloc_pages(virt_raw, num_pages);
} else {
error!(
"leaking coherent DMA pages at {virt_raw:#x}: cache-attribute shootdown failed"
);
}
} else {
self.alloc.dealloc(dma.cpu_addr, layout)
}
Expand Down
2 changes: 2 additions & 0 deletions arceos/modules/axfs/src/fs/ext4/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct Ext4Filesystem {
deletion_generation: AtomicU64,
deletion_worker_running: AtomicBool,
deletion_processing: async_lock::Mutex<()>,
pub(super) directory_mutation: async_lock::Mutex<()>,
}

impl Ext4Filesystem {
Expand Down Expand Up @@ -82,6 +83,7 @@ impl Ext4Filesystem {
deletion_generation: AtomicU64::new(0),
deletion_worker_running: AtomicBool::new(false),
deletion_processing: async_lock::Mutex::new(()),
directory_mutation: async_lock::Mutex::new(()),
});
let root_dir = DirEntry::new_dir(
|this| DirNode::new(Inode::new(fs.clone(), ROOT_INODE, Some(this))),
Expand Down
4 changes: 4 additions & 0 deletions arceos/modules/axfs/src/fs/ext4/inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ impl DirNodeOps for Inode {
) -> VfsResult<DirEntry> {
let fs = &self.fs.inner;
self.validate_inode_num(&fs, self.ino)?;
let _directory_guard = self.fs.directory_mutation.lock().await;

let exists = if let Some(snapshot) = self.dir_cache.get() {
self.cached_entry(&snapshot, name).is_some()
Expand Down Expand Up @@ -608,6 +609,7 @@ impl DirNodeOps for Inode {
async fn link(&self, name: &str, node: &DirEntry) -> VfsResult<DirEntry> {
let fs = &self.fs.inner;
self.validate_inode_num(&fs, self.ino)?;
let _directory_guard = self.fs.directory_mutation.lock().await;
let dir_idx = core::num::NonZeroU32::new(self.ino).ok_or(VfsError::InvalidData)?;
let dir_inode = ext4plus::inode::Inode::read(&fs, dir_idx).await.map_err(into_vfs_err)?;
let mut dir = ext4plus::dir::Dir::open_inode(&fs, dir_inode).map_err(into_vfs_err)?;
Expand All @@ -634,6 +636,7 @@ impl DirNodeOps for Inode {
async fn unlink(&self, name: &str) -> VfsResult<()> {
let fs = &self.fs.inner;
self.validate_inode_num(&fs, self.ino)?;
let _directory_guard = self.fs.directory_mutation.lock().await;

let dir_idx = core::num::NonZeroU32::new(self.ino).ok_or(VfsError::InvalidData)?;
let dir_inode = ext4plus::inode::Inode::read(&fs, dir_idx).await.map_err(into_vfs_err)?;
Expand Down Expand Up @@ -687,6 +690,7 @@ impl DirNodeOps for Inode {
let fs = &self.fs.inner;
self.validate_inode_num(&fs, self.ino)?;
self.validate_inode_num(&fs, dst_dir.ino)?;
let _directory_guard = self.fs.directory_mutation.lock().await;

let src_dir_idx = core::num::NonZeroU32::new(self.ino).ok_or(VfsError::InvalidData)?;
let src_dir_inode = ext4plus::inode::Inode::read(&fs, src_dir_idx).await.map_err(into_vfs_err)?;
Expand Down
18 changes: 14 additions & 4 deletions arceos/modules/axhal/src/dummy.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! Dummy implementation of platform-related interfaces defined in [`axplat`].

#[cfg(feature = "irq")]
use axplat::impl_plat_interface;

use axplat::console::ConsoleIf;
use axplat::init::InitIf;
#[cfg(feature = "irq")]
use axplat::irq::{IpiTarget, IrqHandler, IrqIf};
use axplat::irq::{IpiError, IpiTarget, IrqHandler, IrqIf};
use axplat::mem::{MemIf, RawRange};
use axplat::power::PowerIf;
use axplat::time::TimeIf;
Expand Down Expand Up @@ -90,7 +91,12 @@ impl TimeIf for DummyTime {
#[impl_plat_interface]
impl PowerIf for DummyPower {
#[cfg(feature = "smp")]
fn cpu_boot(_cpu_id: usize, _stack_top_paddr: usize) {}
fn cpu_boot(
_cpu_id: usize,
_stack_top_paddr: usize,
) -> Result<(), axplat::power::CpuBootError> {
Err(axplat::power::CpuBootError::NotSupported)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

fn system_off() -> ! {
unimplemented!()
Expand All @@ -114,7 +120,11 @@ impl IrqIf for DummyIrq {
None
}

fn handle(_irq: usize) {}
fn handle(_irq: usize, _cpu_id: usize) {}

fn send_ipi(_irq: usize, _target: IpiTarget) {}
fn cpu_online(_cpu_id: usize) {}

fn send_ipi(_irq: usize, _target: IpiTarget) -> Result<(), IpiError> {
Err(IpiError::NotSupported)
}
}
4 changes: 2 additions & 2 deletions arceos/modules/axhal/src/irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use axcpu::trap::{IRQ, register_trap_handler};
pub use axplat::irq::{handle, register, set_enable, unregister};

#[cfg(feature = "ipi")]
pub use axplat::irq::{IpiTarget, send_ipi};
pub use axplat::irq::{IpiError, IpiTarget, send_ipi};

#[cfg(feature = "ipi")]
pub use axconfig::devices::IPI_IRQ;
Expand All @@ -18,7 +18,7 @@ pub use axconfig::devices::IPI_IRQ;
#[register_trap_handler(IRQ)]
pub fn irq_handler(vector: usize) -> bool {
let guard = kernel_guard::NoPreempt::new();
handle(vector);
handle(vector, crate::percpu::this_cpu_id());
drop(guard); // rescheduling may occur when preemption is re-enabled.
true
}
55 changes: 50 additions & 5 deletions arceos/modules/axhal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub mod console {
pub mod power {
#[cfg(feature = "smp")]
pub use axplat::power::cpu_boot;
pub use axplat::power::system_off;
pub use axplat::power::{CpuBootError, system_off};
}

/// Trap handling.
Expand All @@ -106,7 +106,6 @@ pub mod context {
}

pub use axcpu::asm;

#[cfg(feature = "smp")]
pub use axplat::init::{init_early_secondary, init_later_secondary};
#[cfg(feature = "smp")]
Expand Down Expand Up @@ -152,12 +151,16 @@ pub fn get_bootarg() -> usize {
*BOOT_ARG
}

/// The number of CPUs in the system. Based on the number declared by the
/// platform crate and limited by the configured maximum CPU number.
/// The number of possible CPUs in the system. Based on the number declared by
/// the platform crate and limited by the configured maximum CPU number.
#[cfg(feature = "smp")]
static CPU_NUM: AtomicUsize = AtomicUsize::new(1);

/// Gets the number of CPUs running in the system.
/// Bit mask of CPUs that completed per-CPU initialization and can receive work.
#[cfg(feature = "smp")]
static ONLINE_CPU_MASK: AtomicUsize = AtomicUsize::new(0);

/// Gets the number of possible CPUs in the system.
///
/// When SMP is disabled, this function always returns 1.
///
Expand Down Expand Up @@ -186,6 +189,43 @@ pub fn cpu_num() -> usize {
}
}

/// Returns a bit mask containing every online logical CPU.
pub fn online_cpu_mask() -> usize {
#[cfg(feature = "smp")]
{
ONLINE_CPU_MASK.load(Ordering::Acquire)
}
#[cfg(not(feature = "smp"))]
{
1
}
}

/// Returns the number of CPUs that are ready to receive tasks and interrupts.
pub fn online_cpu_count() -> usize {
online_cpu_mask().count_ones() as usize
}

/// Returns whether a logical CPU is online.
pub fn is_cpu_online(cpu_id: usize) -> bool {
cpu_id < usize::BITS as usize && online_cpu_mask() & (1usize << cpu_id) != 0
}

/// Publishes a logical CPU after all of its per-CPU runtime state is initialized.
pub fn mark_cpu_online(cpu_id: usize) {
assert!(cpu_id < cpu_num(), "invalid online CPU ID {cpu_id}");
assert!(
cpu_id < usize::BITS as usize,
"online CPU mask is too small"
);
#[cfg(feature = "irq")]
axplat::irq::cpu_online(cpu_id);
#[cfg(feature = "smp")]
ONLINE_CPU_MASK.fetch_or(1usize << cpu_id, Ordering::Release);
#[cfg(not(feature = "smp"))]
let _ = cpu_id;
}

/// Initializes the CPU number information.
fn init_cpu_num() {
#[cfg(feature = "smp")]
Expand All @@ -194,6 +234,11 @@ fn init_cpu_num() {
let max_cpu_num = axconfig::plat::MAX_CPU_NUM;
let cpu_num = plat_cpu_num.min(max_cpu_num);

assert!(
cpu_num <= usize::BITS as usize,
"configured CPU count exceeds the online CPU mask width"
);

info!("CPU number: max = {max_cpu_num}, platform = {plat_cpu_num}, use = {cpu_num}",);
ax_println!("smp = {}", cpu_num); // for test purposes

Expand Down
Loading