-
Notifications
You must be signed in to change notification settings - Fork 0
Interrupt Handling
NtinosTheGamer2324 edited this page Dec 11, 2025
·
1 revision
ModuOS implements a complete interrupt handling system for CPU exceptions and hardware interrupts.
Hardware Event → PIC → CPU → IDT Lookup → ISR/IRQ Handler →
Handle Interrupt → IRET → Resume Execution
File: src/arch/AMD64/interrupts/idt.c
The IDT maps interrupt vectors to handler functions:
struct idt_entry {
uint16_t offset_low; // Handler address bits 0-15
uint16_t selector; // Code segment selector
uint8_t ist; // Interrupt Stack Table
uint8_t type_attr; // Type and attributes
uint16_t offset_mid; // Handler address bits 16-31
uint32_t offset_high; // Handler address bits 32-63
uint32_t zero; // Reserved
} __attribute__((packed));
struct idt_entry idt[256]; // 256 interrupt vectorsvoid idt_init(void) {
// 1. Zero out IDT
memset(&idt, 0, sizeof(idt));
// 2. Set up fault handlers (0-31)
for (int i = 0; i < 32; i++) {
idt_set_gate(i, isr_table[i], 0x08, 0x8E);
}
// 3. Set up IRQ handlers (32-47)
for (int i = 32; i < 48; i++) {
idt_set_gate(i, irq_table[i-32], 0x08, 0x8E);
}
// 4. Load IDT
idtr.limit = sizeof(idt) - 1;
idtr.base = (uint64_t)&idt;
__asm__ volatile("lidt %0" : : "m"(idtr));
}Vectors 0-31: CPU-generated exceptions
| Vector | Name | Type | Error Code |
|---|---|---|---|
| 0 | Divide by Zero | Fault | No |
| 1 | Debug | Fault/Trap | No |
| 2 | Non-Maskable Interrupt | Interrupt | No |
| 3 | Breakpoint | Trap | No |
| 4 | Overflow | Trap | No |
| 5 | Bound Range Exceeded | Fault | No |
| 6 | Invalid Opcode | Fault | No |
| 7 | Device Not Available | Fault | No |
| 8 | Double Fault | Abort | Yes |
| 10 | Invalid TSS | Fault | Yes |
| 11 | Segment Not Present | Fault | Yes |
| 12 | Stack-Segment Fault | Fault | Yes |
| 13 | General Protection Fault | Fault | Yes |
| 14 | Page Fault | Fault | Yes |
| 16 | x87 FPU Error | Fault | No |
| 17 | Alignment Check | Fault | Yes |
| 18 | Machine Check | Abort | No |
| 19 | SIMD Floating-Point | Fault | No |
File: src/arch/AMD64/interrupts/fault.asm
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
push 0 ; Dummy error code
push %1 ; Interrupt number
jmp isr_common
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
push %1 ; Interrupt number
jmp isr_common
%endmacro
isr_common:
; Save all registers
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
; Call C handler
mov rdi, rsp ; Pass stack pointer
call fault_handler
; Restore registers
pop r15
pop r14
; ... (all registers)
pop rax
; Clean up error code and int number
add rsp, 16
iretqFile: src/kernel/fault.c
void fault_handler(registers_t *regs) {
const char *exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
// ... (all 32 exceptions)
};
if (regs->int_no < 32) {
VGA_print("EXCEPTION: ");
VGA_print(exception_messages[regs->int_no]);
VGA_print("\n");
// Special handling for page fault
if (regs->int_no == 14) {
uint64_t faulting_address;
__asm__ volatile("mov %%cr2, %0" : "=r"(faulting_address));
// Analyze error code and address
}
panic("Unrecoverable exception");
}
}Vectors 32-47: Hardware device interrupts
| IRQ | Vector | Device |
|---|---|---|
| 0 | 32 | PIT (Timer) |
| 1 | 33 | Keyboard |
| 2 | 34 | Cascade (PIC2) |
| 3 | 35 | COM2 |
| 4 | 36 | COM1 |
| 5 | 37 | LPT2 |
| 6 | 38 | Floppy |
| 7 | 39 | LPT1 |
| 8 | 40 | RTC |
| 9 | 41 | Free |
| 10 | 42 | Free |
| 11 | 43 | Free |
| 12 | 44 | PS/2 Mouse |
| 13 | 45 | FPU |
| 14 | 46 | Primary ATA |
| 15 | 47 | Secondary ATA |
File: src/arch/AMD64/interrupts/irq.c
typedef void (*irq_handler_t)(registers_t *regs);
static irq_handler_t irq_handlers[16];
void irq_register_handler(int irq, irq_handler_t handler) {
irq_handlers[irq] = handler;
}
void irq_handler(registers_t *regs) {
int irq = regs->int_no - 32;
if (irq_handlers[irq]) {
irq_handlers[irq](regs);
}
// Send EOI to PIC
pic_send_eoi(irq);
}File: src/arch/AMD64/interrupts/pic.c
┌──────────┐ ┌──────────┐
│ PIC1 │ Cascade │ PIC2 │
│ (Master) ├────────►│ (Slave) │
│ IRQ 0-7 │ IRQ 2 │ IRQ 8-15 │
└────┬─────┘ └────┬─────┘
│ │
└────────┬───────────┘
│
CPU INTR Pin
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define PIC_EOI 0x20 // End of Interruptvoid pic_init(void) {
// ICW1: Start initialization
outb(PIC1_COMMAND, 0x11);
outb(PIC2_COMMAND, 0x11);
// ICW2: Set vector offsets
outb(PIC1_DATA, 0x20); // Master: IRQ 0-7 → INT 32-39
outb(PIC2_DATA, 0x28); // Slave: IRQ 8-15 → INT 40-47
// ICW3: Set cascade
outb(PIC1_DATA, 0x04); // Master has slave on IRQ2
outb(PIC2_DATA, 0x02); // Slave cascade identity
// ICW4: 8086 mode
outb(PIC1_DATA, 0x01);
outb(PIC2_DATA, 0x01);
// Unmask all IRQs
outb(PIC1_DATA, 0x00);
outb(PIC2_DATA, 0x00);
}void pic_send_eoi(int irq) {
if (irq >= 8) {
outb(PIC2_COMMAND, PIC_EOI); // Slave PIC
}
outb(PIC1_COMMAND, PIC_EOI); // Master PIC
}File: src/arch/AMD64/interrupts/timer.c
The PIT generates periodic interrupts for scheduling.
#define PIT_CHANNEL0 0x40
#define PIT_COMMAND 0x43
#define PIT_FREQUENCY 1193182 // Base frequency
void pit_init(uint32_t frequency) {
uint32_t divisor = PIT_FREQUENCY / frequency;
// Command: Channel 0, Lo/Hi byte, Rate generator
outb(PIT_COMMAND, 0x36);
// Set divisor
outb(PIT_CHANNEL0, divisor & 0xFF);
outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF);
// Register IRQ0 handler
irq_register_handler(0, timer_handler);
}
void timer_handler(registers_t *regs) {
ticks++;
scheduler_tick(); // Trigger process scheduling
}Vector 0x80: Software interrupt for syscalls
File: src/arch/AMD64/syscall/syscall_entry.asm
global syscall_handler
syscall_handler:
; Save registers
push rbp
push rbx
push r12
push r13
push r14
push r15
; RAX = syscall number
; RDI, RSI, RDX, RCX, R8, R9 = arguments
call syscall_dispatch
; Restore registers
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
iretqstatic inline void cli(void) {
__asm__ volatile("cli"); // Clear interrupt flag
}
static inline void sti(void) {
__asm__ volatile("sti"); // Set interrupt flag
}
static inline uint64_t save_irq_state(void) {
uint64_t rflags;
__asm__ volatile("pushfq; pop %0" : "=r"(rflags));
cli();
return rflags;
}
static inline void restore_irq_state(uint64_t rflags) {
__asm__ volatile("push %0; popfq" : : "r"(rflags));
}void critical_section_enter(void) {
cli();
}
void critical_section_exit(void) {
sti();
}- Process Management - Scheduler interrupts
- System Calls - Syscall interface
- Boot Process - IDT setup