aarch64: virtio-keyboard-pci, interrupt-driven keyboard input (item 4.3.5e)
Punch list §25 item 4.3.5e complete. Extended virtio_input.c with a GIC-routed interrupt path alongside 4.3.5c's PLIC one -- same capability walk, feature negotiation, eventq handling (confirming §27.5.1's prediction that these items would share most of the driver). aarch64_irq_handler() dispatches to virtio_input_isr() before its EOIR write, same claim-dispatch-complete ordering riscv64 uses. Verified with a real QEMU sendkey keypress: exact KEY_A/press match, two real interrupts serviced, identical result to riscv64. Found (not fixed) an unrelated pre-existing bug: BYE's cold-reset path faults on aarch64, discovered incidentally since nobody had exercised it from a monitored session before. Three-arch acceptance boot clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
2a2d7c5e5e
commit
a373c9124a
@@ -33,6 +33,14 @@ extern uint32_t apic_timer_ppi(void);
|
||||
extern void apic_eoi_intid(uint32_t intid);
|
||||
extern void apic_timer_rearm(void);
|
||||
|
||||
/* Defined in virtio_input.c (item 4.3.5e). g_virtio_input_gic_intid is 0
|
||||
* (not a valid SPI INTID -- SPIs start at 32) until
|
||||
* virtio_input_find_keyboard() finds a real device and computes its routed
|
||||
* INTID, so this branch is inert on any boot where the device isn't
|
||||
* present. Same extern-in-place convention as the rest of this file. */
|
||||
extern uint32_t g_virtio_input_gic_intid;
|
||||
extern void virtio_input_isr(void);
|
||||
|
||||
/* INTID 1023 = "spurious" (GICv2 spec): the CPU interface has nothing
|
||||
* pending, typically because another interrupt at the same or higher
|
||||
* priority raced this one to acknowledgement. Architecturally defined,
|
||||
@@ -64,6 +72,13 @@ extern void apic_timer_rearm(void);
|
||||
* the rest of the dispatch means a fault in @c heartbeat_tick() cannot
|
||||
* also cost the next tick — same discipline as @c riscv64_timer_rearm()
|
||||
* (item 0.3).
|
||||
*
|
||||
* virtio-input (item 4.3.5e, @c g_virtio_input_gic_intid): dispatched
|
||||
* **before** the @c GICC_EOIR write below, not after — the ISR itself is
|
||||
* what deasserts the device's (level-triggered) interrupt line by reading
|
||||
* its ISR-status capability; EOI'ing first would let the GIC immediately
|
||||
* re-signal a still-asserted line. Same claim-dispatch-complete ordering
|
||||
* @c riscv64_interrupt_handler() uses for its own PLIC-routed devices.
|
||||
*/
|
||||
void aarch64_irq_handler(void)
|
||||
{
|
||||
@@ -74,6 +89,10 @@ void aarch64_irq_handler(void)
|
||||
heartbeat_tick();
|
||||
}
|
||||
|
||||
if (intid == g_virtio_input_gic_intid) {
|
||||
virtio_input_isr();
|
||||
}
|
||||
|
||||
if (intid != GIC_INTID_SPURIOUS) {
|
||||
apic_eoi_intid(intid);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* virtio_input.c — Virtio 1.0 input device driver for StarKernel (item 4.3.5c)
|
||||
* virtio_input.c — Virtio 1.0 input device driver for StarKernel
|
||||
* (riscv64: item 4.3.5c; aarch64: item 4.3.5e)
|
||||
*
|
||||
* Modern virtio 1.0 interface only (device ID 0x1052). No legacy fallback
|
||||
* exists for virtio-input (unlike virtio-blk's 0x1001) -- input postdates
|
||||
@@ -9,20 +10,24 @@
|
||||
* buffers: unlike virtio_blk.c's synchronous request/response pattern, the
|
||||
* driver posts empty VirtioInputEvent buffers up front and the device
|
||||
* fills+posts them to the used ring asynchronously, signalled by the PLIC
|
||||
* (see virtio_input_isr(), called from arch/riscv64/interrupts.c on a
|
||||
* matching claim) -- no polling anywhere in this path.
|
||||
* (riscv64) or GIC (aarch64) -- see virtio_input_isr(), called from
|
||||
* arch/riscv64/interrupts.c or arch/aarch64/interrupts.c on a matching
|
||||
* claim -- no polling anywhere in this path.
|
||||
*
|
||||
* The PCI capability walker below is a deliberate duplicate of
|
||||
* virtio_blk.c's static walk_virtio_caps(), not a shared/promoted version
|
||||
* -- decided at this item rather than refactoring the working, tested
|
||||
* virtio_blk.c (FABRIC.md item 4.3.5c note, carries forward to 4.3.5e).
|
||||
* -- decided at item 4.3.5c rather than refactoring the working, tested
|
||||
* virtio_blk.c, carried forward here.
|
||||
*
|
||||
* Interrupt routing (PLIC source computation/enable) is riscv64-specific
|
||||
* and arch-guarded below; the capability walk, feature negotiation, and
|
||||
* queue/event handling are arch-agnostic and compiled for all three
|
||||
* targets (same idiom as pci.c itself: config-space access already
|
||||
* differs per arch internally, this file adds one more arch-guarded
|
||||
* piece on top rather than a second copy of the whole file).
|
||||
* Interrupt routing (source computation/enable) is arch-guarded below,
|
||||
* riscv64 (PLIC) and aarch64 (GIC) each with their own slot/pin-to-source
|
||||
* formula (FABRIC.md §27.5.1 aarch64, §27.5.2 riscv64, both derived live
|
||||
* from this host's own QEMU DTB, not assumed identical to each other). The
|
||||
* capability walk, feature negotiation, and queue/event handling are
|
||||
* arch-agnostic and compiled for all three targets (same idiom as pci.c
|
||||
* itself: config-space access already differs per arch internally, this
|
||||
* file adds one more arch-guarded piece on top rather than a second copy
|
||||
* of the whole file).
|
||||
*/
|
||||
|
||||
#ifndef __STARKERNEL__
|
||||
@@ -42,6 +47,12 @@
|
||||
#include "starkernel/plic.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_AARCH64)
|
||||
/* Defined in arch/aarch64/apic.c (item 4.3.5d). Extern-in-place, same
|
||||
* convention that file's own cross-file declarations already use. */
|
||||
extern void apic_spi_enable(uint32_t intid);
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Virtio 1.0 PCI capability structures -- duplicated from virtio_blk.c
|
||||
* (see file header for why), plus VIRTIO_PCI_CAP_ISR_CFG actually used
|
||||
@@ -200,6 +211,12 @@ static int g_vinput_ready = 0;
|
||||
* real claim. Checked by arch/riscv64/interrupts.c's dispatch. */
|
||||
uint32_t g_virtio_input_plic_source = 0;
|
||||
|
||||
/* GIC INTID (aarch64) this device's INTx routes to, computed at init. 0 is
|
||||
* not a valid SPI INTID (SPIs start at 32), so it is likewise a safe
|
||||
* "invalid/not found" sentinel. Checked by arch/aarch64/interrupts.c's
|
||||
* dispatch. */
|
||||
uint32_t g_virtio_input_gic_intid = 0;
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Capability walker -- duplicated from virtio_blk.c, see file header.
|
||||
* ------------------------------------------------------------------------- */
|
||||
@@ -251,11 +268,15 @@ static inline void wmb(void) {
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Interrupt routing -- riscv64 (PLIC). aarch64 (GIC, item 4.3.5e) is not
|
||||
* yet implemented; the #else path reports rather than silently no-ops, so
|
||||
* a future arch attempting to use this file without adding its own
|
||||
* routing fails loudly instead of "working" with a permanently-pending,
|
||||
* never-enabled source.
|
||||
* Interrupt routing -- riscv64 (PLIC, item 4.3.5c) and aarch64 (GIC, item
|
||||
* 4.3.5e). Both compute their target source from the same PCI slot/pin
|
||||
* swizzle shape (§27.5.1 aarch64, §27.5.2 riscv64) but with different base
|
||||
* offsets and controller calls -- derived independently from each board's
|
||||
* own DTB, not assumed identical. The #else path (amd64, which never
|
||||
* attaches this device) reports rather than silently no-ops, so a future
|
||||
* arch attempting to use this file without adding its own routing fails
|
||||
* loudly instead of "working" with a permanently-pending, never-enabled
|
||||
* source.
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ARCH_RISCV64)
|
||||
@@ -275,6 +296,23 @@ static int enable_interrupt_route(const PciDevice *pci)
|
||||
g_virtio_input_plic_source = source;
|
||||
return 0;
|
||||
}
|
||||
#elif defined(ARCH_AARCH64)
|
||||
static int enable_interrupt_route(const PciDevice *pci)
|
||||
{
|
||||
uint8_t pin = pci_read8(pci, (uint16_t)PCI_CFG_INT_PIN);
|
||||
if (pin < 1u || pin > 4u) {
|
||||
console_println("virtio-input: bad/absent INT_PIN");
|
||||
return -1;
|
||||
}
|
||||
uint32_t slot = pci->device;
|
||||
uint32_t spi = 3u + ((slot + (uint32_t)pin - 1u) % 4u);
|
||||
uint32_t intid = 32u + spi;
|
||||
|
||||
apic_spi_enable(intid);
|
||||
|
||||
g_virtio_input_gic_intid = intid;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int enable_interrupt_route(const PciDevice *pci)
|
||||
{
|
||||
@@ -466,7 +504,8 @@ int virtio_input_find_keyboard(void) {
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Interrupt path -- called from arch/riscv64/interrupts.c on a matching
|
||||
* PLIC claim (g_virtio_input_plic_source).
|
||||
* PLIC claim (g_virtio_input_plic_source) or arch/aarch64/interrupts.c on
|
||||
* a matching GIC IRQ (g_virtio_input_gic_intid).
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
void virtio_input_isr(void) {
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
* LAPIC spurious-vector interrupts, both since boot.
|
||||
*
|
||||
* @par VKBD-EVENT ( -- code value -1 | 0 )
|
||||
* Item 4.3.5c. Pop one decoded EV_KEY event (Linux input-event code/value
|
||||
* pair) off the virtio-input interrupt-fed ring buffer. Kernel-only,
|
||||
* riscv64-only today (virtio-keyboard-pci); no-op elsewhere.
|
||||
* Items 4.3.5c (riscv64) / 4.3.5e (aarch64). Pop one decoded EV_KEY event
|
||||
* (Linux input-event code/value pair) off the virtio-input interrupt-fed
|
||||
* ring buffer. Kernel-only, riscv64/aarch64 (virtio-keyboard-pci); no-op
|
||||
* on amd64 (i8042 hardware instead, see KBD-SCAN).
|
||||
*
|
||||
* @par VKBD-DEBUG ( -- isr_count )
|
||||
* Standing diagnostic: count of virtio-input ISR invocations since boot.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "starkernel/i8042.h"
|
||||
#endif
|
||||
|
||||
#if defined(__STARKERNEL__) && defined(ARCH_RISCV64)
|
||||
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||||
#include "starkernel/virtio_input.h"
|
||||
#endif
|
||||
|
||||
@@ -54,16 +54,17 @@ static void kbw_debug(VM *vm)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* VKBD-EVENT ( -- code value -1 | 0 ): item 4.3.5c, riscv64 virtio-input.
|
||||
* Pop one decoded EV_KEY event off the interrupt-fed ring buffer. Pushes
|
||||
* code and value and -1 (true) if one was available, or just 0 (false) if
|
||||
* the buffer was empty. Distinct word from KBD-SCAN rather than a shared
|
||||
* one: different device, different event shape (Linux-style code/value
|
||||
* pair vs. a raw XT scancode byte) -- convergence onto one interface is
|
||||
* item 4.3.5f's explicit job, not this one's. */
|
||||
/* VKBD-EVENT ( -- code value -1 | 0 ): item 4.3.5c (riscv64) / 4.3.5e
|
||||
* (aarch64) virtio-input. Pop one decoded EV_KEY event off the
|
||||
* interrupt-fed ring buffer. Pushes code and value and -1 (true) if one
|
||||
* was available, or just 0 (false) if the buffer was empty. Distinct word
|
||||
* from KBD-SCAN rather than a shared one: different device, different
|
||||
* event shape (Linux-style code/value pair vs. a raw XT scancode byte) --
|
||||
* convergence onto one interface is item 4.3.5f's explicit job, not this
|
||||
* one's. */
|
||||
static void kbw_vevent(VM *vm)
|
||||
{
|
||||
#if defined(__STARKERNEL__) && defined(ARCH_RISCV64)
|
||||
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||||
uint16_t code;
|
||||
uint32_t value;
|
||||
if (virtio_input_pop_event(&code, &value)) {
|
||||
@@ -83,7 +84,7 @@ static void kbw_vevent(VM *vm)
|
||||
extern volatile uint32_t g_virtio_input_isr_count;
|
||||
static void kbw_vdebug(VM *vm)
|
||||
{
|
||||
#if defined(__STARKERNEL__) && defined(ARCH_RISCV64)
|
||||
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||||
vm_push(vm, (cell_t)g_virtio_input_isr_count);
|
||||
#else
|
||||
vm_push(vm, 0);
|
||||
|
||||
Reference in New Issue
Block a user