VGA frame buffer isnt displaying on screen

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
MCorange
Posts: 7
Joined: Mon Sep 02, 2024 11:26 am
Location: Lithuania
Mastodon: @[email protected]
GitHub: https://git.mcorangehq.xyz/MCorange
Contact:

VGA frame buffer isnt displaying on screen

Post 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
nullplan
Member
Member
Posts: 1788
Joined: Wed Aug 30, 2017 8:24 am

Re: VGA frame buffer isnt displaying on screen

Post 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.
Carpe diem!
User avatar
MCorange
Posts: 7
Joined: Mon Sep 02, 2024 11:26 am
Location: Lithuania
Mastodon: @[email protected]
GitHub: https://git.mcorangehq.xyz/MCorange
Contact:

Re: VGA frame buffer isnt displaying on screen

Post 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
User avatar
MCorange
Posts: 7
Joined: Mon Sep 02, 2024 11:26 am
Location: Lithuania
Mastodon: @[email protected]
GitHub: https://git.mcorangehq.xyz/MCorange
Contact:

Re: VGA frame buffer isnt displaying on screen

Post 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.
User avatar
MCorange
Posts: 7
Joined: Mon Sep 02, 2024 11:26 am
Location: Lithuania
Mastodon: @[email protected]
GitHub: https://git.mcorangehq.xyz/MCorange
Contact:

Re: VGA frame buffer isnt displaying on screen

Post 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 ;-;
User avatar
MCorange
Posts: 7
Joined: Mon Sep 02, 2024 11:26 am
Location: Lithuania
Mastodon: @[email protected]
GitHub: https://git.mcorangehq.xyz/MCorange
Contact:

Re: VGA frame buffer isnt displaying on screen

Post by MCorange »

And another thing, apparently gdb cant access the memory at the frame buffer :/
sebihepp
Member
Member
Posts: 186
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: VGA frame buffer isnt displaying on screen

Post 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.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: VGA frame buffer isnt displaying on screen

Post 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.
User avatar
MCorange
Posts: 7
Joined: Mon Sep 02, 2024 11:26 am
Location: Lithuania
Mastodon: @[email protected]
GitHub: https://git.mcorangehq.xyz/MCorange
Contact:

Re: VGA frame buffer isnt displaying on screen

Post 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/
sebihepp
Member
Member
Posts: 186
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: VGA frame buffer isnt displaying on screen

Post by sebihepp »

Just one question out of curiosity: Does it work now? :D
User avatar
MCorange
Posts: 7
Joined: Mon Sep 02, 2024 11:26 am
Location: Lithuania
Mastodon: @[email protected]
GitHub: https://git.mcorangehq.xyz/MCorange
Contact:

Re: VGA frame buffer isnt displaying on screen

Post 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
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: VGA frame buffer isnt displaying on screen

Post 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.
sebihepp
Member
Member
Posts: 186
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: VGA frame buffer isnt displaying on screen

Post 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?
nullplan
Member
Member
Posts: 1788
Joined: Wed Aug 30, 2017 8:24 am

Re: VGA frame buffer isnt displaying on screen

Post 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.
Carpe diem!
sebihepp
Member
Member
Posts: 186
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: VGA frame buffer isnt displaying on screen

Post 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?
Post Reply