From 2a1bf17d8bc121645f4ae47bcd5da3360ef946dc Mon Sep 17 00:00:00 2001 From: Zoe Date: Tue, 18 Aug 2026 12:39:28 -0500 Subject: [PATCH] add IDT and GDT initialization --- src/arch/x86_64/gdt.rs | 147 ++++++++++++++++++++++ src/arch/x86_64/interrupts/exceptions.rs | 151 +++++++++++++++++++++++ src/arch/x86_64/interrupts/idt.rs | 115 +++++++++++++++++ src/arch/x86_64/interrupts/mod.rs | 12 ++ src/arch/x86_64/mod.rs | 22 ++++ src/boot/limine.rs | 84 ++++++++++++- src/boot/mod.rs | 4 +- src/{drivers => debug}/mod.rs | 0 src/{drivers => debug}/serial.rs | 6 +- src/main.rs | 56 +++------ src/memory/mod.rs | 51 ++++++++ 11 files changed, 599 insertions(+), 49 deletions(-) create mode 100644 src/arch/x86_64/gdt.rs create mode 100644 src/arch/x86_64/interrupts/exceptions.rs create mode 100644 src/arch/x86_64/interrupts/idt.rs create mode 100644 src/arch/x86_64/interrupts/mod.rs rename src/{drivers => debug}/mod.rs (100%) rename src/{drivers => debug}/serial.rs (95%) create mode 100644 src/memory/mod.rs diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs new file mode 100644 index 0000000..c1f324a --- /dev/null +++ b/src/arch/x86_64/gdt.rs @@ -0,0 +1,147 @@ +use core::arch::asm; + +#[repr(C, align(8))] +struct Gdt { + entries: [u64; 5], +} + +impl Gdt { + pub const fn new() -> Self { + Self { entries: [0; 5] } + } +} + +#[repr(C, packed)] +struct GdtPointer { + limit: u16, + base: u64, +} + +#[repr(C, packed)] +struct TaskStateSegment { + reserved_0: u32, + privilege_stacks: [u64; 3], + reserved_1: u64, + interrupt_stacks: [u64; 7], + reserved_2: u64, + reserved_3: u16, + iomap_base: u16, +} + +impl TaskStateSegment { + pub const fn new() -> Self { + Self { + reserved_0: 0, + privilege_stacks: [0; 3], + reserved_1: 0, + interrupt_stacks: [0; 7], + reserved_2: 0, + reserved_3: 0, + iomap_base: core::mem::size_of::() as u16, + } + } +} + +// 16 KiB +const DOUBLE_FAULT_STACK_SIZE: usize = 16 * 1024; + +pub(super) const KERNEL_CODE_SELECTOR: u16 = 1 * 8; +pub(super) const KERNEL_DATA_SELECTOR: u16 = 2 * 8; +pub(super) const TSS_SELECTOR: u16 = 3 * 8; + +#[repr(align(16))] +struct ExceptionStack([u8; DOUBLE_FAULT_STACK_SIZE]); + +static mut GDT: Gdt = Gdt::new(); +static mut TSS: TaskStateSegment = TaskStateSegment::new(); +static mut DOUBLE_FAULT_STACK: ExceptionStack = ExceptionStack([0; DOUBLE_FAULT_STACK_SIZE]); + +pub fn init() { + const _: () = assert!(core::mem::size_of::() == 104); + const _: () = assert!(core::mem::size_of::() == 10); + + unsafe { + let stack_bottom = core::ptr::addr_of_mut!(DOUBLE_FAULT_STACK) as u64; + let stack_top = stack_bottom + DOUBLE_FAULT_STACK_SIZE as u64; + + TSS.interrupt_stacks[0] = stack_top; + + let [tss_low, tss_high] = tss_descriptor(core::ptr::addr_of!(TSS)); + + let gdt = Gdt { + entries: [ + 0, + kernel_code_descriptor(), + kernel_data_descriptor(), + tss_low, + tss_high, + ], + }; + core::ptr::addr_of_mut!(GDT).write(gdt); + + gdt_reload(); + } +} + +fn gdt_reload() { + unsafe { + asm!( + "lgdt [{gdt_pointer}]", + + "push {code_selector}", + "lea rax, [rip + 2f]", + "push rax", + "retfq", + "2:", + + "mov ax, {data_selector}", + "mov ds, ax", + "mov es, ax", + "mov fs, ax", + "mov gs, ax", + "mov ss, ax", + + "mov ax, {tss_selector}", + "ltr ax", + + gdt_pointer = in(reg) &GdtPointer { + limit: (core::mem::size_of::() - 1) as u16, + base: core::ptr::addr_of!(GDT) as u64, + }, + code_selector = const KERNEL_CODE_SELECTOR, + data_selector = const KERNEL_DATA_SELECTOR, + tss_selector = const TSS_SELECTOR, + lateout("rax") _, + options(preserves_flags) + ) + } +} + +const PRESENT: u64 = 1 << 47; +const USER_DESCRIPTOR: u64 = 1 << 44; +const EXECUTABLE: u64 = 1 << 43; +const READ_WRITE: u64 = 1 << 41; +const LONG_MODE: u64 = 1 << 53; + +fn kernel_code_descriptor() -> u64 { + PRESENT | USER_DESCRIPTOR | EXECUTABLE | READ_WRITE | LONG_MODE +} + +fn kernel_data_descriptor() -> u64 { + PRESENT | USER_DESCRIPTOR | READ_WRITE +} + +fn tss_descriptor(tss: *const TaskStateSegment) -> [u64; 2] { + let base = tss as u64; + let limit = (core::mem::size_of::() - 1) as u64; + + let low = (limit & 0xFFFF) + | ((base & 0x00FF_FFFF) << 16) + | (0x09 << 40) + | (1 << 47) + | (((limit >> 16) & 0x0F) << 48) + | (((base >> 24) & 0xFF) << 56); + + let high = base >> 32; + [low, high] +} diff --git a/src/arch/x86_64/interrupts/exceptions.rs b/src/arch/x86_64/interrupts/exceptions.rs new file mode 100644 index 0000000..ed1614a --- /dev/null +++ b/src/arch/x86_64/interrupts/exceptions.rs @@ -0,0 +1,151 @@ +use core::arch::asm; + +use super::idt::{self, InterruptStackFrame}; +use crate::{hcf, println}; + +macro_rules! fatal_without_error_code { + ($handler:ident, $name:literal) => { + extern "x86-interrupt" fn $handler(frame: InterruptStackFrame) { + fatal_exception($name, &frame, None); + } + }; +} + +macro_rules! fatal_with_error_code { + ($handler:ident, $name:literal) => { + extern "x86-interrupt" fn $handler(frame: InterruptStackFrame, error_code: u64) { + fatal_exception($name, &frame, Some(error_code)); + } + }; +} + +extern "x86-interrupt" fn debug_handler(frame: InterruptStackFrame) { + fatal_exception("DEBUG EXCEPTION", &frame, None); +} + +extern "x86-interrupt" fn non_maskable_interrupt_handler(frame: InterruptStackFrame) { + fatal_exception("NON-MASKABLE INTERRUPT", &frame, None); +} + +extern "x86-interrupt" fn breakpoint_handler(frame: InterruptStackFrame) { + report_exception("BREAKPOINT", &frame, None); +} + +extern "x86-interrupt" fn double_fault_handler(frame: InterruptStackFrame, error_code: u64) { + fatal_exception("DOUBLE FAULT", &frame, Some(error_code)); +} + +extern "x86-interrupt" fn page_fault_handler(frame: InterruptStackFrame, error_code: u64) { + report_exception("PAGE FAULT", &frame, Some(error_code)); + println!("Faulting address: {:#X}", read_cr2()); + print_page_fault_error(error_code); + hcf(); +} + +fatal_without_error_code!(divide_error_handler, "DIVIDE ERROR"); +fatal_without_error_code!(invalid_opcode_handler, "INVALID OPCODE"); +fatal_without_error_code!(device_not_available_handler, "DEVICE NOT AVAILABLE"); +fatal_without_error_code!(x87_floating_point_handler, "X87 FLOATING-POINT EXCEPTION"); +fatal_without_error_code!(machine_check_handler, "MACHINE CHECK"); +fatal_without_error_code!(simd_floating_point_handler, "SIMD FLOATING-POINT EXCEPTION"); + +fatal_with_error_code!(invalid_tss_handler, "INVALID TSS"); +fatal_with_error_code!(segment_not_present_handler, "SEGMENT NOT PRESENT"); +fatal_with_error_code!(stack_segment_fault_handler, "STACK-SEGMENT FAULT"); +fatal_with_error_code!(general_protection_handler, "GENERAL PROTECTION FAULT"); +fatal_with_error_code!(alignment_check_handler, "ALIGNMENT CHECK"); + +pub(super) fn install(idt: &mut idt::Idt) { + idt.set_handler(0, divide_error_handler, 0); + idt.set_handler(1, debug_handler, 0); + idt.set_handler(2, non_maskable_interrupt_handler, 0); + idt.set_handler(3, breakpoint_handler, 0); + idt.set_handler(6, invalid_opcode_handler, 0); + idt.set_handler(7, device_not_available_handler, 0); + idt.set_error_code_handler(8, double_fault_handler, 1); + idt.set_error_code_handler(10, invalid_tss_handler, 0); + idt.set_error_code_handler(11, segment_not_present_handler, 0); + idt.set_error_code_handler(12, stack_segment_fault_handler, 0); + idt.set_error_code_handler(13, general_protection_handler, 0); + idt.set_error_code_handler(14, page_fault_handler, 0); + idt.set_handler(16, x87_floating_point_handler, 0); + idt.set_error_code_handler(17, alignment_check_handler, 0); + idt.set_handler(18, machine_check_handler, 0); + idt.set_handler(19, simd_floating_point_handler, 0); +} + +fn read_cr2() -> u64 { + let value: u64; + unsafe { + asm!( + "mov {}, cr2", + out(reg) value, + options(nomem, nostack, preserves_flags), + ); + } + value +} + +fn print_page_fault_error(error_code: u64) { + let present = error_code & (1 << 0) != 0; + let write = error_code & (1 << 1) != 0; + let user = error_code & (1 << 2) != 0; + + println!( + "Cause: {}", + if present { + "protection violation" + } else { + "page not present" + } + ); + println!("Access: {}", if write { "write" } else { "read" }); + println!("Mode: {}", if user { "user" } else { "supervisor" }); + + if error_code & (1 << 3) != 0 { + println!("Reserved page-table bit was set"); + } + + if error_code & (1 << 4) != 0 { + println!("Access was an instruction fetch"); + } + + if error_code & (1 << 5) != 0 { + println!("Protection-key violation"); + } + + if error_code & (1 << 6) != 0 { + println!("Shadow-stack access"); + } + + if error_code & (1 << 15) != 0 { + println!("Software Guard Extensions violation"); + } +} + +fn report_exception(name: &'static str, frame: &InterruptStackFrame, error_code: Option) { + println!(); + println!("========= {name} ========="); + println!( + "Origin: {}", + if frame.code_segment & 0b11 == 3 { + "user" + } else { + "kernel" + } + ); + println!("RIP: {:#X}", frame.instruction_pointer.as_u64()); + println!("CS: {:#X}", frame.code_segment); + println!("FLAGS: {:#X}", frame.cpu_flags); + println!("RSP: {:#X}", frame.stack_pointer.as_u64()); + println!("SS: {:#X}", frame.stack_segment); + + if let Some(error_code) = error_code { + println!("ERROR: {:#X}", error_code); + } +} + +fn fatal_exception(name: &'static str, frame: &InterruptStackFrame, error_code: Option) -> ! { + report_exception(name, frame, error_code); + hcf() +} diff --git a/src/arch/x86_64/interrupts/idt.rs b/src/arch/x86_64/interrupts/idt.rs new file mode 100644 index 0000000..13d0baa --- /dev/null +++ b/src/arch/x86_64/interrupts/idt.rs @@ -0,0 +1,115 @@ +use super::exceptions; +use crate::{arch::x86_64::gdt::KERNEL_CODE_SELECTOR, memory::VirtualAddr}; + +#[repr(C, packed)] +#[derive(Clone, Copy)] +struct IdtEntry { + offset_low: u16, + code_selector: u16, + ist: u8, + attributes: u8, + offset_middle: u16, + offset_high: u32, + reserved: u32, +} + +impl IdtEntry { + const fn missing() -> Self { + return Self { + offset_low: 0, + code_selector: 0x08, + ist: 0, + attributes: 0, + offset_middle: 0, + offset_high: 0, + reserved: 0, + }; + } +} + +#[repr(C, packed)] +struct IdtPointer { + limit: u16, + base: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub(super) struct InterruptStackFrame { + pub instruction_pointer: VirtualAddr, + pub code_segment: u64, + pub cpu_flags: u64, + pub stack_pointer: VirtualAddr, + pub stack_segment: u64, +} + +const INTERRUPT_GATE: u8 = 0b1110; +const PRESENT: u8 = 1 << 7; +const KERNEL_INTERRUPT_GATE: u8 = PRESENT | INTERRUPT_GATE; + +pub(super) type Handler = extern "x86-interrupt" fn(InterruptStackFrame); +pub(super) type ErrorCodeHandler = extern "x86-interrupt" fn(InterruptStackFrame, u64); + +pub(super) struct Idt { + entries: [IdtEntry; 256], +} + +impl Idt { + pub const fn new() -> Self { + Self { + entries: [IdtEntry::missing(); 256], + } + } + + pub(super) fn set_handler(&mut self, vector: u8, handler: Handler, ist: u8) { + self.set_handler_address(vector, handler as usize, ist); + } + + pub(super) fn set_error_code_handler( + &mut self, + vector: u8, + handler: ErrorCodeHandler, + ist: u8, + ) { + self.set_handler_address(vector, handler as usize, ist); + } + + fn set_handler_address(&mut self, vector: u8, address: usize, ist: u8) { + self.entries[vector as usize] = IdtEntry { + offset_low: address as u16, + offset_middle: (address >> 16) as u16, + offset_high: (address >> 32) as u32, + code_selector: KERNEL_CODE_SELECTOR, + ist: ist & 0b111, + attributes: KERNEL_INTERRUPT_GATE, + reserved: 0, + }; + } +} + +static mut IDT: Idt = Idt::new(); + +pub fn idt_init() { + const _: () = assert!(core::mem::size_of::() == 16); + const _: () = assert!(core::mem::size_of::() == 10); + const _: () = assert!(core::mem::size_of::() == 40); + + let mut idt = Idt::new(); + + exceptions::install(&mut idt); + + unsafe { + core::ptr::addr_of_mut!(IDT).write(idt); + + let pointer = IdtPointer { + limit: (core::mem::size_of::() - 1) as u16, + base: core::ptr::addr_of!(IDT) as u64, + }; + + core::arch::asm!( + "lidt [{}]", + in(reg) core::ptr::addr_of!(pointer), + options(readonly, nostack, preserves_flags), + ); + } +} diff --git a/src/arch/x86_64/interrupts/mod.rs b/src/arch/x86_64/interrupts/mod.rs new file mode 100644 index 0000000..f8befed --- /dev/null +++ b/src/arch/x86_64/interrupts/mod.rs @@ -0,0 +1,12 @@ +use core::arch::asm; + +mod exceptions; +mod idt; + +pub use idt::idt_init as init; + +pub fn disable_interrupts() { + unsafe { + asm!("cli"); + } +} diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 783e99b..ee4d085 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -1 +1,23 @@ +mod gdt; +mod interrupts; pub mod port; + +use core::arch::asm; + +pub use interrupts::disable_interrupts; + +use crate::println; + +pub fn init() { + disable_interrupts(); + println!("Loading GDT..."); + gdt::init(); + println!("Loading IDT..."); + interrupts::init(); +} + +pub fn halt() { + unsafe { + asm!("hlt"); + } +} diff --git a/src/boot/limine.rs b/src/boot/limine.rs index 132eb9d..bcf02ea 100644 --- a/src/boot/limine.rs +++ b/src/boot/limine.rs @@ -1,5 +1,7 @@ -use limine::request::FramebufferRequest; -use limine::{BaseRevision, RequestsEndMarker, RequestsStartMarker}; +use ::limine as limine_api; + +use limine_api::request::{ExecutableAddressRequest, HhdmRequest, MemmapRequest}; +use limine_api::{BaseRevision, RequestsEndMarker, RequestsStartMarker}; /// Sets the base revision to the latest revision supported by the crate. /// See specification for further info. @@ -7,11 +9,19 @@ use limine::{BaseRevision, RequestsEndMarker, RequestsStartMarker}; #[used] // The .requests section allows limine to find the requests faster and more safely. #[unsafe(link_section = ".requests")] -pub static BASE_REVISION: BaseRevision = BaseRevision::new(); +static BASE_REVISION: BaseRevision = BaseRevision::new(); #[used] #[unsafe(link_section = ".requests")] -pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); +static KERNEL_ADDRESS_REQUEST: ExecutableAddressRequest = ExecutableAddressRequest::new(); + +#[used] +#[unsafe(link_section = ".requests")] +static HHDM_REQUEST: HhdmRequest = HhdmRequest::new(); + +#[used] +#[unsafe(link_section = ".requests")] +static MEMMAP_REQUEST: MemmapRequest = MemmapRequest::new(); /// Define the stand and end markers for Limine requests. #[used] @@ -20,3 +30,69 @@ static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new(); #[used] #[unsafe(link_section = ".requests_end_marker")] static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new(); + +pub struct BootInfo { + pub kernel_address: crate::memory::PhysicalAddr, + pub hhdm_offset: u64, + entries: &'static [&'static limine_api::memmap::Entry], +} + +impl BootInfo { + pub fn memory_regions(&self) -> impl Iterator + '_ { + use crate::memory::{MemoryRegion, MemoryRegionKind}; + self.entries.iter().map(|&entry| MemoryRegion { + start: crate::memory::PhysicalAddr::new(entry.base), + length: entry.length, + kind: match entry.type_ { + limine_api::memmap::MEMMAP_USABLE => MemoryRegionKind::Usable, + limine_api::memmap::MEMMAP_RESERVED => MemoryRegionKind::Reserved, + limine_api::memmap::MEMMAP_ACPI_RECLAIMABLE => MemoryRegionKind::AcpiReclaimable, + limine_api::memmap::MEMMAP_ACPI_NVS => MemoryRegionKind::AcpiNvs, + limine_api::memmap::MEMMAP_BAD_MEMORY => MemoryRegionKind::BadMemory, + limine_api::memmap::MEMMAP_BOOTLOADER_RECLAIMABLE => { + MemoryRegionKind::BootloaderReclaimable + } + limine_api::memmap::MEMMAP_EXECUTABLE_AND_MODULES => { + MemoryRegionKind::KernelAndModules + } + limine_api::memmap::MEMMAP_FRAMEBUFFER => MemoryRegionKind::Framebuffer, + limine_api::memmap::MEMMAP_MAPPED_RESERVED => MemoryRegionKind::MappedReserved, + _ => MemoryRegionKind::Reserved, + }, + }) + } +} + +#[derive(Debug)] +pub enum BootError { + UnsupportedBaseRevision, + FailedToGetKernelAddress, + FailedToGetHHDMAddress, + FailedToGetMemmap, +} + +pub fn load_boot_info() -> Result { + if !BASE_REVISION.is_supported() { + return Err(BootError::UnsupportedBaseRevision); + } + + let kernel_address = KERNEL_ADDRESS_REQUEST + .response() + .ok_or(BootError::FailedToGetKernelAddress)? + .physical_base; + let hhdm_offset = HHDM_REQUEST + .response() + .ok_or(BootError::FailedToGetHHDMAddress)? + .offset; + + let memmap = MEMMAP_REQUEST + .response() + .ok_or(BootError::FailedToGetMemmap)? + .entries(); + + Ok(BootInfo { + kernel_address: crate::memory::PhysicalAddr::new(kernel_address), + hhdm_offset, + entries: memmap, + }) +} diff --git a/src/boot/mod.rs b/src/boot/mod.rs index e0a69ec..746c015 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1 +1,3 @@ -pub mod limine; +mod limine; + +pub use limine::{BootError, BootInfo, load_boot_info}; diff --git a/src/drivers/mod.rs b/src/debug/mod.rs similarity index 100% rename from src/drivers/mod.rs rename to src/debug/mod.rs diff --git a/src/drivers/serial.rs b/src/debug/serial.rs similarity index 95% rename from src/drivers/serial.rs rename to src/debug/serial.rs index 9c17d29..c86a5cd 100644 --- a/src/drivers/serial.rs +++ b/src/debug/serial.rs @@ -169,11 +169,11 @@ pub fn print(args: core::fmt::Arguments) { #[macro_export] macro_rules! print { - ($($arg:tt)*) => ($crate::drivers::serial::print(format_args!($($arg)*))); + ($($arg:tt)*) => ($crate::debug::serial::print(format_args!($($arg)*))); } #[macro_export] macro_rules! println { - () => ($crate::drivers::serial::print(format_args!("\n"))); - ($($arg:tt)*) => ($crate::drivers::serial::print(format_args!("{}\n", format_args!($($arg)*)))); + () => ($crate::debug::serial::print(format_args!("\n"))); + ($($arg:tt)*) => ($crate::debug::serial::print(format_args!("{}\n", format_args!($($arg)*)))); } diff --git a/src/main.rs b/src/main.rs index fc7765d..be2cb20 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,66 +1,40 @@ -#![feature(abi_x86_interrupt, negative_impls)] +#![feature(abi_x86_interrupt)] #![allow(clippy::needless_return)] #![no_std] #![no_main] mod arch; mod boot; -mod drivers; +mod debug; +mod memory; -use boot::limine::{BASE_REVISION, FRAMEBUFFER_REQUEST}; - -use crate::drivers::serial; +use crate::debug::serial; #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { serial::init().unwrap(); - assert!(BASE_REVISION.is_supported()); + arch::init(); + let _boot_info = boot::load_boot_info().unwrap(); - draw_gradient(); + let addr = 0xDEADBEEF as *mut u32; + unsafe { + *addr = 0xDEADBEEF; + } hcf(); } -fn draw_gradient() { - if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.response() { - if let Some(&framebuffer) = framebuffer_response.framebuffers().first() { - let buffer = unsafe { - core::slice::from_raw_parts_mut( - framebuffer.address().cast::(), - framebuffer.size() / 4, - ) - }; - - for y in 0..framebuffer.height { - for x in 0..framebuffer.width { - let r = (255 * x) / (framebuffer.width - 1); - let g = (255 * y) / (framebuffer.height - 1); - let b = 255 - r; - - let pixel = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); - buffer - [(((y * framebuffer.pitch) / (framebuffer.bpp as u64 / 8)) + x) as usize] = - pixel - } - } - } - } -} - #[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { +fn panic(info: &core::panic::PanicInfo) -> ! { + println!("Uh oh, something went wrong!"); + println!("{}", info); + hcf(); } pub fn hcf() -> ! { loop { - unsafe { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - core::arch::asm!("hlt"); - - #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] - core::arch::asm!("wfi"); - } + arch::halt(); } } diff --git a/src/memory/mod.rs b/src/memory/mod.rs new file mode 100644 index 0000000..0ce9a79 --- /dev/null +++ b/src/memory/mod.rs @@ -0,0 +1,51 @@ +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PhysicalAddr(u64); + +impl PhysicalAddr { + pub fn new(addr: u64) -> Self { + Self(addr) + } + + pub const fn as_u64(self) -> u64 { + self.0 + } +} + +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct VirtualAddr(u64); + +impl VirtualAddr { + pub fn new(addr: u64) -> Self { + Self(addr) + } + + pub const fn as_u64(self) -> u64 { + self.0 + } + + pub unsafe fn as_mut_ptr(self) -> *mut T { + self.as_u64() as *mut T + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum MemoryRegionKind { + Usable, + Reserved, + AcpiReclaimable, + AcpiNvs, + BadMemory, + BootloaderReclaimable, + KernelAndModules, + Framebuffer, + MappedReserved, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct MemoryRegion { + pub start: PhysicalAddr, + pub length: u64, + pub kind: MemoryRegionKind, +}