Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion awkernel_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ array-macro = "2.1"
embedded-graphics-core = "0.4"
embedded-graphics = "0.8"
chrono = { version = "0.4", default-features = false, features = ["clock"], optional = true }
fdt = { version = "0.1", optional = true }

[dependencies.awkernel_sync]
git = "https://github.com/tier4/awkernel_sync.git"
Expand Down Expand Up @@ -82,7 +83,7 @@ x86 = [
]
aarch64 = ["dep:awkernel_aarch64", "awkernel_sync/aarch64"]
rv32 = ["dep:riscv", "awkernel_sync/rv32"]
rv64 = ["awkernel_sync/rv64"]
rv64 = ["awkernel_sync/rv64", "dep:fdt"]
std = ["dep:libc", "dep:socket2", "awkernel_sync/std"]
spinlock = ["awkernel_sync/spinlock"]
# LFN (Long File Name) support
Expand Down
133 changes: 133 additions & 0 deletions awkernel_lib/src/arch/rv64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,35 @@ pub mod barrier;
pub(super) mod cpu;
pub(super) mod delay;
pub(super) mod dvfs;
pub(super) mod fdt;
pub(super) mod frame_allocator;
pub(super) mod interrupt;
pub(super) mod page_table;
pub(super) mod paging;
pub(super) mod vm;

use core::sync::atomic::{AtomicUsize, Ordering};

pub struct RV64;

impl super::Arch for RV64 {}

/// # Safety
///
/// This function must be called at initialization,
/// and called by the primary CPU.
pub unsafe fn init_primary() {
delay::init_primary();
}

/// # Safety
///
/// This function must be called at initialization,
/// and called by non-primary CPUs.
pub unsafe fn init_non_primary() {
delay::init_non_primary();
}

pub fn init_page_allocator() {
frame_allocator::init_page_allocator();
}
Expand All @@ -39,3 +58,117 @@ pub fn translate_kernel_address(vpn: address::VirtPageNum) -> Option<page_table:
None
}
}

pub fn get_heap_size() -> usize {
vm::get_heap_size()
}

static BOOT_DTB_PTR: AtomicUsize = AtomicUsize::new(0);

/// Record the DTB pointer supplied by firmware/bootloader.
pub fn set_boot_dtb_ptr(addr: usize) {
BOOT_DTB_PTR.store(addr, Ordering::Relaxed);
}

fn boot_dtb_ptr() -> Option<usize> {
match BOOT_DTB_PTR.load(Ordering::Relaxed) {
0 => None,
addr => Some(addr),
}
}

/// Detect memory size from device tree or by probing
///
/// Returns the detected memory size in bytes, or None if detection fails
pub fn detect_memory_size() -> Option<u64> {
unsafe {
if let Some(dtb_addr) = boot_dtb_ptr() {
if let Some(region) = fdt::detect_memory_from_dtb(dtb_addr) {
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");
return Some(region.size);
} else {
unsafe_puts("Boot DTB pointer invalid, falling back to probe\r\n");
}
}

// First, try to find DTB at common locations
if let Some(dtb_addr) = fdt::probe_dtb_locations() {
if let Some(region) = fdt::detect_memory_from_dtb(dtb_addr) {
unsafe_puts("Memory detected from DTB 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");
return Some(region.size);
}
}

// Fallback: Try memory probing
if let Some(size) = fdt::probe_memory_size() {
use crate::console::unsafe_puts;
unsafe_puts("Memory detected by probing\r\n");
return Some(size);
}
}
None
}

use crate::console::unsafe_puts;

/// Get the memory end address based on detected memory size
///
/// This function attempts to detect the actual available RAM and returns
/// an appropriate MEMORY_END value. Panics if detection fails.
pub fn get_memory_end() -> u64 {
const DRAM_BASE: u64 = 0x80000000;

if let Some(detected_size) = detect_memory_size() {
// Use detected size directly
let memory_end = DRAM_BASE + detected_size;

// Log the detection
unsafe {
use crate::console::unsafe_puts;
unsafe_puts("Detected RAM size: 0x");
crate::console::unsafe_print_hex_u32((detected_size >> 32) as u32);
crate::console::unsafe_print_hex_u32(detected_size as u32);
unsafe_puts("\r\n");
}

memory_end
} else {
// Failed to detect memory - cannot continue boot safely
panic!("Failed to detect memory size from DTB or probing - cannot boot");
}
}

/// Detect CPU count from device tree
///
/// Returns the detected number of CPUs. Panics if detection fails.
pub fn detect_cpu_count() -> usize {
unsafe {
if let Some(dtb_addr) = boot_dtb_ptr() {
if let Some(count) = fdt::detect_cpu_count_from_dtb(dtb_addr) {
unsafe_puts("Detected ");
crate::console::unsafe_print_hex_u32(count as u32);
unsafe_puts(" CPUs from boot DTB\r\n");
return count;
}
}

// Try to find DTB at common locations
if let Some(dtb_addr) = fdt::probe_dtb_locations() {
if let Some(count) = fdt::detect_cpu_count_from_dtb(dtb_addr) {
unsafe_puts("Detected ");
crate::console::unsafe_print_hex_u32(count as u32);
unsafe_puts(" CPUs from probed DTB\r\n");
return count;
}
}

// Failed to detect CPU count - cannot continue boot safely
panic!("Failed to detect CPU count from DTB - cannot boot");
}
}
6 changes: 5 additions & 1 deletion awkernel_lib/src/arch/rv64/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ use core::{
pub const PAGE_SIZE: usize = 0x1000; // 4 KiB
pub const PAGE_OFFSET: usize = 0xc; // 12 bits

pub const MEMORY_END: u64 = 0x8080_0000;
// Memory end for QEMU virt with 1GB RAM (-m 1G)
// QEMU provides 1GB at 0x80000000 - 0xC0000000
// Using 0xC0000000 directly may be too aggressive,
// so we use 0xB0000000 (768MB from start) for safety
pub const MEMORY_END: u64 = 0xB0000000;

/// Design abstraction struct:
/// PhysAddr, VirtAddr, PhysPageNum, VirtPageNum
Expand Down
4 changes: 3 additions & 1 deletion awkernel_lib/src/arch/rv64/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ impl CPU for super::RV64 {
fn cpu_id() -> usize {
let hartid: usize;
unsafe {
core::arch::asm!("csrr {}, mhartid", out(reg) hartid);
// In M-mode, read from tp register (set during boot)
// This avoids repeatedly accessing mhartid CSR
core::arch::asm!("mv {}, tp", out(reg) hartid);
}
hartid
}
Expand Down
33 changes: 23 additions & 10 deletions awkernel_lib/src/arch/rv64/delay.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use crate::delay::Delay;
use core::sync::atomic::{AtomicU64, Ordering};

// we should get this info from device tree
const ACLINT_MTIME_BASE: u32 = 0x0200_0000 + 0x0000bff8;
const RISCV_TIMEBASE_FREQ: u64 = 10_000_000;

static COUNT_START: AtomicU64 = AtomicU64::new(0);

impl Delay for super::RV64 {
fn wait_interrupt() {
unsafe { core::arch::asm!("wfi") };
Expand All @@ -16,19 +19,19 @@ impl Delay for super::RV64 {
}

fn uptime() -> u64 {
// as microsec
unsafe {
let mtime = ACLINT_MTIME_BASE as *const u64;
*mtime * 1_000_000 / RISCV_TIMEBASE_FREQ
}
let start = COUNT_START.load(Ordering::Acquire);
let mtime = ACLINT_MTIME_BASE as *const u64;
let now = unsafe { core::ptr::read_volatile(mtime) };
let diff = now - start;
diff * 1_000_000 / RISCV_TIMEBASE_FREQ
}

fn uptime_nano() -> u128 {
// as microsec
unsafe {
let mtime = ACLINT_MTIME_BASE as *const u128;
*mtime * 1_000_000_000 / RISCV_TIMEBASE_FREQ as u128
}
let start = COUNT_START.load(Ordering::Acquire);
let mtime = ACLINT_MTIME_BASE as *const u64;
let now = unsafe { core::ptr::read_volatile(mtime) };
let diff = now - start;
diff as u128 * 1_000_000_000 / RISCV_TIMEBASE_FREQ as u128
}

fn cpu_counter() -> u64 {
Expand All @@ -39,3 +42,13 @@ impl Delay for super::RV64 {
cycle
}
}

pub(super) unsafe fn init_primary() {
let mtime = ACLINT_MTIME_BASE as *const u64;
let count = core::ptr::read_volatile(mtime);
COUNT_START.store(count, Ordering::Release);
}

pub(super) unsafe fn init_non_primary() {
// No additional initialization needed for non-primary CPUs
}
Loading