feat(RV64): implement dynamic memory/cpu decider#659
feat(RV64): implement dynamic memory/cpu decider#659PeterWrighten wants to merge 3 commits intomainfrom
Conversation
dc941ae to
ae727a2
Compare
ae727a2 to
d665eac
Compare
PeterWrighten
left a comment
There was a problem hiding this comment.
[WIP] Some Debugging code Modification required
d665eac to
ef55de7
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR implements dynamic memory/CPU detection, timer, and interrupt controller support for the RV64 architecture to close issues #463, #489, and #487. The implementation uses Flattened Device Tree (FDT) parsing to dynamically detect system resources instead of relying on hardcoded values.
Key Changes:
- Added FDT-based dynamic memory and CPU count detection with fallback mechanisms
- Implemented RISC-V PLIC (Platform-Level Interrupt Controller) and timer support
- Restructured boot sequence to initialize heap before memory management (required for page tables)
Reviewed Changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
kernel/src/arch/rv64/timer.rs |
New RISC-V timer implementation using ACLINT MTIME/MTIMECMP registers |
kernel/src/arch/rv64/interrupt_controller.rs |
New PLIC interrupt controller implementation with IPI support |
kernel/src/arch/rv64/kernel_main.rs |
Restructured initialization sequence with dynamic heap allocation and DTB registration |
kernel/src/arch/rv64/boot.S |
Added M-mode trap handlers for timer and software interrupts, DTB pointer preservation |
kernel/src/arch/rv64/config.rs |
Removed hardcoded HEAP_START constant |
awkernel_lib/src/arch/rv64/fdt.rs |
New FDT parser for memory and CPU detection with fallback mechanisms |
awkernel_lib/src/arch/rv64/vm.rs |
Dynamic heap size calculation based on detected memory |
awkernel_lib/src/arch/rv64.rs |
Added memory/CPU detection functions and DTB pointer management |
awkernel_lib/src/arch/rv64/delay.rs |
Fixed uptime calculation to use relative time from boot |
awkernel_lib/src/interrupt.rs |
Added RISC-V specific IRQ handler |
kernel/ld/rv64-link.lds |
Changed entry point from 0x80200000 to 0x80000000 for -bios none |
awkernel_lib/Cargo.toml |
Added fdt crate dependency for rv64 feature |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ef55de7 to
67fb94e
Compare
158f627 to
1b3a54d
Compare
|
Following pseudo code explain how to construct heap memory region dynamically. fn map_heap_region() {
let mut frame_allocator = FrameAllocator.new(detected_phy_start, detected_phy_end);
let heap_virt_addr_start = SomeValue;
let i = 0;
while let Some(frame) in frame_allocator.alloc() {
page_table.map_to(heap_virt_addr_start + i * PAGE_SIZE, frame.phy_addr, &mut frame_allocator);
i += 1;
}
let detect_heap_end = heap_virt_addr_start + i * PAGE_SIZE;
}
impl PageTable {
fn map_to(virt_addr: VirtAddr, phy_addr: PhysAddr, frame_allocator: &mut FrameAllocator) {
// map `virt_addr` to `phy_addr`
// if necessary, use `frame_allocator.alloc()` to allocate a page for the page table.
}
} |
I consider the following logics would make frame allocator exhausted, but seems a balanced solution. while let Some(frame) in frame_allocator.alloc() {
page_table.map_to(heap_virt_addr_start + i * PAGE_SIZE, frame.phy_addr, &mut frame_allocator);
i += 1;
} |
Yes. |
1b3a54d to
e761b99
Compare
- Created FDT parser for dynamic memory/cpu detection from device tree, with fallback mechanisms - Register and implement RISC-V timer - Register and implement interrupt controller and IPI
…plicit implementation
Both the frame allocator and TLSF heap previously started at ekernel. find_pte_create() overwrote TLSF metadata when handing out page-table node frames, causing heap corruption after kernel space initialization. Split physical memory into non-overlapping regions: [ekernel, ekernel+N) — frame allocator (PT nodes only) [ekernel+N, memory_end) — heap (backup + primary) N = 10% of available RAM, clamped to [4 MiB, 256 MiB]. Removes hardcoded MEMORY_END; init_page_allocator and init_kernel_space now take explicit physical bounds.
e761b99 to
06cc22e
Compare
FYIThis PR is currently including both #675 and #676 , not split into As mentioned in this comment, we should consider whether it is necessary to still work on PR seperation or just keep this PR for whole features. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 16 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let backup_size = BACKUP_HEAP_SIZE; | ||
| let primary_size = memory_end - heap_start - backup_size; |
| fn disable_mti(&self) { | ||
| unsafe { | ||
| // Clear MIE.MTIE (Machine Timer Interrupt Enable) bit | ||
| core::arch::asm!("csrrc t0, mie, {}", in(reg) 1 << 7); | ||
| } |
| fn enable_software_interrupts(&self) { | ||
| unsafe { | ||
| // Set MIE.MSIE (Machine Software Interrupt Enable) bit (bit 3) | ||
| core::arch::asm!("csrrs t0, mie, {}", in(reg) 1 << 3); |
| unsafe_puts("Memory detected from boot DTB pointer at 0x"); | ||
| crate::console::unsafe_print_hex_u32((dtb_addr >> 16) as u32); | ||
| crate::console::unsafe_print_hex_u32(dtb_addr as u32); | ||
| unsafe_puts("\r\n"); |
| /// Get supervisor mode context for current hart | ||
| fn get_supervisor_context(&self) -> usize { | ||
| // Typically supervisor mode context = hartid * 2 + 1 | ||
| self.get_hart_id() * 2 + 1 |
| fn send_ipi(&mut self, _irq: u16, cpu_id: u32) { | ||
| // Send machine software interrupt to the target hart | ||
| self.send_software_interrupt(cpu_id); | ||
| } |
| let mut memory_set = MemorySet::new_kernel(); | ||
|
|
||
| map_heap_region(&mut memory_set, heap_start, memory_end); | ||
| HEAP_SIZE.store(memory_end - heap_start, Ordering::Relaxed); | ||
|
|
||
| *kernel_space = Some(memory_set); |
| // Timer interrupt is already disabled in assembly by setting mtimecmp to max | ||
| // Handle any pending interrupts (the timer handler will be invoked if registered) |
|
|
||
| // Enable software interrupts for IPIs on primary hart | ||
| unsafe { | ||
| core::arch::asm!("csrrs t0, mie, {}", in(reg) 1 << 3); |
| // 10% of available RAM, floored at 4 MiB (tiny systems) and capped at | ||
| // 256 MiB (large automotive SoCs like Orin). Page-aligned. | ||
| let available = memory_end.saturating_sub(kernel_end); | ||
| let pt_frames_size = | ||
| ((available / 10).clamp(4 * 1024 * 1024, 256 * 1024 * 1024) + 0xfff) & !0xfff; |
Description
In order to close #463 .
Register and implement Interrupt Controller and Timer.
FDT Based Dynamic Decider is implemented as the following design.
Created FDT(Flattened Device Tree) parser for dynamic memory detection from device tree, with
fallback mechanisms. (Using fdt crate)
Dynamic Heap Size and Start Decider implementation in vm.rs
Dynamic CPU Counts implementation.
How was this PR tested?
I tested this heap decider with QEMU memory size 512M, 1G, and 2G. Test results are shown as the following.
Both heap and VM are initialized successfully by using Dynamic Heap Decider.
After Implementation of Interrupt Controller and timer, the RV64 version kernel worked well as the following.