Yet another "my paging is broke" thread

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.
rplacd
Posts: 8
Joined: Tue Dec 06, 2011 9:28 am

Yet another "my paging is broke" thread

Post by rplacd »

Hi - first post. I think I know what I'm doing when it comes to applications programming, so to shake things up a bit this is my first stab at lower-level programming. I've been through the babysteps tutorials, and slowly replacing everything from scratch (with the exception of the Multiboot bootloader) is just my attempt at making sure I understand things without using a crutch.

It hasn't been going too well - I tried tossing everything and tried to reimplement a standard two-level paging system, which led to a dead end. So now I'm dealing with 4MB pages and things seem to have gone carrot-shaped as well. The kernel's loaded, and the moment I enable the paging bit in cr0 - boom, triple-fault. Best-case scenario, I've misread the intel docs on 4MB paging and something's pearshaped with my struct; I'll need fresh eyes for that, though. Worst-case - I've thoroughly misunderstood something about C++, which happens more often than not.

Some searching on the forum says you'll want a Bochs log so that's up at http://pastebin.com/79tiUvb7. It indicates a GPF, but I'm not sure what to make of *that*.

This is the crux of the paging code - the equivalent of the "kernel_main()" that the bootloader jumps into calls install_paging() in order to set things up. Hopefully it's pretty vanilla stuff, except written with some higher-level boilerplate. You'll see I've stolen some bits from JamesM as well...

paging.h

Code: Select all

namespace stage1 {
	// Setup - for the kernel, remember, we'll swap this out for user processes via the TSS if needed -
	// page directory, page tables, and page frames somewhere where the sun don't shine
	// and then enable paging.
	void installPaging();
	
	// The page directory (to 4MB pages).
	// We use two-step construction here, because a significant amount of memory is required for
	// these tables so we can't just (1) first implicitly construct and then (2) re-assign.
	class page_directory {
		class entry {
			u32int inMemoryP : 1;   // Page present in memory
			u32int writeableP : 1;   // Read-only if clear, readwrite if set
			u32int userAccessibleP : 1;   // Supervisor level only if clear
			u32int unused0 : 2; // PWT and PCD, which we conveniently ignore
			u32int accessedP : 1;   // Has the page been accessed since last refresh?
			u32int dirtyP : 1;   // Has the page been written to since last refresh?
			u32int always1 : 2; // Nominally the "page size" bit and "G" bit, but is always 1 since we use 4MB pages.
			u32int unused1 : 3; // Ignored bytes.
			u32int always0 : 1; // PAT index - always 0.
			u32int unused2 : 9;  // The highest 4 bits of the address... we ignore.
			u32int pageFrameAddr : 10; // The next least-significant 10 bits of the addres... remember we lop off the other LSBs.
		
			public:
				entry(): 
					inMemoryP(0), writeableP(0), userAccessibleP(0), unused0(0), accessedP(0), 
					dirtyP(0), always1(3), unused1(0), always0(0), unused2(0), pageFrameAddr(0) {};
					
				// Initialize as inaccessible.
				void initAsInaccessible() {
					inMemoryP = 0;
				}; 
				// Initalize this frame as an identity mapped page - for the kernel, you see, since we can't
				// retcon all our pointers.
				void initAsKernelPage(u32int newTableAddr) {
					inMemoryP = 1; writeableP = 1; userAccessibleP = 1; pageFrameAddr = newTableAddr;
				}
				// Perhaps add another initializer that allocates from the pagetable allocator.
		} __attribute__((packed));	

		entry entries[1024];
		
		public:
			// Identity-map the first 4MB.
			void init();
	} __attribute__((aligned (4096), packed));
}
paging.cpp

Code: Select all

#include "paging.h"

using namespace stage1;

static page_directory our_page_directory;

void stage1::installPaging() {
	our_page_directory.init();
	
	// page directory swapping implementation copied off JamesM.
	asm volatile("mov %0, %%cr3":: "r"(&our_page_directory));
	u32int cr0;
	asm volatile("mov %%cr0, %0": "=r"(cr0));
	cr0 |= 0x80000000; // Enable paging!
	asm volatile("mov %0, %%cr0":: "r"(cr0));
}

void page_directory::init() {
	entries[0].initAsKernelPage(0);
}
Thanks for your patience! I'm silently at wits' end.
Last edited by rplacd on Thu Dec 08, 2011 10:58 am, edited 1 time in total.
User avatar
Muneer
Member
Member
Posts: 104
Joined: Tue Nov 02, 2010 2:05 am
Location: India

Re: Yet another "my paging is broke" thread

Post by Muneer »

Well I didnt read the code, but usually triple fault on enabling paging happens when you have not correclty identity-mapped your current running eip to the same address in the page dir/tables. For eg: if you are running at 0x400000 before paging is enabled, then your pages must be mapped in such a way that 0x400000 is still the same physichal address. Also you must usually have protectedmode enabled.

EDIT: I see from a quick read through the comments that you have attempted identity mapping. Maybe your mapping isnt done correclty. Check if you are writing to the screen after paged address,
Even the smallest person could change the course of the future - Lord Of The Rings.

In the end all that matters is what you have done - Alexander.

Even after a decade oh god those still gives me the shivers.
gedd
Member
Member
Posts: 104
Joined: Thu Apr 10, 2008 1:47 am

Re: Yet another "my paging is broke" thread

Post by gedd »

Maybe you can try to use struct instead object(class) to control the size of page/directory data.
Then use object(class) functions to control your data struct.
[ Grub 2 | Visual Studio 2013 | PE File ]
The OsDev E.T.
Don't send OsDev MIB !
rplacd
Posts: 8
Joined: Tue Dec 06, 2011 9:28 am

Re: Yet another "my paging is broke" thread

Post by rplacd »

@HardCoder
Thanks for your help! I've just checked the linker script and it seems the whole shebang's loaded 1MB in. I think one 4MB page starting at 0x0 gives enough space for a 40kb kernel (I've just checked the .bin), though. The kernel doesn't get beyond the mov x, cr0 before triple-faulting, though. Which is strange, because I've just scrambled to get JamesM-style interrupt handling up and it's still dying with a GPF. I set up the IDT before paging, so the act of calling an interrupt handler seems to be failing - presumably something *is* wrong with the struct.

@gedd
I'm not particularly sure what you mean by that - the class is packed (and guaranteed page-aligned, I did check that), and there's no overhead - it's just the page directory entries. I presume a pointer to the whole object points to the actual page directory, but I think I'll just double-check right now...

...just checked, it does. Pity, I was hoping the solution would be that easy.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Yet another "my paging is broke" thread

Post by bluemoon »

CR3 works on physical address.
Unless you do it on purpose, &our_page_directory usually points to some location defined respected to linker scripts (logical address), and it usually differ to where you load the kernel (physical address).

Also note that lower bits of CR3 is used as flags, so you need to make sure our_page_directory is aligned on 4K,
which I don't know how to declare that with C++, I do that on the linker script.


When working on paging code, I strongly recommend setup the #PF handler first so that you can see what the CPU tries to access.
in the PF handler you can dump register on screen, or setup break point with your debugger.

As a side note, the order of bit field is compiler specific, you may want to consider other coding style.
User avatar
Muneer
Member
Member
Posts: 104
Joined: Tue Nov 02, 2010 2:05 am
Location: India

Re: Yet another "my paging is broke" thread

Post by Muneer »

rplacd wrote:page directory, page tables, and page frames somewhere where the sun don't shine
Lol.
Even the smallest person could change the course of the future - Lord Of The Rings.

In the end all that matters is what you have done - Alexander.

Even after a decade oh god those still gives me the shivers.
User avatar
Muneer
Member
Member
Posts: 104
Joined: Tue Nov 02, 2010 2:05 am
Location: India

Re: Yet another "my paging is broke" thread

Post by Muneer »

Code: Select all

The kernel doesn't get beyond the mov x, cr0 before triple-faulting
Does that "x" mean Eax and that you are triple faulting whlle trying to switch to protected mode. If so try disabling interrupts "cli" and set ds register to 0 before jumping to p-mode
Even the smallest person could change the course of the future - Lord Of The Rings.

In the end all that matters is what you have done - Alexander.

Even after a decade oh god those still gives me the shivers.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Yet another "my paging is broke" thread

Post by Combuster »

00165618064i[CPU0 ] LOCK prefix unallowed (op1=0x53, modrm=0x00)
00165618066i[CPU0 ] LOCK prefix unallowed (op1=0x53, modrm=0x00)
00165618066i[CPU0 ] | RIP=000000000000000b (000000000000000b)
Calling functions on a null pointer?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
rplacd
Posts: 8
Joined: Tue Dec 06, 2011 9:28 am

Re: Yet another "my paging is broke" thread

Post by rplacd »

Sorry, guys, the next two posts are going to be a bit of a mess.
HardCoder wrote:

Code: Select all

The kernel doesn't get beyond the mov x, cr0 before triple-faulting
Does that "x" mean Eax and that you are triple faulting whlle trying to switch to protected mode. If so try disabling interrupts "cli" and set ds register to 0 before jumping to p-mode
Sorry that wasn't clear - I mean mov (cr0 | 0x8...), cr0.
No, I don't worry about switching to p-mode - multiboot guarantees that I'm in p-mode when my bootloader's called.
bluemoon wrote:CR3 works on physical address.
Unless you do it on purpose, &our_page_directory usually points to some location defined respected to linker scripts (logical address), and it usually differ to where you load the kernel (physical address).

Also note that lower bits of CR3 is used as flags, so you need to make sure our_page_directory is aligned on 4K,
which I don't know how to declare that with C++, I do that on the linker script.
GNU extensions allow me to ensure that struct's aligned - check the __attribute(...) portion after the struct definitions. I've just checked with objdump and it seems to be respecting that somehow. Namely:

Code: Select all

$ i586-elf-objdump kernel.bin -t | grep -i our_page_directory
00107000 l     O .bss   00002000 _ZL18our_page_directory
When working on paging code, I strongly recommend setup the #PF handler first so that you can see what the CPU tries to access.
in the PF handler you can dump register on screen, or setup break point with your debugger.
It's triple-faulting. Since I set up the IDT before paging, I assume it can't even call the interrupt handler.
As a side note, the order of bit field is compiler specific, you may want to consider other coding style.
JamesM does that, but you've just made me go check - GCC guarantees that packed bitfields do what they should > GCC 4.4.
Last edited by rplacd on Wed Dec 07, 2011 9:47 am, edited 5 times in total.
rplacd
Posts: 8
Joined: Tue Dec 06, 2011 9:28 am

Re: Yet another "my paging is broke" thread

Post by rplacd »

Combuster wrote:
00165618064i[CPU0 ] LOCK prefix unallowed (op1=0x53, modrm=0x00)
00165618066i[CPU0 ] LOCK prefix unallowed (op1=0x53, modrm=0x00)
00165618066i[CPU0 ] | RIP=000000000000000b (000000000000000b)
Calling functions on a null pointer?
No, that's part of the address - compare the length of it to some of the other extended registers set to 0. That's rather odd, though - the linkerscript ensures my kernel starts at 0x00100000, and all my interrupt handlers are yay higher.

I'm not quite sure what to make of that. I don't actually know what's at 0x0...0b.


So I'm sure it isn't a problem with the placement of the page directory, or how the struct "turns out" when compiled.
User avatar
eryjus
Member
Member
Posts: 286
Joined: Fri Oct 21, 2011 9:47 pm
Libera.chat IRC: eryjus
Location: Tustin, CA USA

Re: Yet another "my paging is broke" thread

Post by eryjus »

Try:

Code: Select all

void initAsKernelPage(u32int newTableAddr) {
               inMemoryP = 1; writeableP = 1; userAccessibleP = 0; pageFrameAddr = newTableAddr;
}
I am not sure the userAccessibleP flag should be set until you are setting up your user space.
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber
rplacd
Posts: 8
Joined: Tue Dec 06, 2011 9:28 am

Re: Yet another "my paging is broke" thread

Post by rplacd »

eryjus wrote:Try:

Code: Select all

void initAsKernelPage(u32int newTableAddr) {
               inMemoryP = 1; writeableP = 1; userAccessibleP = 0; pageFrameAddr = newTableAddr;
}
I am not sure the userAccessibleP flag should be set until you are setting up your user space.
No dice.

But the IA-32 guide only says it's there to restrict items in user mode from accessing addresses w/o it set. I'm still trying to figure out why the hell Bochs seems to be resetting at RIP=somewhere in GRUB.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Yet another "my paging is broke" thread

Post by Combuster »

rplacd wrote:
Combuster wrote:Calling functions on a null pointer?
No, that's part of the address - compare the length of it to some of the other extended registers set to 0. That's rather odd, though - the linkerscript ensures my kernel starts at 0x00100000, and all my interrupt handlers are yay higher.

I'm not quite sure what to make of that. I don't actually know what's at 0x0...0b.


So I'm sure it isn't a problem with the placement of the page directory, or how the struct "turns out" when compiled.
That read like you have no idea how C++ works under the hood, which is a really bad starting point for starting an OS.

Point is, you managed to screw up significantly enough that the processor jumps to address 0. Paging is not enabled so can not be part of the problem. That leaves very few ways of jumping to address zero: one is by calling a virtual function on a null pointer, (or even more directly through a null function pointer which is also less likely) the other is by any other form of memory corruption messing up your stack or pointers.

Go figure what exact line causes the crash for starters. I suppose you qualify the forum rules and your debugging skills are sufficiently adequate to do that?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
rplacd
Posts: 8
Joined: Tue Dec 06, 2011 9:28 am

Re: Yet another "my paging is broke" thread

Post by rplacd »

Combuster wrote:That read like you have no idea how C++ works under the hood, which is a really bad starting point for starting an OS.

Point is, you managed to screw up significantly enough that the processor jumps to address 0. Paging is not enabled so can not be part of the problem. That leaves very few ways of jumping to address zero: one is by calling a virtual function on a null pointer, (or even more directly through a null function pointer which is also less likely) the other is by any other form of memory corruption messing up your stack or pointers.

Go figure what exact line causes the crash for starters. I suppose you qualify the forum rules and your debugging skills are sufficiently adequate to do that?
Done that already - I've said it's it's the mov x, cr0 that's freaking out. I don't think it's changed. If you want a complete reaccounting of my methodology, by all means ask.

That being said, I don't even deal with either suspect - the page directory's in BSS, and the thing crashes in inline assembly and not in a prolog or epilog (the one place where I suppose I do deal with the stack - comment that one line out, though, and things work swimmingly). I ignored that suggestion the first time over, and I'm doing it all over again here; possibly to my detriment. But that's because you've been frustratingly oblique and in all likelihood I'm just not getting the hint. (Am I doing anything I don't know about? No - this is trivially translated to [GNU] C. You don't pay for what you don't need.)
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Yet another "my paging is broke" thread

Post by bluemoon »

rplacd wrote:Am I doing anything I don't know about? No
I doubt that circular logic.

And since there is only a few lines of code posted, and not much description on what you have done (the initialize sequence, what debug method and results?) it's hard to guess what's the problem. Anyway, have you set CR4.PSE = 1 ?
Post Reply