Page 1 of 1

Page Directory being set to all zeros after enabling paging?

Posted: Thu Jun 16, 2011 5:29 pm
by Caleb1994
Okay, I am now trying to get my page directory cloning functions to work. Well, i came across an error that i can only assume was there all along, but never showed itself. For some reason, after executing this bit:

Code: Select all

/*! Switch to a page directory (essentially, set CR3 to dir) */
void vmm_switch_dir(pdir* dir)
{
	pmm_set_pdbr(vmm_get_phys((virt_addr)dir, _curdir));
	_curdir = dir;
	pmm_enable_paging(); // Modifying the CR0 forces a TLB flush
}
all my PDE's are NULL!

I know, it might look a little wierd to call "vmm_get_phys" (which translates a virtual address into a physical one, with a given directory) in the function that also enables paging, but it makes sense. Every page directory is, at the beginning, a clone of the kernel directory, which has the kernel memory and heap mapped in it. Also, the page directories are allocated on the kernel heap (or in the case of the original one, it's in the base kernel memory). So no matter what directory we use, we can assume that the physical address of any new directory is mapped inside it.

Here is the definition of pmm_set_pdbr:

Code: Select all

pmm_set_pdbr:
	mov ebx,dword[esp+4]
	and ebx,0xFFFFF000		; We only want the first 20 bits according to the intel manuals
	mov ecx,cr3
	or ecx,ebx
	mov cr3,ecx
	ret
and pmm_enable_paging:

Code: Select all

pmm_enable_paging:
	mov ebx,cr0
	or ebx,80000000h		; Add the paging bit to cr0
	mov cr0,ebx			; Restore cr0
	ret
So after executing this function with the base kernel directory (the very first directory that just has the heap, and kernel memory mapped), my directory is cleared. All the PDE's are NULL. I have print atleast the first 15-20 just because I was frustrated, and they are all NULL! This causes a problem when I go to copy that directory!

Now I have temporarily fixed the problem like so:

Code: Select all

	kdir = (pdir*)pmm_alloc_block(); // Each directory is an array of 1024 4byte integers (1024*4 = 4096 = page size = block size, 1 block...)
	pdir* tmpdir = (pdir*)pmm_alloc_block();
...
	memcpy(tmpdir, kdir, 4096);
	vmm_switch_dir(kdir);
	memcpy(kdir, tmpdir, 4096);
which seems to work (no errors, I can copy the directory fine. and the new cloned directory is fine after calling vmm_switch_dir). Also, after that first call, that function never changes my kernel directories values again. So it depends on the parameter, but at the same time only effects certain parameters. It doesn't make sense! While this solution works, this is neither efficient nor correct.

It's one thing when it happens every time I use that function, but it's a totally different thing when it only happens after I execute it with a specific parameter.

If you need any more information, let me know. I'm not very secretive when it comes to code xD If anyone can help (which from what I've seen, if anyone can, you guys can :P) I would greatly appreciate it!

Re: Page Directory being set to all zeros after enabling pag

Posted: Thu Jun 16, 2011 5:51 pm
by gerryg400

Code: Select all

Code:
pmm_set_pdbr:
   mov ebx,dword[esp+4]
   and ebx,0xFFFFF000      ; We only want the first 20 bits according to the intel manuals
   mov ecx,cr3   // GG: Why do this ?
   or ecx,ebx     // GG: and this ?
   mov cr3,ecx
   ret
Are you sure you should be or'ing there ? Just load ebx into cr3 and overwrite the old value.

Re: Page Directory being set to all zeros after enabling pag

Posted: Thu Jun 16, 2011 7:10 pm
by Caleb1994
mov ecx,cr3 // GG: Why do this ?
or ecx,ebx // GG: and this ?
Because, according to the intel manuals, there a couple other flags in cr3 (in these bits: 0x00000FFF). Granted, the address of a page directory should always be page aligned and therefore never touch the other bits, but I was having problems and figured I would be extra safe, just to make sure. I'm ORing because I would like to preserve those other bits. I knew it shouldn't make a difference, but I couldn't figure it out, so I was trying everything I could think of. xD

Re: Page Directory being set to all zeros after enabling pag

Posted: Thu Jun 16, 2011 7:13 pm
by gerryg400
When you OR you are preserving more than the lower 12 bits. You are also preserving the 1 bits in the upper 20 bits of the last address that was written to CR3. That is not what you want.

Maybe you want to do this.

Code: Select all

pmm_set_pdbr:
   mov ebx,dword[esp+4]
   and ebx,0xFFFFF000      ; We only want the first 20 bits according to the intel manuals
   mov ecx,cr3
   and ecx, 0xFFF   // This line clears the old address
   or ecx,ebx
   mov cr3,ecx
   ret

Re: Page Directory being set to all zeros after enabling pag

Posted: Thu Jun 16, 2011 7:38 pm
by gerryg400
Note also that your function 'pmm_set_pdbr' is trashing ebx and ecx and 'pmm_enable_paging' is trashing ebx. Your compiler may be upset by that ! Maybe ecx is okay but ebx is probably not safe to use.

Re: Page Directory being set to all zeros after enabling pag

Posted: Thu Jun 16, 2011 9:35 pm
by NickJohnson
Assuming you're using cdecl, only ECX, EDX, and EAX may be trashed (and EAX is the return value, of course.) Forgetting to save anything else invariably results in at least one irritatingly subtle bug. I've learned this the hard way. :P

Re: Page Directory being set to all zeros after enabling pag

Posted: Fri Jun 17, 2011 12:51 pm
by Caleb1994
NickJohnson/Gerry: Whoops! I am using cdecl, so I am doing that wrong! :O thanks! I understand it all, but I'm still slightly new to assembly, so there are something that I miss when communicating with C.

Gerry: You are correct!

I fixed those, and my problem went away! Thanks again! I think I forgot about not using ebx, and just thought "Well, eax is the return value so, the next register is ebx" lol it probably would have taken me a while to realize that. lol