hey,
i have read some stuff on virtual memory and paging and so far i understand it except for the virtual memory addresses. just what ARE the addresses? like 0000 0000 - FFFF FFFF?
virtual memory addresses?
virtual memory addresses?
oh microsoft, microsoft, what souls you have dismayed
- jerryleecooper
- Member
- Posts: 233
- Joined: Mon Aug 06, 2007 6:32 pm
- Location: Canada
There is nothing preventing you from using address 0. The first dword of the realmode IDT is at physical address 0 at boot time, and it works just fine. It is just conventional to make 0 an illegal address in software. So it's more that you would just screw up the error-checking in 10 million C programs if you make 0 a legal variable address (but you can always make that the beginning of the virtial code-space for an app if you want).
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
When virtual memory is not enabled (CR0:Bit 31) memory addresses heading from the CPU to RAM are pretty much direct and unaltered. A address of 0x82736212 hits the RAM or circuit right before the RAM with the address of 0x82736212.i have read some stuff on virtual memory and paging and so far i understand it except for the virtual memory addresses. just what ARE the addresses? like 0000 0000 - FFFF FFFF?
[CPU]->[TLB]->[RAM]
When virtual memory is enabled all addresses pass through a extra stage. If I am not mistaken this is generally the TLB. The TLB will decode the address of 0x82736212 into another address using a set of tables. This set of tables reside in RAM (which were loaded earlier).
Code: Select all
struct PageTable{
unsigned long entry[1024];
};
struct PageDirectory{
unsigned long table[1024];
}
The page directory in total can govern 4GB of memory. (1024 * 4096 * 1024 = 4GB).
This entire structure, all tables associated with the directory and the directory it's self, is loaded into a cache which I am guessing is located on or right beside the TLB (circuit/chip/unit). To decode a address the TLB uses a algorithm. The below is the algorithm in a manner that you would use and can understand, but the concept is exactly the same! Just that the implementation may differ and most likely does in the TLB.
Let vaddress equal the virtual address.
Let paddress equal the physical address.
paddress = ((unsigned long*)(pd[vaddress >> 22] & ~0xFFF))[vaddress << 10 >> 22] & ~0xFFF
This is done for each address that needs to be decoded. The vaddress is the address to decode and the paddress is the decoded address. The TLB is decoding virtual addresses(vaddress) into physical addresses(paddress).
paddress = ((unsigned long*)(pd[vaddress >> 22] & ~0xFFF))[vaddress << 10 >> 22] & ~0xFFF
The 'pd' variable is a pointer to the page directory.
If we turn the equation around we can map physical address to virtual ones.
((unsigned long*)(pd[vaddress >> 22] & ~0xFFF))[vaddress << 10 >> 22] = paddress
If vaddress equals 0x8273000, and paddress equals 0x27000. Then the virtual address 0x8273000 would always decode into 0x27000 when going through the TLB.
((unsigned long*)(pd[0x8273000 >> 22] & ~0xFFF))[0x8273000 << 10 >> 22] = 0x27000
To make a 1:1 mapping which is where virtual addresses equal physical address you could do:
Code: Select all
for(unsigned int x = 0; x < (1024 * 1024); ++x)
{
((unsigned long*)(pd[(x << 12) >> 22] & ~0xFFF))[(x << 12) << 10 >> 22] = x << 12;
}
Of course there are special flags used in the lower twelve bits. These flags are _very_ important and having them all zeroed will result in CPU fault.
#define V_PRESENT 0x1
#define V_WRITE 0x2
#define V_USER 0x4
((unsigned long*)(pd[0x8273000 >> 22] & ~0xFFF))[0x8273000 << 10 >> 22] = 0x27000 | V_PRESENT | V_WRITE | V_USER
Also the actual tables need there flags set.
Thanks for that, Kevin. I needed to see it again. I think you forgot to mention that you still need to copy the bottom 12 bits of the vaddress into the paddress after doing the translation: | (vaddress & 0xFFF)
And urxae is right, of course. You can put 4k of _init code into virtual address 0 if you want to, but after it is run, you need to set the Page Table entry for address 0 to prevent any access to that 1st 4k page. This gives you instant hardware detection of any attempts by software to access any NULL pointers.
And urxae is right, of course. You can put 4k of _init code into virtual address 0 if you want to, but after it is run, you need to set the Page Table entry for address 0 to prevent any access to that 1st 4k page. This gives you instant hardware detection of any attempts by software to access any NULL pointers.