handling exceptions with taskgates
handling exceptions with taskgates
I read in intel manual that using taskgates is more interestiong than intgates since the task context is automatically saved while calling exceptions
so I did a simple test with GPF exception, and it seems to work, but I have a little problem :
when the exception is called for the first time, everything is ok, but when it is called again, it doesn't work
I thing this is due to the fact that EIP is saved to its tss, so how can I do to make EIP re-point to the beginning of my GPF handler code ?
so I did a simple test with GPF exception, and it seems to work, but I have a little problem :
when the exception is called for the first time, everything is ok, but when it is called again, it doesn't work
I thing this is due to the fact that EIP is saved to its tss, so how can I do to make EIP re-point to the beginning of my GPF handler code ?
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:handling exceptions with taskgates
Beware that task gates are not always interresting, especially for interrupts (due to extra context switch overhead plus the fact that they'll generally be handled in a different address space than the faulting code). Any context information will have to be looked up in the outgoing TSS:
Code: Select all
epi_ptr=&((struct TSS*)(BaseAddress(currTSS()->backLink))->eip);
Re:handling exceptions with taskgates
Hi,
It looks really strange because the CPU will return from "jmp next_thread:0" on the next exception (almost like the jump is a call). Typically the "jmp next_thread:0" would be done by your scheduler, which looks more sensible:
While task gates do have plenty of overhead, they are also the ONLY way you can reliably handle some exceptions (e.g. double fault). In this case the overhead is irrelevant, as double faults shouldn't be generated often...
Cheers,
Brendan
Because the interrupt handler is running as a seperate task, you have to do something like:aladdin wrote: I read in intel manual that using taskgates is more interestiong than intgates since the task context is automatically saved while calling exceptions
so I did a simple test with GPF exception, and it seems to work, but I have a little problem :
when the exception is called for the first time, everything is ok, but when it is called again, it doesn't work
I thing this is due to the fact that EIP is saved to its tss, so how can I do to make EIP re-point to the beginning of my GPF handler code ?
Code: Select all
exception_handler:
/* code to handle exception goes here */
jmp next_thread:0
jmp exception_handler
Code: Select all
exception_handler:
/* code to handle exception goes here */
call find_another_task_to_run_and_switch_to_it
jmp exception_handler
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.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:handling exceptions with taskgates
hmm ... that 'jmp task' thingy looks messy to me.
The interrupt handler called by a taskgate should be terminated using "IRETD", which will detect the fact we're in a nested task (NT bit, iirc) and perform the task return, clear the 'Busy' bit in the handler's descriptor, so that the handler can be called again.
If you attempt to do something like "jump to next task", you'll clear the handler too, but you also leave the caller (faulty) task busy, so any attempt to return to it will be going wrong ...
The interrupt handler called by a taskgate should be terminated using "IRETD", which will detect the fact we're in a nested task (NT bit, iirc) and perform the task return, clear the 'Busy' bit in the handler's descriptor, so that the handler can be called again.
If you attempt to do something like "jump to next task", you'll clear the handler too, but you also leave the caller (faulty) task busy, so any attempt to return to it will be going wrong ...
Re:handling exceptions with taskgates
Hi,
Which actually looks worse!
To jump to a different task (ie. not the one that was interrupted) you have to clear the interrupt task's busy bit in it's TSS segment descriptor (unless you never want to run the interrupted task again).
Sorry about my mistake - I used hardware task switching for a kernel about 8 years ago where the only task gate was used for the double fault handler. The double fault handler terminated the interrupted task (and didn't care about returning to it).
Cheers,
Brendan
You're right - for exception handlers that return to the task that was interrupted (and IRQ handlers) it should be:Pype.Clicker wrote: The interrupt handler called by a taskgate should be terminated using "IRETD", which will detect the fact we're in a nested task (NT bit, iirc) and perform the task return, clear the 'Busy' bit in the handler's descriptor, so that the handler can be called again.
Code: Select all
exception_handler:
/* code to handle exception goes here */
iretd
jmp exception_handler
To jump to a different task (ie. not the one that was interrupted) you have to clear the interrupt task's busy bit in it's TSS segment descriptor (unless you never want to run the interrupted task again).
Code: Select all
exception_handler:
/* code to handle exception goes here */
clear_interrupted_task_busy_bit();
jmp new_task:0
jmp exception_handler
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.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:handling exceptions with taskgates
no! no "jmp exception handler" stuff is required. The TSS isn't modified by a return, so if the handler task isn't switched off, its TSS will still hold the handler state for the next run ...
Re:handling exceptions with taskgates
Hi,
For e.g.:
See "Section 6.3 Task Switching" of Intel's "IA-32 Intel Architecture Software Developer?s Manual Volume 3: System Programming Guide", where the steps involved for all types of task switch are detailed (with any differences between task switch types noted), and the paragraph which immediately follows the list of steps:
"The state of the currently executing task is always saved when a successful task switch occurs. If the task is resumed, execution starts with the instruction pointed to by the saved EIP value, and the registers are restored to the values they held when the task was suspended."
Cheers,
Brendan
It does look wrong, but call/retf, <int>/iret and jmp are all closely related. The only differences are the busy bit and the NT flag.Pype.Clicker wrote: no! no "jmp exception handler" stuff is required. The TSS isn't modified by a return, so if the handler task isn't switched off, its TSS will still hold the handler state for the next run ...
For e.g.:
Code: Select all
exception_handler:
/* initialize anything here */
.next_exception:
/* code to handle exception goes here */
iretd
jmp .next_exception
"The state of the currently executing task is always saved when a successful task switch occurs. If the task is resumed, execution starts with the instruction pointed to by the saved EIP value, and the registers are restored to the values they held when the task was suspended."
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.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:handling exceptions with taskgates
hmm ... yup, now i remember ...
Well, the 'trick' pioneers (like Tran/Renaissance) have used was to load TR with a "dummy" or "trash" TSS right before the IRET. That way, the 'handler' TSS was kept clean and the handler context wasn't altered in any way (so it's not required to re-load any register at the handler's prologue).
Well, the 'trick' pioneers (like Tran/Renaissance) have used was to load TR with a "dummy" or "trash" TSS right before the IRET. That way, the 'handler' TSS was kept clean and the handler context wasn't altered in any way (so it's not required to re-load any register at the handler's prologue).
Code: Select all
handler:
...
mov ax,[handler_tss+backlink]
mov [trash_tss+backlink],ax
ltr TRASH_TSS_SELECTOR
iretd
Re:handling exceptions with taskgates
Have a look in LSE/OS since it uses taskgates for task switching. You're right, it is much cleaner using this.
Re:handling exceptions with taskgates
My humble opinion is that task-gates are absolutely useless, and TSS in general is only useful for specifying the kernel stack location. YMMV.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:handling exceptions with taskgates
there is at least one exception that *requires* task gates: the stack fault. Double fault will also benefit of a task gate as it gives a "fresher" state.
Note that depending on your framework, you may never see a stack fault, but if you do (e.g. have appliable limits on a kernel stack segment), you'll have no choice but using a task gate.
Note that depending on your framework, you may never see a stack fault, but if you do (e.g. have appliable limits on a kernel stack segment), you'll have no choice but using a task gate.