1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 18:07:35 +00:00

Kernel: Make separate kernel entry points for each PIC IRQ

Instead of having a common entry point and looking at the PIC ISR to
figure out which IRQ we're servicing, just make a separate entryway
for each IRQ that pushes the IRQ number and jumps to a common routine.

This fixes a weird issue where incoming network packets would sometimes
cause the mouse to stop working. I didn't track it down further than
realizing we were sometimes EOI'ing the wrong IRQ.
This commit is contained in:
Andreas Kling 2019-12-15 12:11:39 +01:00
parent 12cc518d1e
commit f01fd54d1b
4 changed files with 123 additions and 129 deletions

View file

@ -40,24 +40,36 @@ void gdt_free_entry(u16 entry)
s_gdt_freelist->append(entry); s_gdt_freelist->append(entry);
} }
extern "C" void handle_irq(); extern "C" void handle_irq(RegisterDump);
extern "C" void asm_irq_entry(); extern "C" void irq_common_asm_entry();
#define GENERATE_IRQ_ASM_ENTRY(irq, isr_number) \
extern "C" void irq_##irq##_asm_entry(); \
asm(".globl irq_" #irq "_asm_entry\n" \
"irq_" #irq "_asm_entry:\n" \
" pushw $" #isr_number "\n" \
" pushw $0\n" \
" jmp irq_common_asm_entry\n");
asm( asm(
".globl asm_irq_entry\n" ".globl irq_common_asm_entry\n"
"asm_irq_entry: \n" "irq_common_asm_entry: \n"
" pushl $0x0\n"
" pusha\n" " pusha\n"
" pushw %ds\n" " pushl %ds\n"
" pushw %es\n" " pushl %es\n"
" pushw %ss\n" " pushl %fs\n"
" pushw %ss\n" " pushl %gs\n"
" popw %ds\n" " pushl %ss\n"
" popw %es\n" " mov $0x10, %ax\n"
" mov %ax, %ds\n"
" mov %ax, %es\n"
" cld\n" " cld\n"
" call handle_irq\n" " call handle_irq\n"
" popw %es\n" " add $0x4, %esp\n" // "popl %ss"
" popw %ds\n" " popl %gs\n"
" popl %fs\n"
" popl %es\n"
" popl %ds\n"
" popa\n" " popa\n"
" add $0x4, %esp\n" " add $0x4, %esp\n"
" iret\n"); " iret\n");
@ -69,26 +81,21 @@ asm(
".globl " #title "_asm_entry\n" \ ".globl " #title "_asm_entry\n" \
"" #title "_asm_entry: \n" \ "" #title "_asm_entry: \n" \
" pusha\n" \ " pusha\n" \
" pushw %ds\n" \ " pushl %ds\n" \
" pushw %es\n" \ " pushl %es\n" \
" pushw %fs\n" \ " pushl %fs\n" \
" pushw %gs\n" \ " pushl %gs\n" \
" pushw %ss\n" \ " pushl %ss\n" \
" pushw %ss\n" \ " mov $0x10, %ax\n" \
" pushw %ss\n" \ " mov %ax, %ds\n" \
" pushw %ss\n" \ " mov %ax, %es\n" \
" pushw %ss\n" \
" popw %ds\n" \
" popw %es\n" \
" popw %fs\n" \
" popw %gs\n" \
" cld\n" \ " cld\n" \
" call " #title "_handler\n" \ " call " #title "_handler\n" \
" popw %gs\n" \ " add $0x4, %esp \n" \
" popw %gs\n" \ " popl %gs\n" \
" popw %fs\n" \ " popl %fs\n" \
" popw %es\n" \ " popl %es\n" \
" popw %ds\n" \ " popl %ds\n" \
" popa\n" \ " popa\n" \
" add $0x4, %esp\n" \ " add $0x4, %esp\n" \
" iret\n"); " iret\n");
@ -101,26 +108,21 @@ asm(
"" #title "_asm_entry: \n" \ "" #title "_asm_entry: \n" \
" pushl $0x0\n" \ " pushl $0x0\n" \
" pusha\n" \ " pusha\n" \
" pushw %ds\n" \ " pushl %ds\n" \
" pushw %es\n" \ " pushl %es\n" \
" pushw %fs\n" \ " pushl %fs\n" \
" pushw %gs\n" \ " pushl %gs\n" \
" pushw %ss\n" \ " pushl %ss\n" \
" pushw %ss\n" \ " mov $0x10, %ax\n" \
" pushw %ss\n" \ " mov %ax, %ds\n" \
" pushw %ss\n" \ " mov %ax, %es\n" \
" pushw %ss\n" \
" popw %ds\n" \
" popw %es\n" \
" popw %fs\n" \
" popw %gs\n" \
" cld\n" \ " cld\n" \
" call " #title "_handler\n" \ " call " #title "_handler\n" \
" popw %gs\n" \ " add $0x4, %esp\n" \
" popw %gs\n" \ " popl %gs\n" \
" popw %fs\n" \ " popl %fs\n" \
" popw %es\n" \ " popl %es\n" \
" popw %ds\n" \ " popl %ds\n" \
" popa\n" \ " popa\n" \
" add $0x4, %esp\n" \ " add $0x4, %esp\n" \
" iret\n"); " iret\n");
@ -137,11 +139,10 @@ static void dump(const RegisterDump& regs)
esp = regs.esp_if_crossRing; esp = regs.esp_if_crossRing;
} }
kprintf("exception code: %04x\n", regs.exception_code); kprintf("exception code: %04x (isr: %04x)\n", regs.exception_code, regs.isr_number);
kprintf(" pc=%04x:%08x ds=%04x es=%04x fs=%04x gs=%04x\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs); kprintf(" pc=%04x:%08x flags=%04x\n", regs.cs, regs.eip, regs.eflags);
kprintf(" stk=%04x:%08x\n", ss, esp); kprintf(" stk=%04x:%08x\n", ss, esp);
if (current) kprintf(" ds=%04x es=%04x fs=%04x gs=%04x\n", regs.ds, regs.es, regs.fs, regs.gs);
kprintf("kstk=%04x:%08x, base=%08x\n", current->tss().ss0, current->tss().esp0, current->kernel_stack_base());
kprintf("eax=%08x ebx=%08x ecx=%08x edx=%08x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); kprintf("eax=%08x ebx=%08x ecx=%08x edx=%08x\n", regs.eax, regs.ebx, regs.ecx, regs.edx);
kprintf("ebp=%08x esp=%08x esi=%08x edi=%08x\n", regs.ebp, esp, regs.esi, regs.edi); kprintf("ebp=%08x esp=%08x esi=%08x edi=%08x\n", regs.ebp, esp, regs.esi, regs.edi);
@ -409,7 +410,6 @@ void register_irq_handler(u8 irq, IRQHandler& handler)
{ {
ASSERT(!s_irq_handler[irq]); ASSERT(!s_irq_handler[irq]);
s_irq_handler[irq] = &handler; s_irq_handler[irq] = &handler;
register_interrupt_handler(IRQ_VECTOR_BASE + irq, asm_irq_entry);
} }
void unregister_irq_handler(u8 irq, IRQHandler& handler) void unregister_irq_handler(u8 irq, IRQHandler& handler)
@ -437,17 +437,22 @@ void flush_idt()
asm("lidt %0" ::"m"(s_idtr)); asm("lidt %0" ::"m"(s_idtr));
} }
extern "C" void irq7_handler(); GENERATE_IRQ_ASM_ENTRY(0, 0x50)
asm( GENERATE_IRQ_ASM_ENTRY(1, 0x51)
".globl irq7_handler\n" GENERATE_IRQ_ASM_ENTRY(2, 0x52)
"irq7_handler:\n" GENERATE_IRQ_ASM_ENTRY(3, 0x53)
" iret\n"); GENERATE_IRQ_ASM_ENTRY(4, 0x54)
GENERATE_IRQ_ASM_ENTRY(5, 0x55)
extern "C" void irq15_handler(); GENERATE_IRQ_ASM_ENTRY(6, 0x56)
asm( GENERATE_IRQ_ASM_ENTRY(7, 0x57)
".globl irq15_handler\n" GENERATE_IRQ_ASM_ENTRY(8, 0x58)
"irq15_handler:\n" GENERATE_IRQ_ASM_ENTRY(9, 0x59)
" iret\n"); GENERATE_IRQ_ASM_ENTRY(10, 0x5a)
GENERATE_IRQ_ASM_ENTRY(11, 0x5b)
GENERATE_IRQ_ASM_ENTRY(12, 0x5c)
GENERATE_IRQ_ASM_ENTRY(13, 0x5d)
GENERATE_IRQ_ASM_ENTRY(14, 0x5e)
GENERATE_IRQ_ASM_ENTRY(15, 0x5f)
void idt_init() void idt_init()
{ {
@ -475,8 +480,22 @@ void idt_init()
register_interrupt_handler(0x0f, _exception15); register_interrupt_handler(0x0f, _exception15);
register_interrupt_handler(0x10, _exception16); register_interrupt_handler(0x10, _exception16);
register_interrupt_handler(0x57, irq7_handler); register_interrupt_handler(0x50, irq_0_asm_entry);
register_interrupt_handler(0x5f, irq15_handler); register_interrupt_handler(0x51, irq_1_asm_entry);
register_interrupt_handler(0x52, irq_2_asm_entry);
register_interrupt_handler(0x53, irq_3_asm_entry);
register_interrupt_handler(0x54, irq_4_asm_entry);
register_interrupt_handler(0x55, irq_5_asm_entry);
register_interrupt_handler(0x56, irq_6_asm_entry);
register_interrupt_handler(0x57, irq_7_asm_entry);
register_interrupt_handler(0x58, irq_8_asm_entry);
register_interrupt_handler(0x59, irq_9_asm_entry);
register_interrupt_handler(0x5a, irq_10_asm_entry);
register_interrupt_handler(0x5b, irq_11_asm_entry);
register_interrupt_handler(0x5c, irq_12_asm_entry);
register_interrupt_handler(0x5d, irq_13_asm_entry);
register_interrupt_handler(0x5e, irq_14_asm_entry);
register_interrupt_handler(0x5f, irq_15_asm_entry);
for (u8 i = 0; i < 16; ++i) { for (u8 i = 0; i < 16; ++i) {
s_irq_handler[i] = nullptr; s_irq_handler[i] = nullptr;
@ -490,24 +509,10 @@ void load_task_register(u16 selector)
asm("ltr %0" ::"r"(selector)); asm("ltr %0" ::"r"(selector));
} }
void handle_irq() void handle_irq(RegisterDump regs)
{ {
u16 isr = PIC::get_isr(); ASSERT(regs.isr_number >= 0x50 && regs.isr_number <= 0x5f);
if (!isr) { u8 irq = (u8)(regs.isr_number - 0x50);
kprintf("Spurious IRQ\n");
return;
}
u8 irq = 0;
for (u8 i = 0; i < 16; ++i) {
if (i == 2)
continue;
if (isr & (1 << i)) {
irq = i;
break;
}
}
if (s_irq_handler[irq]) if (s_irq_handler[irq])
s_irq_handler[irq]->handle_irq(); s_irq_handler[irq]->handle_irq();
PIC::eoi(irq); PIC::eoi(irq);

View file

@ -376,11 +376,11 @@ private:
struct [[gnu::packed]] RegisterDump struct [[gnu::packed]] RegisterDump
{ {
u16 ss; u32 ss;
u16 gs; u32 gs;
u16 fs; u32 fs;
u16 es; u32 es;
u16 ds; u32 ds;
u32 edi; u32 edi;
u32 esi; u32 esi;
u32 ebp; u32 ebp;
@ -390,13 +390,12 @@ struct [[gnu::packed]] RegisterDump
u32 ecx; u32 ecx;
u32 eax; u32 eax;
u16 exception_code; u16 exception_code;
u16 __exception_code_padding; u16 isr_number;
u32 eip; u32 eip;
u16 cs; u32 cs;
u16 __csPadding;
u32 eflags; u32 eflags;
u32 esp_if_crossRing; u32 esp_if_crossRing;
u16 ss_if_crossRing; u32 ss_if_crossRing;
}; };
struct [[gnu::aligned(16)]] FPUState struct [[gnu::aligned(16)]] FPUState

View file

@ -14,26 +14,21 @@ asm(
"timer_interrupt_entry: \n" "timer_interrupt_entry: \n"
" pushl $0x0\n" " pushl $0x0\n"
" pusha\n" " pusha\n"
" pushw %ds\n" " pushl %ds\n"
" pushw %es\n" " pushl %es\n"
" pushw %fs\n" " pushl %fs\n"
" pushw %gs\n" " pushl %gs\n"
" pushw %ss\n" " pushl %ss\n"
" pushw %ss\n" " mov $0x10, %ax\n"
" pushw %ss\n" " mov %ax, %ds\n"
" pushw %ss\n" " mov %ax, %es\n"
" pushw %ss\n"
" popw %ds\n"
" popw %es\n"
" popw %fs\n"
" popw %gs\n"
" cld\n" " cld\n"
" call timer_interrupt_handler\n" " call timer_interrupt_handler\n"
" popw %gs\n" " add $0x4, %esp\n"
" popw %gs\n" " popl %gs\n"
" popw %fs\n" " popl %fs\n"
" popw %es\n" " popl %es\n"
" popw %ds\n" " popl %ds\n"
" popa\n" " popa\n"
" add $0x4, %esp\n" " add $0x4, %esp\n"
" iret\n"); " iret\n");

View file

@ -12,26 +12,21 @@ asm(
"syscall_asm_entry:\n" "syscall_asm_entry:\n"
" pushl $0x0\n" " pushl $0x0\n"
" pusha\n" " pusha\n"
" pushw %ds\n" " pushl %ds\n"
" pushw %es\n" " pushl %es\n"
" pushw %fs\n" " pushl %fs\n"
" pushw %gs\n" " pushl %gs\n"
" pushw %ss\n" " pushl %ss\n"
" pushw %ss\n" " mov $0x10, %ax\n"
" pushw %ss\n" " mov %ax, %ds\n"
" pushw %ss\n" " mov %ax, %es\n"
" pushw %ss\n"
" popw %ds\n"
" popw %es\n"
" popw %fs\n"
" popw %gs\n"
" cld\n" " cld\n"
" call syscall_handler\n" " call syscall_handler\n"
" popw %gs\n" " add $0x4, %esp\n"
" popw %gs\n" " popl %gs\n"
" popw %fs\n" " popl %fs\n"
" popw %es\n" " popl %es\n"
" popw %ds\n" " popl %ds\n"
" popa\n" " popa\n"
" add $0x4, %esp\n" " add $0x4, %esp\n"
" iret\n"); " iret\n");