Address Spaces

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.
PlayOS

Address Spaces

Post by PlayOS »

Hi all,

Just wondering what the most common (or best) way to handle address spaces between different processes?

Should I use a seperate page directory for each process or should I share a single page directory?

What are your thoughts either way?

Thanks.
Tim

Re:Address Spaces

Post by Tim »

Unless all your processes share most of their pages (and you don't mind rewriting the one page directory on every address space switch), it will be easier to use a separate page directory for each.
_PlayOS

Re:Address Spaces

Post by _PlayOS »

Thanks Tim,

How do I go about switching page directories, are there certain conditions that must be met like when you initially switch into paging?

thanks.
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:Address Spaces

Post by Pype.Clicker »

I recommend that the kernel code that performs thread management (threadCreate, threadDestroy, ...), process management and scheduling is available in every address space (i.e. by mapping that code with the appropriated kernel data in every page directory...).

This way, the kernel runs the same in every address space. (it is theorically possible, using task-based exceptions, task-based IRQ handlers and system calls to keep the whole kernel in a separated address space, but it sounds like a CPU-time waste to my senses)

if you want to switch to another address space, all you need to do is

Code: Select all

    mov eax, [next_thread.pdbr_address]
    mov cr3,eax
which will flush the page mapping cache and reload the page directory base address register (and thus any further memory reference will be interpreted in the new space).
Note however that this operation has a cost: more memory access (the current bottleneck in the architecture) just after the switch.

- at least your kernel code should be marked "global" page so that the switches don't trash the correspondance for it
- if you have a large area (4Mb) of pages that are contiguous in physical memory (that's what i have for my micro-kernel : first 4MB are the same in every space and map first 4MB of physical memory), use a huge (4MB) page rather than 1024 normal (4Kb) pages: you'll save page cache entries for the rest of the system ;)

and, before switching, ensure everything you need is available in the planned directory (i.e. there are pages that map your code) and that the code is still at the proper location (i.e. its physicall address == its logical address).
_PlayOS

Re:Address Spaces

Post by _PlayOS »

So basically the only restriction on changing the page directory is that the code that does the switch is on a page that has a linear address that is equal to its physical 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:Address Spaces

Post by Pype.Clicker »

yep. but for your convenience, its better either to load the kernel *after* paging is engaged or to keep the whole kernel with physical=linear mapping (otherwise, you'll need to relocate the whole kernel to its new base address)
_PlayOS

Re:Address Spaces

Post by _PlayOS »

Thats a bit rough then.

I thought that if the current linear address stays valid then the processor could continue without a problem, for example:

say that the eip register has 0x5ef45ef (Linear) in it, and I change the page directory, but set it up so that the current code is still at the same linear address, which would keep eip valid, wouldn't the processor just fetch eip (which points to 0x5ef45ef) and find a valid instruction execute that address and because this is where it was going anyway I thought that it might just keep going.

Is this just wishful thinking?

thanks.
Tim

Re:Address Spaces

Post by Tim »

The processor is happy as long as EIP doesn't need to change before and after you enable paging. The question is: how do you make linear address 0x5ef45ef valid without enabling paging?

What I do is program the GDT base address with a special value. My kernel starts at virtual address 0xC0000000, which needs to be valid even though paging isn't enabled (which it isn't, at the start). Note that the kernel could be loaded at any physical address.

Remember that the CPU adds the segment base address to the linear address to form a physical address. That is:

physical = base + linear

I have:

0x100000 = base + 0xC0000000

or:

base = 0x100000 - 0xC0000000 = 0x40100000

Although this is a negative value, the CPU doesn't seem to mind, and it just wraps round.
PlayOS

Re:Address Spaces

Post by PlayOS »

OK, well I already have paging enabled, what I am wanting to do it switch to a different page directory everytime the scheduler changes tasks so I was needing a fairly fast and efficient way to do it. That is why I was thinking that if I was at linear address X then if that address stayed consistent for every address space then the processor would just continue processing code at the same address.

What are the most common ways that this is handled?

Is it very common to have a different page directory for each task?

Thanks.
Tim

Re:Address Spaces

Post by Tim »

OK, the best way is to keep your kernel page tables mapped into every address space. That way kernel code and data are always valid, regardless of what user code is running.
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:Address Spaces

Post by Pype.Clicker »

most unices do have a separate page directory for each process. now, what you can also do is (provided that your processes are small enough) is to keep them all in the same address space and give them a separate LOCAL DESCRIPTOR TABLE, just reloading segment descriptors for the user mode (when kernel returns). this will surely be faster and will give you the ability to provide memory sharing with a low cost (just creating segments to the right places)...

damn! this sounds cool (tough not portable :) ... i need this in Clicker too :P
Tim

Re:Address Spaces

Post by Tim »

This thought occurred to me, too. What you could do is split the address space into four 1GB chunks, one of which is always the kernel. Then you could keep, say, the three last used processes in the bottom three chunks. Each of them would think they had a 1GB address space starting at address zero, because they each get a different segment (from the GDT or LDT).

Provided that the kernel is the only piece of software which is allowed to change selectors, the three are protected from each other. It also allows very fast IPC with a selector reload instead of an address space switch.
PlayOS

Re:Address Spaces

Post by PlayOS »

This sounds good, any ideas on how to prevent user programs from trying to force a selector change?
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:Address Spaces

Post by Pype.Clicker »

just mark the selectors it shouldn't access as being not present will cause troubles with multiprocessor systems ... imho, a separate LDT per process is the best way around (the only selectors a process can use are the one the kernel gave it :)
Tim

Re:Address Spaces

Post by Tim »

I think the selectors in this scheme should go into the GDT. If you think about it, you've got (say) four processes running in one address space, each looking at its memory using a different selector. How can that work if each process is using a different LDT?

The purpose of this scheme (well, my scheme at least) is to allow the kernel to access data from different address spaces at no cost. Making it switch LDTs to do that just adds extra complication. In any case, the user-mode apps won't know that this scheme is taking place; all they will notice is that they can only access 1GB instead of 4GB (or less). And once you start using the LDT actively (i.e. giving applications far pointers and expecting them to do their own seg reg loads) you break compatibility with most current 32-bit compilers, assemblers and linkers.
Post Reply