Multitasking comprehension problem

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:

Multitasking comprehension problem

Post by max »

Hey guys! :)

I am currently proceeding my development on my operating system.
By now paging works as follows: The kernel has its own directory. I can create user space directories by giving a start and end address (Paging::createUserspace(0x10000000, 0x20000000) for example). To do that I copy the kernel directory to a blank directory, create new pages for user space and insert them into the new directory. Is this approach correct?

So now the time has come for me to implement multitasking, but I have a little problem understanding it right. This is how I got it:
- Paging is enabled & user directory exists
- Current directory is kernel directory
- The scheduler calls
- Store the kernel register values
- Switch to the user directory
- Restore the processes register values
- Let the process work until scheduler calls
- Store the process register values
- Switch back to kernel directory
- Restore the kernel register values
- Repeat

Is this right? The only problem I have there is, if I copy the kernel directory to the user space directory to keep executing, isnt there the danger that the user code could change the contents of my kernel memory? Do I really have to copy the kernel directory or is there another way?

Thanks in advance! :)
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Multitasking comprehension problem

Post by Brendan »

Hi,
max wrote:Is this right? The only problem I have there is, if I copy the kernel directory to the user space directory to keep executing, isnt there the danger that the user code could change the contents of my kernel memory? Do I really have to copy the kernel directory or is there another way?
Normally the kernel is mapped into every address space. For example, each process might only be able to use addresses from 0x00000000 to 0xBFFFFFFFF in its virtual address space, and the kernel might be mapped into the addresses from 0xC0000000 to 0xFFFFFFFF so that it is the same in every address space.

In this case task switching typically goes like this:
  • a task is running happily
  • something happens to cause the CPU to switch to the kernel. This might be because the task called the kernel's API, or because the task caused an exception, or it might not have been caused by the task itself (e.g. any IRQ).
  • the kernel starts handling whatever caused it to get the CPU (the kernel API call, the exception, the IRQ)
    • the kernel decides (for whatever reason) to do a task switch. Reasons include the task using all the time it was given, the task blocking (waiting for something), an IRQ causing another task to unblock/stop waiting and preempt, etc.
    • the kernel saves its registers for this task
    • the kernel loads its registers for the next task (possibly including CR3)
  • the kernel finishes whatever it was doing, and returns control back to the task
  • a task is running happily again
Note that the kernel may not decide to do a task switch, and may return to the same task that was running before.

Of course this isn't the only way (there are alternatives that do work) - it is the most common way it's done, and also probably the easiest to understand.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
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: Multitasking comprehension problem

Post by Combuster »

Let's start with the proper terminology: the "address space" is the memory laid out to be seen by a process (or chip). A "directory" is an index, typically on your harddisk.

On x86, paging can make the linear address space look different from the physical address space. The mapping is made by data structures called "page tables" and "page directories". Creating a new page directory and page tables implies creating a new address space.

Address spaces contain the entirety of usable memory. Protection mechanisms exist to cut that into separate parts where access is denied for userspace, for writing, or for using directly as code.
max wrote:I am currently proceeding my development on my operating system.
By now paging works as follows: The kernel has its own directory. I can create user space directories by giving a start and end address (Paging::createUserspace(0x10000000, 0x20000000) for example). To do that I copy the kernel directory to a blank directory, create new pages for user space and insert them into the new directory. Is this approach correct?
It could probably work, but it looks rather arbitrarily restricted. Typically a portion of the address space is reserved for the kernel, and the remainder is userspace by design. In between there are large gaps of space that do not point to anything. Hard limiting a process to 256MB RAM max is not a good idea either to keep a more elaborate firefox session alive for long. Also, I hope you are not preallocating that amount of RAM either.

Also, by duplicating the kernel into other address spaces, the kernel technically no longer has an address space of its own. Instead you get the almost universal standard of the kernel being present in all address spaces. Many implementations don't treat that first address space different in any way. It only becomes special because its age makes it quite likely to hold a mission-critical task.
"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 ]
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: Multitasking comprehension problem

Post by Kevin »

Okay, so while I logged in we already got two answers on how it's typically done, so I can leave that part out and just have a look at what you were planning to do.
max wrote:I am currently proceeding my development on my operating system.
By now paging works as follows: The kernel has its own directory. I can create user space directories by giving a start and end address (Paging::createUserspace(0x10000000, 0x20000000) for example). To do that I copy the kernel directory to a blank directory, create new pages for user space and insert them into the new directory. Is this approach correct?
I can't call it exactly wrong, because I think you could get something working this way, but it doesn't make a whole lot of sense.

First thing is that you don't really have a separate kernel page directory. You already copy it into each userspace directory because you need it for IDT, GDT, TSS and some of the kernel (the task switching code) is running with the userspace directory, too. Now if the kernel is already mapped, there's little reason to switch to a different directory, because the current one is already good enough.

The other thing that you don't really need depending on what your kernel looks like is saving and restoring kernel register state. If you switch tasks somewhere in the middle of C code, then you probably need it. More commonly, however, is C code only called from an interrupt handler that effective implements the task switch. Then you don't need the register values any more.

I remember that you speak German, so these parts of the Lowlevel tutorial series could help you a bit, they explain that approach in more detail:
http://www.lowlevel.eu/wiki/Teil_5_-_Interrupts
http://www.lowlevel.eu/wiki/Teil_6_-_Multitasking
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: Multitasking comprehension probleme

Post by max »

Hey guys,

thank you for the information! :)
Ive read a bit more and finally understood my problem.

Ill keep you on track with my further progress!

@Kevin ja stimmt ich komm aus Deutschland ;)

Greetings,
Max
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Multitasking comprehension problem

Post by bluemoon »

The above answers are definitely the standard and good answer, but I would like to add a few ideas on top of that.

In some stage your kernel will be more or less allocate address dynamically and such address are required(*) to be visible across processes,
to keep such address zone synchronized, there are a few approach:

A 32-bit 2 level paging: version control
- Keep a master copy + a version number; whenever the zone changes (note that an allocation as small as 4KB might require to propagate to all process), the changes are commited to the currently page structures and the master copy, and the version number is incremented.
Upon switching address space, if the target version is not equal the master version, a synchronize is performed.

PAE or PM4L:
- Since the kernel may occupy a level2 node, which cover gigabyte scale which is more or less enough, if you limit the size of global address zone you may just share the same (one, or a few) node on all process's address space. Changes on level1(PTE) will be synchronized by design.
- or extend to use the version control method for unlimited size.



*) If a kernel allocate some memory, which require adding new PT/PD entry; then later on it switch to another process, in the new process the page structure may be out of sync and that newly allocated memory is no longer accessible - that's why a synchronization mechanism is required, either done when address layout changes, or done lazily until it is needed.
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: Multitasking comprehension problem

Post by Kevin »

bluemoon wrote:- Keep a master copy + a version number; whenever the zone changes (note that an allocation as small as 4KB might require to propagate to all process), the changes are commited to the currently page structures and the master copy, and the version number is incremented.
Upon switching address space, if the target version is not equal the master version, a synchronize is performed.
It's probably worth noting that you don't need a separate master version, but you can just keep a pointer to the most recently updated context, which then serves as the master copy.

Other people just decide that a few kilobytes aren't worth the hassle and just allocate all page tables for the kernel memory area upfront, so that the page directory for this area never changes.
Developer of tyndur - community OS of Lowlevel (German)
Post Reply