summaryrefslogtreecommitdiffstats
path: root/shell/src/lib.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-07-31 15:51:32 +0200
committersalmonik <salmonik@tuta.io>2026-07-31 15:51:32 +0200
commit2f3eca446c1d9f3a976dbb4e1a82491cef1f0a56 (patch)
treec9e17c7773fcedb9e7ff6201313dcc8f6dc685a1 /shell/src/lib.rs
parentrsnix: memory management — free-list heap, bitmap pages, paging adoption (diff)
downloadrs-dos-2f3eca446c1d9f3a976dbb4e1a82491cef1f0a56.tar.gz
rs-dos-2f3eca446c1d9f3a976dbb4e1a82491cef1f0a56.zip
shell: fix mem memory-type labels, add mmap and stress commands
- 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 <chunks(1-64)> <kb>: allocate chunk Vecs via try_reserve_exact, report heap+page stats while held and after free; exercises heap growth past the base region
Diffstat (limited to '')
-rw-r--r--shell/src/lib.rs162
1 files changed, 156 insertions, 6 deletions
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() -> ! {
47 } 47 }
48 "info" => cmd_info(), 48 "info" => cmd_info(),
49 "mem" => cmd_mem(), 49 "mem" => cmd_mem(),
50 "mmap" => cmd_mmap(),
51 "stress" => cmd_stress(args),
50 _ => { 52 _ => {
51 gop_println!("unknown command: {}", cmd); 53 gop_println!("unknown command: {}", cmd);
52 serial_println!("unknown command: {}", cmd); 54 serial_println!("unknown command: {}", cmd);
@@ -119,10 +121,12 @@ fn cmd_help() {
119 gop_println!(" hello — print 'World!'"); 121 gop_println!(" hello — print 'World!'");
120 gop_println!(" info — show system info"); 122 gop_println!(" info — show system info");
121 gop_println!(" mem — show memory info"); 123 gop_println!(" mem — show memory info");
124 gop_println!(" mmap — dump the UEFI memory map");
125 gop_println!(" stress — stress-test heap/page allocators");
122 gop_println!(" halt — halt the system"); 126 gop_println!(" halt — halt the system");
123 gop_println!(" exit — alias for halt"); 127 gop_println!(" exit — alias for halt");
124 serial_println!("available commands:"); 128 serial_println!("available commands:");
125 serial_println!(" help, echo, clear, hello, info, mem, halt, exit"); 129 serial_println!(" help, echo, clear, hello, info, mem, mmap, stress, halt, exit");
126} 130}
127 131
128fn cmd_echo(args: &str) { 132fn cmd_echo(args: &str) {
@@ -151,6 +155,7 @@ fn cmd_mem() {
151 let mut total_kb = 0u64; 155 let mut total_kb = 0u64;
152 let mut conventional_kb = 0u64; 156 let mut conventional_kb = 0u64;
153 let mut loader_kb = 0u64; 157 let mut loader_kb = 0u64;
158 let mut runtime_kb = 0u64;
154 let mut boot_code_kb = 0u64; 159 let mut boot_code_kb = 0u64;
155 let mut boot_data_kb = 0u64; 160 let mut boot_data_kb = 0u64;
156 let mut reserved_kb = 0u64; 161 let mut reserved_kb = 0u64;
@@ -162,14 +167,14 @@ fn cmd_mem() {
162 let bytes_4k = pages * 4; 167 let bytes_4k = pages * 4;
163 total_kb += bytes_4k; 168 total_kb += bytes_4k;
164 match desc.kind { 169 match desc.kind {
165 1 => reserved_kb += bytes_4k, 170 1 | 2 => loader_kb += bytes_4k, // LoaderCode + LoaderData
166 3 => boot_code_kb += bytes_4k, 171 3 => boot_code_kb += bytes_4k,
167 4 => boot_data_kb += bytes_4k, 172 4 => boot_data_kb += bytes_4k,
168 5 | 10 => acpi_kb += bytes_4k, 173 5 | 6 => runtime_kb += bytes_4k, // RuntimeCode + RuntimeData
169 6 => loader_kb += bytes_4k,
170 7 => conventional_kb += bytes_4k, 174 7 => conventional_kb += bytes_4k,
175 9 | 10 => acpi_kb += bytes_4k, // ACPIReclaim + ACPINVS
171 11 | 12 => mmio_kb += bytes_4k, 176 11 | 12 => mmio_kb += bytes_4k,
172 _ => reserved_kb += bytes_4k, 177 _ => reserved_kb += bytes_4k, // Reserved, Unusable, Pal, ...
173 } 178 }
174 } 179 }
175 180
@@ -192,7 +197,16 @@ fn cmd_mem() {
192 " boot data {:4} MB BootServicesData", 197 " boot data {:4} MB BootServicesData",
193 boot_data_kb / 1024 198 boot_data_kb / 1024
194 ); 199 );
195 let _ = writeln!(out, " loader {:4} MB LoaderData", loader_kb / 1024); 200 let _ = writeln!(
201 out,
202 " loader {:4} MB LoaderCode + LoaderData",
203 loader_kb / 1024
204 );
205 let _ = writeln!(
206 out,
207 " runtime {:4} MB RuntimeServices",
208 runtime_kb / 1024
209 );
196 let _ = writeln!(out, " ACPI {:4} MB", acpi_kb / 1024); 210 let _ = writeln!(out, " ACPI {:4} MB", acpi_kb / 1024);
197 let _ = writeln!(out, " MMIO {:4} MB", mmio_kb / 1024); 211 let _ = writeln!(out, " MMIO {:4} MB", mmio_kb / 1024);
198 let _ = writeln!(out, " reserved {:4} MB", reserved_kb / 1024); 212 let _ = writeln!(out, " reserved {:4} MB", reserved_kb / 1024);
@@ -202,6 +216,142 @@ fn cmd_mem() {
202 total_kb / 1024 216 total_kb / 1024
203 ); 217 );
204 218
219 // Heap (free-list allocator with coalescing)
220 let h = rsnix::memory::heap_stats();
221 let _ = writeln!(out, "heap:");
222 let _ = writeln!(
223 out,
224 " range {:#x}..{:#x} {} KB total",
225 h.heap_start,
226 h.heap_end,
227 h.heap_size / 1024
228 );
229 let _ = writeln!(
230 out,
231 " free {} KB in {} block(s), allocated {} KB",
232 h.free_bytes / 1024,
233 h.free_blocks,
234 h.heap_size.saturating_sub(h.free_bytes) / 1024
235 );
236
237 // Physical pages (bitmap allocator)
238 let ps = rsnix::memory::page_stats();
239 let _ = writeln!(out, "pages:");
240 let _ = writeln!(
241 out,
242 " span base {:#x}, {} MB covered",
243 ps.base_page * rsnix::memory::PAGE_SIZE,
244 ps.span_bytes / 1024 / 1024
245 );
246 let _ = writeln!(
247 out,
248 " free {} pages ({} MB), {} used",
249 ps.free_pages,
250 ps.free_pages * rsnix::memory::PAGE_SIZE / 1024 / 1024,
251 ps.used_pages
252 );
253
254 gop_print!("{}", out);
255 serial_print!("{}", out);
256}
257
258// ---------------------------------------------------------------------------
259// mmap — dump every entry of the UEFI memory map with type names
260// ---------------------------------------------------------------------------
261fn cmd_mmap() {
262 let (map, key) = rsnix::memory::get_map();
263 let mut out = alloc::string::String::new();
264 use alloc::fmt::Write;
265 let _ = writeln!(out, "memory map (key=0x{:x}, {} entries):", key, map.len());
266 let _ = writeln!(
267 out,
268 " # type start pages size"
269 );
270 for (i, d) in map.iter().enumerate() {
271 let _ = writeln!(
272 out,
273 " {:>2} {:<16} {:#014x} {:>9} {:>8} KB",
274 i,
275 rsnix::uefi::memory_type_name(d.kind),
276 d.physical_start,
277 d.number_of_pages,
278 d.number_of_pages * 4
279 );
280 }
281 gop_print!("{}", out);
282 serial_print!("{}", out);
283}
284
285// ---------------------------------------------------------------------------
286// stress — allocate <chunks> blocks of <kb> KB, hold them, then free all.
287// Pushes the heap past its base region so growth into the page allocator
288// is exercised; also verifies a clean return to the free-list after.
289// ---------------------------------------------------------------------------
290fn cmd_stress(args: &str) {
291 let mut it = args.split_whitespace();
292 let chunks: usize = match it.next().and_then(|s| s.parse().ok()) {
293 Some(n) if (1..=64).contains(&n) => n,
294 _ => {
295 gop_println!("usage: stress <chunks(1-64)> <kb>");
296 serial_println!("usage: stress <chunks(1-64)> <kb>");
297 return;
298 }
299 };
300 let kb: usize = match it.next().and_then(|s| s.parse().ok()) {
301 Some(n) if n > 0 && n <= 1024 * 1024 => n,
302 _ => {
303 gop_println!("usage: stress <chunks> <kb>");
304 serial_println!("usage: stress <chunks> <kb>");
305 return;
306 }
307 };
308
309 let mut out = alloc::string::String::new();
310 use alloc::fmt::Write;
311
312 let mut allocated = 0usize;
313 {
314 let mut blocks: [Option<alloc::vec::Vec<u8>>; 64] = core::array::from_fn(|_| None);
315 for i in 0..chunks {
316 let mut b = alloc::vec::Vec::<u8>::new();
317 match b.try_reserve_exact(kb * 1024) {
318 Ok(()) => {
319 b.resize(kb * 1024, 0x42);
320 blocks[i] = Some(b);
321 allocated += 1;
322 }
323 Err(_) => {
324 let _ = writeln!(out, " block {}: out of memory, stopping", i);
325 break;
326 }
327 }
328 }
329 let h = rsnix::memory::heap_stats();
330 let ps = rsnix::memory::page_stats();
331 let _ = writeln!(
332 out,
333 " held {} x {} KB = {} KB",
334 allocated,
335 kb,
336 allocated * kb
337 );
338 let _ = writeln!(
339 out,
340 " heap free {} KB ({} blocks), pages free {} MB",
341 h.free_bytes / 1024,
342 h.free_blocks,
343 ps.free_pages * 4 / 1024
344 );
345 // blocks dropped here → everything freed
346 }
347 let h = rsnix::memory::heap_stats();
348 let _ = writeln!(
349 out,
350 " freed: heap free {} KB in {} blocks",
351 h.free_bytes / 1024,
352 h.free_blocks
353 );
354
205 gop_print!("{}", out); 355 gop_print!("{}", out);
206 serial_print!("{}", out); 356 serial_print!("{}", out);
207} 357}