Conversation
kvpanch
force-pushed
the
kvpanch/arm_recompiler
branch
from
August 20, 2026 14:35
7a0ddbd to
dd2e909
Compare
Implements a second native codegen backend targeting ARMv8.2-A (Neoverse N1 baseline; runs on Apple Silicon), alongside the existing x86-64 backend. Runs through the generic (signal-based) sandbox. - polkavm-assembler: new `aarch64` module (~70 A64 encoders) and a bitfield/ADR fixup path; `finalize()` is cfg-split so the x86 byte-displacement path is unchanged. - polkavm-common: arch-gate `regmap` (guest regs x0-x12, TMP x13, mem-base x14); enable the arch-neutral `zygote` module on aarch64. - compiler/aarch64.rs: all ~150 ArchVisitor handlers (div/rem with RISC-V divide-by-zero/overflow semantics), trampolines, and a fixed-layout gas stub with an embedded cost literal and a UDF underflow trap. `count_set_bits` (needs NEON cnt) and `memset` remain unimplemented. - generic sandbox: aarch64 entry/exit asm, signal-handler register/PC reads, and Apple-Silicon W^X (MAP_JIT + pthread_jit_write_protect_np + icache flush). - Gate the compiler on aarch64+macos+generic-sandbox; add the libc dep. DOOM and 12 new end-to-end backend tests pass on aarch64-apple-darwin; the x86-64 backend is unaffected. Known gaps: popcount/memset handlers and the dynamic-paging segfault PC-recovery path
…c comments) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Upstream refactored the assembler from an Instruction<T> wrapper struct to an InstructionT trait (encode/fixup now take EncodeFlags). Port the AArch64 backend: instruction types impl InstructionT, constructors return the type directly, and the compiler's push() takes 'impl InstructionT'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The AArch64 generic-sandbox recompiler was gated to macOS only. Enable it on aarch64-linux so it can run at a 4K page size (macOS is 16K-only): - generic sandbox uses libc for its sys module on aarch64-linux (polkavm-linux-raw is x86_64-only); add SIGBUS handling and the Linux ucontext register/fault-address extraction; flush the I-cache via __clear_cache after writing code. - gate the Linux sandbox (zygote/userfaultfd, x86-only) and its shm/allocator modules to x86_64-linux; the generic sandbox is the only compiled backend on aarch64-linux, and SandboxKind::Linux::is_supported() reflects that. All 709 generic-sandbox compiler tests pass at a 4K page size (plus memset_with_dynamic_paging, which is skipped on macOS 16K). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
macOS on Apple Silicon is 16K-only, so the recompiler's paging/mprotect logic is never exercised at 4K on a Mac. This adds a ci/jobs script that boots a Linux guest under Virtualization.framework (Lima vz backend, 4K kernel, near-native speed) and runs the generic-sandbox compiler tests at a real 4K page size, plus a section in RECOMPILER_ARCHITECTURE.md documenting the workflow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o it New `SandboxKind::Hypervisor` behind the `hypervisor-sandbox` feature (aarch64). On macOS it uses Apple Hypervisor.framework to run guest code in a vCPU with its own stage-1 MMU (TCR_EL1.TG0 = 4K), giving faithful 4K guest pages / dynamic paging on any host page size, plus hardware-enforced isolation. Real: the Hypervisor.framework FFI (from the SDK headers); the micro-VM engine (VM/vCPU create, guest-RAM + page-table mapping, identity 4K page tables, MMU sysreg injection, run-loop exit decode, register accessors, per-4K-page protection); and the memory/register-backed Sandbox trait methods. Wiring: config/sandbox/api/compiler/error. On aarch64 the default sandbox now prefers Hypervisor when the feature is enabled (else Generic), gated experimental. The tests pin Generic/Linux explicitly, so they are unaffected. Still todo!() (need PolkaVM's VmCtx/ExitReason shared out of the generic module + compiler-emitted hvc trampolines): run, load_module, prepare_program, address_table, offset_table, sbrk; plus the KVM backend for aarch64-linux. Tests: `cargo test -p polkavm` 717 pass; `--features generic-sandbox, hypervisor-sandbox` 2162 pass; clippy clean. Not yet executed at runtime (needs a binary signed with com.apple.security.hypervisor). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orks)
Builds on the backend scaffold: the Hypervisor.framework sandbox now runs real
PolkaVM programs in a vCPU at a 4K guest granule on a 16K macOS host.
Execution path (hypervisor.rs):
- prepare_program/load_module: copy code into guest RAM (W^X: RW data + RX code
via separate hv_vm_map, since Apple forbids RWX at stage-2), install the hvc
trampoline stubs + guest EL1 exception vector, materialize the memory map with
per-4K-page protections, init the guest VmCtx.
- run/execute: enter via the sysenter stub, decode hvc / data-abort exits into
InterruptKind mirroring the generic sandbox; offset_table/address_table match
the shared aarch64 codegen (gas at 0x60).
- Dynamic paging round-trip: a stage-1 fault traps to the guest's own VBAR_EL1
-> hvc -> host reports Segfault{page_address,page_size}; after the host maps the
page, run() resumes by re-entering at the faulting instruction start (register
snapshot + sysenter), honoring host register edits and not re-firing gas/step
stubs -- same model as generic's handle_guest_pagefault.
- Correct teardown (destroy vCPU before the VM; fixed a vcpu-id-0 sentinel bug),
and a process-global VM lock + thread-local guard: Apple allows one VM per
process, so a second simultaneous instance errors cleanly instead of hanging.
Wiring:
- config.rs: default sandbox prefers Hypervisor on macOS+aarch64 (feature on);
is_supported = macos && aarch64 && feature. Gated experimental.
- compiler/aarch64.rs: vmctx_addr assert accepts Generic | Hypervisor (both put
the vmctx one page below the memory base -> shared codegen).
Tests (tests.rs) + harness:
- 8 hypervisor smoke tests (add/trap, ret, ecall, sbrk, segfault, static-oob,
host-calls, dynamic-paging), all passing via a codesigning test runner
(ci/hypervisor/sign-and-run.sh + hypervisor.entitlements) -- required because
hv_vm_create needs com.apple.security.hypervisor, which cargo-test binaries lack.
- The existing aarch64_backend corpus routes through the hypervisor under
POLKAVM_TEST_HYPERVISOR (env-gated, diagnostic only): 13/13 pass.
Mandatory gates unchanged: cargo test -p polkavm = 717; signed both-features
(no env var) = 2170; clippy 0. Tests pin Generic/Linux so the default flip does
not route them through the hypervisor.
Still todo!(): the KVM backend for aarch64-linux.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hypervisor sandbox - jump table via `adrp` (±4 GiB) instead of `adr` (±1 MiB), which panicked on any program with >1 MiB of native code; out-of-range fixups are now a CompileError, not a panic - immediates/shifts/rotates/comparisons use the immediate encodings, and guest accesses use `[x14, wN, uxtw]`: 1-2 instructions instead of 2-4 - hypervisor: refund gas and preserve registers on mid-run exhaustion, invalidate the guest TLB after page-table edits, enforce accessible_aux_size, and stop reset_memory revoking static protections - hypervisor-sandbox no longer needs generic-sandbox to work - CI: assembler tests actually run, plus aarch64-linux and signed hypervisor jobs
Route the whole test corpus through the Hypervisor.framework sandbox via a new
compiler_hypervisor_* lane -- the only lane exercising a real 4K guest page size
on a 16K macOS host.
Fixes found by doing so:
- Honor the module's page size instead of hardcoding GUEST_PAGE_SIZE. Faults
are reported at that size; stage-1 descriptors stay 4K, so any multiple works.
- Recover the guest program counter on plain traps (trap_at): the EL1 vector
saves nothing, so resolve it from ELR, else from the jump site the
indirect-jump codegen stashed. program_counter() now reads the VmCtx so the
guest stubs' own stores are visible.
- Clear next_program_counter on segfault and gas traps rather than pinning it
to the faulting PC, which wrongly forced a re-entry target.
- Start aux data fully accessible, and bound accessible_for by
accessible_aux_size; also add overflow checks and apply it to protect_memory,
which previously let absent pages be re-protected.
- Bound the VM_LOCK wait (5s) instead of blocking forever: the current owner
may be the caller's own live instance, which never yields.
kvpanch
force-pushed
the
kvpanch/arm_recompiler
branch
from
September 10, 2026 12:42
dd2e909 to
3644a58
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements a second native codegen backend targeting ARMv8.2-A (Neoverse N1 baseline; runs on Apple Silicon), alongside the existing x86-64 backend. Runs through the generic sandbox.
aarch64module