Skip to content

Memory Interrupt Vector Lifetimes

Codex edited this page Oct 10, 2026 · 1 revision

Owned interrupt-vector roots and excess-stub lifetime

Identity and review boundary

Owned reconstructed release64 tree 1277f2b7bf45a0992ef56d45d55815396d46ac8d, product main d4350b603452e029d0862fb48e7d4907e489e8ef. The relative owned source paths below identify the reconstructed kernel build.

References below are relative to that reconstructed source tree. Exact linked size metadata is retained in the local lab's current64-inventory.json and current64-all-symbols.csv, and published in Memory-Function-and-Table-Ledger. No product edits, private reference reads, builds/tests, rig actions, or firmware qualification were performed.

Current GitHub searches for IDT, vector, unexpected handlers and interrupt stubs found no dedicated implementation PR. Issue #106 comment6091844208 already publishes this 1,344-byte lead and its unresolved arithmetic/invalid-vector boundary. PR118 and PR131 comment timelines returned no comments. This is further evidence for the existing #106 lead; do not open duplicate tracking based on this report. Search absence is not a guarantee that no unindexed work exists.

Exact emitted range

ntoskrnl/ke/i386/trap.s:83–100 restricts Xbox IDT generation to16 hardware-vector entries after vector47 and sets its descriptor limit to 0x1ff: 64 entries /512 bytes, vectors0–63. ke/i386/exp.c:29–34 explicitly limits selector conversion to those64 entries. ke/i386/kiinit.c:854–859 installs that descriptor as the live IDT.

But the separate handler generator at trap.s:111–118 uses unconditional REPEAT208, emitting vectors48–255. Each generated handler is a two-byte push plus five-byte relative jump to the shared tail. Existing owned COFF boundaries are:

Boundary VA
Vector48 / KiStartUnexpectedRange 0x84001208
Vector63 0x84001271
Vector64 0x84001278
Vector255 0x840017b1
Following KiTrap00 0x840017b8

Thus excess vectors64–255 occupy the half-open range 0x84001278–0x840017b8 =192 ×7 =1,344 bytes. This is a fixed emitted assembly range with source and adjacent boundary confirmation, not an inferred compiler-function envelope. All208 stubs total1,456 bytes; valid PIC's first16 total112 bytes. Shared tail/template/trap code is excluded from that proposed excess range.

Main .text contains328,884 virtual bytes /81 pages. A layout-neutral1,344-byte reduction would yield327,540 bytes, below the80-page boundary327,680. Potential recovery is one4KiB image page, contingent on final relink/alignment and physical ownership; it is not an already measured saving or permission to discard live pages. Both memory capacities share the same source contract, but these exact VA/size measurements are release64.

Consumer-domain ledger

Consumer/publication Actual source domain Evidence and consequence
Initial/live hardware IDT 0–63 entries; PIC handlers48–63 trap.s:83–100, kiinit.c:859. Vector64+ cannot normally dispatch through this installed descriptor; an interrupt/software INT beyond its limit faults rather than selecting an extra stub.
PIC delayed software interrupt reentry IRQ0–15 → vectors48–63 hal/halx86/pic/pic.c:152–195 emits16 fixed INT wrappers; its20-entry pending table contains four software slots plus16 hardware handlers (198–220).
HAL timer/RTC installation timer0x30; RTC0x38 hal/halx86/pic/halinit.c:34–52. These keep valid handlers/template/dispatch ownership resident.
Static owned device tree IRQ1,9,4,5,6,14,15,3 → PIC vectors ntoskrnl/xb/devtree.c:34–87; translation at 288–307. Its current hardware resources lie inside0–15.
KiGetVectorDispatch no range validation; HAL result narrowed to UCHAR ke/i386/irqobj.c:26–81; computes KiStartUnexpectedRange + (Entry-48)*KiUnexpectedEntrySize, then queries IDT. This arithmetic root is invisible to a direct-edge-only graph. Entries below48 underflow its intended stub domain; entries64+ exceed the real IDT.
HalVectorToIDTEntry (UCHAR)Vector fstub/halstub.c:121–125; no installed replacement was found in the Xbox HAL sources. Large ULONG values wrap to an8-bit IDT entry, not an admission check.
KeQueryInterruptHandler / KeRegisterInterruptHandler indexes Pcr->IDT[Entry] without limit check include/internal/i386/ke.h:330–368. Beyond63 is a data read/write past the512-byte IDT even though CPU dispatch would reject that vector. Extra code stubs do not make this memory access valid.
KeInitializeInterrupt stores arbitrary caller ULONG Vector irqobj.c:327–385. Initialization itself copies/patches the per-object dispatch template and records Vector; no connect-time table access yet.
KeConnectInterrupt validates IRQL, CPU, synchronization, floating save; no Vector check irqobj.c:407–428. Calls KiGetVectorDispatch before HalEnableSystemInterrupt. Invalid vectors therefore reach IDT access before the HAL's later enable rejection.
Connect/share/disconnect setter trusts Interrupt->Vector irqobj.c:92–129,430–479,505–570. KiConnectVectorToInterrupt re-queries and writes the IDT; last disconnect restores the arithmetic NoDispatch pointer. Correct admission must cover the whole lifecycle, not only initial publication.
Native IoConnectInterrupt forwards Vector unvalidated io/iomgr/irq.c:23–105; driver callers must use translated resources, but the native entry itself does not enforce the Xbox bound.
Xbox ordinal109 initializer forwards title's Vector to native initializer xb/interrupt.c:101–120; shadow storage prevents structure overrun, not vector overrun. Driver-owned shadows reject replacement.
Xbox connect/disconnect wrappers forward owned shadow to native lifecycle xb/interrupt.c:161–191; driver-owned objects follow separate borrowed-owner rules. Ordinary shadows can retain invalid Vector from initialization.
Xbox ordinal44 HAL translator title-supplied IRQ passed to ISA HAL xb/xbe.c:2800–2809, xb/ordinals.map:82. It exposes the broad root-translator boundary described below.
Interrupt template and copied return path required for all connected valid IRQs trap.s:149–162; irqobj.c:370–385 copies template to mutable object storage and patches object's address. No Vector-specific copy of an unexpected stub is made. Common template, template handler and shared unexpected tail remain runtime code.
Processor IDT save/restore and lock-erratum relocation preserve existing descriptor limit ke/i386/cpu.c:997,1035,1167–1174. Copy/restore of current IDTR does not broaden its512-byte limit or create IDT roots for64–255. Title-supplied CPU state/direct ring0 modification is outside a normal fixed-platform admission proof.

The Xbox HAL build includes PIC and system-bus sources explicitly (hal/halx86/xbox.cmake:20,40,67). APIC vector allocation rules in other source variants are not evidence of Xbox consumers.

Concrete unresolved correctness boundary

The current source does not implement one consistent fixed-PIC admission domain:

  1. HalpGetRootInterruptVector accepts BusInterruptLevel <=23 (hal/halx86/pic/pic.c:1265–1290). It adds primary vector base48, producing vectors64–71 for IRQs16–23. This is reachable from public ordinal44 through XeHalGetInterruptVector, ISA bus handler registration and inheritance (legacy/bussupp.c:169–180,220–231; legacy/bus/bushndlr.c:349–357) and HalpGetSystemInterruptVector (legacy/bus/sysbus.c:115–135). The latter checks usage flags, not hardware/IDT capacity. These nonexistent PIC IRQs are accepted by implementation, not valid Xbox hardware interrupt sources.
  2. HalEnableSystemInterrupt rejects only Irq >= CLOCK2_LEVEL (pic.c:965–967), where CLOCK2_LEVEL is28 (sdk/include/ndk/i386/asm.h:593). It therefore admits IRQ16–27 by its numeric check. Its dismiss tables have 16 entries (pic.c:55,87); level-sensitive enable can index beyond them at 983. HalBeginSystemInterrupt also directly indexes the16-entry dismiss table (1049–1050). Those are existing bounds problems, not made safe by retaining handlers64–255.
  3. The native connect path dereferences/query-writes the64-entry IDT before enable validation. Arbitrary title Vector values can also wrap through UCHAR, including into exception vectors. Assertions are not release admission checks.

Therefore the normal architectural domain is PIC IRQ0–15 /vectors48–63, but the published software APIs do not yet prove that all admitted calls stay in it. No legal fixed-PIC hardware source needs the extra192 handlers; nevertheless, unqualified deletion today would leave arithmetic addresses for invalid calls pointing into unrelated following code. The existing path is already unsafe before handler execution, so this is not evidence that the stubs are required to preserve valid behavior.

Because titles run ring0, a title could intentionally jump to any kernel byte or install its own IDT. This report does not promise to preserve arbitrary private-address execution. Public export and documented interrupt lifecycle behavior, valid resource translation, rejection of unsupported vectors and callback ownership are the relevant boundaries.

Conditions required before removal

This is a correctness-first source boundary list, not an authorized implementation or broad testing campaign:

  • Define one Xbox PIC domain and reject unsupported IRQ translation before returning a supposedly usable vector.
  • Reject unsupported native connect vectors before IDT query/set, arithmetic stub lookup, PIC bit shifts/table indexing or connected-state mutation. Initialization can retain an invalid marker/value only if every later consumer rejects it safely.
  • Cover raw native driver paths and Xbox shadow wrappers; preserve driver-owned borrowed-interrupt lifecycle and valid shared-vector connect/disconnect behavior.
  • Keep exception/debug/NMI/task-gate consumers0–47 distinct from device interrupt admission; do not apply a48–63 filter to every generic IDT helper without tracing their non-device callers.
  • Bound PIC enable/disable/begin consumers according to their16-entry tables and preserve dispatch-template lifetime for valid IRQs. Establish whether all such internal calls are dominated by validated publication.
  • Only then make Xbox handler generation match its16-entry IDT handler family. Retain KiUnexpectedEntrySize for the first16, the shared tail, and the per-object template. Verify final link/pages before reporting4KiB recovery.

Status: valid hardware root absence beyond63 is source-established; safe deletion is unproved until software admission and arithmetic consumers are closed. This audit does not claim current title crashes originate here.

Other emitted arrays and false unused symbols

Two related arrays are visibly retained at current owned COFF addresses: HalpIDTUsage at 0x8405f620 and HalpIDTUsageFlags at 0x8405f820. hal/halx86/generic/usage.c:18–19 declares each for256 entries. Their declarations use a two-byte IDTUsage payload (KIRQL byte plus relative-vector byte) and one-byte flag (hal/halx86/include/halp.h:189–198), suggesting 768 declared payload bytes versus192 for64 entries, a 576-byte domain-specialization lead. The accompanying Memory-Additional-Table-Lifetimes now independently proves both production array bodies with the captured compiler flags: 512 and 256 bytes. The 576-byte specialization difference remains conditional, not a recovered page.

They are not currently removable arrays: usage registration indexes SystemVector (usage.c:571–575), HAL translation reads flags for the broad accepted domain (sysbus.c:132–135), and generic reporting scans through MAXIMUM_IDTVECTOR (usage.c:399–409). Whole reporting-path runtime inclusion also requires care: its source presence alone does not prove a linked consumer. Shrinking only declarations would be unsafe while these readers/writers retain their bounds. They share .bss backing with live objects;576 bytes is not a demonstrated page recovery.

KiInterruptTemplate2ndDispatch and KiInterruptTemplateObject appear unrooted as standalone static graph labels, but they are interior labels in the template copied by KeInitializeInterrupt, used to compute its patch destination. They are not unused functions/stubs. Likewise the first16 unexpected handlers and SWInterruptHandlerTable entries are runtime indirect roots. No other safely unneeded retained array or public/address-taken stub was established by this bounded audit.

SpiritBoot reference

Internal contracts

BIOS sizes and layouts

Resident memory research

Retail 5838 and current main sizing update — 2026-10-10

Memory removal workbook and kernel overhaul

Clone this wiki locally