177 lines
4.6 KiB
Rust
Raw Normal View History

2023-07-29 19:31:56 +03:00
use abi::error::Error;
2023-07-30 16:40:30 +03:00
use yboot_proto::{v1::FramebufferOption, AvailableRegion, IterableMemoryMap};
2023-07-28 14:26:39 +03:00
2023-07-29 21:11:15 +03:00
use crate::{
arch::x86_64::table::{init_fixed_tables, KERNEL_TABLES},
debug::DebugSink,
device::{
display::{fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
platform::Platform,
},
2023-07-30 16:40:30 +03:00
mem::phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
2023-07-29 21:11:15 +03:00
util::OneTimeInit,
};
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
use super::Architecture;
2023-07-28 14:26:39 +03:00
2023-07-30 16:40:30 +03:00
#[macro_use]
pub mod intrinsics;
2023-07-29 19:31:56 +03:00
pub mod boot;
2023-07-30 16:40:30 +03:00
pub mod exception;
pub mod gdt;
2023-07-29 19:31:56 +03:00
pub mod table;
2023-07-28 14:26:39 +03:00
2023-07-30 16:40:30 +03:00
pub trait AbstractAvailableRegion {
fn start_address(&self) -> usize;
fn page_count(&self) -> usize;
}
pub trait AbstractMemoryMap<'a>: 'a {
type AvailableRegion: AbstractAvailableRegion;
type Iter: Iterator<Item = &'a Self::AvailableRegion> + Clone;
fn reserved_range(&self) -> PhysicalMemoryRegion;
fn iter(&self) -> Self::Iter;
}
impl<T: AvailableRegion> AbstractAvailableRegion for T {
fn start_address(&self) -> usize {
<T as AvailableRegion>::start_address(self)
}
fn page_count(&self) -> usize {
<T as AvailableRegion>::page_count(self)
}
}
impl<'a, T: IterableMemoryMap<'a> + 'a> AbstractMemoryMap<'a> for T {
type AvailableRegion = T::Entry;
type Iter = T::Iter;
fn reserved_range(&self) -> PhysicalMemoryRegion {
PhysicalMemoryRegion {
base: self.data_physical_base(),
size: (self.data_size() + 0xFFF) & !0xFFF,
}
}
fn iter(&self) -> Self::Iter {
<T as IterableMemoryMap>::iter_with_offset(self, X86_64::KERNEL_VIRT_OFFSET)
}
}
2023-07-29 21:11:15 +03:00
pub struct X86_64 {
yboot_framebuffer: OneTimeInit<FramebufferOption>,
}
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
impl Architecture for X86_64 {
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
unsafe fn init_mmu(&self, bsp: bool) {
if bsp {
init_fixed_tables();
}
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
let cr3 = KERNEL_TABLES.physical_address();
core::arch::asm!("wbinvd; mov {0}, %cr3", in(reg) cr3, options(att_syntax));
}
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
fn map_device_pages(&self, phys: usize, count: usize) -> Result<usize, Error> {
unsafe { KERNEL_TABLES.map_device_pages(phys, count) }
}
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
fn wait_for_interrupt() {
2023-07-29 21:11:15 +03:00
unsafe {
core::arch::asm!("hlt");
}
2023-07-29 19:31:56 +03:00
}
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
unsafe fn set_interrupt_mask(mask: bool) {
2023-07-29 21:11:15 +03:00
if mask {
core::arch::asm!("cli");
} else {
core::arch::asm!("sti");
}
2023-07-29 19:31:56 +03:00
}
2023-07-28 14:26:39 +03:00
2023-07-29 19:31:56 +03:00
fn interrupt_mask() -> bool {
2023-07-29 21:11:15 +03:00
let mut flags: u64;
unsafe {
core::arch::asm!("pushfd; pop {0}", out(reg) flags, options(att_syntax));
}
// If IF is zero, interrupts are disabled (masked)
flags & (1 << 9) == 0
}
}
impl Platform for X86_64 {
2023-07-30 16:40:30 +03:00
const KERNEL_PHYS_BASE: usize = 0x400000;
2023-07-29 21:11:15 +03:00
unsafe fn init(&'static self, _is_bsp: bool) -> Result<(), Error> {
Ok(())
}
unsafe fn init_primary_debug_sink(&self) {
let Some(fb) = self.yboot_framebuffer.try_get() else {
// TODO fallback to serial as primary
return;
};
LINEAR_FB.init(
LinearFramebuffer::from_physical_bits(
fb.res_address as _,
fb.res_size as _,
fb.res_stride as _,
fb.res_width,
fb.res_height,
)
.unwrap(),
);
FB_CONSOLE.init(FramebufferConsole::from_framebuffer(
LINEAR_FB.get(),
&bitmap_font::tamzen::FONT_6x12,
));
}
fn name(&self) -> &'static str {
"x86-64"
}
fn primary_debug_sink(&self) -> Option<&dyn DebugSink> {
if let Some(console) = FB_CONSOLE.try_get() {
Some(console)
} else {
None
}
2023-07-29 19:31:56 +03:00
}
}
2023-07-28 14:26:39 +03:00
2023-07-30 16:40:30 +03:00
impl X86_64 {
unsafe fn init_physical_memory<'a, M: AbstractMemoryMap<'a>>(memory_map: &M) {
// Reserve the lower 8MiB of memory
reserve_region(
"lower-memory",
PhysicalMemoryRegion {
base: 0,
size: 8 << 21,
},
);
// Reserve memory map
reserve_region("memory-map", memory_map.reserved_range());
phys::init_from_iter(memory_map.iter().map(|r| PhysicalMemoryRegion {
base: r.start_address(),
size: r.page_count() * 0x1000,
}))
.expect("Failed to initialize the physical memory manager");
}
}
2023-07-29 21:11:15 +03:00
pub static ARCHITECTURE: X86_64 = X86_64 {
yboot_framebuffer: OneTimeInit::new(),
};
static LINEAR_FB: OneTimeInit<LinearFramebuffer> = OneTimeInit::new();
static FB_CONSOLE: OneTimeInit<FramebufferConsole> = OneTimeInit::new();