1#![cfg_attr(all(target_os = "none", test), no_main)]
2#![cfg_attr(target_os = "none", no_std)]
3#![cfg_attr(target_os = "none", feature(alloc_error_handler))]
4#![allow(unused_unsafe)]
5#![doc = include_str!("../README.md")]
6
7extern crate alloc;
8extern crate rlibc;
9
10pub mod allocator;
11pub mod arch;
12pub mod drivers;
13pub mod rt;
14pub mod shell;
15pub mod wasm;
16
17#[cfg(test)]
18mod tests;
19
20use core::fmt::Write;
21use hal_core::{boot::BootInfo, mem};
22
23pub const MYCELIUM_VERSION: &str = concat!(
24 env!("VERGEN_BUILD_SEMVER"),
25 "-",
26 env!("VERGEN_GIT_BRANCH"),
27 ".",
28 env!("VERGEN_GIT_SHA_SHORT")
29);
30
31#[cfg_attr(target_os = "none", global_allocator)]
32static ALLOC: allocator::Allocator = allocator::Allocator::new();
33
34pub fn kernel_start(bootinfo: impl BootInfo, archinfo: crate::arch::ArchInfo) -> ! {
35 let mut writer = bootinfo.writer();
36 writeln!(
37 writer,
38 "hello from mycelium {} (on {})",
39 MYCELIUM_VERSION,
40 arch::NAME
41 )
42 .unwrap();
43 writeln!(writer, "booting via {}", bootinfo.bootloader_name()).unwrap();
44
45 if let Some(subscriber) = bootinfo.subscriber() {
46 tracing::dispatch::set_global_default(subscriber).unwrap();
47 }
48
49 #[cfg(not(test))]
50 if let Some(mut framebuf) = bootinfo.framebuffer() {
51 use hal_core::framebuffer::{Draw, RgbColor};
52 tracing::trace!("framebuffer exists!");
53 framebuf.clear();
54 let mut color = 0;
55 for row in 0..framebuf.height() {
56 color += 1;
57 match color {
58 1 => {
59 framebuf.fill_row(row, RgbColor::RED);
60 }
61 2 => {
62 framebuf.fill_row(row, RgbColor::GREEN);
63 }
64 3 => {
65 framebuf.fill_row(row, RgbColor::BLUE);
66 color = 0;
67 }
68 _ => {}
69 }
70 }
71 tracing::trace!("made it grey!");
72
73 use embedded_graphics::{
74 mono_font::{ascii, MonoTextStyle},
75 pixelcolor::{Rgb888, RgbColor as _},
76 prelude::*,
77 text::{Alignment, Text},
78 };
79 let center = Point::new(
80 (framebuf.width() / 2) as i32,
81 (framebuf.height() / 2) as i32,
82 );
83 let mut target = framebuf.clear().as_draw_target();
84 let small_style = MonoTextStyle::new(&ascii::FONT_6X10, Rgb888::WHITE);
85 Text::with_alignment(
86 "the glorious\n",
87 Point::new(center.x, center.y - 20),
88 small_style,
89 Alignment::Center,
90 )
91 .draw(&mut target)
92 .expect("never panics");
93 Text::with_alignment(
94 "MYCELIUM\n",
95 center,
96 MonoTextStyle::new(&ascii::FONT_10X20, Rgb888::WHITE),
97 Alignment::Center,
98 )
99 .draw(&mut target)
100 .expect("never panics");
101 Text::with_alignment(
102 concat!("operating system\n\n v", env!("CARGO_PKG_VERSION"), "\n"),
103 Point::new(center.x, center.y + 10),
104 small_style,
105 Alignment::Center,
106 )
107 .draw(&mut target)
108 .expect("never panics");
109
110 tracing::trace!("hahahaha yayyyy we drew a screen!");
111 }
112
113 arch::interrupt::enable_exceptions();
114 bootinfo.init_paging();
115 ALLOC.init(&bootinfo);
116
117 let mut regions = 0;
118 let mut free_regions = 0;
119 let mut free_bytes = 0;
120
121 {
122 let span = tracing::info_span!("memory map");
123 let _enter = span.enter();
124 for region in bootinfo.memory_map() {
125 let kind = region.kind();
126 let size = region.size();
127 tracing::info!(
128 " {:>10?} {:>15?} {:>15?} B",
129 region.base_addr(),
130 kind,
131 size,
132 );
133 regions += 1;
134 if region.kind() == mem::RegionKind::FREE {
135 free_regions += 1;
136 free_bytes += size;
137 unsafe {
138 ALLOC.add_region(region);
139 }
140 }
141 }
142
143 tracing::info!(
144 "found {} memory regions, {} free regions ({} bytes)",
145 regions,
146 free_regions,
147 free_bytes,
148 );
149 }
150
151 let clock = arch::init(&bootinfo, &archinfo);
154
155 rt::init(clock);
157
158 #[cfg(test)]
159 arch::run_tests();
160
161 kernel_main(bootinfo);
162}
163
164fn kernel_main(bootinfo: impl BootInfo) -> ! {
165 rt::spawn(keyboard_demo());
166
167 let mut core = rt::Core::new();
168 tracing::info!(
169 version = %MYCELIUM_VERSION,
170 arch = %arch::NAME,
171 bootloader = %bootinfo.bootloader_name(),
172 "welcome to the Glorious Mycelium Operating System",
173 );
174
175 loop {
176 core.run();
177 tracing::warn!("someone stopped CPU 0's core! restarting it...");
178 }
179}
180
181#[cfg_attr(target_os = "none", alloc_error_handler)]
182pub fn alloc_error(layout: core::alloc::Layout) -> ! {
183 arch::oops(arch::Oops::alloc_error(layout))
184}
185
186#[cfg_attr(target_os = "none", panic_handler)]
187#[cold]
188pub fn panic(panic: &core::panic::PanicInfo<'_>) -> ! {
189 arch::oops(arch::Oops::from(panic))
190}
191
192#[cfg(all(test, not(target_os = "none")))]
193pub fn main() {
194 }
196
197async fn keyboard_demo() {
200 #[cfg(target_os = "none")]
201 use alloc::string::String;
202 use drivers::ps2_keyboard::{self, DecodedKey, KeyCode};
203
204 let mut line = String::new();
205 tracing::info!("type `help` to list available commands");
206 loop {
207 let key = ps2_keyboard::next_key().await;
208 let mut newline = false;
209 match key {
210 DecodedKey::Unicode('\n') | DecodedKey::Unicode('\r') => {
211 newline = true;
212 }
213 DecodedKey::RawKey(KeyCode::Backspace)
215 | DecodedKey::RawKey(KeyCode::Delete)
216 | DecodedKey::Unicode('\u{0008}') => {
217 line.pop();
218 }
219 DecodedKey::Unicode(c) => line.push(c),
220 DecodedKey::RawKey(key) => tracing::warn!(?key, "you typed something weird"),
221 }
222 if newline {
223 shell::eval(&line);
224 line.clear();
225 }
226 }
227}