Hi,
I am reading wiki articles about paging, and I think I understand how translation of adress from linear adress space to physical adress space works.
But, how is it designed to work with multiple processes.
Lets say we are switching from process A to process B, should I clear paging structures and and load them with new mapping for process B? It is doable, but seems like a too much work after each switch, considering there will be lots of switching in a second.
How about switching back to A later? Should I create a copy of old mapping each time I switch from a process? This, again, seems a lot of work after each task switch.
How do you even switch a task? If an interrupt occur while userspace process is doing work, kernel is not mapped, so interrupt handlers cannot be called.
I could keep kernel mapped at all times, but wouldn't it make kernel memory accessable to each process? Wouldn't that negate the whole point of having memory protection?
I am probably missing some very important key points here, otherwise, paging doesn't make much sense to me.
Best Regards,
How is paging supposed to work in multiprocessing kernel
-
- Member
- Posts: 28
- Joined: Thu Sep 27, 2018 5:10 pm
- Libera.chat IRC: yasar
- Location: Turkey
- Contact:
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: How is paging supposed to work in multiprocessing kernel
Normally each process has its own set of page tables. When you switch between them, you only have to change the top-level pointer to the paging structures. On x86, this is accomplished by changing CR3.yasar11732 wrote:Lets say we are switching from process A to process B, should I clear paging structures and and load them with new mapping for process B? It is doable, but seems like a too much work after each switch, considering there will be lots of switching in a second.
How about switching back to A later? Should I create a copy of old mapping each time I switch from a process? This, again, seems a lot of work after each task switch.
Most architectures provide user/supervisor separation at the page level, so you actually can keep the kernel mapped at all times without giving direct access to userspace. However, some architectures provide a mechanism to automatically map the kernel when an interrupt or system call occurs and unmap it upon returning to userspace. If your target architecture doesn't provide this functionality but you really need to have the kernel unmapped while userspace is running (e.g. to increase usable address space or prevent speculative execution vulnerabilities), you can use a stub that's always mapped to handle mapping and unmapping the rest of the kernel during privilege changes.yasar11732 wrote:How do you even switch a task? If an interrupt occur while userspace process is doing work, kernel is not mapped, so interrupt handlers cannot be called.
I could keep kernel mapped at all times, but wouldn't it make kernel memory accessable to each process? Wouldn't that negate the whole point of having memory protection?
-
- Member
- Posts: 426
- Joined: Tue Apr 03, 2018 2:44 am
Re: How is paging supposed to work in multiprocessing kernel
What @Octocontrabass said, but there have been systems that also maintain a single paging directory, that is updated at task switch in-situ.yasar11732 wrote:Hi,
I am reading wiki articles about paging, and I think I understand how translation of adress from linear adress space to physical adress space works.
But, how is it designed to work with multiple processes.
Lets say we are switching from process A to process B, should I clear paging structures and and load them with new mapping for process B? It is doable, but seems like a too much work after each switch, considering there will be lots of switching in a second.
How about switching back to A later? Should I create a copy of old mapping each time I switch from a process? This, again, seems a lot of work after each task switch.
SCO OpenServer worked like this. There was a single static page directory page, with the upper entries pointing to kernel page tables, and the lower entries (I don't know the user/kernel cut-off off hand) pointing to the current user process.
Given its vintage, we're not talking a huge amount of page table entries being required. Given 4K page sizes, and a 256KB process working set, you might only have to clear out 64 ptes per task switch, then the new task can fault back in ptes on demand.
My own kernel goes for a hybrid approach. Page tables are transient, and assigned to an address space on an as needed purpose, so a process that is sleeping for a long time may lose its page tables.
I interface with my MMU using a TLB like interface, without exposing the hardware MMU data structures at all to the rest of the kernel.
So, given a user address space handle, which is itself just a segment map, I switch to a user address space using:
Code: Select all
if (old->process != thread->process) {
if (thread->process) {
vmap_set_asid(thread->process->as);
} else {
vmap_set_asid(0);
}
}
The hardware MMU protects the kernel portion of the address space from user access. Page table entries can be marked as supervisor only, which means they're only accessible in kernel mode. User mode access to pages mapped by such supervisor only page table entries will produce a trap, and the kernel will generate a SIGSEGV signal or access violation exception to your process in response.yasar11732 wrote: How do you even switch a task? If an interrupt occur while user space process is doing work, kernel is not mapped, so interrupt handlers cannot be called.
I could keep kernel mapped at all times, but wouldn't it make kernel memory accessible to each process? Wouldn't that negate the whole point of having memory protection?