Printing after entering 64-bit kernel

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.
Post Reply
CRoemheld
Member
Member
Posts: 55
Joined: Wed May 02, 2018 1:26 pm
Libera.chat IRC: CRoemheld

Printing after entering 64-bit kernel

Post by CRoemheld »

Hello there,

I just managed to get the jump to the 64-bit kernel to work, using a separate loader.
When I first managed to do that, I noticed that the prints aren't working anymore. After thinking about it for a bit, I realized that the VGA frame buffer address (0xb8000) which I assigned to a pointer inside the 32-bit loader for printing, is a physical address, however, after I enabled paging, every address is being recognized as a virtual one.
Given that, I thought I was simply missing a mapping entry for the VGA frame buffer, so I did the following:

Code: Select all

#define VGA_TEXT_BUFFER_ADDRESS_X86               0xb8000
#define VGA_TEXT_BUFFER_ADDRESS_X86_64            0xffffffff802b8000

#if defined(__i386__)
#define VGA_TEXT_BUFFER_ADDRESS                   VGA_TEXT_BUFFER_ADDRESS_X86
#endif
#if defined(__x86_64__)
#define VGA_TEXT_BUFFER_ADDRESS                   VGA_TEXT_BUFFER_ADDRESS_X86_64
#endif
And in my bootstrap file, before entering the kernel, I mapped the addresses 0xffffffff802b8000 to 0xb8000.

Code: Select all

memmap(MAP_MODE_PT, VGA_TEXT_BUFFER_ADDRESS_X86_64, 
		VGA_TEXT_BUFFER_ADDRESS_X86, (X86_64_PTE_FLAG_PRESENT | X86_64_PTE_FLAG_READ_WRITE), 0x1000);
Here I map the addresses, on 4KiB pages (MAP_MODE_PT) with a mapping size of 4KiB (VGA buffer size (80 x 25) x 2, since buffer holds 16-bit entries = 4000 bytes < 4KiB)
When checking if the mapping was successful, the linear memdump for 0xffffffff802b8000 in Bochs displayed the contents of the frame buffer correctly, so I thought it should definitely work now, but it doesn't.

Am I missing something important here?
Last edited by CRoemheld on Tue Jun 12, 2018 11:50 am, edited 1 time in total.
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

Re: Printing after entering 64-bit kernel

Post by isaacwoods »

Very simple, but have you remembered to update the address used to write into the framebuffer?
CRoemheld
Member
Member
Posts: 55
Joined: Wed May 02, 2018 1:26 pm
Libera.chat IRC: CRoemheld

Re: Printing after entering 64-bit kernel

Post by CRoemheld »

I am compiling the vga.c file twice, the first time I am compiling it using my i386-cross-compiler, which sets the address to

Code: Select all

#define VGA_TEXT_BUFFER_ADDRESS                   VGA_TEXT_BUFFER_ADDRESS_X86
and when I compile it for the kernel with my x86-64-cross-compiler, I am using the other value:

Code: Select all

#define VGA_TEXT_BUFFER_ADDRESS                   VGA_TEXT_BUFFER_ADDRESS_X86_64
Then when initializing vga, I am setting the address to the pointer which is used when printing:

Code: Select all

void vga_initialize(void) 
{
	vga_row = 0;
	vga_column = 0;
	vga_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
	vga_buffer = (uint16_t*) VGA_TEXT_BUFFER_ADDRESS;
	for (size_t y = 0; y < VGA_HEIGHT; y++) {
		for (size_t x = 0; x < VGA_WIDTH; x++) {
			const size_t index = y * VGA_WIDTH + x;
			vga_buffer[index] = vga_entry(' ', vga_color);
		}
	}
}
A quick check in the disassembled file also shows, that the value set for the pointer seems to be correct:

Code: Select all

ffffffff80201e7f:	48 c7 00 00 80 2b 80 	movq   $0xffffffff802b8000,(%rax)
It should be noted that the approach I'm following is the one from here.
nullplan
Member
Member
Posts: 1801
Joined: Wed Aug 30, 2017 8:24 am

Re: Printing after entering 64-bit kernel

Post by nullplan »

Hi,

"doesn't work" is not an error description. From your OP I assume that reading works but writing doesn't appear to do anything. In that case it appears likely to be a caching issue. Try to determine the cache type for the memory region (i.e. what does the PAT say about the virtual address, and what do the MTRRs say about the physical address?) The Intel manual will be able to tell you what that means for the cache type. For a framebuffer you generally want write-combining. Write-through and uncacheable also work, though at degraded performance.

Finally, if you don't want to mess with this stuff, you could also try the "wbinvd" instruction after completing your writes, possibly preceeded by "sfence".

Ciao,
Markus
Carpe diem!
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Printing after entering 64-bit kernel

Post by iansjack »

Would caching explain why the code works in 32-bit mode, but not 64? It seems more likely to me that, when writing to the simple text buffer at 0xb8000, the cause lies elsewhere. Otherwise this would be a huge problem that almost every hobby OS suffers from. As far as I know this is not the case.

I'm tempted to tell the OP to single-step his code in a debugger to see what is happening. But that obvious advice is ignored so consistently that there's little point in repeating it.
User avatar
Velko
Member
Member
Posts: 153
Joined: Fri Oct 03, 2008 4:13 am
Location: Ogre, Latvia, EU

Re: Printing after entering 64-bit kernel

Post by Velko »

CRoemheld wrote:I am compiling the vga.c file twice...
But are you calling vga_initialize() twice? Are you re-initializing it after entering Long mode?
If something looks overcomplicated, most likely it is.
CRoemheld
Member
Member
Posts: 55
Joined: Wed May 02, 2018 1:26 pm
Libera.chat IRC: CRoemheld

Re: Printing after entering 64-bit kernel

Post by CRoemheld »

Velko wrote:
CRoemheld wrote:I am compiling the vga.c file twice...
But are you calling vga_initialize() twice? Are you re-initializing it after entering Long mode?
...

I am so. ashamed right now, that's why I had a feeling the issue was something pretty stupid. I am so sorry about troubling you all.
Post Reply