mycelium_kernel/arch/x86_64/
boot.rs1use super::framebuf::{self, FramebufWriter};
4use bootloader_api::info;
5use hal_core::{boot::BootInfo, mem, PAddr, VAddr};
6use hal_x86_64::{mm, serial, vga};
7use mycelium_util::sync::InitOnce;
8
9#[derive(Debug)]
10pub struct BootloaderApiBootInfo {
11 inner: &'static info::BootInfo,
12 has_framebuffer: bool,
13}
14
15#[derive(Debug)]
16pub struct ArchInfo {
17 pub(in crate::arch) rsdp_addr: Option<PAddr>,
18}
19
20type MemRegionIter = core::slice::Iter<'static, info::MemoryRegion>;
21
22impl BootInfo for BootloaderApiBootInfo {
23 type MemoryMap = core::iter::Map<MemRegionIter, fn(&info::MemoryRegion) -> mem::Region>;
25
26 type Writer = vga::Writer;
27
28 type Framebuffer = FramebufWriter;
29
30 fn memory_map(&self) -> Self::MemoryMap {
32 fn convert_region_kind(kind: info::MemoryRegionKind) -> mem::RegionKind {
33 match kind {
34 info::MemoryRegionKind::Usable => mem::RegionKind::FREE,
35 info::MemoryRegionKind::UnknownUefi(_) => mem::RegionKind::UNKNOWN,
37 info::MemoryRegionKind::UnknownBios(_) => mem::RegionKind::UNKNOWN,
38 info::MemoryRegionKind::Bootloader => mem::RegionKind::BOOT,
39 _ => mem::RegionKind::UNKNOWN,
40 }
41 }
42
43 fn convert_region(region: &info::MemoryRegion) -> mem::Region {
44 let start = PAddr::from_u64(region.start);
45 let size = {
46 let end = PAddr::from_u64(region.end).offset(1);
47 assert!(start < end, "bad memory range from boot_info!");
48 let size = start.difference(end);
49 assert!(size >= 0);
50 size as usize + 1
51 };
52 let kind = convert_region_kind(region.kind);
53 mem::Region::new(start, size, kind)
54 }
55 self.inner.memory_regions[..].iter().map(convert_region)
56 }
57
58 fn writer(&self) -> Self::Writer {
59 vga::writer()
60 }
61
62 fn framebuffer(&self) -> Option<Self::Framebuffer> {
63 if !self.has_framebuffer {
64 return None;
65 }
66
67 Some(unsafe { framebuf::mk_framebuf() })
68 }
69
70 fn subscriber(&self) -> Option<tracing::Dispatch> {
71 use mycelium_trace::{
72 color::AnsiEscapes,
73 embedded_graphics::MakeTextWriter,
74 writer::{self, MakeWriterExt},
75 Subscriber,
76 };
77
78 type FilteredFramebuf = writer::WithMaxLevel<MakeTextWriter<FramebufWriter>>;
79 type FilteredSerial = writer::WithFilter<
80 AnsiEscapes<&'static serial::Port>,
81 fn(&tracing::Metadata<'_>) -> bool,
82 >;
83
84 static COLLECTOR: InitOnce<Subscriber<FilteredFramebuf, Option<FilteredSerial>>> =
85 InitOnce::uninitialized();
86
87 if !self.has_framebuffer {
88 return None;
91 }
92
93 fn serial_filter(meta: &tracing::Metadata<'_>) -> bool {
94 const DISABLED_TARGETS: &[&str] = &[
98 "maitake::task",
100 "runtime::waker",
101 "mycelium_alloc",
102 ];
103 DISABLED_TARGETS
104 .iter()
105 .all(|target| !meta.target().starts_with(target))
106 }
107
108 let collector = COLLECTOR.get_or_else(|| {
109 let display_writer = MakeTextWriter::new(|| unsafe { framebuf::mk_framebuf() })
110 .with_max_level(tracing::Level::INFO);
111 let serial = serial::com1().map(|com1| {
112 let com1 = AnsiEscapes::new(com1);
113 com1.with_filter(serial_filter as for<'a, 'b> fn(&'a tracing::Metadata<'b>) -> bool)
114 });
115 Subscriber::<_, Option<FilteredSerial>>::display_only(display_writer)
116 .with_serial(serial)
117 });
118 Some(tracing::Dispatch::from_static(collector))
119 }
120
121 fn bootloader_name(&self) -> &str {
122 "rust-osdev/bootloader"
123 }
124
125 fn init_paging(&self) {
126 mm::init_paging(self.vm_offset())
127 }
128}
129
130impl BootloaderApiBootInfo {
131 fn vm_offset(&self) -> VAddr {
132 VAddr::from_u64(
133 self.inner
134 .physical_memory_offset
135 .into_option()
136 .expect("haha wtf"),
137 )
138 }
139
140 pub(super) fn from_bootloader(inner: &'static mut info::BootInfo) -> (Self, ArchInfo) {
141 let has_framebuffer = framebuf::init(inner);
142 let archinfo = ArchInfo {
143 rsdp_addr: inner.rsdp_addr.into_option().map(PAddr::from_u64),
144 };
145 let bootinfo = Self {
146 inner,
147 has_framebuffer,
148 };
149 (bootinfo, archinfo)
150 }
151}