Page 1 of 1

Printing after entering 64-bit kernel

Posted: Mon Jun 11, 2018 6:52 pm
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?

Re: Printing after entering 64-bit kernel

Posted: Tue Jun 12, 2018 9:59 am
by isaacwoods
Very simple, but have you remembered to update the address used to write into the framebuffer?

Re: Printing after entering 64-bit kernel

Posted: Tue Jun 12, 2018 10:08 am
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.

Re: Printing after entering 64-bit kernel

Posted: Wed Jun 13, 2018 11:02 pm
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

Re: Printing after entering 64-bit kernel

Posted: Thu Jun 14, 2018 12:21 am
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.

Re: Printing after entering 64-bit kernel

Posted: Thu Jun 14, 2018 12:58 am
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?

Re: Printing after entering 64-bit kernel

Posted: Thu Jun 14, 2018 1:54 am
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.