I'm unsure of my understanding of paging. I'd like to check, by creating a hypothetical page directory, and asking the community to point out my mistakes along the way.
Let's suppose that the kernel code fits into the first frame - 0x0000 to 0x1000, and that the page directory will be put at 0x10000. It will be an identity map.
So first, I went to the intel 80386 manual, and found this illustration
╔══════════════════════════════════════╤═══════╤═══╤═╤═╤═══╤═╤═╤═╗ ║ │ │ │ │ │ │U│R│ ║ ║ PAGE FRAME ADDRESS 31..12 │ AVAIL │0 0│D│A│0 0│/│/│P║ ║ │ │ │ │ │ │S│W│ ║ ╚══════════════════════════════════════╧═══════╧═══╧═╧═╧═══╧═╧═╧═╝
The page directory will have only one entry (the present bit won't be set on the others). Here it is:
11000000 00001000 10000000 00000000
So this means that it is present, and that the corresponding page table is at 00000000 0000001 0001
, right shifted 12 bit. this evaluates to 0x11000
. (This is what i was aiming for, but does it actually mean this?). Now I understand the present bit, but what does read/write mean in this case? It isn't referring to a frame, so...
For the page table located at 0x11000
:
everything is almost the same, except for addresses.
11000000 0000000 00000000 00000000
11000000 0000100 00000000 00000000
etc
11000000 0000100 01000000 00000000
And that is the complete page table directory for the kernel. Is this correct? Are there any mistakes along the way? What does the read/write bit mean as a page directory entry?
See Table 4-5 in Intel's System Programming Guide, as well as Section 4-6. In a page directory entry, the R/W bit controls writability for all the pages in the corresponding page table, i.e. for the whole 4MB region of virtual memory. So if you clear the bit, all the pages in that region are read-only, regardless of what their individual R/W bits may be set to. If you set the bit, then the CPU consults the R/W bit on the page itself to decide whether writing is allowed.
In other words, the effective read-write status of a page is the logical AND of the R/W bits in all the paging structures that you walk to reach it. If you are trying to write, and the CPU encounters a cleared R/W bit at any stage in its page table walk, it can bail out early with a page fault. This principle continues to hold in 64-bit mode when there are more levels.
This may be convenient if you need to set a large region of memory to be read-only; you can just clear the R/W bit in the page directory entry, without iterating over all the pages in the table. A common example would be a Unix process that calls fork()
; all its writable memory needs to become read-only so that it can be copy-on-write.