draw to framebuffer
This commit is contained in:
parent
f1570c06b1
commit
cffad21a64
|
|
@ -3,6 +3,7 @@ codegen-backend = "llvm"
|
||||||
|
|
||||||
[unstable]
|
[unstable]
|
||||||
json-target-spec = true # lets us specify a custom target specification file
|
json-target-spec = true # lets us specify a custom target specification file
|
||||||
|
build-std-features = ["compiler-builtins-mem"]
|
||||||
build-std = ["core", "compiler_builtins"]
|
build-std = ["core", "compiler_builtins"]
|
||||||
|
|
||||||
[build]
|
[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]
|
#![no_std]
|
||||||
|
#![feature(const_trait_impl, const_default)]
|
||||||
|
|
||||||
|
pub mod limine;
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
|
|
||||||
/// # Safety
|
/// # 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)]
|
#[unsafe(no_mangle)]
|
||||||
fn _start() -> ! {
|
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()
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,29 @@
|
||||||
{
|
{
|
||||||
"arch": "x86_64",
|
"arch": "x86_64",
|
||||||
"code-model": "kernel",
|
"code-model": "kernel",
|
||||||
"cpu": "x86-64",
|
"cpu": "x86-64",
|
||||||
"crt-objects-fallback": "false",
|
"crt-objects-fallback": "false",
|
||||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||||
"disable-redzone": true,
|
"disable-redzone": true,
|
||||||
"target-endian": "little",
|
"target-endian": "little",
|
||||||
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
|
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
|
||||||
"linker": "mold",
|
"linker": "rust-lld",
|
||||||
"linker-flavor": "gnu",
|
"linker-flavor": "ld.lld",
|
||||||
"llvm-target": "x86_64-unknown-none-elf",
|
"llvm-target": "x86_64-unknown-none-elf",
|
||||||
"max-atomic-width": 64,
|
"max-atomic-width": 64,
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"plt-by-default": false,
|
"plt-by-default": false,
|
||||||
"position-independent-executables": true,
|
"os": "none",
|
||||||
"relro-level": "full",
|
"executables": true,
|
||||||
"rustc-abi": "softfloat",
|
"relro-level": "full",
|
||||||
"stack-probes": {
|
"rustc-abi": "softfloat",
|
||||||
"kind": "inline"
|
"stack-probes": {
|
||||||
},
|
"kind": "inline"
|
||||||
"static-position-independent-executables": true,
|
},
|
||||||
"supported-sanitizers": [
|
"supported-sanitizers": [
|
||||||
"kcfi",
|
"kcfi",
|
||||||
"kernel-address"
|
"kernel-address"
|
||||||
],
|
],
|
||||||
"target-pointer-width": 64
|
"target-pointer-width": 64,
|
||||||
|
"target-c-int-width": 32
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue