Fail to update page dir/table

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
McZ

Fail to update page dir/table

Post 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.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Fail to update page dir/table

Post 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...
McZ

Re:Fail to update page dir/table

Post 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.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Fail to update page dir/table

Post 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.
McZ

Re:Fail to update page dir/table

Post 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
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Fail to update page dir/table

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:Fail to update page dir/table

Post 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
;)
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Fail to update page dir/table

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:Fail to update page dir/table

Post 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.
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
McZ

Re:Fail to update page dir/table

Post 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 ::)
McZ

Re:Fail to update page dir/table

Post 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.
McZ

Re:Fail to update page dir/table

Post 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;
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Fail to update page dir/table

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Post Reply