diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-31 02:58:31 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-31 02:58:31 +0200 |
| commit | 6a5c32fa6ae8ec34e3e5b44d7e5a78ded8fe729b (patch) | |
| tree | ed59a5bd59a94b3a731b28c68c507f18afc44b0b /src/main.rs | |
| parent | auto-version all strings from Cargo.toml via env!("CARGO_PKG_VERSION") (diff) | |
| download | rs-dos-6a5c32fa6ae8ec34e3e5b44d7e5a78ded8fe729b.tar.gz rs-dos-6a5c32fa6ae8ec34e3e5b44d7e5a78ded8fe729b.zip | |
restructure: rsnix kernel + shell crate + rsdos entry point
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").
Diffstat (limited to '')
| -rw-r--r-- | src/main.rs | 186 |
1 files changed, 0 insertions, 186 deletions
diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 9a901f5..0000000 --- a/src/main.rs +++ /dev/null | |||
| @@ -1,186 +0,0 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![allow(static_mut_refs, unsafe_code, dead_code, unused_doc_comments)] | ||
| 4 | |||
| 5 | // SAFETY: single-core kernel, no preemption — static mut access is sound | ||
| 6 | // Toy kernel: dead code and unused items during active development | ||
| 7 | |||
| 8 | extern crate alloc; | ||
| 9 | |||
| 10 | mod font; | ||
| 11 | mod gop; | ||
| 12 | mod interrupts; | ||
| 13 | mod memory; | ||
| 14 | mod ps2; | ||
| 15 | mod serial; | ||
| 16 | mod shell; | ||
| 17 | mod uefi; | ||
| 18 | |||
| 19 | use core::panic::PanicInfo; | ||
| 20 | use uefi::*; | ||
| 21 | |||
| 22 | // --------------------------------------------------------------------------- | ||
| 23 | // Panic handler | ||
| 24 | // --------------------------------------------------------------------------- | ||
| 25 | #[panic_handler] | ||
| 26 | fn panic(info: &PanicInfo) -> ! { | ||
| 27 | use core::fmt::Write; | ||
| 28 | serial::write_str("\r\n*** PANIC ***\r\n"); | ||
| 29 | let _ = write!(&mut serial::SerialWriter, "{}\r\n", info.message()); | ||
| 30 | if let Some(loc) = info.location() { | ||
| 31 | let _ = write!( | ||
| 32 | &mut serial::SerialWriter, | ||
| 33 | " at {}:{}\r\n", | ||
| 34 | loc.file(), | ||
| 35 | loc.line() | ||
| 36 | ); | ||
| 37 | } | ||
| 38 | loop { | ||
| 39 | unsafe { | ||
| 40 | core::arch::asm!("cli; hlt"); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | // --------------------------------------------------------------------------- | ||
| 46 | // EFI entry point | ||
| 47 | // --------------------------------------------------------------------------- | ||
| 48 | #[no_mangle] | ||
| 49 | pub extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemTable) -> ! { | ||
| 50 | let st = unsafe { &mut *system_table }; | ||
| 51 | let bs = unsafe { &mut *st.boot_services }; | ||
| 52 | let con_out = unsafe { &mut *st.con_out }; | ||
| 53 | |||
| 54 | // ---- Phase 1: UEFI boot services alive ---- | ||
| 55 | |||
| 56 | // Print banner via UEFI console | ||
| 57 | unsafe { | ||
| 58 | let banner: [u16; 28] = [ | ||
| 59 | 'r' as u16, 'a' as u16, 'i' as u16, 's' as u16, 'e' as u16, 'r' as u16, 'n' as u16, | ||
| 60 | 'i' as u16, 'c' as u16, 's' as u16, ' ' as u16, 'v' as u16, '0' as u16, '.' as u16, | ||
| 61 | '1' as u16, ' ' as u16, '-' as u16, ' ' as u16, 'b' as u16, 'o' as u16, 'o' as u16, | ||
| 62 | 't' as u16, 'i' as u16, 'n' as u16, 'g' as u16, '.' as u16, '.' as u16, 0x0A, | ||
| 63 | ]; | ||
| 64 | (con_out.output_string)(con_out, banner.as_ptr()); | ||
| 65 | } | ||
| 66 | |||
| 67 | // Init serial early so we can debug-print before EBS | ||
| 68 | serial::init(); | ||
| 69 | |||
| 70 | serial_println!("=== raisernics boot ==="); | ||
| 71 | |||
| 72 | // Stash the memory map | ||
| 73 | let map_key = memory::capture_memory_map(bs); | ||
| 74 | let map_key = match map_key { | ||
| 75 | Ok(k) => k, | ||
| 76 | Err(e) => { | ||
| 77 | serial_println!("mem: capture_memory_map failed 0x{:x}", e); | ||
| 78 | 0 | ||
| 79 | } | ||
| 80 | }; | ||
| 81 | |||
| 82 | // Locate GOP (Graphics Output Protocol) | ||
| 83 | let mut gop_interface: *mut core::ffi::c_void = core::ptr::null_mut(); | ||
| 84 | let gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; | ||
| 85 | let gop_result = unsafe { | ||
| 86 | (bs.locate_protocol)( | ||
| 87 | &gop_guid as *const Guid, | ||
| 88 | core::ptr::null_mut(), | ||
| 89 | &mut gop_interface, | ||
| 90 | ) | ||
| 91 | }; | ||
| 92 | if gop_result == EFI_SUCCESS { | ||
| 93 | let gop = unsafe { &mut *(gop_interface as *mut GraphicsOutputProtocol) }; | ||
| 94 | serial_println!("gop: framebuffer found"); | ||
| 95 | gop::init(gop); | ||
| 96 | } else { | ||
| 97 | serial_println!("gop: not found (0x{:x})", gop_result); | ||
| 98 | } | ||
| 99 | |||
| 100 | // ExitBootServices — we now own the machine | ||
| 101 | let ebs_result = unsafe { (bs.exit_boot_services)(image_handle, map_key) }; | ||
| 102 | if ebs_result != EFI_SUCCESS { | ||
| 103 | // Memory map may have changed; try again with fresh map | ||
| 104 | // (This is the standard UEFI EBS retry dance.) | ||
| 105 | serial_println!( | ||
| 106 | "WARN: ExitBootServices failed (0x{:x}), retrying...", | ||
| 107 | ebs_result | ||
| 108 | ); | ||
| 109 | let _map_key = match memory::refresh_and_exit(bs, image_handle) { | ||
| 110 | Ok(k) => k, | ||
| 111 | Err(e) => { | ||
| 112 | serial_println!("FATAL: cannot ExitBootServices (0x{:x})", e); | ||
| 113 | loop { | ||
| 114 | unsafe { | ||
| 115 | core::arch::asm!("cli; hlt"); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | }; | ||
| 120 | } | ||
| 121 | |||
| 122 | // ---- Phase 2: Native mode ---- | ||
| 123 | |||
| 124 | serial::init(); | ||
| 125 | serial_println!("serial: COM1 115200 8N1"); | ||
| 126 | |||
| 127 | // PS/2 keyboard | ||
| 128 | ps2::init(); | ||
| 129 | serial_println!("ps2: keyboard initialized"); | ||
| 130 | |||
| 131 | // Interrupts — IDT, PIC, PIT timer, keyboard IRQ handler | ||
| 132 | interrupts::init(); | ||
| 133 | serial_println!("intr: IDT loaded, PIC remapped, timer ~100 Hz"); | ||
| 134 | |||
| 135 | // Memory: the bump allocator was set up during capture_memory_map. | ||
| 136 | // `alloc::Vec`, `alloc::String`, `format!` etc. are now usable. | ||
| 137 | |||
| 138 | // Print memory summary | ||
| 139 | dump_memory_summary(); | ||
| 140 | |||
| 141 | serial_println!("boot: entering shell"); | ||
| 142 | shell::run(); | ||
| 143 | } | ||
| 144 | |||
| 145 | // --------------------------------------------------------------------------- | ||
| 146 | // Print a memory summary from the stashed memory map | ||
| 147 | // --------------------------------------------------------------------------- | ||
| 148 | fn dump_memory_summary() { | ||
| 149 | let (map, key) = memory::get_map(); | ||
| 150 | let mut conventional_4k = 0u64; | ||
| 151 | let mut addr_space_4k = 0u64; | ||
| 152 | for desc in map.iter() { | ||
| 153 | let pages = desc.number_of_pages; | ||
| 154 | addr_space_4k += pages; | ||
| 155 | if desc.kind == 7 { | ||
| 156 | conventional_4k += pages; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | serial_println!( | ||
| 160 | "mem: {} entries, key=0x{:x}, usable: {} KB ({} MB)", | ||
| 161 | map.len(), | ||
| 162 | key, | ||
| 163 | conventional_4k * 4, | ||
| 164 | (conventional_4k * 4) / 1024, | ||
| 165 | ); | ||
| 166 | serial_println!( | ||
| 167 | "mem: address space: {} MB (incl. PCIe MMIO)", | ||
| 168 | (addr_space_4k * 4) / 1024, | ||
| 169 | ); | ||
| 170 | } | ||
| 171 | |||
| 172 | // --------------------------------------------------------------------------- | ||
| 173 | // Helper: write a panic-proof string via UEFI console (used before serial) | ||
| 174 | // --------------------------------------------------------------------------- | ||
| 175 | #[allow(dead_code)] | ||
| 176 | unsafe fn uefi_puts(con_out: *mut SimpleTextOutput, s: &str) { | ||
| 177 | // Simple ASCII → UEFI-CHAR16 conversion (stack buffer, panic-safe) | ||
| 178 | let mut buf: [u16; 128] = [0; 128]; | ||
| 179 | let len = s.len().min(127); | ||
| 180 | for (i, &b) in s.as_bytes()[..len].iter().enumerate() { | ||
| 181 | buf[i] = b as u16; | ||
| 182 | } | ||
| 183 | buf[len] = 0x0A; // LF | ||
| 184 | let out = unsafe { &mut *con_out }; | ||
| 185 | (out.output_string)(out, buf.as_ptr()); | ||
| 186 | } | ||
