Page 1 of 1
an issue about isr stack
Posted: Sun May 27, 2012 9:09 pm
by orighost
a issue ablout Bran's Kernel Development tutorial
--------------------------
...
irq_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push eax ;???
mov eax, _irq_handler
call eax
pop eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
-------------------------------------
struct regs
{
unsigned int gs, fs, es, ds; /* pushed the segs last */
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */
unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */
unsigned int eip, cs, eflags, useresp, ss; /* pushed by the processor automatically */
};
-------------------------------------------
I am confused why push esp into stack, and in the regs struct has no correspondence variable?
Re: an issue about isr stack
Posted: Sun May 27, 2012 10:17 pm
by Brendan
Hi,
orighost wrote:I am confused why push esp into stack, and in the regs struct has no correspondence variable?
I'd assume that the interrupt handler uses a prototype like this:
Code: Select all
void _irq_handler(struct regs * registers);
C passes parameters on the stack. The "push %eax" puts the "struct regs *registers" parameter on the stack.
If you used this instead:
Code: Select all
_irq_handler(struct regs registers);
Then the compiler would need to create a copy of the structure (which would be slower and consume more stack space), and your interrupt handler couldn't modify anything in the original structure as it'd only be modifying a copy and not the original (note: this isn't very important for IRQs, but is important for exceptions and kernel APIs).
However, an IRQ handler should never trash the interrupted code's registers, so a more correct function prototype would be:
Code: Select all
void _irq_handler(struct regs const * const registers);
However, an IRQ handler probably doesn't need to care what values were in the interrupted code's registers either, so it'd probably make more sense to forget about "struct regs" entirely and do:
Code: Select all
void _irq_handler(unsigned int int_no);
Exceptions and software interrupts are very different to IRQs. For these I'd want a separate stub for each exception and software interrupt, with a prototype like:
Code: Select all
void _whatever_handler(struct regs * registers);
Note: I hope you understand that for exceptions and software interrupts, then idea of having a generic handler that does nothing more than "switch(int_no) { .... }" is silly (or excessively lazy).
For "different stub for each exception and software interrupt", there's no need for "struct regs" to have an "unsigned int int_no" field (e.g. the general protection fault handler already knows that it is "interrupt 0x0D"); and half the exception/software interrupt handlers won't need "error code", and some exception handlers may need a slightly different "struct regs" structure (e.g. for the page fault handler it's a good idea to have a "CR2" field and save CR2 in the stub), and some (double fault, NMI, machine check) might be task gates that need a radically different structure.
Cheers,
Brendan
Re: an issue about isr stack
Posted: Mon May 28, 2012 12:40 am
by bluemoon
A "faster" method is:
Code: Select all
push edi
push esi
...
push ebx
push eax
call handler
add esp, 4
pop ebx
pop ...
struct {
uint32_t eax, ebx, ...;
} reg;
int handler(const struct reg registers) {
...
}
Since the stub already "copied" the parameter on stack.
Re: an issue about isr stack
Posted: Mon May 28, 2012 3:55 am
by orighost
Thanks Brendan.
I know that the process 's argument is a pointer, not a value. So push the the address of struct(or stack top) .
Re: an issue about isr stack
Posted: Mon May 28, 2012 6:39 am
by Combuster
Brendan wrote:However, an IRQ handler should never trash the interrupted code's registers, so a more correct function prototype would be:
Code: Select all
void _irq_handler(struct regs const * const registers);
However, an IRQ handler is a typical cause for a task switch - especially in microkernels. So you want to make sure that's still possible.