[Paging] How to fill the stack on process creation?

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
User avatar
max
Member
Member
Posts: 616
Joined: Mon Mar 05, 2012 11:23 am
Libera.chat IRC: maxdev
Location: Germany
Contact:

[Paging] How to fill the stack on process creation?

Post by max »

Hey guys! :)

I'm currently in the following situation. My kernel is running in the higher half, starting at 0xC0000000. In my initial paging directory I created the tables at index 0 and 768-1022 as kernel-tables (to ensure that any change to the kernel space happens in all processes) and entry 1023 mapped to the directory itself. So far so good - now the time has come to implement preemptive multitasking. My problem is the following: I am now inside of the setup function of my kernel. Now I want to kick off the first process. To do so, I have to create a copy of the page directory (copying only the kernel tables), so entries 1-767 can be used as user space.

Now, I ask my physical page allocator for a new page to create a directory for this new process. But, as currently the initial page directory is enabled, I have no access to the physical pages. The same problem occurs with the kernel stack - I need to put the initial register values on it, to allow my interrupt stub to pop them off the stack initially. And when I finally want to load a binary image to that space, I again have that problem.. How do you solve this?

I figured out these two methods:
a) Temporarily map the pages of the directory, the kernel stack and so on to the current (process-creating) directory, and unmap them after creating the process? (this seems dirty to me..)
b) Fetch the current page directory, temporarily switch to the newly created directory, and after creation switch back? (this seems even dirtier, also I am still forced to map at least the new page directory temporarily to copy the values)

Also, my physical page allocator does not give back zeroed pages, for the same reason as above, and I also cannot 0 all pages when pushing them into the allocator, that would be really slow. So that is another place where I temporarily have to map..

Is there an elegant solution for all of this?

Thanks a lot!
Greets, Max
Last edited by max on Mon May 05, 2014 2:13 am, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: How to fill the stack on process creation?

Post by Combuster »

As you said, you will have to map memory one way or another if you're not considering disabling paging altogether (which is probably even more ugly - especially for a higherhalf kernel).

At any rate, being able to randomly map pages is something you'll be using on numerous occasions anyway...
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
max
Member
Member
Posts: 616
Joined: Mon Mar 05, 2012 11:23 am
Libera.chat IRC: maxdev
Location: Germany
Contact:

Re: How to fill the stack on process creation?

Post by max »

Combuster wrote:At any rate, being able to randomly map pages is something you'll be using on numerous occasions anyway...
Okay I already thought that this would be the case.. :P
But, is there some kind of best practice to implement this? Like, you have something like a function "virt_addr mapTemporarily(phys_addr)" that uses some address space (like 0xB0000000 to 0xC0000000)? It just feels a little like misung these addresses :mrgreen:

(using that area, would also conflict a little with my idea of putting the kernel stack to 0xBFFFF000 and the user stack to 0xBFFFE000, but okay, i can put them somewhere else)
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: How to fill the stack on process creation?

Post by thepowersgang »

Hey, that's what I do. For now I have a range of 16 pages set aside around the top of the address space (just above the area I use for hardware mappings) that are used by MM_MapTemp and MM_FreeTemp. It works pretty well for those few cases when you need to manipulate something outside your current address space.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: [Paging] How to fill the stack on process creation?

Post by bluemoon »

my mmap can also take physical address as a parameter:

Code: Select all

    int          MMU_mmap   (void* mem, MMU_PADDR paddr, size_t size, unsigned int flag);
Now it become handy to map/unmap any physical address to the "temp virtual address pool".
User avatar
Pancakes
Member
Member
Posts: 75
Joined: Mon Mar 19, 2012 1:52 pm

Re: [Paging] How to fill the stack on process creation?

Post by Pancakes »

For the initial process creation Linux creates the address space for init then switches to that space, and works with the memory from there.
http://lxr.free-electrons.com/source/init/main.c#L780
http://lxr.free-electrons.com/source/fs/exec.c#L1440

You should switch to the new process directory (or use the existing for the new process) and I think you should be able to just leave it at that since your kernel is still mapped in. Then once your scheduler fires it can actually switch to the process thread (and of course either set CR3/TTBR or not if it is already set but writing it again should not hurt anything and keeps you from having to insert a condition in your scheduler code path). Your very first page directory could even be used for the process maybe? Unless, you are going to use it somewhere else.

The Way I Am Doing It Currently

My way is likely not the fastest by any means. But, I just switch to the target address space. I use the address space already created for the process (not a temporary one). I flush the entire TLB for that area so of course there is a performance hit. But, I am not doing this every second. The only reason I have to switch to the target address space is to manipulate memory there like copying the ELF sections into memory. I can actually create a process and setup it's threads with out switching, but I understand you are not in that situation. I like doing it this way because it is straight forward and simple.

Also, for creating threads I do not have to switch address spaces. I just create a new thread structure and place it into the system's scheduler infrastructure. If you have one kernel stack per thread then you could consider having the stack inside the kernel address space since that would prevent you from having to switch to the target address space just to set it up.

I guess I should add that I am on ARM so I have two different page directories set at one time. One is for the kernel space and the other is for user space so when I boot up the user space is simply set back to the kernel. So I do not have the problem of having to use a page directory for the original process but rather the problem of having to create one to begin with (and always using the kernel directory).
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: How to fill the stack on process creation?

Post by Kevin »

max wrote:But, is there some kind of best practice to implement this? Like, you have something like a function "virt_addr mapTemporarily(phys_addr)" that uses some address space (like 0xB0000000 to 0xC0000000)? It just feels a little like misung these addresses :mrgreen:
Why do you need a separate area for temporary mappings? Can't you just take the general kernel area?

And yes, tyndur has an interface that looks somewhat like what you suggested (even though it's just a convenience wrapper around mmc_automap() which has a few more arguments):

Code: Select all

vaddr_t vmm_kernel_automap(paddr_t start, size_t size);
void vmm_kernel_unmap(vaddr_t start, size_t size);
Developer of tyndur - community OS of Lowlevel (German)
User avatar
max
Member
Member
Posts: 616
Joined: Mon Mar 05, 2012 11:23 am
Libera.chat IRC: maxdev
Location: Germany
Contact:

Re: How to fill the stack on process creation?

Post by max »

Thanks for the suggestions!! Looks quite much like the things I'd imagined.
Kevin wrote:Why do you need a separate area for temporary mappings? Can't you just take the general kernel area?

And yes, tyndur has an interface that looks somewhat like what you suggested (even though it's just a convenience wrapper around mmc_automap() which has a few more arguments):

Code: Select all

vaddr_t vmm_kernel_automap(paddr_t start, size_t size);
void vmm_kernel_unmap(vaddr_t start, size_t size);
Currently my kernel is layouted like this in higher memory:

0xC0000000 - ca. 0xC0500000: Kernel binary
0xC0500000 - 0xC1000000: Kernel heap (grows upwards if necessary)
0xFFC00000 - 0xFFFFFFFF: The recursively mapped directory

and now I'm planning to use the areas 0xFFB00000 - 0xFFC00000 as temporary addresses for these special cases. Thats how I seperate it. ;)
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: [Paging] How to fill the stack on process creation?

Post by bluemoon »

Normally you only need to map one single new page for the startup thread's stack.
Everything else, like loading the executable, can be done on new thread's own context.
Post Reply