starkernel: item 4.3.5 -- amd64 I/O APIC + i8042 keyboard, interrupt-driven

Punch list §25 item 4.3.5 complete.

New ioapic.c/i8042.c drivers (MADT-derived I/O APIC base, no hardcoded
constants) plus a KBD-SCAN/KBD-DEBUG diagnostic word pair. Three real
bugs found and fixed en route, all blocking this item's own acceptance:
a fatal LAPIC spurious-vector crash (nothing had driven a real external
interrupt through the I/O APIC before), OVMF leaving the keyboard device
itself scanning-disabled (0xF4 fix), and isr.S's stub table only having
individually-numbered stubs through vector 32 -- everything above that,
including our IRQ1 vector 33, silently reported as vector 255 regardless
of which IDT slot actually fired. Verified live via QEMU sendkey against
KBD-SCAN: correct XT Set-1 make/break codes for two different keys.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-08 00:18:48 -04:00
co-authored by Claude Sonnet 5
parent 78ff335b97
commit 88eb73cfe8
14 changed files with 914 additions and 11 deletions
+40
View File
@@ -0,0 +1,40 @@
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
Licensed under the StarForth License, Version 1.0
*/
#ifndef KEYBOARD_WORDS_H
#define KEYBOARD_WORDS_H
#include "vm.h"
/**
* @defgroup keyboard_words Keyboard Words
* @{
*
* @brief Raw hardware-boundary FORTH word for verifying the interrupt-driven
* keyboard path (FABRIC.md item 4.3.5). Deliberately a diagnostic peek at
* the raw scancode ring buffer -- no set-2 translation, no REPL wiring.
* Those belong to the later REPL keyboard-input work noted in FABRIC.md.
*
* Kernel-only, amd64-only today (i8042 is amd64 hardware); no-op elsewhere
* so dictionary parity across all three architectures is unaffected.
*
* @par KBD-SCAN ( -- c -1 | 0 )
* Pop one raw scancode off the interrupt-fed ring buffer. Pushes the
* scancode and -1 (true) if one was available, or just 0 (false) if the
* buffer was empty.
*
* @par KBD-DEBUG ( -- isr_count spurious_count )
* Standing diagnostic: count of real keyboard IRQs serviced and count of
* LAPIC spurious-vector interrupts, both since boot.
* @}
*/
void register_keyboard_words(VM *vm);
#endif /* KEYBOARD_WORDS_H */
+57
View File
@@ -0,0 +1,57 @@
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
Licensed under the StarForth License, Version 1.0
*/
/* keyboard_words.c — raw scancode-ring diagnostic word (FABRIC.md item
* 4.3.5). Kernel-only, amd64-only; no-op elsewhere. */
#include "include/keyboard_words.h"
#include "../../include/word_registry.h"
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
#include "starkernel/i8042.h"
#endif
/* KBD-SCAN ( -- c -1 | 0 ) */
static void kbw_scan(VM *vm)
{
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
uint8_t sc;
if (i8042_pop_scancode(&sc)) {
vm_push(vm, (cell_t)sc);
vm_push(vm, -1);
} else {
vm_push(vm, 0);
}
#else
vm_push(vm, 0);
#endif
}
/* KBD-DEBUG ( -- isr_count spurious_count ): cheap standing diagnostic,
* not scaffolding -- confirms the interrupt path is alive (isr_count) and
* flags the failure mode item 4.3.5 found (a real IRQ misreported as
* spurious) without needing a live debugger. */
extern volatile uint32_t g_i8042_isr_count;
extern volatile uint32_t g_spurious_count;
static void kbw_debug(VM *vm)
{
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
vm_push(vm, (cell_t)g_i8042_isr_count);
vm_push(vm, (cell_t)g_spurious_count);
#else
vm_push(vm, 0);
vm_push(vm, 0);
#endif
}
void register_keyboard_words(VM *vm)
{
register_word(vm, "KBD-SCAN", kbw_scan);
register_word(vm, "KBD-DEBUG", kbw_debug);
}