From 8ea9d5ee8a4613a788da224566c8eceb378c16c1 Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Mon, 20 Oct 2025 15:21:07 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat(mm):=20=E5=AE=9E=E7=8E=B0=20global=20a?= =?UTF-8?q?llocator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/Cargo.lock | 26 ++++++ os/Cargo.toml | 4 +- os/src/config.rs | 10 +- os/src/linker.ld | 3 + os/src/main.rs | 28 ++---- .../mm/global_allocator/global_allocator.rs | 91 +++++++++++++++++++ os/src/mm/global_allocator/mod.rs | 11 +++ os/src/mm/mod.rs | 7 +- 8 files changed, 155 insertions(+), 25 deletions(-) create mode 100644 os/src/mm/global_allocator/global_allocator.rs create mode 100644 os/src/mm/global_allocator/mod.rs diff --git a/os/Cargo.lock b/os/Cargo.lock index 14aa4ba4..866197f2 100644 --- a/os/Cargo.lock +++ b/os/Cargo.lock @@ -14,12 +14,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "os" version = "0.1.0" dependencies = [ + "lock_api", "riscv", "sbi-rt", + "talc", ] [[package]] @@ -94,6 +105,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "static_assertions" version = "1.1.0" @@ -111,6 +128,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "talc" +version = "4.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ae828aa394de34c7de08f522d1b86bd1c182c668d27da69caadda00590f26d" +dependencies = [ + "lock_api", +] + [[package]] name = "unicode-ident" version = "1.0.19" diff --git a/os/Cargo.toml b/os/Cargo.toml index ffda7c71..da6b057b 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -5,4 +5,6 @@ edition = "2024" [dependencies] sbi-rt = { version = "0.0.2", features = ["legacy"] } -riscv = "0.15.0" \ No newline at end of file +riscv = "0.15.0" +talc = { version = "4" } +lock_api = "0.4" diff --git a/os/src/config.rs b/os/src/config.rs index ae61eec4..7f88ac09 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -1,4 +1,4 @@ -// constants for the operating system +//! constants for the operating system (platform-independent) #![allow(unused)] // about memory management @@ -6,4 +6,10 @@ pub const PAGE_SIZE: usize = 4096; pub const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024; // 16MB pub const USER_STACK_SIZE: usize = 4 * 1024 * 1024; // 4MB -pub use crate::arch::riscv::platform::qemu::*; \ No newline at end of file +pub use crate::arch::riscv::platform::qemu::*; + +// memory layout constants +// temporarily set for QEMU RISC-V virt machine +// FIXME: refactor it to arch/riscv because it's platform-dependent +// TODO: fetch it form device tree in the future(after/while implemented devices feature) +pub const MEMORY_END: usize = 0x88000000; // 128MB for QEMU RISC-V virt diff --git a/os/src/linker.ld b/os/src/linker.ld index 8bcce1a7..1782077e 100644 --- a/os/src/linker.ld +++ b/os/src/linker.ld @@ -40,6 +40,9 @@ SECTIONS . = ALIGN(4K); ebss = .; + sheap = .; + . = . + 16M; + eheap = .; ekernel = .; /DISCARD/ : { diff --git a/os/src/main.rs b/os/src/main.rs index edd1ce4e..01fa489f 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -6,25 +6,6 @@ extern crate alloc; -use core::alloc::{GlobalAlloc, Layout}; - -/// TODO: replace with proper heap allocator -/// Dummy allocator that always fails - placeholder until heap allocator is implemented -struct DummyAllocator; - -unsafe impl GlobalAlloc for DummyAllocator { - unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - core::ptr::null_mut() - } - - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { - panic!("dealloc called on DummyAllocator"); - } -} - -#[global_allocator] -static ALLOCATOR: DummyAllocator = DummyAllocator; - #[macro_use] mod console; mod sbi; @@ -52,17 +33,22 @@ global_asm!(include_str!("entry.asm")); #[unsafe(no_mangle)] pub extern "C" fn rust_main() -> ! { + unsafe extern "C" { + fn ekernel(); + } clear_bss(); + mm::init_frame_allocator(ekernel as usize, config::MEMORY_END); + mm::init_heap(); println!("Hello, world!"); // 初始化工作 trap::init(); timer::init(); trap::enable_interrupts(); - + #[cfg(test)] test_main(); - + shutdown(false) } diff --git a/os/src/mm/global_allocator/global_allocator.rs b/os/src/mm/global_allocator/global_allocator.rs new file mode 100644 index 00000000..eef03395 --- /dev/null +++ b/os/src/mm/global_allocator/global_allocator.rs @@ -0,0 +1,91 @@ +//! Global allocator module +//! +//! This module provides dynamic heap memory allocation functionality using the talc allocator. +//! +//! # Components +//! +//! - Global heap allocator based on talc::Talck +//! - Heap memory region defined by linker symbols +//! - Initialization function to set up the heap + +use core::cell::UnsafeCell; +use lock_api::{GuardSend, RawMutex}; +use talc::{Span, Talc, Talck}; + +/// Empty mutex implementation for single-core, single-task environment +/// +/// This is a zero-overhead placeholder that provides no actual locking, +/// as it's only used before multitasking is enabled. +/// +/// TODO: Replace with proper synchronization primitive when multitasking is implemented +pub struct EmptyRawMutex; + +unsafe impl RawMutex for EmptyRawMutex { + #[allow(clippy::declare_interior_mutable_const)] + const INIT: Self = EmptyRawMutex; + + type GuardMarker = GuardSend; + + fn lock(&self) { + // No-op: single-task environment doesn't need locking + } + + fn try_lock(&self) -> bool { + // Always succeeds: no contention possible + true + } + + unsafe fn unlock(&self) { + // No-op: nothing to unlock + } +} + +/// Global heap allocator instance +/// +/// Uses talc's lock-based allocator (Talck) with a placeholder empty mutex. +/// In single-core, single-task environment, locking is not needed. +/// +/// Initialized with an empty span; actual memory will be claimed in init_heap(). +#[global_allocator] +static ALLOCATOR: Talck = Talc::new(unsafe { + talc::ClaimOnOom::new(Span::empty()) +}) +.lock(); + +/// Initialize the heap allocator with the heap memory region defined in linker script +/// +/// This function must be called early in the boot process, after BSS clearing +/// but before any heap allocations are attempted. +/// +/// # Safety +/// +/// - Must be called exactly once during boot +/// - Must be called before any heap allocations +/// - Heap region defined by linker symbols (sheap, eheap) must be valid +pub fn init_heap() { + unsafe extern "C" { + fn sheap(); + fn eheap(); + } + + let heap_start = sheap as usize; + let heap_end = eheap as usize; + let heap_size = heap_end - heap_start; + + println!( + "Initializing heap: start={:#x}, end={:#x}, size={:#x} ({} MB)", + heap_start, + heap_end, + heap_size, + heap_size / 1024 / 1024 + ); + + unsafe { + ALLOCATOR + .lock() + .claim(Span::new(heap_start as *mut u8, heap_end as *mut u8)) + .expect("Failed to initialize heap allocator"); + } + + println!("Heap allocator initialized successfully"); +} diff --git a/os/src/mm/global_allocator/mod.rs b/os/src/mm/global_allocator/mod.rs new file mode 100644 index 00000000..48a9fca1 --- /dev/null +++ b/os/src/mm/global_allocator/mod.rs @@ -0,0 +1,11 @@ +//! Global allocator module +//! +//! This module provides dynamic heap memory allocation functionality using the talc allocator. +//! +//! # Components +//! +//! - [`init_heap`]: Initialize the global heap allocator + +mod global_allocator; + +pub use global_allocator::init_heap; diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 8f2f29ea..68f43816 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -7,6 +7,11 @@ //! //! - [`address`]: Address and page number abstractions //! - [`frame_allocator`]: Physical frame allocation +//! - [`global_allocator`]: Global heap allocator mod address; -mod frame_allocator; \ No newline at end of file +mod frame_allocator; +mod global_allocator; + +pub use frame_allocator::init_frame_allocator; +pub use global_allocator::init_heap; \ No newline at end of file From 700f8d9b57a1bce83aaa236b458906d3b47c2304 Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Mon, 20 Oct 2025 13:52:44 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(config):=20=E4=BF=AE=E5=A4=8D=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E5=AF=BC=E5=87=BA=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/src/config.rs b/os/src/config.rs index 7f88ac09..2bf0a4e3 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -6,10 +6,10 @@ pub const PAGE_SIZE: usize = 4096; pub const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024; // 16MB pub const USER_STACK_SIZE: usize = 4 * 1024 * 1024; // 4MB -pub use crate::arch::riscv::platform::qemu::*; - // memory layout constants // temporarily set for QEMU RISC-V virt machine // FIXME: refactor it to arch/riscv because it's platform-dependent // TODO: fetch it form device tree in the future(after/while implemented devices feature) pub const MEMORY_END: usize = 0x88000000; // 128MB for QEMU RISC-V virt + +pub use crate::arch::platform::qemu::*; \ No newline at end of file