curiOS/kernel/src/limine.rs
2026-07-26 04:32:21 +02:00

275 lines
6.9 KiB
Rust

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::<u64>().add(2).read_volatile() == 0 }
}
pub fn base_revision(&self) -> u64 {
unsafe { self.0.get().cast::<u64>().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<T, U = ()> {
magic: [u64; 2],
id: [u64; 2],
revision: u64,
response: UnsafeCell<Option<NonNull<Response<T>>>>,
request: U,
}
unsafe impl<T: Sync, U: Sync> Sync for Request<T, U> {}
#[repr(C)]
pub struct Response<T> {
revision: u64,
response: T,
}
impl<T, U> Request<T, U> {
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<T>> {
unsafe {
self.response
.get()
.cast::<Option<NonNull<Response<T>>>>()
.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<FramebufferResponse>;
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<MemMapResponse>;
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<HhdmResponse>;
impl HhdmRequest {
const ID: [u64; 2] = [0x48dcf1cb8ad2b852, 0x63984e959a98244b];
pub const fn new() -> Self {
Self::new_raw(Self::ID, 0, ())
}
pub fn offset(&self) -> Option<u64> {
self.response().map(|response| response.response.offset)
}
}