Skip to content

Commit

Permalink
style(x86_64): split up arch::x86_64 into mods (#347)
Browse files Browse the repository at this point in the history
The `x86_64.rs` file has just kind of been a dumping ground for random
arch stuff for a while. This commit pulls out the `bootloader` crate
glue code and the tests into separate files.
  • Loading branch information
hawkw committed Oct 14, 2022
1 parent f44641b commit 665124e
Show file tree
Hide file tree
Showing 3 changed files with 283 additions and 276 deletions.
282 changes: 6 additions & 276 deletions src/arch/x86_64.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use bootloader::boot_info;
use hal_core::{boot::BootInfo, mem, PAddr, VAddr};
use hal_x86_64::{cpu, serial, vga};
use hal_x86_64::{cpu, vga};
pub use hal_x86_64::{cpu::entropy::seed_rng, mm, NAME};
use mycelium_util::sync::InitOnce;

mod acpi;
mod bootloader;
mod framebuf;
pub mod interrupt;
mod oops;
pub mod pci;
pub use self::oops::{oops, Oops};

use self::framebuf::FramebufWriter;
#[cfg(test)]
mod tests;

pub type MinPageSize = mm::size::Size4Kb;

Expand All @@ -21,137 +22,10 @@ pub fn tick_timer() {
interrupt::TIMER.advance_ticks(0);
}

#[derive(Debug)]
pub struct RustbootBootInfo {
inner: &'static boot_info::BootInfo,
has_framebuffer: bool,
}

type MemRegionIter = core::slice::Iter<'static, boot_info::MemoryRegion>;

impl BootInfo for RustbootBootInfo {
// TODO(eliza): implement
type MemoryMap = core::iter::Map<MemRegionIter, fn(&boot_info::MemoryRegion) -> mem::Region>;

type Writer = vga::Writer;

type Framebuffer = FramebufWriter;

/// Returns the boot info's memory map.
fn memory_map(&self) -> Self::MemoryMap {
fn convert_region_kind(kind: boot_info::MemoryRegionKind) -> mem::RegionKind {
match kind {
boot_info::MemoryRegionKind::Usable => mem::RegionKind::FREE,
// TODO(eliza): make known
boot_info::MemoryRegionKind::UnknownUefi(_) => mem::RegionKind::UNKNOWN,
boot_info::MemoryRegionKind::UnknownBios(_) => mem::RegionKind::UNKNOWN,
boot_info::MemoryRegionKind::Bootloader => mem::RegionKind::BOOT,
_ => mem::RegionKind::UNKNOWN,
}
}

fn convert_region(region: &boot_info::MemoryRegion) -> mem::Region {
let start = PAddr::from_u64(region.start);
let size = {
let end = PAddr::from_u64(region.end).offset(1);
assert!(start < end, "bad memory range from boot_info!");
let size = start.difference(end);
assert!(size >= 0);
size as usize + 1
};
let kind = convert_region_kind(region.kind);
mem::Region::new(start, size, kind)
}
self.inner.memory_regions[..].iter().map(convert_region)
}

fn writer(&self) -> Self::Writer {
vga::writer()
}

fn framebuffer(&self) -> Option<Self::Framebuffer> {
if !self.has_framebuffer {
return None;
}

Some(unsafe { framebuf::mk_framebuf() })
}

fn subscriber(&self) -> Option<tracing::Dispatch> {
use mycelium_trace::{
embedded_graphics::MakeTextWriter,
writer::{self, MakeWriterExt},
Subscriber,
};

type FilteredFramebuf = writer::WithMaxLevel<MakeTextWriter<FramebufWriter>>;
type FilteredSerial =
writer::WithFilter<&'static serial::Port, fn(&tracing::Metadata<'_>) -> bool>;

static COLLECTOR: InitOnce<Subscriber<FilteredFramebuf, Option<FilteredSerial>>> =
InitOnce::uninitialized();

if !self.has_framebuffer {
// TODO(eliza): we should probably write to just the serial port if
// there's no framebuffer...
return None;
}

fn serial_filter(meta: &tracing::Metadata<'_>) -> bool {
// disable really noisy traces from maitake
// TODO(eliza): it would be nice if this was configured by
// non-arch-specific OS code...
const DISABLED_TARGETS: &[&str] = &["maitake::time"];
DISABLED_TARGETS
.iter()
.all(|target| !meta.target().starts_with(target))
}

let collector = COLLECTOR.get_or_else(|| {
let display_writer = MakeTextWriter::new(|| unsafe { framebuf::mk_framebuf() })
.with_max_level(tracing::Level::INFO);
let serial = serial::com1().map(|com1| {
com1.with_filter(serial_filter as for<'a, 'b> fn(&'a tracing::Metadata<'b>) -> bool)
});
Subscriber::display_only(display_writer).with_serial(serial)
});

Some(tracing::Dispatch::from_static(collector))
}

fn bootloader_name(&self) -> &str {
"rust-bootloader"
}

fn init_paging(&self) {
mm::init_paging(self.vm_offset())
}
}

impl RustbootBootInfo {
fn vm_offset(&self) -> VAddr {
VAddr::from_u64(
self.inner
.physical_memory_offset
.into_option()
.expect("haha wtf"),
)
}

fn from_bootloader(inner: &'static mut boot_info::BootInfo) -> Self {
let has_framebuffer = framebuf::init(inner);

Self {
inner,
has_framebuffer,
}
}
}

#[cfg(target_os = "none")]
bootloader::entry_point!(arch_entry);

pub fn arch_entry(info: &'static mut boot_info::BootInfo) -> ! {
pub fn arch_entry(info: &'static mut bootloader::boot_info::BootInfo) -> ! {
unsafe {
cpu::intrinsics::cli();
}
Expand All @@ -165,7 +39,7 @@ pub fn arch_entry(info: &'static mut boot_info::BootInfo) -> ! {
// lol we're hosed
} */

let boot_info = RustbootBootInfo::from_bootloader(info);
let boot_info = bootloader::RustbootBootInfo::from_bootloader(info);
crate::kernel_start(&boot_info);
}

Expand Down Expand Up @@ -206,147 +80,3 @@ pub(crate) fn qemu_exit(exit_code: QemuExitCode) -> ! {
cpu::halt()
}
}

mycotest::decl_test! {
fn alloc_some_4k_pages() -> Result<(), hal_core::mem::page::AllocErr> {
use hal_core::mem::page::Alloc;
let page1 = tracing::info_span!("alloc page 1").in_scope(|| {
let res = crate::ALLOC.alloc(mm::size::Size4Kb);
tracing::info!(?res);
res
})?;
let page2 = tracing::info_span!("alloc page 2").in_scope(|| {
let res = crate::ALLOC.alloc(mm::size::Size4Kb);
tracing::info!(?res);
res
})?;
assert_ne!(page1, page2);
tracing::info_span!("dealloc page 1").in_scope(|| {
let res = crate::ALLOC.dealloc(page1);
tracing::info!(?res, "deallocated page 1");
res
})?;
let page3 = tracing::info_span!("alloc page 3").in_scope(|| {
let res = crate::ALLOC.alloc(mm::size::Size4Kb);
tracing::info!(?res);
res
})?;
assert_ne!(page2, page3);
tracing::info_span!("dealloc page 2").in_scope(|| {
let res = crate::ALLOC.dealloc(page2);
tracing::info!(?res, "deallocated page 2");
res
})?;
let page4 = tracing::info_span!("alloc page 4").in_scope(|| {
let res = crate::ALLOC.alloc(mm::size::Size4Kb);
tracing::info!(?res);
res
})?;
assert_ne!(page3, page4);
tracing::info_span!("dealloc page 3").in_scope(|| {
let res = crate::ALLOC.dealloc(page3);
tracing::info!(?res, "deallocated page 3");
res
})?;
tracing::info_span!("dealloc page 4").in_scope(|| {
let res = crate::ALLOC.dealloc(page4);
tracing::info!(?res, "deallocated page 4");
res
})
}
}

mycotest::decl_test! {
fn alloc_4k_pages_and_ranges() -> Result<(), hal_core::mem::page::AllocErr> {
use hal_core::mem::page::Alloc;
let range1 = tracing::info_span!("alloc range 1").in_scope(|| {
let res = crate::ALLOC.alloc_range(mm::size::Size4Kb, 16);
tracing::info!(?res);
res
})?;
let page2 = tracing::info_span!("alloc page 2").in_scope(|| {
let res = crate::ALLOC.alloc(mm::size::Size4Kb);
tracing::info!(?res);
res
})?;
tracing::info_span!("dealloc range 1").in_scope(|| {
let res = crate::ALLOC.dealloc_range(range1);
tracing::info!(?res, "deallocated range 1");
res
})?;
let range3 = tracing::info_span!("alloc range 3").in_scope(|| {
let res = crate::ALLOC.alloc_range(mm::size::Size4Kb, 10);
tracing::info!(?res);
res
})?;
tracing::info_span!("dealloc page 2").in_scope(|| {
let res = crate::ALLOC.dealloc(page2);
tracing::info!(?res, "deallocated page 2");
res
})?;
let range4 = tracing::info_span!("alloc range 4").in_scope(|| {
let res = crate::ALLOC.alloc_range(mm::size::Size4Kb, 8);
tracing::info!(?res);
res
})?;
tracing::info_span!("dealloc range 3").in_scope(|| {
let res = crate::ALLOC.dealloc_range(range3);
tracing::info!(?res, "deallocated range 3");
res
})?;
tracing::info_span!("dealloc range 4").in_scope(|| {
let res = crate::ALLOC.dealloc_range(range4);
tracing::info!(?res, "deallocated range 4");
res
})
}
}

mycotest::decl_test! {
fn alloc_some_pages() -> Result<(), hal_core::mem::page::AllocErr> {
use hal_core::mem::page::Alloc;
let page1 = tracing::info_span!("alloc page 1").in_scope(|| {
let res = crate::ALLOC.alloc(mm::size::Size4Kb);
tracing::info!(?res);
res
})?;
let page2 = tracing::info_span!("alloc page 2").in_scope(|| {
let res = crate::ALLOC.alloc(mm::size::Size4Kb);
tracing::info!(?res);
res
})?;
assert_ne!(page1, page2);
tracing::info_span!("dealloc page 1").in_scope(|| {
let res = crate::ALLOC.dealloc(page1);
tracing::info!(?res, "deallocated page 1");
res
})?;
// TODO(eliza): when 2mb pages work, test that too...
// let page3 = tracing::info_span!("alloc page 3").in_scope(|| {
// let res = crate::ALLOC.alloc(mm::size::Size2Mb);
// tracing::info!(?res);
// res
// })?;
tracing::info_span!("dealloc page 2").in_scope(|| {
let res = crate::ALLOC.dealloc(page2);
tracing::info!(?res, "deallocated page 2");
res
})?;
// let page4 = tracing::info_span!("alloc page 4").in_scope(|| {
// let res = crate::ALLOC.alloc(mm::size::Size2Mb);
// tracing::info!(?res);
// res
// })?;
// tracing::info_span!("dealloc page 3").in_scope(|| {
// let res = crate::ALLOC.dealloc(page3);
// tracing::info!(?res, "deallocated page 3");
// res
// })?;
// tracing::info_span!("dealloc page 4").in_scope(|| {
// let res = crate::ALLOC.dealloc(page4);
// tracing::info!(?res, "deallocated page 4");
// res
// })?;
Ok(())
}
}
Loading

0 comments on commit 665124e

Please sign in to comment.