Reputation: 1308
I have my common isr stub defined as:
isr_common_stub:
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isr_handler
;call saySomething
pop ebx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
;call saySomething
popa ; Pops edi,esi,ebp...
;add esp, 8 ; Cleans up the pushed error code and pushed ISR number
;sti
;call saySomething
;iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
ret ;Return to the caller. Iret and interrupt enabling is handled within caller.
This code gets called from each interrupt as follows:
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts firstly.
push byte 0 ; Push a dummy error code.
push byte %1 ; Push the interrupt number.
jmp isr_common_stub ; Go to our common handler code.
sub esp, 2 ;Removes 2 bytes from stack
;sti ;Iret enables interrupts again
iret ;Return from interrupt
%endmacro
This code calls the external handling method appropiately, but causes gpf interrupt after returning from the external handling method.
Also I have mapped my gdt to cover the whole 4G address space with 0 priviledge level data and code descriptors (and null descriptor). Any help is appreciated.
Upvotes: 1
Views: 2418
Reputation: 37232
Here we go...
a) In the macro, doing cli
is silly. Use an "interrupt gate" (instead of a "trap gate") and the CPU will automatically disable IRQs for you without the risk of race conditions (e.g. IRQ after interrupt handler started but before it finishes executing the cli
).
b) In the macro, the code after the jmp
is never executed and is therefore pointless.
c) If you push 2 bytes onto the stack, then you've messed up stack alignment and deserve the performance penalty you're going to get. Push 2 dwords instead to avoid this.
d) The CPU provides a 32-bit error code for some exceptions; therefore your dummy error code should also be 32-bit.
e) You are passing nothing to the ISR. Most exception handlers will need to know the state of general purpose registers, etc. at the time the exception occurred.
f) You can not expect ret
to return from an interrupt and need to uncomment the iret
.
g) It's probably a bad idea to trash all the segment registers (DS, ES, FS, GS). Either the OS treats them as constants and you have no reason to load them before returning from the ISR, or they must be saved and then reloaded properly.
h) Different exceptions have different requirements, so having a "common exception handler" is silly. It's better to have different exception handlers for different exceptions, which is what the IDT provides (and in this case there'd be no point pushing an "interrupt number" on the stack).
j) IRQs are different to exceptions. For IRQs the interrupt handler never needs a pointless error code (or the state of the interrupted code). Note that it's nice to handle/hide the PIC chip's "spurious IRQ" within the assembly stub, which means examining the PIC's "in service register" to tell the difference between a real IRQ7 and a spurious IRQ7, and the difference between a real IRQ15 and a spurious IRQ15. For spurious IRQ15 you'd need to send EOI to master but not slave, and for spurious IRQ7 you mustn't send any EOI at all. If you're using IO APICs then there's no sane way to disable/mask the PIC chip's spurious IRQs so you still need spurious IRQ handlers for both PIC chips (in addition to a handler for the APIC's own spurious interrupt).
Upvotes: 2