From 2f3eca446c1d9f3a976dbb4e1a82491cef1f0a56 Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 31 Jul 2026 15:51:32 +0200 Subject: shell: fix mem memory-type labels, add mmap and stress commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cmd_mem: correct type grouping — 1|2 loader, 5|6 runtime (new line), 9|10 ACPI, 7 conventional, 11|12 MMIO (previously 6 was mislabeled LoaderData and 5|10 were called ACPI) - cmd_mmap: per-region dump using uefi::memory_type_name with index/type/start/pages/size columns - cmd_stress : allocate chunk Vecs via try_reserve_exact, report heap+page stats while held and after free; exercises heap growth past the base region --- shell/src/lib.rs | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 156 insertions(+), 6 deletions(-) (limited to 'shell/src') diff --git a/shell/src/lib.rs b/shell/src/lib.rs index bdd79c6..4d5ba9c 100644 --- a/shell/src/lib.rs +++ b/shell/src/lib.rs @@ -47,6 +47,8 @@ pub fn run() -> ! { } "info" => cmd_info(), "mem" => cmd_mem(), + "mmap" => cmd_mmap(), + "stress" => cmd_stress(args), _ => { gop_println!("unknown command: {}", cmd); serial_println!("unknown command: {}", cmd); @@ -119,10 +121,12 @@ fn cmd_help() { gop_println!(" hello — print 'World!'"); gop_println!(" info — show system info"); gop_println!(" mem — show memory info"); + gop_println!(" mmap — dump the UEFI memory map"); + gop_println!(" stress — stress-test heap/page allocators"); gop_println!(" halt — halt the system"); gop_println!(" exit — alias for halt"); serial_println!("available commands:"); - serial_println!(" help, echo, clear, hello, info, mem, halt, exit"); + serial_println!(" help, echo, clear, hello, info, mem, mmap, stress, halt, exit"); } fn cmd_echo(args: &str) { @@ -151,6 +155,7 @@ fn cmd_mem() { let mut total_kb = 0u64; let mut conventional_kb = 0u64; let mut loader_kb = 0u64; + let mut runtime_kb = 0u64; let mut boot_code_kb = 0u64; let mut boot_data_kb = 0u64; let mut reserved_kb = 0u64; @@ -162,14 +167,14 @@ fn cmd_mem() { let bytes_4k = pages * 4; total_kb += bytes_4k; match desc.kind { - 1 => reserved_kb += bytes_4k, + 1 | 2 => loader_kb += bytes_4k, // LoaderCode + LoaderData 3 => boot_code_kb += bytes_4k, 4 => boot_data_kb += bytes_4k, - 5 | 10 => acpi_kb += bytes_4k, - 6 => loader_kb += bytes_4k, + 5 | 6 => runtime_kb += bytes_4k, // RuntimeCode + RuntimeData 7 => conventional_kb += bytes_4k, + 9 | 10 => acpi_kb += bytes_4k, // ACPIReclaim + ACPINVS 11 | 12 => mmio_kb += bytes_4k, - _ => reserved_kb += bytes_4k, + _ => reserved_kb += bytes_4k, // Reserved, Unusable, Pal, ... } } @@ -192,7 +197,16 @@ fn cmd_mem() { " boot data {:4} MB BootServicesData", boot_data_kb / 1024 ); - let _ = writeln!(out, " loader {:4} MB LoaderData", loader_kb / 1024); + let _ = writeln!( + out, + " loader {:4} MB LoaderCode + LoaderData", + loader_kb / 1024 + ); + let _ = writeln!( + out, + " runtime {:4} MB RuntimeServices", + runtime_kb / 1024 + ); let _ = writeln!(out, " ACPI {:4} MB", acpi_kb / 1024); let _ = writeln!(out, " MMIO {:4} MB", mmio_kb / 1024); let _ = writeln!(out, " reserved {:4} MB", reserved_kb / 1024); @@ -202,6 +216,142 @@ fn cmd_mem() { total_kb / 1024 ); + // Heap (free-list allocator with coalescing) + let h = rsnix::memory::heap_stats(); + let _ = writeln!(out, "heap:"); + let _ = writeln!( + out, + " range {:#x}..{:#x} {} KB total", + h.heap_start, + h.heap_end, + h.heap_size / 1024 + ); + let _ = writeln!( + out, + " free {} KB in {} block(s), allocated {} KB", + h.free_bytes / 1024, + h.free_blocks, + h.heap_size.saturating_sub(h.free_bytes) / 1024 + ); + + // Physical pages (bitmap allocator) + let ps = rsnix::memory::page_stats(); + let _ = writeln!(out, "pages:"); + let _ = writeln!( + out, + " span base {:#x}, {} MB covered", + ps.base_page * rsnix::memory::PAGE_SIZE, + ps.span_bytes / 1024 / 1024 + ); + let _ = writeln!( + out, + " free {} pages ({} MB), {} used", + ps.free_pages, + ps.free_pages * rsnix::memory::PAGE_SIZE / 1024 / 1024, + ps.used_pages + ); + + gop_print!("{}", out); + serial_print!("{}", out); +} + +// --------------------------------------------------------------------------- +// mmap — dump every entry of the UEFI memory map with type names +// --------------------------------------------------------------------------- +fn cmd_mmap() { + let (map, key) = rsnix::memory::get_map(); + let mut out = alloc::string::String::new(); + use alloc::fmt::Write; + let _ = writeln!(out, "memory map (key=0x{:x}, {} entries):", key, map.len()); + let _ = writeln!( + out, + " # type start pages size" + ); + for (i, d) in map.iter().enumerate() { + let _ = writeln!( + out, + " {:>2} {:<16} {:#014x} {:>9} {:>8} KB", + i, + rsnix::uefi::memory_type_name(d.kind), + d.physical_start, + d.number_of_pages, + d.number_of_pages * 4 + ); + } + gop_print!("{}", out); + serial_print!("{}", out); +} + +// --------------------------------------------------------------------------- +// stress — allocate blocks of KB, hold them, then free all. +// Pushes the heap past its base region so growth into the page allocator +// is exercised; also verifies a clean return to the free-list after. +// --------------------------------------------------------------------------- +fn cmd_stress(args: &str) { + let mut it = args.split_whitespace(); + let chunks: usize = match it.next().and_then(|s| s.parse().ok()) { + Some(n) if (1..=64).contains(&n) => n, + _ => { + gop_println!("usage: stress "); + serial_println!("usage: stress "); + return; + } + }; + let kb: usize = match it.next().and_then(|s| s.parse().ok()) { + Some(n) if n > 0 && n <= 1024 * 1024 => n, + _ => { + gop_println!("usage: stress "); + serial_println!("usage: stress "); + return; + } + }; + + let mut out = alloc::string::String::new(); + use alloc::fmt::Write; + + let mut allocated = 0usize; + { + let mut blocks: [Option>; 64] = core::array::from_fn(|_| None); + for i in 0..chunks { + let mut b = alloc::vec::Vec::::new(); + match b.try_reserve_exact(kb * 1024) { + Ok(()) => { + b.resize(kb * 1024, 0x42); + blocks[i] = Some(b); + allocated += 1; + } + Err(_) => { + let _ = writeln!(out, " block {}: out of memory, stopping", i); + break; + } + } + } + let h = rsnix::memory::heap_stats(); + let ps = rsnix::memory::page_stats(); + let _ = writeln!( + out, + " held {} x {} KB = {} KB", + allocated, + kb, + allocated * kb + ); + let _ = writeln!( + out, + " heap free {} KB ({} blocks), pages free {} MB", + h.free_bytes / 1024, + h.free_blocks, + ps.free_pages * 4 / 1024 + ); + // blocks dropped here → everything freed + } + let h = rsnix::memory::heap_stats(); + let _ = writeln!( + out, + " freed: heap free {} KB in {} blocks", + h.free_bytes / 1024, + h.free_blocks + ); + gop_print!("{}", out); serial_print!("{}", out); } -- cgit v1.2.3