Page 1 of 2

VGA frame buffer isnt displaying on screen

Posted: Mon Sep 02, 2024 12:02 pm
by MCorange
Ive been really going at this "kernel" for a long time, and this finally got the best of me.
I wanna make this into a bootable game (funny, i know), and ive got all of the basics working except the actualy display part. I got past the memory errors by mapping the buffer in memory. But i just cant manage to make it work.

So i get the frame buffer address, size, and pixel format through the multiboot2 header, i set the vga mode through the mb2 header.

Repo: https://git.mcorangehq.xyz/XOR64/poppin/
MB2 header: https://git.mcorangehq.xyz/XOR64/poppin ... ultiboot.s
The vga framebuffer code: https://git.mcorangehq.xyz/XOR64/poppin ... deo/mod.rs

Serial output:

Code: Select all

[INFO] kernel::logger: Logger init OK
[INFO] kernel::gdt: gdt init
[DEBUG] kernel::gdt: gdt             = 0x197978
[DEBUG] kernel::gdt: tss             = 0x197904
[DEBUG] kernel::gdt: kernel_stack    = 0x1979d8
[DEBUG] kernel::gdt: user_stack      = 0x19c9d8
[DEBUG] kernel::gdt: kernel_code_sel = SegmentSelector { index: 1, rpl: Ring0 }
[DEBUG] kernel::gdt: kernel_data_sel = SegmentSelector { index: 2, rpl: Ring0 }
[DEBUG] kernel::gdt: tss_sel         = SegmentSelector { index: 3, rpl: Ring0 }
[DEBUG] kernel::gdt: user_code_sel   = SegmentSelector { index: 6, rpl: Ring3 }
[DEBUG] kernel::gdt: user_code_sel   = SegmentSelector { index: 5, rpl: Ring3 }
[INFO] kernel::interrupts: IDT init
[INFO] kernel::mem::paging: Remaping kernel
[DEBUG] kernel::mem::paging: Switched to new table
[DEBUG] kernel::mem::paging: Put guard page at 0x18e000
[INFO] kernel::std::vga::video: VGA VIDEO adddr: fd000000
[INFO] kernel::std::vga::video: VGA VIDEO FB TYPE: Ok(RGB { red: FramebufferField { position: 16, size: 8 }, green: FramebufferField { position: 8, size: 8 }, blue: FramebufferField { position: 0, size: 8 } })
[INFO] kernel: end of work
The code for a lot of the system is copy pasted. Though i think i understand it enough by now (i hope)
Its in rust, which i like. I hope you do too

Re: VGA frame buffer isnt displaying on screen

Posted: Mon Sep 02, 2024 1:06 pm
by nullplan
MCorange wrote: Mon Sep 02, 2024 12:02 pm Its in rust, which i like. I hope you do too
As a rule, I don't look at hype languages. Let's talk about this further in a decade.

Anyway, the set_px function in the file you linked to is immediately suspicious. Not only do you not verify that the coordinates are in range, but the pixel address is wrong. The correct formula for most framebuffer types is "y * pitch + x". I don't know if you are recording frame buffer pitch somewhere, but you probably should, because there are framebuffers where pitch might exceed width.

Re: VGA frame buffer isnt displaying on screen

Posted: Mon Sep 02, 2024 4:23 pm
by MCorange
nullplan wrote: Mon Sep 02, 2024 1:06 pm As a rule, I don't look at hype languages. Let's talk about this further in a decade.
Will do. :3

Alright so the whole structure that i get from grub is this:

Code: Select all

FramebufferTag { 
	typ: Framebuffer, 
	size: 38, 
	buffer_type: RGB { 
		red: FramebufferField { 
			position: 16, size: 8 
		},
		 green: FramebufferField { 
		 	position: 8,
		 	size: 8 
		 }, 
		 blue: FramebufferField { 
		 	position: 0, 
		 	size: 8 
		 },
	},
	address: 4244635648, // 0xFD000000
	pitch: 4096, 
	width: 1024, 
	height: 768, 
	bpp: 32 
}
and my code immediately segfaults if i do x * pitch + y
So what should i do when the pitch is 4k

Re: VGA frame buffer isnt displaying on screen

Posted: Mon Sep 02, 2024 4:28 pm
by MCorange
Okay so, i did some diggin in the forums and found this: viewtopic.php?p=272361#p272361
I can figure that out but the problem is i dont see anything being drawn on the screen, not a single pixel.

Re: VGA frame buffer isnt displaying on screen

Posted: Mon Sep 02, 2024 4:51 pm
by MCorange
Well i thought it could be the paging, but if the normal text vga buffer works normally then the video one should work too, so why isnt it displaying anything ;-;

Re: VGA frame buffer isnt displaying on screen

Posted: Mon Sep 02, 2024 5:49 pm
by MCorange
And another thing, apparently gdb cant access the memory at the frame buffer :/

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 03, 2024 4:42 am
by sebihepp

Code: Select all

let vga_video_buffer_frame_end = Frame::containing_address((mem_info.vga_vide_start + mem_info.vga_vide_size*3));
Here you assume the video buffer has a size of vga_vide_size*3 - but you didn't check the bpc (bits per color) field of the multiboot2 info. Maybe your Framebuffer is setup to use only 16 bpc or even 32 bpc.

If you use this, you can skip the multiply by 3.

Code: Select all

let vga_video_buffer_frame_end = Frame::containing_address((mem_info.vga_vide_start + <pitch> * <height>));
Also make sure you set the pages to WriteThrough, otherwise you written stuff remains in the processors cache and wont be written to the memory directly.

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 03, 2024 6:01 am
by iansjack
Try this version of set_px:

Code: Select all

    
    pub fn set_px(&self, x: usize, y: usize, c: Color) {
        let ptr = self.buf_addr as *mut () as *mut u8;
        let px = ptr.wrapping_add(4 * x +  0x1000 * y);
      	 unsafe {
            *px.wrapping_add((self.r_ofs % 8) as usize) = c.r;
            *px.wrapping_add((self.g_ofs % 8) as usize + 1) = c.g;
            *px.wrapping_add((self.b_ofs % 8) as usize + 2) = c.b; 
        }
    }
Obviously you need to work out what the magic numbers should be rather than using the ones I have hard-coded (which should work for the mode you set). I'll leave you to work out why those numbers work.

As an aside, I tried using Rust for a kernel but, in the end, I found it was just too much hard work fighting against the language, particularly;y as it is in such a state of flux. What works today won't work tomorrow. I feel that most of the advantages of Rust are lost because you need to use many "unsafe" blocks, which makes the whole thing more complicated - and harder to debug - than simple C or C++.

Just my opinion.

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 03, 2024 7:07 am
by MCorange
sebihepp wrote: Tue Sep 03, 2024 4:42 am

Code: Select all

let vga_video_buffer_frame_end = Frame::containing_address((mem_info.vga_vide_start + mem_info.vga_vide_size*3));
Here you assume the video buffer has a size of vga_vide_size*3 - but you didn't check the bpc (bits per color) field of the multiboot2 info. Maybe your Framebuffer is setup to use only 16 bpc or even 32 bpc.

If you use this, you can skip the multiply by 3.

Code: Select all

let vga_video_buffer_frame_end = Frame::containing_address((mem_info.vga_vide_start + <pitch> * <height>));
Also make sure you set the pages to WriteThrough, otherwise you written stuff remains in the processors cache and wont be written to the memory directly.
I did fix this without saying anything here! I now use bpp to calculate how big the buffer is, i did add WRITE_THROUGH though.
Heres the new updated code for the framebuffer remap (the calculation itself was earlier in the execution in mem/mod.rs)

Code: Select all

// mem/mod.rs:152
let vv_info = boot_info.framebuffer_tag().unwrap().unwrap();
let vv_start = vv_info.address();
let vv_size = vv_info.pitch() * vv_info.height();

// mem/heap/paging/mod.rs:211
let vga_video_buffer_frame_start = Frame::containing_address(mem_info.vga_vide_start);
let vga_video_buffer_frame_end = Frame::containing_address(mem_info.vga_vide_start + mem_info.vga_vide_size);
for frame in Frame::range_inclusive(vga_video_buffer_frame_start, vga_video_buffer_frame_end) {
    mapper.identity_map(frame, EntryFlags::WRITABLE | EntryFlags::WRITE_THROUGH, allocator);
}
iansjack wrote: Tue Sep 03, 2024 6:01 am Try this version of set_px:

Code: Select all

    
    pub fn set_px(&self, x: usize, y: usize, c: Color) {
        let ptr = self.buf_addr as *mut () as *mut u8;
        let px = ptr.wrapping_add(4 * x +  0x1000 * y);
      	 unsafe {
            *px.wrapping_add((self.r_ofs % 8) as usize) = c.r;
            *px.wrapping_add((self.g_ofs % 8) as usize + 1) = c.g;
            *px.wrapping_add((self.b_ofs % 8) as usize + 2) = c.b; 
        }
    }
Obviously you need to work out what the magic numbers should be rather than using the ones I have hard-coded (which should work for the mode you set). I'll leave you to work out why those numbers work.

As an aside, I tried using Rust for a kernel but, in the end, I found it was just too much hard work fighting against the language, particularly;y as it is in such a state of flux. What works today won't work tomorrow. I feel that most of the advantages of Rust are lost because you need to use many "unsafe" blocks, which makes the whole thing more complicated - and harder to debug - than simple C or C++.

Just my opinion.
Oh my god im actually stupid, thank you.
For one, i was mod'ing the offsets instead of dividing for some reason (to be fair it was in the middle of the night)
And the pixel location calculation works now!

This is the updated set_px function:

Code: Select all

pub fn set_px(&self, x: usize, y: usize, c: Color) {
    assert!(x <= self.size.x && y <= self.size.x);
    let ptr = self.buf_addr as *mut () as *mut u8;
    let px = ptr.wrapping_add((self.bpp / 8) as usize * x + self.pitch * y);
    unsafe {
        *px.wrapping_add((self.r_ofs / 8) as usize) = c.r;
        *px.wrapping_add((self.g_ofs / 8) as usize) = c.g;
        *px.wrapping_add((self.b_ofs / 8) as usize) = c.b;
    }
}
On the rust thing:
I get where youre coming from, i love coding in c, its really nice. Its an amazing language but i just prefer rust because i consider myself better in it.And i love the features i get, especially macros (that are a lot diffrent from C's). Although it gets tiresome to write a lot of the quite verbose syntax in rust. TLDR, both languages are amazing, but they have diffrent places that they fill.

Oh and. One last thing. Thanks you all. Honestly an amazing experience asking my first question here.

(Except the register captcha question. That one sucked)

As always, code is here: https://git.mcorangehq.xyz/XOR64/poppin/

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 03, 2024 8:51 am
by sebihepp
Just one question out of curiosity: Does it work now? :D

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 03, 2024 10:55 am
by MCorange
Yes! It was pretty sllow when drawing a gradient (like 2 sec draw time) but i enabled kvm and it was down to like 400ms im guessing.

Although, i got my SO to test a build on a couple laptops but none worked fully except one where the graphics worked but the keyboard int and regular text vga buffer didnt work. Rhough on quemu works perfectly :3

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 03, 2024 1:01 pm
by Octocontrabass
sebihepp wrote: Tue Sep 03, 2024 4:42 amAlso make sure you set the pages to WriteThrough, otherwise you written stuff remains in the processors cache and wont be written to the memory directly.
On x86 PCs, you usually don't need to specify page-level cache attributes because the firmware has already initialized the MTRRs to disable caching on all MMIO.

If you're going to go through the trouble of changing the MTRRs, you should configure your framebuffer as WC instead of WT.

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 10, 2024 3:04 am
by sebihepp
Octocontrabass wrote: Tue Sep 03, 2024 1:01 pm On x86 PCs, you usually don't need to specify page-level cache attributes because the firmware has already initialized the MTRRs to disable caching on all MMIO.

If you're going to go through the trouble of changing the MTRRs, you should configure your framebuffer as WC instead of WT.
Does this mean I need to specify the Pages as UC- (Uncached but overwritable by MTRRs) or is normal UC enough?

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 10, 2024 8:34 am
by nullplan
sebihepp wrote: Tue Sep 10, 2024 3:04 am Does this mean I need to specify the Pages as UC- (Uncached but overwritable by MTRRs) or is normal UC enough?
No, specify the pages as WC in the PAT. That way, MTRR memory type is ignored, and you get WC behavior. WC is type 1, which is not in the PAT register reset value, so you have to add it.

Re: VGA frame buffer isnt displaying on screen

Posted: Tue Sep 10, 2024 11:54 am
by sebihepp
Sorry, I meant if I don't fiddle with the MTRRs and PAT and only use paging - what should I set the paging attributes to for the LFB?