Higher Half Kernel using Visual C++

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
User avatar
Apophis
Posts: 8
Joined: Wed Nov 03, 2010 2:29 am

Higher Half Kernel using Visual C++

Post 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?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Higher Half Kernel using Visual C++

Post by Solar »

The info in Visual Studio set aside, the canon suggestion is to use a GCC Cross-Compiler as backend instead.
Every good solution is obvious once you've found it.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Higher Half Kernel using Visual C++

Post 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.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Apophis
Posts: 8
Joined: Wed Nov 03, 2010 2:29 am

Re: Higher Half Kernel using Visual C++

Post 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?
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Higher Half Kernel using Visual C++

Post 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. :)
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Apophis
Posts: 8
Joined: Wed Nov 03, 2010 2:29 am

Re: Higher Half Kernel using Visual C++

Post 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
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Higher Half Kernel using Visual C++

Post 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
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Apophis
Posts: 8
Joined: Wed Nov 03, 2010 2:29 am

Re: Higher Half Kernel using Visual C++

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