Skip to content

Conversation

@PeterWrighten
Copy link
Contributor

@PeterWrighten PeterWrighten commented Nov 11, 2025

Description

In order to close #463 , #489, #487 .

Register and implement Interrupt Controller and Timer.

FDT Based Dynamic Decider is implemented as the following design.

  1. Created FDT(Flattened Device Tree) parser for dynamic memory detection from device tree, with
    fallback mechanisms. (Using fdt crate)

  2. Dynamic Heap Size and Start Decider implementation in vm.rs

  3. 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.

// 512M Memory Size

qemu-system-riscv64 -machine virt -bios none -kernel target/riscv64gc-unknown-none-elf/release/awkernel -m 512M -nographic -smp 4 -monitor telnet::5556,server,nowait

=== AWkernel RV64 Starting ===
Console port initialized
UART driver initialized
Setting up heap allocation...
Memory detected from boot DTB pointer at 0x00009fe09fe00000
Detected RAM size: 0x0000000020000000
Using dynamic heap configuration\r\nHeap allocation complete\r\nInitializing page allocator...
Initializing kernel space...
Memory detected from boot DTB pointer at 0x00009fe09fe00000
Detected RAM size: 0x0000000020000000
Mapping kernel text section...
Mapping kernel rodata section...
Mapping kernel data section...
Mapping kernel bss section...
Mapping physical memory...
  from ekernel: 0x800d7000
  to MEMORY_END: 0xa0000000 (dynamic)
Memory detected from boot DTB pointer at 0x00009fe09fe00000
Detected RAM size: 0x0000000020000000
Dynamic heap calculation:
  Kernel end: 0x800d7000
  Heap start: 0x800d7000
  Memory end: 0xa0000000
  Max heap size: 0x1ff29000
Activating kernel space...
Virtual memory system initialized
Initializing RISC-V interrupt controller...\r\nInitializing RISC-V timer...\r\nTimer and interrupt controller initialized\r\n[            3 INFO] AWkernel RV64 primary CPU initialization complete
[            5 INFO] CPU#0 is starting.
[            6 INFO] CPU#2 is starting.
[            6 INFO] CPU#3 is starting.
[            7 INFO] CPU#1 is starting.
[            8 INFO] interrupt::INTERRUPT_CONTROLLER has been initialized.
[            9 INFO] interrupt::PREEMPT_FN has been initialized.
[           10 INFO] timer::TIMER has been initialized.
[           12 INFO] A local timer has been initialized.
// 1G Memory Size

qemu-system-riscv64 -machine virt -bios none -kernel target/riscv64gc-unknown-none-elf/release/awkernel -m 1G -nographic -smp 4 -monitor telnet::5556,server,nowait

=== AWkernel RV64 Starting ===
Console port initialized
UART driver initialized
Setting up heap allocation...
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000040000000
Using dynamic heap configuration\r\nHeap allocation complete\r\nInitializing page allocator...
Initializing kernel space...
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000040000000
Mapping kernel text section...
Mapping kernel rodata section...
Mapping kernel data section...
Mapping kernel bss section...
Mapping physical memory...
  from ekernel: 0x800d7000
  to MEMORY_END: 0xc0000000 (dynamic)
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000040000000
Dynamic heap calculation:
  Kernel end: 0x800d7000
  Heap start: 0x800d7000
  Memory end: 0xc0000000
  Max heap size: 0x3ff29000
Activating kernel space...
Virtual memory system initialized
Initializing RISC-V interrupt controller...\r\nInitializing RISC-V timer...\r\nTimer and interrupt controller initialized\r\n[            3 INFO] AWkernel RV64 primary CPU initialization complete
[            5 INFO] CPU#0 is starting.
[            6 INFO] CPU#3 is starting.
[            6 INFO] CPU#1 is starting.
[            7 INFO] CPU#2 is starting.
[            7 INFO] interrupt::INTERRUPT_CONTROLLER has been initialized.
[            8 INFO] interrupt::PREEMPT_FN has been initialized.
[            9 INFO] timer::TIMER has been initialized.
[           11 INFO] A local timer has been initialized.
// 2G Memory Size

qemu-system-riscv64 -machine virt -bios none -kernel target/riscv64gc-unknown-none-elf/release/awkernel -m 2G -nographic -smp 4 -monitor telnet::5556,server,nowait

=== AWkernel RV64 Starting ===
Console port initialized
UART driver initialized
Setting up heap allocation...
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000080000000
Using dynamic heap configuration\r\nHeap allocation complete\r\nInitializing page allocator...
Initializing kernel space...
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000080000000
Mapping kernel text section...
Mapping kernel rodata section...
Mapping kernel data section...
Mapping kernel bss section...
Mapping physical memory...
  from ekernel: 0x800d7000
  to MEMORY_END: 0x00000000 (dynamic)
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000080000000
Dynamic heap calculation:
  Kernel end: 0x800d7000
  Heap start: 0x800d7000
  Memory end: 0x00000000
  Max heap size: 0x7ff29000
Activating kernel space...
Virtual memory system initialized
Initializing RISC-V interrupt controller...\r\nInitializing RISC-V timer...\r\nTimer and interrupt controller initialized\r\n[            3 INFO] AWkernel RV64 primary CPU initialization complete
[            6 INFO] CPU#0 is starting.
[            6 INFO] CPU#3 is starting.
[            7 INFO] CPU#2 is starting.
[            8 INFO] CPU#1 is starting.
[            8 INFO] interrupt::INTERRUPT_CONTROLLER has been initialized.
[            9 INFO] interrupt::PREEMPT_FN has been initialized.
[           10 INFO] timer::TIMER has been initialized.
[           12 INFO] A local timer has been initialized.

After Implementation of Interrupt Controller and timer, the RV64 version kernel worked well as the following.

// All basic function including timer, interrupt controller and dynamic cpu counts worked well
make qemu-riscv64
qemu-system-riscv64 -machine virt -bios none -kernel target/riscv64gc-unknown-none-elf/release/awkernel -m 1G -nographic -smp 4 -monitor telnet::5556,server,nowait

=== AWkernel RV64 Starting ===
Console port initialized
UART driver initialized
Setting up heap allocation...
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000040000000
Using dynamic heap configuration
Heap allocation complete
Initializing page allocator...
Initializing kernel space...
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000040000000
Mapping kernel text section...
Mapping kernel rodata section...
Mapping kernel data section...
Mapping kernel bss section...
Mapping physical memory...
  from ekernel: 0x00000000800df000
  to MEMORY_END: 0x00000000c0000000 (dynamic)
Memory detected from boot DTB pointer at 0x0000bfe0bfe00000
Detected RAM size: 0x0000000040000000
Dynamic heap calculation:
  Kernel end: 0x00000000800df000
  Heap start: 0x00000000800df000
  Memory end: 0x00000000c0000000
  Max heap size: 0x000000003ff21000
Activating kernel space...
Virtual memory system initialized
Initializing RISC-V interrupt controller...
Initializing RISC-V timer...
Timer and interrupt controller initialized
[            1 INFO] AWkernel RV64 primary CPU initialization complete
Detected 00000004 CPUs from boot DTB
[            5 INFO] CPU#0 is starting.
[            6 INFO] CPU#1 is starting.
[            6 INFO] CPU#2 is starting.
[            7 INFO] CPU#3 is starting.
[            7 INFO] interrupt::INTERRUPT_CONTROLLER has been initialized.
[            8 INFO] interrupt::PREEMPT_FN has been initialized.
[            9 INFO] timer::TIMER has been initialized.
[           12 INFO] A local timer has been initialized.
[           15 INFO] Starting [Awkernel] network service.

@PeterWrighten PeterWrighten force-pushed the fix-rv64-heap-pagetable branch 3 times, most recently from dc941ae to ae727a2 Compare November 11, 2025 11:22
@PeterWrighten PeterWrighten marked this pull request as draft November 11, 2025 11:25
@PeterWrighten PeterWrighten force-pushed the fix-rv64-heap-pagetable branch from ae727a2 to d665eac Compare November 11, 2025 11:38
Copy link
Contributor Author

@PeterWrighten PeterWrighten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[WIP] Some Debugging code Modification required

@PeterWrighten PeterWrighten marked this pull request as ready for review November 11, 2025 11:46
@PeterWrighten PeterWrighten changed the title fix/feat(RV64): implement dynamic heap start/size decider by using fdt crate and reading DTB pointer when booting fix/feat(RV64): implement dynamic heap start/size decider by using fdt crate and reading DTB pointer when booting, and timer Nov 12, 2025
@PeterWrighten PeterWrighten changed the title fix/feat(RV64): implement dynamic heap start/size decider by using fdt crate and reading DTB pointer when booting, and timer fix/feat(RV64): implement dynamic heap start/size decider by using fdt crate and reading DTB pointer when booting, Interrupt Controller and timer Nov 12, 2025
@PeterWrighten PeterWrighten changed the title fix/feat(RV64): implement dynamic heap start/size decider by using fdt crate and reading DTB pointer when booting, Interrupt Controller and timer fix/feat(RV64): implement dynamic heap start/size and cpu counts decider by using fdt crate and reading DTB pointer when booting, Interrupt Controller and timer Nov 12, 2025
@PeterWrighten PeterWrighten force-pushed the fix-rv64-heap-pagetable branch from d665eac to ef55de7 Compare November 12, 2025 10:59
@PeterWrighten PeterWrighten changed the title fix/feat(RV64): implement dynamic heap start/size and cpu counts decider by using fdt crate and reading DTB pointer when booting, Interrupt Controller and timer feat(RV64): implement dynamic memory/cpu decider, timer and interrupt controller Nov 12, 2025
@PeterWrighten PeterWrighten self-assigned this Nov 12, 2025
@ytakano ytakano requested a review from Copilot November 14, 2025 07:32
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

- 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
@PeterWrighten PeterWrighten force-pushed the fix-rv64-heap-pagetable branch from ef55de7 to 67fb94e Compare November 14, 2025 12:42
@PeterWrighten PeterWrighten force-pushed the fix-rv64-heap-pagetable branch from 0667506 to b52a912 Compare November 19, 2025 11:14
# Conflicts:
#	awkernel_lib/src/arch/rv64/vm.rs

// Calculate available memory after kernel
let kernel_end = PhyAddr::from_usize(ekernel as *const () as usize);
let memory_end = PhyAddr::from_usize(memory_end_addr as usize);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ekernel to MEMORY_END will be used by MMU for the page table as follows.

if let Some(allocator_ref) = allocator.as_mut() {
allocator_ref.init(
PhyAddr::from_usize(ekernel as *const () as usize).ceil(),
PhyAddr::from_usize(MEMORY_END as usize).floor(),
);

ekernel to memory_end_addr will be used by heap.

I think some memory frames are used as heap memory and page tables.
As a result of this, the page table will be corrupted.

@ytakano
Copy link
Collaborator

ytakano commented Nov 20, 2025

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.
    }
}

@PeterWrighten
Copy link
Contributor Author

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;
}

@ytakano
Copy link
Collaborator

ytakano commented Nov 21, 2025

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.
By using this algorithm, all memory frame will be used by either the heap memory or the page table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RV64 QEMU-Virt Initialization Issue

3 participants