Skip to content

KZT, fix: Preserve callback control-flow boundaries - #508

Open
baibaidashixiong wants to merge 6 commits into
lat-opensource:masterfrom
baibaidashixiong:dev_steam_callbacks
Open

baibaidashixiong wants to merge 6 commits into
lat-opensource:masterfrom
baibaidashixiong:dev_steam_callbacks

Conversation

@baibaidashixiong

@baibaidashixiong baibaidashixiong commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Preserve KZT callback control flow when translated code begins with a fixed LoongArch branch, and limit callback-sentinel exits to RunFunctionWithState so ordinary guest INT3 events follow the guest signal path.

  • Decode complete b/bl and pcaddu18i/jirl destinations, restore the required base/link registers, and track installation by TB, code pointer, flush generation, callback, and guest address.
  • Keep every one-word source branch patched with a one-word b. For a distant callback bridge, allocate a near entry relay and leave the second instruction at its original PC. This preserves PC-relative instructions and the original BL return address, and removes the continuation return jump that overwrote live t0 values.
  • Keep published relay slots immutable, reclaim pages after their TB generation is flushed, and leave source code unchanged if a near relay cannot be allocated. Failed installation remains retryable.
  • Hold conflicting temporary registers until the fixed bridge obtains one distinct from both the restored base and link registers.
  • Register the callback harness in lat-pr-fast. Check execution results for PCADDI, a relative second branch, and a second instruction that writes t0 followed by a read. Cover allocation failure/retry, relay lifetime, and the earlier decoder/bridge/lifecycle regressions.

Validation

Candidate: 48763285d48, rebased onto 182d9f195ec. The five existing commits retain their authors and DCO trailers; the continuation repair is a separate sixth commit.

On a LoongArch host with GCC 14.2 and UBSan:

python3 tests/unit/kzt/test-kzt-callback-branch.py . --cc gcc

Passed portable execution-model and lifecycle checks, production bridge register-allocation checks, and 24 native instruction-execution cases covering forward/backward, near/far, B/BL, and the three continuation cases. Native execution uses the production installer and jump encoders with a minimal callback-body substitute; it is not full application acceptance. The reviewed head failed all three continuation cases on the same host.

A dual-guest test configuration was created with:

mkdir build-tests
cd build-tests
../configure --target-list=x86_64-linux-user,i386-linux-user \
  --enable-latx --enable-latx-avx-opt --enable-tests --disable-werror \
  --optimize-O1 --extra-ldflags=-ldl --disable-docs \
  --meson=meson --with-git-submodules=ignore
meson test --suite lat-pr-fast --print-errorlogs

Both product binaries built successfully, and the complete lat-pr-fast suite passed 47/47 on the rebased candidate. The portable callback harness also passed locally with Clang and UBSan.

The KZT configuration uses the same configure options, with --target-list=x86_64-linux-user --enable-kzt. Validation commands:

ninja -C build-kzt -j8 latx-x86_64 tests/unit/test-kzt-callback-fpr
meson test -C build-kzt --no-rebuild \
  test-kzt-callback-branch test-kzt-elf-lifecycle test-kzt-callback-fpr \
  --print-errorlogs
meson test -C build-kzt --no-rebuild --suite latx-integration \
  test-x11-xcb-wrapper-abi test-x11-async-bridge test-int3-sigtrap-rip \
  --print-errorlogs

KZT product linking succeeded and the three focused tests passed 3/3. All three integration tests exited 77: the X11 tests lack the x86-64 guest sysroot, and the INT3 test lacks Clang to build its guest. These are skips, not passes.

The full KZT-enabled test build has a separate test-latx-aot-segment-unmap link dependency on kzt_wine_bridge, addressed separately in #509. No application acceptance is claimed for this final candidate. Local checks are separate from hosted CI.

Checklist

  • Read CONTRIBUTING.md.
  • Every commit contains a DCO sign-off.
  • Build/test results and remaining validation gates are recorded above.

@baibaidashixiong
baibaidashixiong force-pushed the dev_steam_callbacks branch 2 times, most recently from d9db452 to 455e71b Compare October 14, 2026 07:14
baibaidashixiong and others added 6 commits October 15, 2026 16:38
Exit the KZT cpu_loop only for the RunFunctionWithState callback sentinel. Other guest INT3 events now continue through the normal guest signal path instead of terminating the translator.

Validation: build64/build32; focused INT3 RIP integration coverage passes.
Signed-off-by: zqz <OrzZzznn@gmail.com>
Track callback patch state per translation block, host code pointer, flush generation, callback identity, and guest address. When the target translation block starts with a fixed PC-relative branch, decode the complete LoongArch displacement and restore the original base and link registers before entering the target instead of copying instructions to a different address.

Decode b, bl, and pcaddu18i/jirl without truncation or signed-shift assumptions. Rebuild relocated source instructions from their new buffer, publish two-word patches atomically, flush the instruction cache, and keep TB lookup outside the installation lock so its allocation path cannot leave mmap_lock held.

Validation: build64/build32; focused callback decoder, relocation, identity, and bridge-register tests pass.
Signed-off-by: zqz <OrzZzznn@gmail.com>
Extract the production KZT decoder, installer, and fixed bridge generator into a focused harness. Cover b/bl and pcaddu18i/jirl decoding, source relocation and flush generations, callback identity, lock balance, atomic head publication, and independent base/link register restoration.

The bridge test also forces temporary-register aliasing so target materialization cannot overwrite a restored base or link register.

Validation: build64/latx-x86_64; test-kzt-callback-branch and seven existing callback/KZT focused tests pass.
Signed-off-by: zqz <OrzZzznn@gmail.com>
light_tb_target_set_jmp_target() publishes two words under
CONFIG_LATX_LARGE_CC even when the target is inside the b range, but a
one-word source b/bl reads pinsn[1] as its branch target or link return.
The entry patch therefore replaced the instruction a bl returns to, or
the one a b +4 branches to, and the guest resumed in the middle of the
callback patch.

Keep the one-word entry patch while the bridge stays inside the b range
so pinsn[1] remains untouched.  When the bridge is out of range, keep the
two-word patch and redirect the link return and the b +4 target to a
continuation in front of the bridge that replays the covered word and
then jumps to pinsn + 2.

Validation: build64/latx-x86_64; the callback branch harness covers BL
return, b +4, near and far entry patches, the two-word fixed pair, and the
unchanged normal bridge path.

Signed-off-by: zqz <OrzZzznn@gmail.com>
generate_kzt_fixed_callback_context() restores the decoded base and link
registers before materializing the branch target with a temporary.  The
previous code checked the first temporary against base_reg and link_reg
only once: when the allocator returned base_reg first and link_reg
second, the alternate was used without a second check and li_d()
overwrote the link register the bridge had just restored.

Hold every conflicting temporary while the next one is allocated so the
allocator cannot hand the same register back, and release the held
candidates after a usable temporary is found.

Validation: build64/latx-x86_64; the callback bridge harness covers
separate, aliased and successively conflicting base/link/target
registers.

Signed-off-by: zqz <OrzZzznn@gmail.com>
Keep single-word callback source branches patched with a single b. When the callback bridge is outside b range, use a nearby relay instead of relocating the second instruction and returning through a t0-clobbering long jump. Preserve PC-relative instruction semantics and the original BL return address.

Allocate immutable relay slots under mmap_lock, reclaim previous-generation pages after TB flush, and leave the source unchanged when no nearby mapping is available. Register the callback regression harness in lat-pr-fast and check PCADDI, relative branch, and live t0 results with both portable execution modeling and native LoongArch instruction execution.

Validation on the reviewed base: LoongArch native execution 24/24, UBSan callback and lifecycle checks, dual-guest lat-pr-fast 47/47, KZT product link and three focused KZT tests. Integration tests require unavailable guest development tools; full KZT test linking is blocked by the existing AOT test kzt_wine_bridge dependency.

Signed-off-by: Hanlu Li <heuleehanlu@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants