Page 1 of 1

Paging

Posted: Thu Oct 15, 2009 3:06 am
by Daevius
Hi, I've been working on getting paging correct and dynamic. Almost there, but I have a few questions :)

Let me get this right: we have a page directory, with page directory entries. Each page directory entry points to the physical location of a page table, which has page (table) entries. Each page (table) entry points to the physical location of a piece of memory. The virtual location is determined by the Nth location the page table entry has in the directory (so for 4 MB pages, the 3rd entry covers the virtual addresses from 8 MB to 12 MB).

Is it right that we only ever have (or need) one page directory? So I only ever set cr3 once?

When using 4 MB sized pages, 1024 page table entries is enough to cover the whole memory, then why the need for more page tables? Is this because also 4 KB sized pages are supported, or does it have other advantages? Such as, each process uses a different page table?
As I can see it now, to make code not dependent on the physical address the data is at, we use pages, but this makes the code dependent on the virtual address, unless each process uses a different page table...what if 2 processes have in their code that all data is at 3GB, and they use the same page table, they both get mapped to the same physical address, isn't it?

Then, another point. I've been following this wiki 'tutorial': http://wiki.osdev.org/Higher_Half_bare_bones, in ASM it sets up a page directory, but nowhere I see it setting up a page table. In fact, it looks like the page directory defines 2 page tables, both at offset 0 of the physical memory location? I have no tables at offset 0 :S, have I?

Also, if I dynamically want to add and subtract pages, I will have to map the page directory and page tables themselves too I suppose? Else I can't write to or read from the page description.

Thanks!

Re: Paging

Posted: Thu Oct 15, 2009 5:03 am
by AJ
Hi,
Is it right that we only ever have (or need) one page directory? So I only ever set cr3 once?
No. Generally when you are multitasking, you will have one PD for every task, so each task cannot interfere with other tasks memory.
When using 4 MB sized pages, 1024 page table entries is enough to cover the whole memory
In 32 bit mode, with 4MiB pages, you only have a page directory. Each PDE points to the start of a 4MiB page, not to a page table.
Also, if I dynamically want to add and subtract pages, I will have to map the page directory and page tables themselves too I suppose? Else I can't write to or read from the page description.
There's a clever trick here. Map the last (or whatever) PDE to the address of the PD itself. This means that the last 4MiB of virtual RAM represent all the page tables. The page table for the 0-4MiB range therefore resides at 0xFFC00000. The page table for the 4-8MiB range is at 0xFFC01000 and so on. You will find the PD itself accessible at 0xFFFFF000. This may take some thinking about to start with!

In this method, to add a new page, first assign a free physical page as a Page Table - write it to the appropriarte PD location. For example, I want to map a page at 0x1000-0x2000 virtual. Write the address of a free physical page to 0xFFFFF000, which maps the first 4MiB range in to your PD. This also locates the PT at 0xFFC00000! We can then assign another free physical page and write its address to 0xFFC00004 (the second PT entry). You now have a virtual memory page accessible at your desired, paged in location.

As for the barebones, hopefully my answer to the 4MiB page size question has answered that :)

Cheers,
Adam

Re: Paging

Posted: Thu Oct 15, 2009 5:09 am
by -m32
Daevius wrote:Is it right that we only ever have (or need) one page directory? So I only ever set cr3 once?
No; unless your processes don't need their own execution space. You need to change page directories every time you do a context switch.
Daevius wrote:what if 2 processes have in their code that all data is at 3GB, and they use the same page table, they both get mapped to the same physical address, isn't it?
That is correct.
Daevius wrote:Then, another point. I've been following this wiki 'tutorial': http://wiki.osdev.org/Higher_Half_bare_bones, in ASM it sets up a page directory, but nowhere I see it setting up a page table. In fact, it looks like the page directory defines 2 page tables, both at offset 0 of the physical memory location? I have no tables at offset 0 :S, have I?
This is because 4MB pages are mapped into the page directory, not a separate page table. The separate page table is used for finer granularity in addressing smaller pages.
Daevius wrote:Also, if I dynamically want to add and subtract pages, I will have to map the page directory and page tables themselves too I suppose? Else I can't write to or read from the page description.
True. You will have to either map the page directory into itself (so it is self-referencing) or, swap in/out pages (or tables if using 4Kb pages) to a temporary space.

Re: Paging

Posted: Thu Oct 15, 2009 5:10 am
by -m32
Someone's (AJ) a slightly faster typer than I am :)

Re: Paging

Posted: Thu Oct 15, 2009 5:31 am
by Daevius
Thanks for your replies! It makes much more sense now.

As to AJ's trick:
That's for 4 KB sized pages, isn't it? So for 4 MB pages, when mapping the last page directory entry to the page directory itself, it would be on 0xFFC00000 (the last 4 MB). The page directory is of size 0x1000, so from 0xFFC01000 on we have 4092 KB of unused memory. The second entry in the page directory would be at 0xFFC00004.

Re: Paging

Posted: Thu Oct 15, 2009 5:50 am
by AJ
Hi,

Not quite (and yes, it is for 4KiB pages).

If the last PD entry is set to itself, think what happens:
* A PD entry (in 4KiB mode) points to a PT.
* The last PD entry points to the PD.
* This means that the Page *Table* representing the last 4MiB of virtual address space is the PD(!).
* The Last PD entry points to the PD, therefore the last PT entry (representing 0xFFFFF000 - 0xFFFFFFFF) also points to the PD.

This means your PD is located at 0xFFFFF000-0xFFFFFFFF virtual. 0xFFC00000-0xFFC00FFF will represent your first page *table*, meaning 0-0x400000 in virtual ram. 0xFFC01000-0xFFC01FFF represents 0x400000-0x800000 and so on...

It's really worth wrapping your head around this design in the long run. Once you have sorted it out, it works equally well for long mode!

Cheers,
Adam

Re: Paging

Posted: Thu Oct 15, 2009 7:56 am
by Daevius
Thanks AJ. I think I got it now ;-), indeed a clever trick!

For 4MB sized pages it'll be much easier since we have no page tables, and it'd be like I described, right? For the 4KB sized pages it's like you described.

Now I need to decided whether I go for 4KB or 4MB sized pages...^^
Thanks guys!

Re: Paging

Posted: Thu Oct 15, 2009 2:35 pm
by AJ
Daevius wrote:Thanks AJ. I think I got it now ;-), indeed a clever trick!
Glad it helped :)
For 4MB sized pages it'll be much easier since we have no page tables, and it'd be like I described, right?
Pretty much. Of course 4MiB pages are 4MiB aligned in both physical and virtual memory, so if you want your PD to be at 0xFFFFF000, you'll need to dump it at the top of a 4MiB range somewhere and then set the PDE to the start address of that 4MiB range. e.g. PD at 0x7FF000 physical, last PDE = (0x400000 | flags) will give you an accessible PD at 0xFFFFF000.
Now I need to decided whether I go for 4KB or 4MB sized pages...^^
Unless you have a specific reason in mind, I'd advise [a] 4MiB page for the kernel itself and 4KiB pages for everything else. The TLB for 4MiB pages is separate, so if you have a single Global 4MiB page for the kernel, it avoids unnecessary TLB reloads.

For everything else, use 4KiB pages - if you look at the PD example I have just given you, you'll see that 4MiB pages are often overkill. If a process needs 0x401000 bytes allocated to it, using pure 4MiB pages you are obliged to give that process 8MiB of paged-in address space which is a complete waste. With the 4KiB scheme, you may lose 4MiB of virtual address space for each process' page tables, but you only add a page table when needed, so the "wasted" physical memory can be kept to a minimum.

Cheers,
Adam