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