Interrupts & Timers
Contents[hide] |
Interrupt sources
nexOS has five live sources: CPU exceptions (vectors 0–31), PIT timer on IRQ0, PS/2 keyboard on IRQ1, PS/2 mouse on IRQ12, and the NIC on its PCI IRQ. Each handler is an assembly stub that saves registers, calls C, then iretd. A sixth gate at vector 128 (INT 0x80, DPL 3) is the syscall entry.
| Vector | Source | Handler | Selector | Flags |
|---|---|---|---|---|
| 0–31 | CPU exceptions | isr0..31 → exception_handler() | 0x08 | 0x8E |
| 32 (0x20) | PIT timer, IRQ0 | isr32 → sched_tick() | 0x08 | 0x8E |
| 33 (0x21) | PS/2 keyboard, IRQ1 | isr33 → keyboard_handler() | 0x08 | 0x8E |
| 43 (0x2B) | NIC, PCI IRQ (usually 11) | isr43 → net_handler() | 0x08 | 0x8E |
| 44 (0x2C) | PS/2 mouse, IRQ12 | isr44 → mouse_handler() | 0x08 | 0x8E |
| 128 (0x80) | Syscalls | isr128 → syscall_handler() | 0x08 | 0xEE |
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; push esp; call _sched_tick; add esp,4;
mov esp,eax; popa; iretd ; timer: switch stacks
_isr43: pusha; call _net_handler; popa; iretd ; NIC
_isr128: pusha; push esp; call _syscall_handler; add esp,4;
popa; iretd ; syscall, regs in/out
; vectors 0-31: NASM macros push dummy-or-real error code + vector,
; then share _isr_common (pusha, push err, push vec, call, iretd).
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,0xFF); // masks (slave fully masked...)
...then pic_unmask_irq() opens exactly keyboard (IRQ1), mouse (IRQ12) and the NIC IRQ read from PCI config; the NIC gate is registered at 32+irq (43 on QEMU) in case firmware routed it elsewhere.
| PIC | Ports | Base | Mask | Enabled |
|---|---|---|---|---|
| Master | 0x20/0x21 | 0x20 | 0xF8 | IRQ0 (PIT) + IRQ1 (kbd) + IRQ2 (cascade) |
| Slave | 0xA0/0xA1 | 0x28 | 0xFF then unmask | IRQ12 (mouse) + NIC IRQ from PCI |
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); sched_tick(savesp): pit_ticks++; outb(0x20, 0x20); // EOI if (!sched_on) return savesp; return sched_pick(savesp); // may resume another task
The tick preempts: every 10 ms the stub swaps stacks round-robin across up to 8 tasks (sched_pick saves the current esp, returns the next task's). The main loop still polls the counter for NIC work every 10 ticks.
Scheduler and syscalls
Tasks are kernel stacks (8 KiB from the heap) with a forged interrupt frame (eflags/cs/eip = task_begin + zeroed registers). task_create() builds the frame; task_sleep(ticks) parks the task until a tick count (int $32 yields immediately). States: EMPTY / READY / RUNNING / SLEEPING. The taskbar shows live T ticks S switches counters.
INT 0x80 dispatches yield / getticks / log / exit with arguments in eax/ebx/ecx/edx; a 2 KiB kernel log ring backs the DMSG command.
CPU exceptions
Vectors 0-31 share one common stub that pushes a dummy error code where the CPU pushes none, then calls exception_handler(vec, err). It clears the screen and prints a KERNEL PANIC card (fault name + vector/error) instead of triple-faulting into a reboot loop. Try it live: run CRASH in the terminal.
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