Page 1 of 1

Fail to update page dir/table

Posted: Sat Mar 04, 2006 10:42 am
by McZ
I have tried to map my pagedirectory to the highest 4mb of the virtual 4gb address space, but I fail.

This is basicly what I do:
Grub loads my kernel at 1mb
my asm loader initialize paging which maps my kernel to 3gb From FAQ
Then I remap my kernels PageDir into the top 4mb 0xFFC00000 works perfect.
Now I try to map a random free physical address to a random free virtual address and now the strange things start to appear, first I print the "old" flags and address of that page entry and then I set the flags and print the new one but the problem is that the new flags is NOT set?

some code

Code: Select all

kprintf("old flags 0x%X address 0x%X", pte->flags, pte->address);
kprintf("set flags 0x%X address 0x%X", flags, address);

pte->flags = 0x7FF & flags;
pte->address = (paddr >> 11);

kprintf("new flags 0x%X address 0x%X", pte->flags, pte->address);
this will print

Code: Select all

old flags 0x7FF address 0xFFFFF
set flags 0x3 address 0x???
new flags 0x7FF address 0xFFFFF
Why can't I set the flags and address? I don't get any page fault or anything like that unless I try to access the virtual address I tried to map.

Re:Fail to update page dir/table

Posted: Sat Mar 04, 2006 11:07 am
by Pype.Clicker
old flags 0x7FF address 0xFFFFF
that terribly sounds like a missing physical frame that is read to 0xffff,ffff because of floating state to me. On a missing page, you can "write" whatever you want, what you read is always bus noise...

Re:Fail to update page dir/table

Posted: Sat Mar 04, 2006 1:03 pm
by McZ
now I have rewritten a few parts and now I can set the flags and address. BUT i still can't map any virtual address to physical address if I "remap" my PageDir into the highest 4mb.

now I can allocate the physical page for the PageTable entry for the new PageDir address and set the address for that one. and then change my pointer to the PageDir so it points to the new virtual address. But after I have done that I can no longer change map any new virt->phys addresses I have tried to map 0x0 to the first allocated physical address I get from my Physical Memory Manager but without any success.

I get a page fault when I try to set the PageTable entry flags and address even though I have allocated a Physical page for that page table and mapped the PageDir entry to that address.

Re:Fail to update page dir/table

Posted: Sat Mar 04, 2006 3:58 pm
by Pype.Clicker
if running under bochs or QEMU, you might want to run a couple of "x 0xffc00000" commands to check the content of RAM. using "xp /format <phys_addr>" can also be helpful to check the PDBR points where you expect it and that the content there is what you expect too.

Re:Fail to update page dir/table

Posted: Sun Mar 05, 2006 12:38 pm
by McZ
Now I have tried to create a new Page directory to replace the old one.

This is how I do.
1) map the paddr to some vaddr in the old PD
2) set the PD entries (for testing I just copy the old PD to the new one)
3) set PT entries
4) set cr3 to the new PD's paddr

but it crash when returning after I have set cr3 to the new physical address.

this is how I set cr3

Code: Select all

writecr3:
   ; Write cr3
   push ebp
   mov ebp, esp
   mov eax, [ebp+8]
   mov cr3, eax
   ret ; <- at this line it will crash/reset bochs Page fault
in bochsout.txt it says cr3 is the new paddr and cr2 is some virtual address that I can't find when doing an objdump -D kernel.elf

Re:Fail to update page dir/table

Posted: Sun Mar 05, 2006 1:30 pm
by Brendan
Hi,
McZ wrote:

Code: Select all

writecr3:
   ; Write cr3
   push ebp
   mov ebp, esp
   mov eax, [ebp+8]
   mov cr3, eax
   ret ; <- at this line it will crash/reset bochs Page fault
I like optimizing code - how about this version:

Code: Select all

writecr3:
   ; Write cr3
   mov eax, [esp+4]
   mov cr3, eax
   jmp ebp
My optimized version would do exactly the same thing, but it's 2 instructions shorter! ;)


Cheers,

Brendan

Re:Fail to update page dir/table

Posted: Sun Mar 05, 2006 3:46 pm
by Colonel Kernel
Brendan wrote: Hi,
McZ wrote:

Code: Select all

writecr3:
   ; Write cr3
   push ebp
   mov ebp, esp
   mov eax, [ebp+8]
   mov cr3, eax
   ret ; <- at this line it will crash/reset bochs Page fault
I like optimizing code - how about this version:

Code: Select all

writecr3:
   ; Write cr3
   mov eax, [esp+4]
   mov cr3, eax
   jmp ebp
My optimized version would do exactly the same thing, but it's 2 instructions shorter! ;)


Cheers,

Brendan
How about making it optimal, and correct, like this:

Code: Select all

writecr3:
   ; Write cr3
   mov eax, [esp+4]
   mov cr3, eax
   ret
;)

Re:Fail to update page dir/table

Posted: Sun Mar 05, 2006 4:08 pm
by Brendan
Hi,
Colonel Kernel wrote:How about making it optimal, and correct, like this:
That's a good idea, but doesn't encourage McZ to think about the code he's written...

I was hoping McZ would see my reply and start wondering why I did "jmp ebp", and then figure it out himself. :)


Cheers,

Brendan

Re:Fail to update page dir/table

Posted: Sun Mar 05, 2006 5:13 pm
by Colonel Kernel
Brendan wrote: That's a good idea, but doesn't encourage McZ to think about the code he's written...

I was hoping McZ would see my reply and start wondering why I did "jmp ebp", and then figure it out himself. :)
I know, but irony is rarely helpful in such situations.

Re:Fail to update page dir/table

Posted: Sun Mar 05, 2006 5:29 pm
by McZ
Colonel Kernel wrote:
Brendan wrote: That's a good idea, but doesn't encourage McZ to think about the code he's written...

I was hoping McZ would see my reply and start wondering why I did "jmp ebp", and then figure it out himself. :)
I know, but irony is rarely helpful in such situations.
Actually it did help, altough I was a bit confused at first but then I noticed I had missed a pop ebp.. but optimized code isn't first priority at the moment though ::)

Re:Fail to update page dir/table

Posted: Sun Mar 05, 2006 5:53 pm
by McZ
just another question, have I understand the PageDir/PageTable stuff correct if I say it would build a tree that looks something like this:

Code: Select all

PD
|
+- Entry (entry * 4MB) = vaddr
|    |
|    +- Flags
|    |
|    +- Address -> PT 
|                  |
|                  +- Entry (PD entry * 4mb + PT entry *4KB) = vaddr
|                      |
|                      +- Flags
|                      |
|                      +- PhysicalAddress
|
+- Entry (entry * 4MB) = vaddr
|    |
|    +- Flags
|    |
|    +- Address -> PT 
|                  |
|                  +- Entry (PD entry * 4mb + PT entry *4KB) = vaddr
|                      |
|                      +- Flags
|                      |
|                      +- PhysicalAddress
|
unless you have 4MB pages then the address in the PD entry will point at the Physical address of that 4MB page and not a Page table.

Re:Fail to update page dir/table

Posted: Mon Mar 06, 2006 2:34 am
by McZ
how can I keep control over my PageDirectory and the relation between the physical and virtual addresses I have mapped into it?

And how can I do to make it easy to find the virtual address to a page table of a specefic PD entry?

I have been thinking of two ways

1) Allocate 4mb +4kb for entire pagedir and all 1024 pagetables and map it all to some address for exampel the highest 4mb and then calculate a way to easy translate virtual address to physical address.

to map a vaddr to a paddr you would do

Code: Select all

n = vaddr / SIZE_4MB; // find PD entry
PageTablePtr = P2V(PageDirPtr->Entry[n].address << 11);

n = vaddr...; // find PT entry
PageTablePtr->Entry[n].flags = someFlags;
PageTablePtr->Entry[n].address = paddr >> 11;
2) Have a structure that stores a pointer to the pagedir and 1024 pointers to each pagetable and whenever a new pagetable is allocated that PT's virtual address is stored in the pointer table this way you don't need to allocate more than you use BUT to use the Pagedir you must have correct mapping for the virtual addresses the pointers use to access the physical address of the PD and PT's

To map a vaddr to paddr

Code: Select all

struct PageDirectory {
 struct PageEntry *Entries; // This is the actual PD

 unsigned long PhysicalAddress; // This is the Physical Address to the PD to set into cr3

 struct PageEntry *PageTable[1024]; // This is pointers to each PT
};

x = vaddr / SIZE_4MB; // find PD entry

PD.Entries[x].flags = newFlags;

y = vaddr...; // find PT entry

PD.PageTable[x]->Entries[y].flags = newFlags;
PD.PageTable[x]->Entries[y].address = paddr << 11;

Re:Fail to update page dir/table

Posted: Mon Mar 06, 2006 3:37 am
by Brendan
Hi,

Normally (for plain 32 bit paging), when I create a new page directory I do something like this:

Code: Select all

    mov eax,edi                 ;eax = physical address of page directory
    or eax,00000011b            ;eax = page directory entry (present and read/write flags set)
    mov [edi+0xFFC],eax         ;Set page directory into itself
After this, all page directory entries will be mapped from 0xFFFFF000 to 0xFFFFFFFF, and all page table entries will be mapped from 0xFFC00000 to 0xFFFFFFFF.

It works because the page directory becomes the highest page table, and all page tables become pages.

To find the physical address of a page you'd do something like:

Code: Select all

;Input
; esi = linear address of page

convertLinearToPhysical:
   mov eax,esi                       ;eax = linear address
   shr eax,21                        ;eax = page directory entry number for linear address
   test [0xFFFFF000+eax*4],1         ;Is page table present?
   je .pageNotPresent                ; no, error
   mov eax,esi                       ;eax = linear address
   shr eax,12                        ;eax = page table entry number for linear address
   mov eax,[0xFFC00000+eax*4]        ;eax = page table entry
   test eax,1                        ;Is page present?
   je .pageNotPresent                ; no, error
   and eax,0xFFFFF000                ;eax = physical address of page
   ret
To add a page to the address space you'd do something like:

Code: Select all

;Input
; ebx = physical address of page to map
; ecx = access flags for page
; esi = linear address to map page

mapPage:
   or ebx,ecx                        ;ebx = page table entry
   mov eax,esi                       ;eax = linear address
   shr eax,21                        ;eax = page directory entry number for linear address
   test [0xFFFFF000+eax*4],1         ;Is page table present?
   jne .hasPT                        ; yes
   call allocatePhysicalPage         ; no, allocate a physical page,
   or eax,<page_dir_flags>           ;     and set the access flags,
   mov [0xFFFFF000+eax*4],eax        ;     and put the page table into the page directory
.hasPT:
   mov eax,esi                       ;eax = linear address
   shr eax,12                        ;eax = page table entry number for linear address
   test [0xFFC00000+eax*4],1         ;Is a page already present?
   jne .pageNotPresent               ; yes, error
   mov [0xFFC00000+eax*4],ebx        ;Set the new page table entry
   ret
Of course this will not work if the same page or page table needs to be mapped into other addresss spaces. For solutions to this problem see the other discussion.

I've also ignored things like re-entrancy locking, proper error handling and probably other things, but it hopefully gives you a good idea of how this works...


Cheers,

Brendan