275 lines
6.9 KiB
Rust
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)
|
|
}
|
|
}
|