Skip to content

Commit 4d5beaa

Browse files
committed
feat(memory): 实现动态堆内存增长和内存保护机制
1 parent 7e70c8e commit 4d5beaa

File tree

9 files changed

+318
-23
lines changed

9 files changed

+318
-23
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ AGENTS.md
1515

1616
assets/initrd.cpio
1717

18-
book/
18+
book/
19+
20+
.sisyphus/

kernel/linker.ld

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,45 @@ SECTIONS {
1818

1919
/* Code (text) sections */
2020
.text : {
21+
__text_start = .;
2122
*(.text .text.*)
23+
__text_end = .;
2224
} :text
2325

2426
/* Move to the next memory page */
2527
. = ALIGN(CONSTANT(MAXPAGESIZE));
2628

2729
/* Read-only data (rodata) sections */
2830
.rodata : {
31+
__rodata_start = .;
2932
*(.rodata .rodata.*)
33+
__rodata_end = .;
3034
} :rodata
3135

3236
/* Move to the next memory page */
3337
. = ALIGN(CONSTANT(MAXPAGESIZE));
3438

3539
/* Data sections */
3640
.data : {
41+
__data_start = .;
3742
*(.data .data.*)
3843

3944
/* Place the sections that contains the limine request */
4045
KEEP(*(.requests_start_marker))
4146
KEEP(*(.requests))
4247
KEEP(*(.requests_end_marker))
48+
__data_end = .;
4349
} :data
4450

4551
/* Move to the next memory page */
4652
. = ALIGN(CONSTANT(MAXPAGESIZE));
4753

4854
/* BSS sections */
4955
.bss : {
56+
__bss_start = .;
5057
*(.bss .bss.*)
5158
*(COMMON)
59+
__bss_end = .;
5260
} :bss
5361

5462
/* Something we want to discard */

kernel/src/interrupts/handler.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,17 @@ pub extern "x86-interrupt" fn pagefault_handler(
8080
Err(_) => VirtAddr::zero(),
8181
};
8282

83+
{
84+
let mut ms_lock = crate::memory::vmm::KERNEL_MEMORY_SET.lock();
85+
if let Some(ms) = ms_lock.as_mut() {
86+
if ms.handle_page_fault(fault_address).is_ok() {
87+
return;
88+
}
89+
}
90+
}
91+
8392
serial_println!(
84-
"EXCEPTION: PAGE FAULT at {:#x}\n \
85-
Cause: {:?}\n \
86-
Frame: {:#?}",
93+
"EXCEPTION: PAGE FAULT at {:#x}\n Cause: {:?}\n Frame: {:#?}",
8794
fault_address,
8895
error_code,
8996
stack_frame

kernel/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#![feature(abi_x86_interrupt)]
1111
#![test_runner(crate::test::test_runner)]
1212
#![reexport_test_harness_main = "test_main"]
13+
14+
extern crate alloc;
15+
1316
pub mod drivers;
1417
pub mod fs;
1518
pub mod graphics;

kernel/src/main.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,17 @@ pub extern "C" fn kernel_main() -> ! {
2828
// Check is limine version supported
2929
assert!(BASE_REVISION.is_supported(), "Limine version not supported");
3030

31-
// Init
31+
// Init interrupts early for Page Fault handling during memory init
32+
proka_kernel::interrupts::gdt::init(); // Initialize GDT
33+
proka_kernel::interrupts::idt::init_idt(); // Initialize IDT
34+
proka_kernel::interrupts::pic::init(); // Initialize PIC
35+
36+
// Init memory management
3237
proka_kernel::memory::init(); // Initialize memory management
3338
proka_kernel::drivers::init_devices(); // Initialize devices
3439
proka_kernel::libs::time::init(); // Init time system
3540
proka_kernel::libs::logger::init_logger(); // Init log system
3641
proka_kernel::libs::initrd::load_initrd(); // Load initrd
37-
proka_kernel::interrupts::gdt::init(); // Initialize GDT
38-
proka_kernel::interrupts::idt::init_idt(); // Initialize IDT
39-
proka_kernel::interrupts::pic::init(); // Initialize PIC
4042
x86_64::instructions::interrupts::enable(); // Enable interrupts
4143

4244
#[allow(unused_parens)]

kernel/src/memory/allocator.rs

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Heap allocator module
22
//!
33
//! This module implements the heap allocator for the kernel.
4-
//! It uses the `linked_list_allocator` crate to manage heap memory.
4+
//! It uses the `talc` crate to manage heap memory with dynamic growth support.
55
66
use crate::config::KERNEL_DEFAULT_HEAP_SIZE;
7-
use talc::{ClaimOnOom, Span, Talc, Talck};
7+
use talc::{Span, Talc, Talck};
88
use x86_64::{
99
structures::paging::{
1010
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
@@ -15,31 +15,77 @@ use x86_64::{
1515
/// The starting virtual address of the heap
1616
pub const HEAP_START: usize = 0x_4444_4444_0000;
1717

18+
/// OOM handler for the kernel heap
19+
pub struct KernelOomHandler;
20+
21+
impl talc::OomHandler for KernelOomHandler {
22+
fn handle_oom(talc: &mut Talc<Self>, _layout: core::alloc::Layout) -> Result<(), ()> {
23+
// Expand by 1MB at least
24+
let expand_size = 1024 * 1024;
25+
26+
let mut ms_lock = crate::memory::vmm::KERNEL_MEMORY_SET.lock();
27+
let memory_set = ms_lock.as_mut().ok_or(())?;
28+
29+
// Find heap area
30+
let (old_end, new_end) = {
31+
let heap_area = memory_set.areas.iter_mut().find(|a| a.name == "heap").ok_or(())?;
32+
let old_end = heap_area.end;
33+
let new_end = old_end + expand_size;
34+
heap_area.end = new_end;
35+
(old_end, new_end)
36+
};
37+
38+
// Map the new pages MANUALLY to avoid deadlock via #PF
39+
let page_range = {
40+
let start_page = Page::containing_address(old_end);
41+
let end_page = Page::containing_address(new_end - 1u64);
42+
Page::range_inclusive(start_page, end_page)
43+
};
44+
45+
let memory_map_response = crate::MEMORY_MAP_REQUEST
46+
.get_response()
47+
.expect("Failed to get memory map response");
48+
let mut frame_allocator = unsafe { crate::memory::paging::init_frame_allocator(memory_map_response) };
49+
50+
for page in page_range {
51+
let frame = frame_allocator.allocate_frame().ok_or(())?;
52+
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE;
53+
unsafe {
54+
memory_set.page_table.map_to(page, frame, flags, &mut frame_allocator).map_err(|_| ())?.flush();
55+
}
56+
}
57+
58+
drop(ms_lock);
59+
60+
unsafe {
61+
talc.claim(Span::new(old_end.as_mut_ptr(), new_end.as_mut_ptr())).map_err(|_| ())?;
62+
}
63+
64+
Ok(())
65+
}
66+
}
67+
1868
#[global_allocator]
19-
pub static ALLOCATOR: Talck<spin::Mutex<()>, ClaimOnOom> = Talc::new(unsafe {
20-
// if we're in a hosted environment, the Rust runtime may allocate before
21-
// main() is called, so we need to initialize the arena automatically
22-
ClaimOnOom::new(Span::empty())
23-
})
24-
.lock();
69+
pub static ALLOCATOR: Talck<spin::Mutex<()>, KernelOomHandler> = Talc::new(KernelOomHandler).lock();
2570

2671
/// Initialize the heap
2772
///
28-
/// This function maps the heap memory region and initializes the global allocator.
73+
/// This function initializes the global allocator with a small pre-mapped area.
2974
///
3075
/// # Arguments
3176
/// * `mapper` - The page table mapper
3277
/// * `frame_allocator` - The frame allocator
3378
///
3479
/// # Returns
3580
/// * `Ok(())` on success
36-
/// * `Err(MapToError)` on failure
3781
pub fn init_heap(
3882
mapper: &mut impl Mapper<Size4KiB>,
3983
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
4084
) -> Result<(), MapToError<Size4KiB>> {
4185
let heap_start = VirtAddr::new(HEAP_START as u64);
42-
let heap_end = heap_start + KERNEL_DEFAULT_HEAP_SIZE;
86+
// Map initial 64KB for boot-strapping VMM
87+
let initial_size = 64 * 1024;
88+
let heap_end = heap_start + initial_size;
4389

4490
let page_range = {
4591
let heap_start_page = Page::containing_address(heap_start);
@@ -51,7 +97,7 @@ pub fn init_heap(
5197
let frame = frame_allocator
5298
.allocate_frame()
5399
.ok_or(MapToError::FrameAllocationFailed)?;
54-
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
100+
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE;
55101
unsafe {
56102
mapper.map_to(page, frame, flags, frame_allocator)?.flush();
57103
}

kernel/src/memory/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod allocator;
22
pub mod frame_allocator;
33
pub mod paging;
44
pub mod protection;
5+
pub mod vmm;
56

67
pub fn init() {
78
let memory_map_response = crate::MEMORY_MAP_REQUEST
@@ -10,8 +11,13 @@ pub fn init() {
1011
let hhdm_offset = paging::get_hhdm_offset();
1112
let mut mapper = unsafe { paging::init_offset_page_table(hhdm_offset) };
1213
let mut frame_allocator = unsafe { paging::init_frame_allocator(memory_map_response) };
14+
15+
// 1. Initialize heap with a small pre-mapped area for bootstrapping
1316
allocator::init_heap(&mut mapper, &mut frame_allocator).expect("Failed to init heap");
1417

18+
// 2. Initialize VMM (uses heap for VMAs)
19+
vmm::init(mapper);
20+
1521
// Print memory stats
1622
paging::print_memory_stats(&frame_allocator);
1723
}

0 commit comments

Comments
 (0)