Not logged inTalkContributionsCreate accountLog in

Interrupts & Timers

From nexOS Wiki
IDT, 8259 PIC remap, PIT 100 Hz, PS/2 keyboard & mouse

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.

VectorSourceHandlerSelectorFlags
0–31CPU exceptionsisr0..31 → exception_handler()0x080x8E
32 (0x20)PIT timer, IRQ0isr32 → sched_tick()0x080x8E
33 (0x21)PS/2 keyboard, IRQ1isr33 → keyboard_handler()0x080x8E
43 (0x2B)NIC, PCI IRQ (usually 11)isr43 → net_handler()0x080x8E
44 (0x2C)PS/2 mouse, IRQ12isr44 → mouse_handler()0x080x8E
128 (0x80)Syscallsisr128 → syscall_handler()0x080xEE

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.

PICPortsBaseMaskEnabled
Master0x20/0x210x200xF8IRQ0 (PIT) + IRQ1 (kbd) + IRQ2 (cascade)
Slave0xA0/0xA10x280xFF then unmaskIRQ12 (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