diff options
Diffstat (limited to 'rsdos')
| -rw-r--r-- | rsdos/Cargo.toml | 8 | ||||
| -rw-r--r-- | rsdos/src/main.rs | 138 |
2 files changed, 146 insertions, 0 deletions
diff --git a/rsdos/Cargo.toml b/rsdos/Cargo.toml new file mode 100644 index 0000000..5bf83fe --- /dev/null +++ b/rsdos/Cargo.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [package] | ||
| 2 | name = "rsdos" | ||
| 3 | version.workspace = true | ||
| 4 | edition.workspace = true | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | rsnix = { path = "../rsnix" } | ||
| 8 | shell = { path = "../shell" } | ||
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 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![allow(static_mut_refs, unsafe_code)] | ||
| 4 | |||
| 5 | use core::panic::PanicInfo; | ||
| 6 | use rsnix::uefi::*; | ||
| 7 | |||
| 8 | // --------------------------------------------------------------------------- | ||
| 9 | // Panic handler | ||
| 10 | // --------------------------------------------------------------------------- | ||
| 11 | #[panic_handler] | ||
| 12 | fn panic(info: &PanicInfo) -> ! { | ||
| 13 | use core::fmt::Write; | ||
| 14 | rsnix::serial::write_str("\r\n*** PANIC ***\r\n"); | ||
| 15 | let _ = write!(&mut rsnix::serial::SerialWriter, "{}\r\n", info.message()); | ||
| 16 | if let Some(loc) = info.location() { | ||
| 17 | let _ = write!( | ||
| 18 | &mut rsnix::serial::SerialWriter, | ||
| 19 | " at {}:{}\r\n", | ||
| 20 | loc.file(), | ||
| 21 | loc.line() | ||
| 22 | ); | ||
| 23 | } | ||
| 24 | loop { | ||
| 25 | unsafe { | ||
| 26 | core::arch::asm!("cli; hlt"); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | // --------------------------------------------------------------------------- | ||
| 32 | // EFI entry point | ||
| 33 | // --------------------------------------------------------------------------- | ||
| 34 | #[no_mangle] | ||
| 35 | pub extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemTable) -> ! { | ||
| 36 | let st = unsafe { &mut *system_table }; | ||
| 37 | let bs = unsafe { &mut *st.boot_services }; | ||
| 38 | let con_out = unsafe { &mut *st.con_out }; | ||
| 39 | |||
| 40 | // ---- Phase 1: UEFI boot services alive ---- | ||
| 41 | |||
| 42 | // Print banner via UEFI console | ||
| 43 | unsafe { | ||
| 44 | let s = concat!("rsnix v", env!("CARGO_PKG_VERSION"), " booting..\n"); | ||
| 45 | let bytes = s.as_bytes(); | ||
| 46 | let mut buf: [u16; 48] = [0; 48]; | ||
| 47 | for (i, &b) in bytes.iter().enumerate().take(47) { | ||
| 48 | buf[i] = b as u16; | ||
| 49 | } | ||
| 50 | (con_out.output_string)(con_out, buf.as_ptr()); | ||
| 51 | } | ||
| 52 | |||
| 53 | rsnix::serial::init(); | ||
| 54 | rsnix::serial_println!("=== rsnix boot ==="); | ||
| 55 | |||
| 56 | // Stash the memory map | ||
| 57 | let map_key = match rsnix::memory::capture_memory_map(bs) { | ||
| 58 | Ok(k) => k, | ||
| 59 | Err(e) => { | ||
| 60 | rsnix::serial_println!("mem: capture_memory_map failed 0x{:x}", e); | ||
| 61 | 0 | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | |||
| 65 | // Locate GOP (Graphics Output Protocol) | ||
| 66 | let mut gop_interface: *mut core::ffi::c_void = core::ptr::null_mut(); | ||
| 67 | let gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; | ||
| 68 | let gop_result = unsafe { | ||
| 69 | (bs.locate_protocol)( | ||
| 70 | &gop_guid as *const Guid, | ||
| 71 | core::ptr::null_mut(), | ||
| 72 | &mut gop_interface, | ||
| 73 | ) | ||
| 74 | }; | ||
| 75 | if gop_result == EFI_SUCCESS { | ||
| 76 | let gop = unsafe { &mut *(gop_interface as *mut GraphicsOutputProtocol) }; | ||
| 77 | rsnix::serial_println!("gop: framebuffer found"); | ||
| 78 | rsnix::gop::init(gop); | ||
| 79 | } else { | ||
| 80 | rsnix::serial_println!("gop: not found (0x{:x})", gop_result); | ||
| 81 | } | ||
| 82 | |||
| 83 | // ExitBootServices — we now own the machine | ||
| 84 | if unsafe { (bs.exit_boot_services)(image_handle, map_key) } != EFI_SUCCESS { | ||
| 85 | rsnix::serial_println!("WARN: ExitBootServices failed, retrying..."); | ||
| 86 | match rsnix::memory::refresh_and_exit(bs, image_handle) { | ||
| 87 | Ok(_) => {} | ||
| 88 | Err(e) => { | ||
| 89 | rsnix::serial_println!("FATAL: cannot ExitBootServices (0x{:x})", e); | ||
| 90 | loop { | ||
| 91 | unsafe { | ||
| 92 | core::arch::asm!("cli; hlt"); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | // ---- Phase 2: Native mode ---- | ||
| 100 | rsnix::serial::init(); | ||
| 101 | rsnix::serial_println!("serial: COM1 115200 8N1"); | ||
| 102 | rsnix::ps2::init(); | ||
| 103 | rsnix::serial_println!("ps2: keyboard initialized"); | ||
| 104 | rsnix::interrupts::init(); | ||
| 105 | rsnix::serial_println!("intr: IDT loaded, PIC remapped, timer ~100 Hz"); | ||
| 106 | |||
| 107 | dump_memory_summary(); | ||
| 108 | |||
| 109 | rsnix::serial_println!("boot: entering shell"); | ||
| 110 | shell::run(); | ||
| 111 | } | ||
| 112 | |||
| 113 | // --------------------------------------------------------------------------- | ||
| 114 | // Print a memory summary from the stashed memory map | ||
| 115 | // --------------------------------------------------------------------------- | ||
| 116 | fn dump_memory_summary() { | ||
| 117 | let (map, key) = rsnix::memory::get_map(); | ||
| 118 | let mut conventional_4k = 0u64; | ||
| 119 | let mut addr_space_4k = 0u64; | ||
| 120 | for desc in map.iter() { | ||
| 121 | let pages = desc.number_of_pages; | ||
| 122 | addr_space_4k += pages; | ||
| 123 | if desc.kind == 7 { | ||
| 124 | conventional_4k += pages; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | rsnix::serial_println!( | ||
| 128 | "mem: {} entries, key=0x{:x}, usable: {} KB ({} MB)", | ||
| 129 | map.len(), | ||
| 130 | key, | ||
| 131 | conventional_4k * 4, | ||
| 132 | (conventional_4k * 4) / 1024, | ||
| 133 | ); | ||
| 134 | rsnix::serial_println!( | ||
| 135 | "mem: address space: {} MB (incl. PCIe MMIO)", | ||
| 136 | (addr_space_4k * 4) / 1024, | ||
| 137 | ); | ||
| 138 | } | ||
