draw to framebuffer
This commit is contained in:
parent
f1570c06b1
commit
cffad21a64
|
|
@ -3,6 +3,7 @@ codegen-backend = "llvm"
|
|||
|
||||
[unstable]
|
||||
json-target-spec = true # lets us specify a custom target specification file
|
||||
build-std-features = ["compiler-builtins-mem"]
|
||||
build-std = ["core", "compiler_builtins"]
|
||||
|
||||
[build]
|
||||
|
|
|
|||
6
kernel/build.rs
Normal file
6
kernel/build.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
println!("cargo::rerun-if-changed=build.rs");
|
||||
|
||||
println!("cargo::rustc-link-arg-bin=kernel=-Tkernel.lds");
|
||||
println!("cargo::rerun-if-changed=kernel.lds");
|
||||
}
|
||||
43
kernel/kernel.lds
Normal file
43
kernel/kernel.lds
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
ENTRY(_start)
|
||||
|
||||
PHDRS {
|
||||
limine_requests PT_LOAD;
|
||||
text PT_LOAD;
|
||||
rodata PT_LOAD;
|
||||
data PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
. = 0xffffffff80000000;
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
KEEP(*(.limine_requests_end))
|
||||
} :limine_requests
|
||||
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame*)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![feature(const_trait_impl, const_default)]
|
||||
|
||||
pub mod limine;
|
||||
pub mod x86_64;
|
||||
|
||||
/// # Safety
|
||||
|
|
|
|||
164
kernel/src/limine.rs
Normal file
164
kernel/src/limine.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
use core::{cell::UnsafeCell, ptr::NonNull};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct BaseRevision(UnsafeCell<[u64; 3]>);
|
||||
|
||||
unsafe impl Send for BaseRevision {}
|
||||
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, U> Send for Request<T, U> {}
|
||||
unsafe impl<T, U> 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() })
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
pub 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_le_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,
|
||||
}
|
||||
|
||||
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<'limine>(&self) -> &'limine [&'limine 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::<&'limine Framebuffer>(),
|
||||
response.response.count as usize,
|
||||
)
|
||||
})
|
||||
.unwrap_or(&[])
|
||||
}
|
||||
}
|
||||
|
|
@ -8,5 +8,48 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|||
|
||||
#[unsafe(no_mangle)]
|
||||
fn _start() -> ! {
|
||||
assert!(limine_requests::LIMINE_BASE_REVISION.is_supported());
|
||||
|
||||
let fb = limine_requests::FRAMEBUFFER_REQUEST
|
||||
.framebuffers()
|
||||
.first()
|
||||
.expect("No framebuffer found");
|
||||
|
||||
for y in 0..fb.height {
|
||||
for x in 0..fb.width {
|
||||
let mut bits = ((x * 255 / fb.width) as u32) << 8;
|
||||
bits ^= (y * 255 / fb.height) as u32;
|
||||
|
||||
fb.draw_pixel(
|
||||
x,
|
||||
y,
|
||||
kernel::limine::Color(*bits.to_le_bytes().first_chunk().unwrap()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
kernel::x86_64::halt_loop()
|
||||
}
|
||||
|
||||
mod limine_requests {
|
||||
use kernel::limine::{
|
||||
BaseRevision, FramebufferRequest, REQUESTS_END_MARKER, REQUESTS_START_MARKER,
|
||||
RequestsEndMarker, RequestsStartMarker,
|
||||
};
|
||||
|
||||
#[unsafe(link_section = ".limine_requests_start")]
|
||||
#[unsafe(no_mangle)]
|
||||
static LIMINE_REQUESTS_START: RequestsStartMarker = REQUESTS_START_MARKER;
|
||||
|
||||
#[unsafe(link_section = ".limine_requests")]
|
||||
#[unsafe(no_mangle)]
|
||||
pub static LIMINE_BASE_REVISION: BaseRevision = BaseRevision::from_revision(6);
|
||||
|
||||
#[unsafe(link_section = ".limine_requests")]
|
||||
#[unsafe(no_mangle)]
|
||||
pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
||||
|
||||
#[unsafe(link_section = ".limine_requests_end")]
|
||||
#[unsafe(no_mangle)]
|
||||
static LIMINE_REQUESTS_END: RequestsEndMarker = REQUESTS_END_MARKER;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,22 +7,23 @@
|
|||
"disable-redzone": true,
|
||||
"target-endian": "little",
|
||||
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
|
||||
"linker": "mold",
|
||||
"linker-flavor": "gnu",
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld",
|
||||
"llvm-target": "x86_64-unknown-none-elf",
|
||||
"max-atomic-width": 64,
|
||||
"panic-strategy": "abort",
|
||||
"plt-by-default": false,
|
||||
"position-independent-executables": true,
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"relro-level": "full",
|
||||
"rustc-abi": "softfloat",
|
||||
"stack-probes": {
|
||||
"kind": "inline"
|
||||
},
|
||||
"static-position-independent-executables": true,
|
||||
"supported-sanitizers": [
|
||||
"kcfi",
|
||||
"kernel-address"
|
||||
],
|
||||
"target-pointer-width": 64
|
||||
"target-pointer-width": 64,
|
||||
"target-c-int-width": 32
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue