Switch a task... and stop IRQs!

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

Switch a task... and stop IRQs!

Post by falconfx »

Hello! I'm new to this forum and this is my first question about OS Development. :D

I am very expert at C/C++ Development and a bit at ASM coding ;)

I started coding my own OS about 2 months ago, and I implemented successfully the GDT, the IDT, exceptions, IRQs (timer, keyboard...) and some Paging (just the base...)

Now I'm trying to get work a simple TSS-based Multitasking Environiment: I wrote the "create_task" function which creates a new task starting from its name, entry function, privilege level and priority. For this I use two lists, one for the tasks and one for the TSSs. I use the function "gdt_add_tss" which adds the new TSS to the GDT and returns its 'selector'.

So I create three tasks: one dummy (just for the LTR command), one for the 'init' program and one for a test task, which prints some 'A' on the console screen. Then I use the lcall/ljmp instruction to switch between the tasks in Timer IRQ. The problem is this: my kernel successfully switches to the 'init' function that prints a welcome message and then to my test task that works as well; but then IRQs stop firing!!! :(

The scheduler stops, the keyboard doesn't respond... it should print the scancode on the screen but no, I can't even reboot the system! >:(

Can someone help me??? I'll post the code if it's necessary. ;D
Ushma

Re:Switch a task... and stop IRQs!

Post by Ushma »

I had a problem like this in one of my schedulers. The timer ISR would check for expired quantum, and if so, schedule(). The problem was, I'd send EOI *after* this code, so when there was a scheduling, EOI would never happen, and a new task would start, the PIC never having been sent EOI. So IRQs wouldn't fire anymore. Maybe something similar is going on in your system?
falconfx

Re:Switch a task... and stop IRQs!

Post by falconfx »

Ushma wrote: I had a problem like this in one of my schedulers. The timer ISR would check for expired quantum, and if so, schedule(). The problem was, I'd send EOI *after* this code, so when there was a scheduling, EOI would never happen, and a new task would start, the PIC never having been sent EOI. So IRQs wouldn't fire anymore. Maybe something similar is going on in your system?
Thanks Ushma, you're right. But now, what can I do? Probably I have to change multitasking mode...

What do you think about the stack-swapping method? Is it fast?
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:Switch a task... and stop IRQs!

Post by Pype.Clicker »

falconfx wrote: What do you think about the stack-swapping method? Is it fast?
It mainly gets faster when you have many intra-process switches (e.g. switching between two threads of the same address space), and only if you take care of not reloading CR3 when staying in the same address space.

Otherwise, the performance penalty is not measurable on modern systems, afaik.
CloudNine

Re:Switch a task... and stop IRQs!

Post by CloudNine »

I'm sure nothing happens if you reload the cr3 register with the same value y'know.
bluecode

Re:Switch a task... and stop IRQs!

Post by bluecode »

Pype.Clicker wrote:
falconfx wrote: What do you think about the stack-swapping method? Is it fast?
It mainly gets faster when you have many intra-process switches (e.g. switching between two threads of the same address space), and only if you take care of not reloading CR3 when staying in the same address space.

Otherwise, the performance penalty is not measurable on modern systems, afaik.
Don't you use separate page directories/cr3 in every thread? Not because of "really" different address spaces, but only because of different stacks?
Kim

Re:Switch a task... and stop IRQs!

Post by Kim »

CloudNine wrote: I'm sure nothing happens if you reload the cr3 register with the same value y'know.
Even if you load the cr3 register with the same value it will flush the caches, example if you would change something in the current page dir and setting the same value for cr3 wouldn't flush the cach you would have a big problem (without using invalidate instruction)...
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:Switch a task... and stop IRQs!

Post by Pype.Clicker »

bluecode wrote: Don't you use separate page directories/cr3 in every thread? Not because of "really" different address spaces, but only because of different stacks?
No. Each thread will have to receive its own fresh stack and the system is responsible to co-locate all those stacks together. A trivial approach is of course to let the user allocate the future stack space (or at least, give a hint on the maximal stack size) ...

but i also plan to allow "expansible stack" by "tunnelling" a stack that has reached its limit to another place ... that's something i definitely need to write a paper on ... it's staying on my mind for too long unused and i fear it'll get garbage-collected soon if i don't share it in a near future ...
DruG5t0r3

Re:Switch a task... and stop IRQs!

Post by DruG5t0r3 »

You might be clearing the IF flag in eflags when you switch to your other task.
JoeKayzA

Re:Switch a task... and stop IRQs!

Post by JoeKayzA »

Pype.Clicker wrote: but i also plan to allow "expansible stack" by "tunnelling" a stack that has reached its limit to another place ... that's something i definitely need to write a paper on ... it's staying on my mind for too long unused and i fear it'll get garbage-collected soon if i don't share it in a near future ...
Do you mean by placing a guard page at the top of a stack, and when a thread faults in there, you replace %esp with some newly allocated stack space? Smart...

cheers Joe
bluecode

Re:Switch a task... and stop IRQs!

Post by bluecode »

Pype.Clicker wrote:
bluecode wrote: Don't you use separate page directories/cr3 in every thread? Not because of "really" different address spaces, but only because of different stacks?
No. Each thread will have to receive its own fresh stack and the system is responsible to co-locate all those stacks together. A trivial approach is of course to let the user allocate the future stack space (or at least, give a hint on the maximal stack size) ...
what do you exactly mean with co-locate? Do you have the same virtual address for the stack in every thread (this would involve switching address space, when switching from thread to thread) or don't you?
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:Switch a task... and stop IRQs!

Post by Pype.Clicker »

@joe: yes. You got the basics of it. In addition to "send ESP to another location", we need to take care that the current stack frame is preserved, for instance, by having the last function's frame mapped in both ancient stack and new stack. That way, any reference taken from the old stack's values are still valid, such as reference to ESP or EBP things (yep, EBP needs to be 'wrapped' too)

@bluecode: when i say "co-locate" i mean they are both living in the same address space, at different virtual addresses. When you switch threads, you just switch to another ESP value. nothing more, nothing less, and they still can damage each other's stack such as they could damage each other's whatever else.

This also means that the usercode has to tell how much space each thread should use as stack, or be happy with the kernel's default value.
`When I use a word,' Humpty Dumpty said, in rather a scornful tone, `it means just what I choose it to mean -- neither more nor less.'
bluecode

Re:Switch a task... and stop IRQs!

Post by bluecode »

@pype: sorry, but co-locate didn't make any sense to me at first glance and I didn't find it in any dictionary and I've got the good old "Oxford Advanced Learner's Dictionary". Only http://babelfish.altavista.com/ translated "co-locate" into german, but "Co-finden sie" is actually german nonsense ;D . So, I'm really sorry if that question bothered you.
AR

Re:Switch a task... and stop IRQs!

Post by AR »

http://en.wikipedia.org/wiki/Co
A prefix (form of com-, signifying with, together, in conjunction, joint)
Whenever something has a co- prefix it usually indicates 2+ things working together. (eg. co-operate)

@Pype: How exactly do you "preserve the stack frame", how would you even determine the size to begin with? ESP and EBP would be configured for the function currently executing which may have just "sub $12, %esp; movl $6, (%esp)" which now requires ESP to be redirected, how do you handle it (especially if -fomit-frame-pointer/-O* was used, or better yet, written in Assembly with only ESP used and EBP being used as an additional general register)?
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:Switch a task... and stop IRQs!

Post by Pype.Clicker »

@bluecode: np. The humty-dumpty quote should have proved you i was in a joking-day mode...

@AR: the 'stack tunnelling' trick of course puts expectation on what code the compiler can generate. A first possible approach is to have in your binary program a collection of "stack size" for your function and resolve the EIP of guard-hitting function to guess what's (in pages) the size of the current stackframe.

Of course, this doesn't work with

Code: Select all

int myFunc(int some_size)
{
   char myData[some_size];
   some_code();
}
My favourite approach remains to make use of EBP and ESP to tell what has to be tunnelled. Whatever beyond ESP is - by definition - unsafe and thus it doesn't need to be tunnelled at all. Keep in mind, too, that i make use of segmentation to tell if there's a stack overflow. So even if you jump over the stack guard page with

Code: Select all

void grunt()
{
    char fool[8192];
    fool[0]=0xdeadbeef; // stack grows downward, so fool[0] is the furthest you can go
}
you'll be caught by the Stack Fault.

The other thing is that you have to know how deep you should keep things. EBP is a hint, but [ EBP ] is the real stuff. You'll be accessing local variables and arguments with EBP and arguments cannot go further than the previous stackframe's base.

Indeed, ASM-coded and -fomit-stackpointer are showkillers. Probably those programs should tell the OS they don't allow stack tunnelling, or they should manually maintain a "keep_base_stack" pointer that will be used as lowest stack address to be kept.
Post Reply