From 6a5c32fa6ae8ec34e3e5b44d7e5a78ded8fe729b Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 31 Jul 2026 02:58:31 +0200 Subject: restructure: rsnix kernel + shell crate + rsdos entry point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Architecture: rs-dos/ (workspace root, was raisernics/) ├── rsnix/ — kernel lib crate (uefi, serial, gop, ps2, interrupts, memory) ├── shell/ — shell lib crate (prompt, commands, line input) ├── rsdos/ — binary crate (efi_main, init, panic handler) └── rsboot/ — future git submodule No functional changes — boots to shell prompt identically. Version auto-pulled from Cargo.toml via env!("CARGO_PKG_VERSION"). --- rsdos/src/main.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 rsdos/src/main.rs (limited to 'rsdos/src/main.rs') diff --git a/rsdos/src/main.rs b/rsdos/src/main.rs new file mode 100644 index 0000000..543556b --- /dev/null +++ b/rsdos/src/main.rs @@ -0,0 +1,138 @@ +#![no_std] +#![no_main] +#![allow(static_mut_refs, unsafe_code)] + +use core::panic::PanicInfo; +use rsnix::uefi::*; + +// --------------------------------------------------------------------------- +// Panic handler +// --------------------------------------------------------------------------- +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + use core::fmt::Write; + rsnix::serial::write_str("\r\n*** PANIC ***\r\n"); + let _ = write!(&mut rsnix::serial::SerialWriter, "{}\r\n", info.message()); + if let Some(loc) = info.location() { + let _ = write!( + &mut rsnix::serial::SerialWriter, + " at {}:{}\r\n", + loc.file(), + loc.line() + ); + } + loop { + unsafe { + core::arch::asm!("cli; hlt"); + } + } +} + +// --------------------------------------------------------------------------- +// EFI entry point +// --------------------------------------------------------------------------- +#[no_mangle] +pub extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemTable) -> ! { + let st = unsafe { &mut *system_table }; + let bs = unsafe { &mut *st.boot_services }; + let con_out = unsafe { &mut *st.con_out }; + + // ---- Phase 1: UEFI boot services alive ---- + + // Print banner via UEFI console + unsafe { + let s = concat!("rsnix v", env!("CARGO_PKG_VERSION"), " booting..\n"); + let bytes = s.as_bytes(); + let mut buf: [u16; 48] = [0; 48]; + for (i, &b) in bytes.iter().enumerate().take(47) { + buf[i] = b as u16; + } + (con_out.output_string)(con_out, buf.as_ptr()); + } + + rsnix::serial::init(); + rsnix::serial_println!("=== rsnix boot ==="); + + // Stash the memory map + let map_key = match rsnix::memory::capture_memory_map(bs) { + Ok(k) => k, + Err(e) => { + rsnix::serial_println!("mem: capture_memory_map failed 0x{:x}", e); + 0 + } + }; + + // Locate GOP (Graphics Output Protocol) + let mut gop_interface: *mut core::ffi::c_void = core::ptr::null_mut(); + let gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + let gop_result = unsafe { + (bs.locate_protocol)( + &gop_guid as *const Guid, + core::ptr::null_mut(), + &mut gop_interface, + ) + }; + if gop_result == EFI_SUCCESS { + let gop = unsafe { &mut *(gop_interface as *mut GraphicsOutputProtocol) }; + rsnix::serial_println!("gop: framebuffer found"); + rsnix::gop::init(gop); + } else { + rsnix::serial_println!("gop: not found (0x{:x})", gop_result); + } + + // ExitBootServices — we now own the machine + if unsafe { (bs.exit_boot_services)(image_handle, map_key) } != EFI_SUCCESS { + rsnix::serial_println!("WARN: ExitBootServices failed, retrying..."); + match rsnix::memory::refresh_and_exit(bs, image_handle) { + Ok(_) => {} + Err(e) => { + rsnix::serial_println!("FATAL: cannot ExitBootServices (0x{:x})", e); + loop { + unsafe { + core::arch::asm!("cli; hlt"); + } + } + } + } + } + + // ---- Phase 2: Native mode ---- + rsnix::serial::init(); + rsnix::serial_println!("serial: COM1 115200 8N1"); + rsnix::ps2::init(); + rsnix::serial_println!("ps2: keyboard initialized"); + rsnix::interrupts::init(); + rsnix::serial_println!("intr: IDT loaded, PIC remapped, timer ~100 Hz"); + + dump_memory_summary(); + + rsnix::serial_println!("boot: entering shell"); + shell::run(); +} + +// --------------------------------------------------------------------------- +// Print a memory summary from the stashed memory map +// --------------------------------------------------------------------------- +fn dump_memory_summary() { + let (map, key) = rsnix::memory::get_map(); + let mut conventional_4k = 0u64; + let mut addr_space_4k = 0u64; + for desc in map.iter() { + let pages = desc.number_of_pages; + addr_space_4k += pages; + if desc.kind == 7 { + conventional_4k += pages; + } + } + rsnix::serial_println!( + "mem: {} entries, key=0x{:x}, usable: {} KB ({} MB)", + map.len(), + key, + conventional_4k * 4, + (conventional_4k * 4) / 1024, + ); + rsnix::serial_println!( + "mem: address space: {} MB (incl. PCIe MMIO)", + (addr_space_4k * 4) / 1024, + ); +} -- cgit v1.2.3