use core::{cell::UnsafeCell, fmt::Debug, ptr::NonNull}; #[repr(C)] pub struct BaseRevision(UnsafeCell<[u64; 3]>); unsafe impl Sync for BaseRevision {} impl BaseRevision { pub const fn from_revision(revision: u64) -> Self { Self(UnsafeCell::new([ 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, revision, ])) } pub fn is_supported(&self) -> bool { unsafe { self.0.get().cast::().add(2).read_volatile() == 0 } } pub fn base_revision(&self) -> u64 { unsafe { self.0.get().cast::().add(2).read_volatile() } } } #[repr(transparent)] pub struct RequestsStartMarker([u64; 4]); pub const REQUESTS_START_MARKER: RequestsStartMarker = RequestsStartMarker([ 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, 0x785c6ed015d3e316, 0x181e920a7852b9d9, ]); #[repr(transparent)] pub struct RequestsEndMarker([u64; 2]); pub const REQUESTS_END_MARKER: RequestsEndMarker = RequestsEndMarker([0xadc0e0531bb10d03, 0x9572709f31764c62]); #[repr(C)] pub struct Request { magic: [u64; 2], id: [u64; 2], revision: u64, response: UnsafeCell>>>, request: U, } unsafe impl Sync for Request {} #[repr(C)] pub struct Response { revision: u64, response: T, } impl Request { pub const MAGIC: [u64; 2] = [0xc7b1dd30df4c8b88, 0x0a82e883a194f07b]; pub const fn new_raw(id: [u64; 2], revision: u64, request: U) -> Self { Self { magic: Self::MAGIC, id, revision, response: UnsafeCell::new(None), request, } } pub fn response(&self) -> Option<&Response> { unsafe { self.response .get() .cast::>>>() .read_volatile() } .map(|ptr| unsafe { ptr.as_ref() }) } } #[derive(Debug)] #[repr(C)] pub struct Framebuffer { pub addr: *mut u8, pub width: u64, pub height: u64, pub pitch: u64, pub bpp: u16, pub memory_model: u8, pub red_mask_size: u8, pub red_mask_shift: u8, pub green_mask_size: u8, pub green_mask_shift: u8, pub blue_mask_size: u8, pub blue_mask_shift: u8, pub reserved: [u8; 7], pub edid_size: u64, pub edid: *mut u8, } pub struct Color(pub [u8; 3]); impl Framebuffer { /// # Safety /// the caller must ensure they have exclusive access to the region of the /// framebuffer they are writing to. pub unsafe fn draw_pixel(&self, x: u64, y: u64, color: Color) { assert!(self.bpp <= 64); let bytes_per_pixel = self.bpp.div_ceil(8) as usize; let [r, g, b] = color.0; let mask_color = |c: u8, bits: u8, shift: u8| { let mask = (1 << bits) - 1; (c as u64 & mask) << shift }; let mut pixel = 0u64; pixel |= mask_color(r, self.red_mask_size, self.red_mask_shift); pixel |= mask_color(g, self.green_mask_size, self.green_mask_shift); pixel |= mask_color(b, self.blue_mask_size, self.blue_mask_shift); let pixel = pixel.to_ne_bytes(); let dst = unsafe { self.addr .add((y * self.pitch + x * bytes_per_pixel as u64) as usize) }; unsafe { super::volatile_copy(pixel.as_ptr(), dst, bytes_per_pixel) } } } #[repr(C)] pub struct FramebufferResponse { count: u64, framebuffers: *const *const Framebuffer, } // SAFETY: We only ever read from the framebuffer array. unsafe impl Send for FramebufferResponse {} unsafe impl Sync for FramebufferResponse {} pub type FramebufferRequest = Request; const impl Default for FramebufferRequest { fn default() -> Self { Self::new() } } impl FramebufferRequest { pub const ID: [u64; 2] = [0x9d5827dcd881dd75, 0xa3148604f6fab11b]; pub const fn new() -> Self { Self::new_raw(Self::ID, 0, ()) } pub fn framebuffers<'a>(&self) -> &'a [&'a Framebuffer] { // SAFETY: limine responses are guaranteed to be valid for the lifetime of the memory mapping. self.response() .map(|response| unsafe { core::slice::from_raw_parts( response.response.framebuffers.cast::<&'a Framebuffer>(), response.response.count as usize, ) }) .unwrap_or(&[]) } } #[repr(C)] pub struct MemMapResponse { count: u64, entries: *const *const MemMapEntry, } unsafe impl Send for MemMapResponse {} unsafe impl Sync for MemMapResponse {} pub type MemMapRequest = Request; impl MemMapRequest { const ID: [u64; 2] = [0x67cf3d9d378a806f, 0xe304acdfc50c3c62]; pub const fn new() -> Self { Self::new_raw(Self::ID, 0, ()) } pub fn entries<'a>(&self) -> &'a [&'a MemMapEntry] { // SAFETY: limine responses are guaranteed to be valid for the lifetime of the memory mapping. self.response() .map(|response| unsafe { core::slice::from_raw_parts( response.response.entries.cast::<&'a MemMapEntry>(), response.response.count as usize, ) }) .unwrap_or(&[]) } } #[repr(u64)] #[derive(Debug)] pub enum MemMapEntryKind { Usable = 0, Reserved = 1, AcpiReclaimable = 2, AcpiNvs = 3, BadMemory = 4, BootloaderReclaimable = 5, KernelAndModules = 6, Framebuffer = 7, ReservedMapped = 8, Unknown = u64::MAX, } impl MemMapEntryKind { pub fn from_u64(value: u64) -> Self { match value { 0 => Self::Usable, 1 => Self::Reserved, 2 => Self::AcpiReclaimable, 3 => Self::AcpiNvs, 4 => Self::BadMemory, 5 => Self::BootloaderReclaimable, 6 => Self::KernelAndModules, 7 => Self::Framebuffer, 8 => Self::ReservedMapped, _ => Self::Unknown, } } } #[repr(C)] #[derive(Clone, Copy)] pub struct MemMapEntry { pub base: u64, pub length: u64, pub kind: u64, } impl MemMapEntry { pub fn kind(&self) -> MemMapEntryKind { MemMapEntryKind::from_u64(self.kind) } } impl Debug for MemMapEntry { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("MemMapEntry") .field("base", &format_args!("{:#x}", self.base)) .field("length", &format_args!("{:#x}", self.length)) .field("kind", &self.kind()) .finish() } } #[repr(C)] #[derive(Debug)] pub struct HhdmResponse { pub offset: u64, } pub type HhdmRequest = Request; impl HhdmRequest { const ID: [u64; 2] = [0x48dcf1cb8ad2b852, 0x63984e959a98244b]; pub const fn new() -> Self { Self::new_raw(Self::ID, 0, ()) } pub fn offset(&self) -> Option { self.response().map(|response| response.response.offset) } }