Skip to content

Add macOS (hvf) and aarch64 support - #308

Open
simongdavies wants to merge 6 commits into
mainfrom
simongdavies-macos-support
Open

simongdavies wants to merge 6 commits into
mainfrom
simongdavies-macos-support

Conversation

@simongdavies

@simongdavies simongdavies commented Sep 16, 2026 •

Copy link
Copy Markdown
Member

Upstream hyperlight-host 0.17.0 already ships the Hypervisor.framework driver, virtual_machine/hvf/, and regs/aarch64/. The remaining work is on the hyperlight-js side: platform wiring, an architecture-derived guest target, and CI/packaging.

Stack: this is the bottom layer of a planned stack. Layer 2 (npm linux-arm64 packaging) follows, and #295 is intended to be rebased on top and appended retrospectively. Review/merge this one first.

Notable Changes

  • Introduce cfg aliases (kvm, mshv3, hvf, whp, crashdump, gdb) in build.rs, mirroring upstream's semantics so platform code never tests a bare feature = "..." flag. Enable hvf by default; scope libc to cfg(unix).

  • Gate with_interrupt_retry_delay on any(kvm, mshv3, hvf) rather than the Linux-only drivers.

  • Add a mach-based thread CPU-time backend for macOS. js-host-api enables monitor-cpu-time unconditionally, so this must compile on every host platform.

  • Add src/hyperlight-js-runtime/include/math.h. This is the one non-obvious change and it is what unblocks aarch64 guest builds:

    newlib guards its __builtin_* fast path with … && !defined(__clang__). cargo-hyperlight drives clang, so math.h falls back to a sizeof dispatch whose never-taken (long double) branch is still code-generated. That is free on x86_64 (80-bit x87) but emits __extenddftf2/__extendsftf2 soft-float libcalls on aarch64 (binary128), which fail to link against the guest sysroot. The shim uses #include_next <math.h> and restores the builtin path under clang.

Pre-existing crashdump build failure

crashdump builds are broken on main today — verified by checking out a clean origin/main into a temp worktree and reproducing the identical E0596. The snapshot helpers take &self but call hyperlight-host APIs requiring &mut self. Fixed at both call sites and gated on the new crashdump alias, which also restricts them to x86_64 in line with upstream.

CI and packaging

  • dep_build matrix goes 6 → 10 jobs: macOS/hvf on the same self-hosted ["self-hosted","macos","arm64","hvf"] runners hyperlight already uses, plus Linux aarch64 KVM. These run the full test suite
  • npm-publish gains an aarch64-apple-darwin binary on macos-15, with a new darwin-arm64 npm package.

@simongdavies simongdavies added the kind/enhancement New feature or improvement label Sep 16, 2026
@simongdavies
simongdavies force-pushed the simongdavies-macos-support branch 2 times, most recently from 2e3b3d6 to 6791f66 Compare September 16, 2026 18:52
@simongdavies
simongdavies added this pull request to stack #311 September 16, 2026 20:37
@simongdavies simongdavies added the ready-for-review PR is ready for (re-)review label Sep 16, 2026

@ludfjig ludfjig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some questions. Also maybe @syntactically could have a look

Comment thread .github/workflows/dep_build.yml
Comment thread .github/workflows/dep_build.yml
Comment thread .github/workflows/dep_build.yml Outdated
Comment thread .github/workflows/npm-publish.yml Outdated
Comment thread .github/workflows/npm-publish.yml
Comment thread .github/workflows/npm-publish.yml
Comment thread docs/release.md Outdated
Comment thread docs/release.md
Comment thread src/hyperlight-js-runtime/include/math.h
Comment thread src/hyperlight-js/src/sandbox/monitor/cpu_time.rs Outdated
simongdavies added a commit that referenced this pull request Sep 28, 2026
`just lint` runs cargo hyperlight clippy, cargo clippy --all-targets and
lint-js, none of which need artifacts from the preceding build steps, so
nothing was gained by running it after them.

clippy executes build.rs, which builds and links the guest, so lint-first
also catches guest toolchain and link failures. This is not theoretical:
during PR #308 a macOS llvm-ar failure surfaced only in the Build step,
many minutes in, when lint-first would have caught it.

clippy and cargo build have separate fingerprints, so the reorder does not
duplicate compilation work.

Net effect: cheap, fast-failing checks run before expensive ones, which
shortens the feedback loop on a matrix of 10+ jobs, several of which run
on scarce self-hosted runners.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
@simongdavies
simongdavies force-pushed the simongdavies-macos-support branch from e5c3eea to 4ae9e57 Compare September 28, 2026 19:37

@ludfjig ludfjig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with the following ai nits

  • Document local LLVM discovery README.md lists Xcode tools, but cargo-hyperlight 0.1.14 searches PATH for llvm-ar and can fall back to Apple's incompatible archiver. Installing llvm-tools does not update PATH. Document adding the active toolchain's LLVM bin directory or a provisioned LLVM installation to PATH.
  • Explain new Mach unsafe operations /src/hyperlight-js/src/sandbox/monitor/cpu_time/macos.rs add safety comments for structure initialization, buffer/count compatibility, cross-thread port use, and single-owner deallocation.
  • Unused alias . Remove whp from /src/hyperlight-js/build.rs; it has no consumer.

simongdavies and others added 6 commits September 29, 2026 08:50
Upstream hyperlight-host 0.17.0 already ships the Hypervisor.framework driver
and aarch64 register support, so the remaining work is on the hyperlight-js
side: platform wiring, an architecture-derived guest target, and CI/packaging.

Hypervisor and platform wiring:
- Introduce cfg aliases (kvm, mshv3, hvf, whp, crashdump, gdb) in build.rs
  mirroring upstream's semantics, so platform code never tests a bare feature
  flag. Enable the `hvf` feature by default and scope `libc` to cfg(unix).
- Gate `with_interrupt_retry_delay` on any(kvm, mshv3, hvf) rather than on the
  Linux-only drivers.
- Add a mach-based thread CPU-time backend for macOS. js-host-api enables
  `monitor-cpu-time` unconditionally, so this has to compile on every host.

Architecture generalisation:
- Derive the guest target triple as `{arch}-hyperlight-none` in build.rs and
  the Justfile instead of hard-coding x86_64.
- Add src/hyperlight-js-runtime/include/math.h. newlib excludes clang from its
  __builtin_* fast path, so math.h falls back to a sizeof dispatch whose
  never-taken `long double` branch is still code-generated. That is free on
  x86_64 (80-bit x87) but emits __extenddftf2/__extendsftf2 soft-float
  libcalls on aarch64, which fail to link against the guest sysroot. The shim
  uses #include_next and restores the builtin path under clang.

Fix a pre-existing crashdump build failure:
- `crashdump` builds are broken on main: the snapshot helpers take &self but
  call hyperlight-host APIs that require &mut self. Take &mut self at both
  call sites and gate them on the new `crashdump` alias, which also restricts
  them to x86_64 in line with upstream.

CI and packaging:
- Extend the dep_build matrix from 6 to 10 jobs, covering macOS/hvf on the
  self-hosted arm64 runners upstream already uses, plus Linux aarch64 KVM.
  These run the full test suite rather than build-only.
- Publish an aarch64-apple-darwin binary and add the darwin-arm64 npm package.

Not yet exercised on real macOS or Linux aarch64 hardware; CI is the first run.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
The self-hosted Mac minis are shared and non-ephemeral, so concurrent
jobs race on ~/.rustup/downloads and rustup intermittently dies with
"could not rename 'downloaded' file from <hash>.partial". Skip the
download when llvm-ar is already present and retry with backoff
otherwise, failing loudly if it still cannot be found.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
The macOS job is the first thing that has ever compiled this code, and
clippy runs with -D warnings, so three diagnostics failed the lint step:
a doc comment on an extern block (rustdoc does not document those), and
libc's mach_thread_self / mach_task_self both being deprecated in favour
of the mach2 crate.

Declare mach_thread_self alongside the existing mach_port_deallocate
declaration rather than taking a new dependency for two symbols.
mach_task_self is a C macro over the mach_task_self_ global, so declare
that global directly; it is only ever read, so an immutable extern
static is sufficient. Demote the extern block's doc comment to a plain
comment.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Every sandbox test failed on macOS with
HyperlightVmError(Create(Vm(CreateVm(CreateVmFd(HvfError(0xfae94007)))))).
0xfae94007 is HV_DENIED: Hypervisor.framework refuses hv_vm_create()
unless the calling process carries com.apple.security.hypervisor, which
is mandatory on Apple Silicon and which plain cargo test binaries do not
have.

Add a cargo target runner for macOS that ad-hoc codesigns each binary
with that entitlement before executing it, mirroring dev/macos-sign-and-run.sh
in hyperlight-dev/hyperlight. Cargo resolves a runner path containing a
separator relative to the config file rather than the working directory,
so a single root .cargo/config.toml also covers the recipes that cd into
src/hyperlight-js. The guest target is unaffected because the runner is
scoped to cfg(target_os = "macos").

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
The cargo runner added in .cargo/config.toml only signs binaries cargo
launches, so the js-host-api suite -- which runs under node via vitest --
still failed with HV_DENIED: 115 failed, 17 passed, the survivors being
the tests that never create a VM.

Copy node into RUNNER_TEMP, ad-hoc sign the copy with the hypervisor
entitlement and prepend it to PATH. npm resolves node through a
/usr/bin/env shebang and entitlements apply per exec, so vitest and its
workers pick the signed copy up. Sign a private copy rather than the
shared tool cache because these runners are not ephemeral.

npm-publish.yml needs no equivalent: it only builds and publishes, and
never creates a VM.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Fix release publishing and validation, make CI architecture and LLVM setup explicit, and split CPU-time implementations by platform.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
@simongdavies
simongdavies force-pushed the simongdavies-macos-support branch from 4ae9e57 to 35f9311 Compare September 29, 2026 07:50
@simongdavies

Copy link
Copy Markdown
Member Author

lgtm with the following ai nits

  • Document local LLVM discovery README.md lists Xcode tools, but cargo-hyperlight 0.1.14 searches PATH for llvm-ar and can fall back to Apple's incompatible archiver. Installing llvm-tools does not update PATH. Document adding the active toolchain's LLVM bin directory or a provisioned LLVM installation to PATH.
  • Explain new Mach unsafe operations /src/hyperlight-js/src/sandbox/monitor/cpu_time/macos.rs add safety comments for structure initialization, buffer/count compatibility, cross-thread port use, and single-owner deallocation.
  • Unused alias . Remove whp from /src/hyperlight-js/build.rs; it has no consumer.

I'll open a new PR in the stack to address this.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement New feature or improvement ready-for-review PR is ready for (re-)review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants