diff options
Diffstat (limited to 'shell/src')
| -rw-r--r-- | shell/src/lib.rs | 162 |
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 | ||
| 128 | fn cmd_echo(args: &str) { | 132 | fn 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 | // --------------------------------------------------------------------------- | ||
| 261 | fn 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 | // --------------------------------------------------------------------------- | ||
| 290 | fn 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 | } |
