rust-osdev / bootloader

An experimental pure-Rust x86 bootloader
Apache License 2.0
1.31k stars 204 forks source link

HELP how to edit the frame buffer. #216

Closed Merlin1846 closed 2 years ago

Merlin1846 commented 2 years ago

I've been attempting to edit the frame buffer but no matter what I do I can not get a single output from anything it just sits there with yellow words, I'm running this on a physical machine and using UEFI. This is my code hope someone knows what's wrong, or rather what's missing.

#![no_std] // Don't link the Rust standard library.
#![no_main] // Disable all Rust-level entry points.

use core::panic::PanicInfo;
use bootloader::*;
use bootloader::boot_info::*;

// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[no_mangle]
pub extern "C" fn _start(boot_info: &'static mut BootInfo) -> ! {
    let mut frame_buffer:&mut Option<&mut FrameBuffer> = &mut boot_info.framebuffer.as_mut(); // Get a mut reference to the frame buffer.

    //Whatever makes the screen change that I can't seem to figure out.

    loop {}
}
Merlin1846 commented 2 years ago

Also sorry if I'm not supposed to put this here but I couldn't think of a place to write a help message since if I, for example, put it on stack exchange then chances are it would get drowned out and even if someone saw it they probably wouldn't be using this crate/library/tool (never know what to call these things.)

Merlin1846 commented 2 years ago

Well I changed the frame_buffer getter to this. let mut frame_buffer:&mut FrameBuffer = &mut boot_info.framebuffer.as_mut().unwrap();

Merlin1846 commented 2 years ago

Ok, so I did this.

let frame_buffer:&mut FrameBuffer = &mut boot_info.framebuffer.as_mut().unwrap();

let frame_buffer_data:&mut [u8] = frame_buffer.buffer_mut();
for i in frame_buffer_data.iter_mut() {
    *i = 0xC0 as u8;
}

loop {}

But it appears to be grayscale even though the hexadecimal value should be maxed out Red or Max Blue since I believe it's running in BGR.

bjorn3 commented 2 years ago

The framebuffer probably uses 24bit and not 8bit colors. This means that every group of 3 (or 4 depending on the color format used) bytes represents a single pixel with each byte being a different channel.

Merlin1846 commented 2 years ago

But the frame_buffer.buffer_mut() only returns u8, unless I'm misunderstanding and I have to set one u8 then the next to the green channel, and then the next to the blue channel? But that doesn't make sense since if I add a counter that counts how many times it's activated and tell it to stop at 1366 it does a single full-length line, which would mean that each pixel is a single u8 right? I think I am misunderstanding something major.

Merlin1846 commented 2 years ago

Ok so I did what you suggested and it almost worked? Only the words changed color. But then I set v2 to 0xFF and then the entire thing changed but it looked odd, I don't know how to describe it.

    let v1:u8 = 0xFF as u8;
    let v2:u8 = 0x00 as u8;
    let v3:u8 = 0x00 as u8;
    let mut counter:u8 = 0;
    for i in frame_buffer_data.iter_mut() {
        match counter {
            0 => {*i = v1},
            1 => {*i = v2},
            2 => {*i = v3},
            _ => {counter = 0},
        }
        counter += 1;
    }
Merlin1846 commented 2 years ago

This works but now I have a new adventure, make it so that things other than the yellow but now blue words change color.

#[no_mangle]
pub extern "C" fn _start(boot_info: &'static mut BootInfo) -> ! {
    let frame_buffer:&mut FrameBuffer = &mut boot_info.framebuffer.as_mut().unwrap(); // Get a mut reference to the frame buffer.

    let frame_buffer_data:&mut [u8] = frame_buffer.buffer_mut();

    let v1:u8 = 0xFF as u8;
    let v2:u8 = 0x00 as u8;
    let v3:u8 = 0x00 as u8;
    let v4:u8 = 0xFF as u8;
    let mut counter:u8 = 0;
    for i in frame_buffer_data.iter_mut() {
        match counter {
            0 => {*i = v1},
            1 => {*i = v2},
            2 => {*i = v3},
            3 => {*i = v4},
            _ => {counter = 0},
        }
        counter += 1;
    }

    loop {}
}
bjorn3 commented 2 years ago

[...] and I have to set one u8 then the next to the green channel, and then the next to the blue channel?

For the RGB you have to do that. For the BGR the channels are in the opposite order. For the U8 pixel format every byte is a single grayscale pixel.

https://github.com/rust-osdev/bootloader/blob/fa617315a4c01ed31e8593d5848e7d302ebf9fe8/src/boot_info.rs#L204-L224

You can look at the pixel_format field of frame_buffer.info() to know which pixel format to use.

But that doesn't make sense since if I add a counter that counts how many times it's activated and tell it to stop at 1366 it does a single full-length line, which would mean that each pixel is a single u8 right?

Maybe the screen is 455 pixels wide? (1366/3 = 455) Note that resizing the qemu window does not resize the framebuffer.

Ok so I did what you suggested and it almost worked? Only the words changed color. But then I set v2 to 0xFF and then the entire thing changed but it looked odd, I don't know how to describe it.

    let v1:u8 = 0xFF as u8;
    let v2:u8 = 0x00 as u8;
    let v3:u8 = 0x00 as u8;
    let mut counter:u8 = 0;
    for i in frame_buffer_data.iter_mut() {
        match counter {
            0 => {*i = v1},
            1 => {*i = v2},
            2 => {*i = v3},
            _ => {counter = 0},
        }
        counter += 1;
    }

That code skips the 0 => { *i = v1 }, arm due to counter being incremented immediately after setting it to 0. In addition I just read that you have to step bytes_per_pixel bytes every time with all bytes after the first 3 being ignored. Try

// FIXME move next statement before let frame_buffer_data:&mut [u8] = frame_buffer.buffer_mut();
let bytes_per_pixel = frame_buffer.info().bytes_per_pixel;

let v1:u8 = 0xFF as u8;
let v2:u8 = 0x00 as u8;
let v3:u8 = 0x00 as u8;
for pixel in frame_buffer_data.chunks_mut(bytes_per_pixel) {
    *pixel[0] = v1;
    *pixel[1] = v2;
    *pixel[2] = v3;
}
Merlin1846 commented 2 years ago

Ok, I'll try that, also I'm not using qemu I have a physical computer.

Merlin1846 commented 2 years ago

Well the code worked perfectly, the entire screen is blue, and now I can get on with writing a graphics driver.