Hypervisor Support for M4+ SoCs#622
Closed
ADevWithAnIdea wants to merge 34 commits into
Closed
Conversation
Signed-off-by: Yureka <yuka@yuka.dev>
Signed-off-by: Yureka <yuka@yuka.dev>
Signed-off-by: Yureka <yuka@yuka.dev>
Signed-off-by: Yureka <yuka@yuka.dev>
Signed-off-by: Yureka <yuka@yuka.dev>
Signed-off-by: Yureka <yuka@yuka.dev>
RVBAR (cpu_impl_reg+0) isn't writable on newer chips, so we can't set it to the guest entry, and there is no way the guest can choose a different secondary entry later on. Instead, return the guest entry on reads to make m1n1 happy, and use the initial guest entry as secondary entry. Signed-off-by: Yureka <yuka@yuka.dev>
This fixes use with the new pmgr on A18 Pro / M4 Pro. Signed-off-by: Yureka <yuka@yuka.dev>
Writing a locked RVBAR causes an SError, so skip the write. Signed-off-by: Cody Ho <codyho@stanford.edu>
T8140 also needs DAPF programmed for more DARTs. Other SoCs gate on the ADT, so this will not break existing chips. Signed-off-by: Cody Ho <codyho@stanford.edu>
Some platforms do not expose usable MCC TZ window registers to m1n1, but iBoot still publishes the protected memory ranges under /chosen/carveout-memory-map. Factor the unmap/bookkeeping logic into a helper and, if the MCC TZ register walk yields no regions, unmap region-id-4 and region-id-2 from the ADT carveout map instead. Existing SoCs keep the register-derived path; the ADT fallback only runs when no MCC TZ carveouts were recorded. Signed-off-by: Cody Ho <codyho@stanford.edu>
Add the T8140 AMCC register discovery path. T8140 publishes the AMCC register index and topology through ADT properties and /chosen/lock-regs/amcc rather than matching the older MCC register layouts. The existing cache enable path controls MCC/system-level-cache registers, not CPU caches. Mark older supported layouts as having that cache-control interface, and let T8140 skip it because this boot path does not have usable PLANE_CACHE_ENABLE/STATUS programming for the guarded AMCC state. T8140 also leaves tz unset so protected carveouts are taken from the ADT fallback added by the previous commit. Signed-off-by: Cody Ho <codyho@stanford.edu>
m1n1 maps RAM Normal-WB, which allocates AMCC SLC directory tags. Two
regions are read non-coherently after handoff and then hit those stale
tags, raising AMCC UNEXP_RT_HIT_DIR / RO_RGN_ACCESS_VIO:
- The iBoot handoff carveout (/chosen/iboot-handoff, or carveout
region-id-1): keep m1n1's aliases uncached over that sub-range so no
new WB state is added for the iBoot-RO-locked page.
- The boot framebuffer (/vram): XNU's non-coherent framebuffer writes
hit stale SLC tags -> PEH panic. Remap it Normal-NC (which also cleans
the lines), avoiding the panic without disabling the SLC.
Signed-off-by: Cody Ho <codyho@stanford.edu>
Add find_msgbuf_va() and dump_msgbuf() to recover the XNU kernel message buffer when the serial/panic path is unavailable: Signed-off-by: Cody Ho <codyho@stanford.edu>
Signed-off-by: Cody Ho <codyho@stanford.edu>
CNTVOFF_EL2 is per physical CPU. Apply the current stolen-time offset before entering the boot CPU and secondary CPUs, as well as when returning from an exception, so newly entered guest CPUs do not run with a stale virtual counter offset until their first trap. Signed-off-by: Cody Ho <codyho@stanford.edu>
On SPTM-enabled SoCs XNU boots with the mmu already enabled and expect seeded state (previous SoCs would enable the mmu and create the state themselves). Leaving stale m1n1 EL2 state causes the secondaries to fault; program them with the running guest EL1 state instead. Signed-off-by: Cody Ho <codyho@stanford.edu>
Allow callers to override the primary and secondary guest entry ABI while preserving the existing defaults: primary guests still receive the bootargs pointer, and secondaries still use the discovered RVBAR/entry path unless explicit override state is set. Signed-off-by: Cody Ho <codyho@stanford.edu>
Passing through MMIO acceses to these pages results in EL2 SErrors that we have not figured out how to avoid. This file selectively guards MMIO to prevent the SErrors: reads pass through, writes are selectively forwarded or blackholed by writer-PC range and page index. The exact policy (which writes to forward vs drop) was arrived at over nearly two weeks of trial-and-error. We are not happy with this file, as it is a very ugly hack, however we cannot figure out how to get rid of it. Signed-off-by: Cody Ho <codyho@stanford.edu>
For SPTM enabled devices, booting macOS requires some boot args. Set these by default to avoid users needing to specify them manually. Signed-off-by: Cody Ho <codyho@stanford.edu>
The hypervisor doesn't yet support exclaves, so remove the stale adt nodes to not confuse XNU. Signed-off-by: Cody Ho <codyho@stanford.edu>
M4-class CPUs and above support SME, but XNU's native boot path normally runs with the privilege to program EL2 SME controls directly. Under m1n1 the macOS guest runs at EL1, so those architectural EL2 registers are not writable by the guest even though the hardware feature exists. Add an M4 feature flag, expose it through the proxy ABI, and have EL2 seed CPTR_EL2/FGT/SMPRIMAP_EL2 on the boot CPU and secondaries. Guest loaders can use the same SoC capability bit when deciding whether XNU's direct EL2 SME-control writes need to be neutralized. Signed-off-by: Cody Ho <codyho@stanford.edu>
Signed-off-by: Cody Ho <codyho@stanford.edu>
On M4-class (guarded) SoCs the Apple impdef system registers are GL2-only and fault when executed from EL2, so the HV must intercept the guest's EL1 accesses and soft-model/shadow them (the KERNEL_CNTV timer and the SYSREG_SHADOW bank). Set HCR_EL2.TIDCP so those accesses trap to EL2. Gate it on !apple_sysregs_unlocked: on unlocked SoCs the guest accesses these registers directly at EL1, and trapping them would regress existing (M1-M3) virtualization.
Alongside SYSREG_MAP and SYSREG_PASS, add SYSREG_SHADOW(sr, store): return the last value the guest wrote (or a seeded reset default on first read) and swallow the write, dropping the register hardware side effect. This is for guarded Apple impdef registers that fault at EL2 but whose value XNU reads back (RMW or context save/restore) Signed-off-by: Cody Ho <codyho@stanford.edu>
XNU on Apple Silicon schedules off Apple's impdef KERNEL_CNTV_* timer, not the architectural timer that m1n1 current virtualizes; its CTL/TVAL registers are write-locked at EL2 on M4-class SoCs, so they can't be passed through to hardware. Soft-model it: trap KERNEL_CNTV_CTL/TVAL, keep the deadline and ctl in a per-CPU shadow, read "now" from the counter (KERNEL_CNTVCTSS aliases the already-passed-through CNTVCT_ALIAS), and assert a virtual FIQ from hv_update_fiq() once the soft deadline elapses. Delivery currently rides the periodic HV tick; arming the tick to the exact deadline is a latency refinement. Signed-off-by: Cody Ho <codyho@stanford.edu>
Signed-off-by: Cody Ho <codyho@stanford.edu>
XNU round-trips several Apple impdef registers through RMW and context save/restore paths, but m1n1 does not consume their state. On guarded SoCs those accesses trap to EL2, so keep per-CPU shadows to preserve guest read-after-write behavior. Signed-off-by: Cody Ho <codyho@stanford.edu>
XNU still probes and context-switches Apple AMX state on M4-class SoCs even though userspace uses SME there. The AMX control/state registers fault at EL2 on guarded systems, so preserve guest read-after-write behavior with per-CPU shadows while keeping the existing real-register path on unlocked SoCs. Return a valid AMXIDR value on guarded systems so XNU accepts the AMX version probe during boot. Signed-off-by: Cody Ho <codyho@stanford.edu>
added 4 commits
July 10, 2026 03:51
Signed-off-by: Cody Ho <codyho@stanford.edu>
SPRR registers are locked on M4+ SoCs. Seed and soft-cache SPRR_PERM_EL0 with the sane default values. Signed-off-by: Cody Ho <codyho@stanford.edu>
XNU's AppleT8140CLPC (and presumably other SoCs) path accesses Apple-private sampler registers such as S3_1_C15_C0_3 which are locked on M4+ SoCs. Handle the previously proven CLPC sampler family in C: keep read-after-write coherent state for control registers and provide monotonic guest-visible counters for CLPC perf/accumulator reads. This avoids the Python/EL2 replay fallback without claiming to drive physical CLPC hardware. Signed-off-by: Cody Ho <codyho@stanford.edu>
ACTLR_EL2 is locked on M4+ SoCs so skip the write. Signed-off-by: Cody Ho <codyho@stanford.edu>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
This patch series adds partial support for booting macOS under hypervisor on
A18 Pro (and presumably M4). It is not sufficient by itself; it requires either
a virtualized SPTM companion or SPTM emulator. To this end, we are making
significant progress documenting SPTM and our emulator to allow a clean room
implementation.
Exclaves are not supported and may come in a future patch series. Suspend is
not supported and may require significant work.
One change is required on the base system before installing m1n1: during the
configuration of macOS before m1n1 is installed, the command:
must be run to disable the WindowServer exclave integration. If the directory
does not already exist, it should be created with
root:wheelownership and0644permissions.There is a small amount of known nondeterminism encountered during development:
While testing this hypervisor for upstreaming, we did not hit any of these
issues. We speculate that at least the first two are due to timing related
side effects that are mostly resolved now, however, they are documented here in
case they are found in wider usage of this hypervisor.
There are two known issues with this PR:
The
hv_t8140.cfile is horrific and we spent almost two weeks trying to getrid of it but ultimately were unable to; the current file is the result of many
hours of trial and error and finding the only thing that worked.
The commpage changes currently require hardcoded addresses from the
kernelcache to force the ARM fallback paths. Some values in the commpage are
hardcoded directly in the instructions of the kernelcache with no gate or
other way to disable them. Another option would be to patch the commpage once
it is already published in memory, but this comes with its own set of
tradeoffs. Notably, it has to be located, and guest introspection would be
required to identify when it's been published and will no longer be modified
by XNU. This change is not meant to be immediately upstreamable, but rather
to start a dialog to identify a viable upstreamable path.
Tested on a MacBook Neo running 26.6 Beta 4 using a tainted (not published)
SPTM emulator. NOT tested on any M1-M3 devices to check if any changes
regressed.
Depends on #604 for detecting apple_sysregs_unlocked from the proxyclient
The commits are divided into roughly three sections (the first commit just merges yuka's branch):