Page 1 of 1

Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 10:03 am
by Apophis
I'm writing a kernel that I would like to be a higher half kernel. I'm trying to set up paging and map my kernel at 3GB, but am running into problems getting everything set up correctly. I'm using GRUB to boot into my kernel which then sets everything up and tries to enable paging. I've read about the GDT trick of using a base to offset kernel addresses from 3GB down to 1MB (where the kernel is in physical memory) so the kernel will work correctly until the paging is set up. The problem that I'm running into is that the kernel is linked with a base address of 3GB but since it starts out running at 1MB I can't set up the trick GDT.

The solution that I've seen for this problem is to create a .setup or .init section and link that section with a base address of 1MB. Then, in that section, setup the trick GDT and jump into the main part of the kernel which is based at 3GB (once the GDT is setup). The problem with this solution is that I'm using Visual C++ and I have been unable to find a way to change the base address of individual sections. The linker has a single option for base address and it applies to the entire resulting image.

Any ideas on how I can pull this off?

Re: Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 11:36 am
by Solar
The info in Visual Studio set aside, the canon suggestion is to use a GCC Cross-Compiler as backend instead.

Re: Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 11:57 am
by neon
Hello,

An alternative solution (no GDT trick required) is to have the kernels phase 1 startup code to remain position independent. It can setup a temporary page table and jump to its virtual address at 3gb for the 2nd phase of startup which can initialize the real memory manager and page structures.

This is what I personally do anyways. All of the above can be done in MSVC without any tricks.

Re: Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 2:24 pm
by Apophis
neon wrote:An alternative solution (no GDT trick required) is to have the kernels phase 1 startup code to remain position independent. It can setup a temporary page table and jump to its virtual address at 3gb for the 2nd phase of startup which can initialize the real memory manager and page structures.
Do you have any examples? It was my understanding that the MSVC++ compiler always uses an absolute address for data, which (I assume) is where the temporary page table info would come from. How does the phase 1 startup code refer to data when the address of that data would be 3G even though the data is actually at 1MB?

Re: Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 3:01 pm
by neon
Hello,
Apophis wrote:Do you have any examples? It was my understanding that the MSVC++ compiler always uses an absolute address for data, which (I assume) is where the temporary page table info would come from. How does the phase 1 startup code refer to data when the address of that data would be 3G even though the data is actually at 1MB?
You are somewhat correct - you cant call functions (as-is...) in the startup code, or reference global or static data as they will have the base of 3gb. However this doesnt, of course, limit the usage of the stack. Because the stack was initially set up by the bootloader, its almost guaranteed to be below 1MB.

So all thats needed is for the phase 1 startup code is to choose some location in memory for a page table and directory (I personally use 0x1000 and 0x2000 physical here, but it doesnt matter.), and reference them by pointers on the stack to initialize them. Only 2 page tables is needed to map 1mb-3gb virtual.

If you still request for an example, please let me know and Ill provide one. :)

Re: Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 3:17 pm
by Apophis
I think I see what you're saying. I do believe an example would make it clear though, and I would much appreciate it. :D

Re: Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 3:33 pm
by neon
Hello,

The startup code can look something like this. It doesnt include installing the PDBR and enabling paging, however does provide where you will need to perform it. You should be able to access the MB_INFO structure when at 1mb linear or 3gb virtual.

Please let me know if it helps or if there are any questions.

Code: Select all

int Startup () {

	uint32_t* pageTable1 = (uint32_t*)0x2000;
	uint32_t* pageTable2 = (uint32_t*)0x3000;
	uint32_t* pageDirectory = (uint32_t*)0x1000;

	unsigned int i = 0, addr=0;

	//! identity map
	for (i=0; i<1024; i++, addr+=4096) {
		pageTable1[i] = addr;
		pageTable1[i] |= 3;
	}

	//! map 1mb->3gb virtual
	for (i=0,addr=0x100000;i<1024;i++, addr+=4096) {
		pageTable2[i] = addr;
		pageTable2[i] |= 3;
	}

	//install page table 1 - 0-4mb
	pageDirectory[0] = &pageTable1[0];
	pageDirectory[0] |= 3;

	//install page table 2
	pageDirectory[768] = &pageTable2[0];
	pageDirectory[768] |= 3;

	//! install PDBR to 0x1000 here...
	//! enable paging here...

	//! jump to virtual address
	_asm {

		lea ecx, [startVirt]
		jmp ecx

startVirt:
	}

//! here you are now running at 3gb virtual

Re: Higher Half Kernel using Visual C++

Posted: Fri Nov 05, 2010 5:18 pm
by Apophis
That looks very straightforward. I'll try it out as soon as I can and let you know how it works out.

Thanks so much for your help!