First of all, this assembly function is called whenever there is an IRQ,
Code: Select all
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
Code: Select all
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 */
};
Also, in this code irq_handler is moved to eax before being called. What's the difference between this and just calling irq_handler directly?
To setup each IRQ in the table, the following function is called idt_set_gate(32, (unsigned)irq0, 0x08, 0x8E); The function is defined as,
Code: Select all
void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags) // Sets an IDT entry
{
idt[num].base_lo = (base & 0xFFFF); // Sets first 16 bits of base address
idt[num].base_hi = (base >> 16) & 0xFFFF; // Sets last 16 bits of base address
idt[num].sel = sel; // Sets selector
idt[num].always0 = 0; // This value is always 0
idt[num].flags = flags; // Sets flags
}
Finally, in the following code,
Code: Select all
global gdt_flush ; Allows the C code to link to this
extern gp ; Says that 'gp' is in another file
gdt_flush:
lgdt [gp] ; Load the GDT with our '_gp' which is a special pointer
mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:flush2 ; 0x08 is the offset to our code segment (because he GDT starts with a NULL descriptor): Far jump!
flush2:
ret ; Returns back to the C code!