Interrupts & Timers
Contents[hide] |
Interrupt sources
nexOS now has three live sources (the old “timer masked” note is obsolete): PIT timer on IRQ0, PS/2 keyboard on IRQ1, PS/2 mouse on IRQ12. Each handler is an assembly stub that saves registers, calls C, then iretd.
| Vector | Source | Handler | Selector | Flags |
|---|---|---|---|---|
| 32 (0x20) | PIT timer, IRQ0 | isr32 → timer_handler() | 0x08 | 0x8E |
| 33 (0x21) | PS/2 keyboard, IRQ1 | isr33 → keyboard_handler() | 0x08 | 0x8E |
| 44 (0x2C) | PS/2 mouse, IRQ12 | isr44 → mouse_handler() | 0x08 | 0x8E |
| 0–255 | others | (zeroed) | 0 | 0 |
IDT structures
typedef struct { u16 lo; u16 sel; u8 zero; u8 fl; u16 hi; } __attribute__((packed)) idt_e;
typedef struct { u16 lim; u32 base; } __attribute__((packed)) idt_p;
static idt_e idt[256]; static idt_p idt_r; // 2048 bytes, loaded with lidt
ISR stubs (kernel_entry.asm)
_isr44: pusha; call _mouse_handler; popa; iretd ; mouse INT 44 _isr33: pusha; call _keyboard_handler; popa; iretd ; keyboard INT 33 _isr32: pusha; call _timer_handler; popa; iretd ; timer INT 32
8259 PIC remap
remap_pic(): outb(0x20,0x11); outb(0xA0,0x11); // ICW1 outb(0x21,0x20); outb(0xA1,0x28); // ICW2: master 0x20, slave 0x28 outb(0x21,0x04); outb(0xA1,0x02); // ICW3: slave on IRQ2 outb(0x21,0x01); outb(0xA1,0x01); // ICW4: 8086 mode outb(0x21,0xF8); outb(0xA1,0xEF); // masks
| PIC | Ports | Base | Mask | Enabled |
|---|---|---|---|---|
| Master | 0x20/0x21 | 0x20 | 0xF8 | IRQ0 (PIT) + IRQ1 (kbd) + IRQ2 (cascade) |
| Slave | 0xA0/0xA1 | 0x28 | 0xEF | IRQ12 (mouse) |
Master 0xF8 = 11111000b: bits 0–2 clear = unmasked. The old mask 0xF9 kept the timer masked; the current tree unmasks IRQ0 for the scheduler tick.
PIT 100 Hz tick
pit_init():
u16 div = 11932; // 1193182 / 11932 ~= 100 Hz
outb(0x43, 0x36); // ch0, lo/hi, mode 3 square wave
outb(0x40, div & 0xFF);
outb(0x40, (div >> 8) & 0xFF);
timer_handler(): pit_ticks++; outb(0x20, 0x20); // EOI
// main loop polling (every 10 ticks = 10 Hz):
if (pit_ticks - last_poll >= 10) { last_poll = pit_ticks; if (net_poll()) redraw = 1; }
The tick does not preempt; it increments a counter the main loop polls for NIC work and redraw timing.
Mouse press queue
A single mouse_updated flag collapsed press+release inside one render window (“nothing happened”). The current handler records press edges into a 4-deep ring; the main loop drains one per iteration as a synthetic press, so fast 0.05 s clicks survive long renders. Movement uses 2× gain and clamps to true screen edges.
ACPI shutdown
shutdown_system(): cli; outw(0x604, 0x2000); for(;;) hlt; // QEMU/Bochs power port