fix: ISR GS clobber, serial IRQ stuck, ring3 page fault
1. **ISR GS clobber (III) — FIXED**
- interrupts.S: save/restore GS separately instead of overwriting
with 0x10. DS/ES/FS still set to kernel data, but GS now
preserves the per-CPU selector across interrupt entry/exit.
- struct registers: new 'gs' field at offset 0.
- ARCH_REGS_SIZE: 64 → 68.
- x86_enter_usermode_regs: updated all hardcoded register offsets
(+4 for the new GS field).
2. **Serial keyboard blocking (II) — FIXED**
- Root cause: hal_uart_init() runs early (under PIC), enabling
UART RX interrupts. Later, IOAPIC routes IRQ 4 as edge-triggered.
If any character arrived between PIC-era init and IOAPIC setup,
the UART IRQ line stays asserted — the IOAPIC never sees a
rising edge, permanently blocking all future serial input.
- Fix: hal_uart_drain_rx() clears pending UART FIFO + IIR + MSR
immediately after ioapic_route_irq(4, ...) to de-assert the
IRQ line and allow future edges.
3. **Ring3 page fault at 0xae1000 (V) — FIXED**
- The ring3 code emitter wrote to code_phys as a virtual address,
relying on an identity mapping that doesn't exist for all
physical addresses. Now uses P2V (phys + 0xC0000000) to access
physical pages via the kernel's higher-half mapping.