summaryrefslogtreecommitdiff
path: root/na
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-05-02 01:48:10 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-05-02 01:48:10 +0800
commitae72f8dcb029eed0f054b4c8b845868229b07038 (patch)
treeb85a0288afde4f5350e424e6cc0e12a4bad13a95 /na
parent12bd3efdbbabde0fda7d56ee82def083006e0c26 (diff)
downloadlume-ae72f8dcb029eed0f054b4c8b845868229b07038.tar.gz
lume-ae72f8dcb029eed0f054b4c8b845868229b07038.tar.xz
feat: update UART handling and memory management parameters for improved functionality
Diffstat (limited to 'na')
-rw-r--r--na/arch/riscv/include/arch/config.h4
-rw-r--r--na/drivers/uart.cc11
-rw-r--r--na/fdt/fdt.cc35
-rw-r--r--na/include/lume/device_node.h2
-rw-r--r--na/include/lume/fdt.h8
-rw-r--r--na/include/lume/pmm.h6
-rw-r--r--na/mm/pmm.cc18
7 files changed, 58 insertions, 26 deletions
diff --git a/na/arch/riscv/include/arch/config.h b/na/arch/riscv/include/arch/config.h
index 2a70f2a..86cd8b1 100644
--- a/na/arch/riscv/include/arch/config.h
+++ b/na/arch/riscv/include/arch/config.h
@@ -21,8 +21,4 @@ inline constexpr uint64 kVAOffset = 0xFFFFFFC000000000ULL;
/* Physical memory base (where RAM starts on RISC-V virt platform) */
inline constexpr uint64 kPhysBase = 0x80000000ULL;
-/* Platform default MMIO base addresses (QEMU virt) */
-inline constexpr uint64 kDefaultUartPA = 0x10000000ULL;
-inline constexpr uint64 kDefaultPlicPA = 0x0C000000ULL;
-
} // namespace arch
diff --git a/na/drivers/uart.cc b/na/drivers/uart.cc
index 802e88d..97c3e38 100644
--- a/na/drivers/uart.cc
+++ b/na/drivers/uart.cc
@@ -13,7 +13,8 @@
#include <lume/addr.h>
#include <arch/config.h>
-static uint64 g_uart_pa = arch::kDefaultUartPA;
+static uint64 g_uart_pa = 0;
+static uint64 g_uart_size = 0;
extern "C" void early_putc(char c) {
if (!g_uart_pa) return;
@@ -27,9 +28,11 @@ extern "C" void early_puts(const char* s) {
void console_early_init(uint64 fdt_paddr) {
uint64 pa = 0;
- FdtManager::early_scan_uart(fdt_paddr, &pa);
+ uint64 size = 0;
+ FdtManager::early_scan_uart(fdt_paddr, &pa, &size);
if (pa != 0) {
g_uart_pa = pa;
+ if (size != 0) g_uart_size = size;
}
}
@@ -38,7 +41,7 @@ void console_init() {
* Once vmm_init() activates the new page table, the 1GB identity map is dropped.
* The UART must be explicitly registered into the active page table.
*/
- if (g_uart_pa != 0) {
- vmm_map_kernel_mmio(g_uart_pa, 0x1000);
+ if (g_uart_pa != 0 && g_uart_size != 0) {
+ vmm_map_kernel_mmio(g_uart_pa, g_uart_size);
}
}
diff --git a/na/fdt/fdt.cc b/na/fdt/fdt.cc
index 8262aeb..a572b1b 100644
--- a/na/fdt/fdt.cc
+++ b/na/fdt/fdt.cc
@@ -19,7 +19,7 @@
#include <lume/fdt.h>
#include <lume/new.h>
-#include <lume/panic.h>
+#include <lume/klog.h>
#include <lume/addr.h>
/* ------------------------------------------------------------------ */
@@ -250,9 +250,9 @@ void FdtManager::early_scan_mem(uint64 fdt_paddr, uint64 *base, uint64 *size)
* Unlike early_scan_mem, failure here is non-fatal: we fall back to
* the platform's default UART address (0x10000000 for QEMU virt).
*/
-void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr)
+void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr, uint64 *uart_size)
{
- if (!uart_addr)
+ if (!uart_addr || !uart_size)
return;
const fdt_header *hdr = reinterpret_cast<const fdt_header *>(fdt_paddr);
@@ -269,6 +269,9 @@ void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr)
uint32 address_cells[16] = {2};
uint32 size_cells[16] = {1};
bool in_uart_node = false;
+ bool has_current_node_reg = false;
+ uint64 current_node_reg = 0;
+ uint64 current_node_size = 0;
while (true) {
uint32 token = bswap32(
@@ -288,11 +291,13 @@ void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr)
size_cells[depth] = size_cells[depth - 1];
}
in_uart_node = false;
+ has_current_node_reg = false;
} else if (token == FDT_END_NODE) {
if (depth >= 0)
depth--;
in_uart_node = false;
+ has_current_node_reg = false;
} else if (token == FDT_PROP) {
uint32 len = bswap32(
@@ -316,11 +321,24 @@ void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr)
reinterpret_cast<const char *>(prop_val),
len, "ns16550a")) {
in_uart_node = true;
+ if (has_current_node_reg) {
+ *uart_addr = current_node_reg;
+ *uart_size = current_node_size;
+ return;
+ }
}
- } else if (in_uart_node && str_equals(prop_name, "reg")) {
+ } else if (str_equals(prop_name, "reg")) {
uint32 p_depth = (depth > 0) ? depth - 1 : 0;
- *uart_addr = read_cells(prop_val, address_cells[p_depth]);
- return; // Found it
+ current_node_reg = read_cells(prop_val, address_cells[p_depth]);
+ current_node_size = read_cells(
+ prop_val + address_cells[p_depth] * 4,
+ size_cells[p_depth]);
+ has_current_node_reg = true;
+ if (in_uart_node) {
+ *uart_addr = current_node_reg;
+ *uart_size = current_node_size;
+ return; // Found it
+ }
}
}
@@ -336,6 +354,7 @@ void FdtManager::early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr)
}
*uart_addr = 0;
+ *uart_size = 0;
}
/* ------------------------------------------------------------------ */
@@ -549,7 +568,7 @@ void fdt_early_get_mem_info(uint64 *base, uint64 *size)
FdtManager::early_scan_mem(g_fdt->get_paddr(), base, size);
}
-void fdt_early_get_uart_info(uint64 *uart_addr)
+void fdt_early_get_uart_info(uint64 *uart_addr, uint64 *uart_size)
{
- FdtManager::early_scan_uart(g_fdt->get_paddr(), uart_addr);
+ FdtManager::early_scan_uart(g_fdt->get_paddr(), uart_addr, uart_size);
}
diff --git a/na/include/lume/device_node.h b/na/include/lume/device_node.h
index 14b4a9c..e35f22d 100644
--- a/na/include/lume/device_node.h
+++ b/na/include/lume/device_node.h
@@ -10,7 +10,7 @@
* Nodes form a parent-children hierarchy via intrusive linked lists.
* After unflattening, the tree is globally read-only and requires no locks.
*
- * Created during Phase 2 (fdt_unflatten) when Slab is available.
+ * Created when Slab is available.
*
* Reference: docs/specs/fdt.md §3.2
*/
diff --git a/na/include/lume/fdt.h b/na/include/lume/fdt.h
index 8da223c..783b030 100644
--- a/na/include/lume/fdt.h
+++ b/na/include/lume/fdt.h
@@ -33,9 +33,9 @@ public:
// Panics if the FDT is invalid or /memory is missing.
static void early_scan_mem(uint64 fdt_paddr, uint64 *base, uint64 *size);
- // Extract the UART base address by matching compatible = "ns16550a".
- // Falls back to platform default (0x10000000) on failure.
- static void early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr);
+ // Extract the UART base address and size by matching compatible = "ns16550a".
+ // Falls back to platform default on failure.
+ static void early_scan_uart(uint64 fdt_paddr, uint64 *uart_addr, uint64 *uart_size);
// --- Phase 2: Object tree construction (requires Slab) ---
@@ -78,4 +78,4 @@ DeviceNode *fdt_get_node_by_path(const char *path);
// Early scan wrappers (delegate to FdtManager static methods).
void fdt_early_get_mem_info(uint64 *base, uint64 *size);
-void fdt_early_get_uart_info(uint64 *uart_addr);
+void fdt_early_get_uart_info(uint64 *uart_addr, uint64 *uart_size);
diff --git a/na/include/lume/pmm.h b/na/include/lume/pmm.h
index 1ac1e17..b970404 100644
--- a/na/include/lume/pmm.h
+++ b/na/include/lume/pmm.h
@@ -24,8 +24,10 @@
/* Buddy system constants */
inline constexpr int kMaxOrder = 11; // Orders 0..10 → 4KB..4MB
-inline constexpr int kPcpHighWatermark = 64; // Max frames cached per CPU
-inline constexpr int kPcpBatchSize = 32; // Frames moved per refill/drain
+
+/* Per-CPU cache dynamic parameters (calculated in pmm_init) */
+extern uint32 g_pcp_high_watermark;
+extern uint32 g_pcp_batch_size;
/* ================================================================== */
/* Public free-function API */
diff --git a/na/mm/pmm.cc b/na/mm/pmm.cc
index fc743a9..00f998c 100644
--- a/na/mm/pmm.cc
+++ b/na/mm/pmm.cc
@@ -24,7 +24,7 @@
#include <lume/config.h>
#include <lume/fdt.h>
#include <lume/new.h>
-#include <lume/panic.h>
+#include <lume/klog.h>
#include <lume/types.h>
#include <arch/cpu.h>
#include <kernel/sync/spinlock.h>
@@ -57,6 +57,9 @@ static uint64 g_mem_base = 0; // Physical memory base (from
static uint64 g_mem_size = 0; // Total physical memory size
static uint64 g_num_frames = 0; // Total managed frames
+uint32 g_pcp_high_watermark = 0;
+uint32 g_pcp_batch_size = 0;
+
/* ------------------------------------------------------------------ */
/* Address conversion helpers */
/* ------------------------------------------------------------------ */
@@ -216,7 +219,7 @@ static void buddy_free(Frame* frame, uint8 order)
static void refill_pcp(PerCpuCache* pcp)
{
LockGuard guard(g_pmm_lock);
- for (int i = 0; i < kPcpBatchSize; i++) {
+ for (uint32 i = 0; i < g_pcp_batch_size; i++) {
Frame* f = buddy_alloc(0);
if (!f)
break;
@@ -325,7 +328,7 @@ void pmm_free_frame(Frame* frame)
pcp->count++;
// Drain if over high watermark
- if (pcp->count >= kPcpHighWatermark)
+ if (pcp->count >= g_pcp_high_watermark)
drain_pcp(pcp);
if (was_on)
@@ -406,6 +409,15 @@ void pmm_init()
g_num_frames = mem_size / kPageSize;
/*
+ * Dynamically calculate PCP parameters based on memory size.
+ * Rule of thumb: batch_size = max(16, total_pages / (cpu_count * 1024))
+ * This avoids depleting global memory on small RAM systems.
+ */
+ uint32 calc_batch = static_cast<uint32>(g_num_frames / (kMaxCpus * 1024));
+ g_pcp_batch_size = (calc_batch > 16) ? calc_batch : 16;
+ g_pcp_high_watermark = g_pcp_batch_size * 2;
+
+ /*
* 2. Place the frame_map array.
*
* The frame_map lives right after the kernel image (_kernel_end),