Paging confusion

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
trime

Paging confusion

Post by trime »

I'm very confused as to how I can safely change the page tables. My kernel is currently loaded at the 2MB mark, and I set up a linear translation for the first 16MB of memory. If I want to load in a program that expects to also start at the 2MB mark for instance, I need to change the physical address corresponding to virtual 2MB, but then immediately things will go wrong, because all of a sudden eip is pointing to a totally different part of memory. How do I get around this? I seem to vaguely recall reading somewhere that people loaded the kernel very high ( close to 4GB ) but I can't seem to find any hint of that in the early versions of linux I have the source for.

Can anyone shed some light on my confusion? Thanks :)
Tim

Re:Paging confusion

Post by Tim »

Move the kernel somewhere else, then, or have programs load at a different address. Mobius has kernel space from 0x80000000 upwards; Windows NT from 0x80000000 or 0xC0000000 upwards; Linux from 0xC0000000 upwards.

On the other hand, you could map the kernel in the bottom part of the address space, and require that programs are linked to run near the top. One downside of this approach is that you can't easily run V86 mode tasks.
trime

Re:Paging confusion

Post by trime »

Ok that sounds like what I expected but for one problem:

The paging is set up after I load my C++ kernel, and I can't load the kernel into 0xC0000000 until I start up paging obviously. Does this mean I'm going to have to tell the linker that I want it assembled at 0xC0000000 and then get the boot loader to set up the paging in assembly? My understanding of data structures in assembly isn't that great you see... Or am I missing an easier option?

Thanks
Tux

Re:Paging confusion

Post by Tux »

The easier option would be follow your own standards. Compability is why you have to pay. Wouldn't life be a little easier without the A20?
trime

Re:Paging confusion

Post by trime »

Hehe right. I'd really prefer to be able to load programs at the low end of memory, so I guess I'll wrestle with some assembly code to set up paging. Thanks for the help.
Tim

Re:Paging confusion

Post by Tim »

I explained the trick for this in my memory management 1 tutorial.

A summary:
You want to put the kernel at a high virtual address, say 0xC0000000. But you want to load it at a low physical address, say 0x100000. How can you do this? Paging -- but paging isn't available until the memory manager has been initialised.

Two ways to get around this:
1. Use all position-independent code until paging has been enabled. Hard to write and debug.

2. Use the GDT to perform the translation until paging has been enabled. Recall how segmentation works:
Address + Base = Linear
That is, the CPU adds the segment's base address to all addresses given to it to form a linear address. But we want to go backwards: we want to subtract a number from 0xC0000000 to turn it into 0x100000. So:
0xC000xxxx + Base = 0x10xxxx
Base = 0x10xxxx - 0xC000xxxx
Base = -0xBFF00000 (the same as 0x40100000)
A negative number! Surely that won't work! The CPU will add that to the addresses we give it and run off the top of memory!

It won't. Because of the way hardware adders work, the linear address generated will wrap round. So it's safe to set the base address to a high number such as 0x40100000 for the example above. The CPU will add it to the addresses we give it (which are higher than 0xC0000000), the address generated will wrap round, resulting in a low address (higher than 0x100000).
Post Reply