Repository navigation
Releases
0.7.9 beta (not tested on hardware)
0.7.9 BETA: PKU hidden for Android, read-only mappings for Apple's Virtualization framework, Docker settings fix
Beta. Install at your own risk. The kext changes in this build have not been run on a real PC yet: they compile, the unit tests pass and the kernel symbols resolve, but I have not booted this kext. A bug in a kernel extension can freeze or crash the machine. Keep a fallback OpenCore entry (or the previous kext) at hand. If you need something stable, stay on 0.7.8.
What changed since 0.7.8:
- Android Emulator (issue 8): PKU/OSPKE are hidden from the guest. macOS never enables PKRU in XCR0, but the emulator passes the host's CPUID leaf 7 through, so a Linux guest set
CR4.PKEand failed every signal frame (get_xsave_addr_userwarning, black screen, adboffline). The kext now clears those two bits for every client. This is pull request 11 by @suwardhana, who found the cause and tested it on a Ryzen 7 7700X (Android boots,sys.boot_completed=1). CPUID exits are now tracked for every client, not only HyperKit and Parallels, so please check that Docker and Parallels still start. - Apple Virtualization framework (issue 14): read-only mappings. A range the process can only read (a firmware image mapped from a file) failed with
VM map: cannot pin the buffer: 0x2. If the normal pinning fails, the range is now pinned for reading and mapped without write for the guest (the log says so:mapped read-only). I reproduced the log line with a small program (build/hvf-ro-map-test, in the archive's source tree), but I could not run the Virtualization framework sample itself. Whether it then starts is not known. - Docker Desktop (issue 13):
./rhv docker-desktopno longer stops atsettings-store.json.plutilcannot write a file that is just{}; a missing or empty file is now written whole.
Still open: Android Emulator hangs seen on 0.7.8 other than the PKU one (an endless nested page fault; a loop in firmware with the host GPU), UTM 5.0.8 and the Windows installer (issue 15), Docker with code-signing enforcement on (issues 1, 10), USB in Parallels (issue 6). Sleep/wake with a running VM is in review (pull request 12 by @quangnguyenn98, not part of this build).
Thanks to everyone whose reports and logs led to this build: @suwardhana (the PKU diagnosis and the fix), @qualchrone (testing every Android build and the logs that showed the invalid CR0), @Tresillo2017 (the detailed Android report and the stale hyperkit.pid hint), @georgwacker (issue 14 with logs, and the reports on Docker, Parallels and UTM), @Astral420 (issue 13), @aklusa022 (issue 10), @wh0ami7 (UTM), @quangnguyenn98 (the sleep/wake work).
Tested: the unit tests (make test), the kext builds and all its imported symbols resolve against the kernel. Not tested: the 0.7.9 kext on hardware (any machine), Android Emulator, Virtualization framework, Docker and Parallels with this kext, macOS 26.
Update: unpack, ./rhv kext --native, reboot. Boot service: ./rhv autostart install if you have not run it since 0.7.7.
0.7.8
0.7.8: Android Emulator no longer hits an invalid guest state, a self-contained RyzenHV.app, Parallels check without the signature test
- Android Emulator / QEMU HVF clients (issue 8). These clients write CR0 with NW set and CD clear at reset. That guest state is illegal on AMD, so VMRUN was rejected over and over (
VMEXIT_INVALID,cr0=0x20000030inrhv-info log). The kext now keeps NW in the field (the client reads it back) and leaves it out of the VMCB when CD is clear. Whether the emulator then starts is not known: I could not test the Android Emulator here. - RyzenHV.app contains the release. The app no longer downloads anything or needs a terminal: it installs the embedded release by itself and reinstalls when the embedded one is newer (version, then build stamp). Download
RyzenHV-0.7.8-app-macos-x86_64.zip, unzip, open. - Parallels. The signature (TeamIdentifier) test in
parallels-shim.shis gone; only a leftover wrapper script from an older install is refused. The patch is still found by pattern in other Parallels builds (./rhv parallels check). - Open points from the issues:
docs/ROADMAP.md, items 13 to 19. VMware Fusion's hang at the Windows logo is still not solved.
Tested on a Ryzen 7 5800H, macOS 15.8.1: the unit tests (the CR0 rule is covered), the kext builds. Not tested: Android Emulator, other machines, macOS 26.
Update: unpack, ./rhv kext --native, reboot (or use the app). Boot service: ./rhv autostart install if you have not run it since 0.7.7.
0.7.7
0.7.7: a stale Docker pid file is removed at boot, the kext logs why HyperKit may be killed on macOS 26, CR2 writes are applied
- Docker after a reboot. HyperKit refused to start ("Failed to set up pidfile") when
hyperkit.pidfrom the previous boot was still there. The boot service now removes a pid file that does not name a running HyperKit. Run./rhv autostart installonce to get the new script. - macOS 26 and Docker (issue 1). Before it patches HyperKit, the kext writes the process's code-signing flags to the log (
rhv-info log | grep "client fix-ups"):enforcement offis what a machine with AMFI relaxed shows; withenforcement ONit adds a warning, because on macOS 26.7.1 a HyperKit with enforcement on was killed (Code Signature Invalid) right after the patch. Whether relaxing AMFI is enough on macOS 26 is not known (not tested there). - CR2. The kext did not apply a write of CR2 by the client; it does now (VMware's instruction emulator injects page faults). No program tried here writes it.
- For debugging a stalled client (off by default, no cost when off):
rhv-info hv debug N,hv flightdump [N [SKIP]],hv readguest <hex va>: a ring of the last 2048 exits with registers, GS/KERNEL_GS_BASE and what the client wrote before each run, and a read of guest memory through the guest's own page tables. It was used to look at VMware Fusion's hang at the Windows logo, which is not solved: the guest ends in a recursive page fault in Windows'KiPageFaultwith the user GS base (details indocs/ROADMAP.md, item 12). - The open points from the issues are in
docs/ROADMAP.md(items 13 to 19). One of them: HyperKit sometimes aborts in its vCPU thread (once in about six starts here, also once on an older build); starting Docker again works.
Tested on a Ryzen 7 5800H, macOS 15.8.1: Docker hello-world and alpine in native mode (the kext in the archive has the same code as the one tested); Parallels (native), Windows 10 boot with the keyboard armed and prlctl exec; the unit tests. Not tested: other machines, macOS 26.
Update: unpack, ./rhv kext --native, reboot, ./rhv autostart install.
0.7.6
0.7.6: Parallels' keyboard fix is found by bytes, not by address (shim only; the kext is the same code as 0.7.5)
To make the keyboard work, the stand-in library for Parallels calls libMonitor's POST-code handler and sets its flags. Until now it found them at fixed offsets from Parallels 26.5.0 (build 57613). It now finds the handler by the bytes of its start, and the two flags by reading the addresses out of the instructions that test and set them. It acts only if the code matches exactly once; otherwise it leaves the monitor alone and ~/.ryzenhv/prl-patch.log says POST code handler: pattern not found. The log also shows where it found them (handler at +0xβ¦, flags at β¦). Both the native-mode library and the old shim use it. The CPUID vendor check was already found by bytes.
This helps if a Parallels build moves the code around; a build that changes this function itself still needs a new pattern. Only build 57613 was tried.
Tested, Ryzen 7 5800H, macOS 15.8.1: the pattern finder on synthetic cases and on the installed libMonitor (same offsets as before); Parallels in native mode, a Windows 10 VM resumed with the new library: handler and flags found, keyboard armed. The kext in the archive has the same code as 0.7.5 (only the version string differs), so a 0.7.5 kext in your EFI keeps working. Not tested: other Parallels builds, other machines.
Update: unpack, ./rhv parallels native again (it replaces the library in the private copy). No reboot is needed if the kext is already 0.7.5.
RyzenHV 0.7.5: VMware Fusion gets past its BIOS
0.7.5: VMware Fusion 26 gets past its BIOS (a fix in the kext's run trap)
VMware Fusion 26 used to show a black screen with no error. The cause was in the kext: when a client switches on NMI-window exiting, the run trap answers at once without running the guest, and it dropped the registers (RIP, RSP, RFLAGS, GPRs) of that batch while it kept the VMCS fields. Fusion enters SMM exactly like this (its BIOS sends itself an SMI through the local APIC, then Fusion sets the NMI window and writes CS=0x3000, RIP and the rest in one batch), so its guest ended up with the new code segment and the old RIP and ran off into zeros. The registers are now applied before that early return.
With 0.7.5 Fusion's BIOS finishes and Windows starts: the boot logo appears. It then stays there: the guest sits in a loop in the Windows kernel and the installer does not go on. So Fusion is not usable yet (details and what is known in docs/ROADMAP.md, item 12). The change does not touch the other programs' paths.
Tested on this build (the kext in the archive has the same code as the one tested), Ryzen 7 5800H, macOS 15.8.1: Docker Desktop hello-world and alpine (16 vCPUs); hvf-smoke and selftest pass; Parallels Desktop in native mode: Windows 10 cold boot in 16 s, keyboard, suspend and resume (the Parallels Desktop app open); VirtualBox 7.2: a Windows 10 VM runs to its first-start setup screen; Fusion as above. Not tested: other machines.
Also in the repository since 0.7.4: the reason Parallels' 3D acceleration crashes with the third-party NVIDIA Metal driver (docs/PARALLELS.md; it is the driver, not RyzenHV).
Install: unpack, ./rhv kext --native, reboot, ./rhv doctor, ./rhv autostart install, then ./rhv parallels native. Keep a working EFI without the kext.
RyzenHV 0.7.4: SVM on CPU cores that come online late (issue 1)
0.7.4: SVM on CPU cores that come online after the kext starts (issue 1)
On macOS 26 the kext was started when only one core was online (cpus=1 in the log of a Ryzen 9 5900X), so SVM was switched on for that core alone, and a VM thread that ran on any other core stopped with VmRun: SVM cannot be used on cpu N. The kext now looks for cores again: svm::rescan() probes the ones it has not seen, gives them a host save area and turns SVM on. It runs when a VM or a vCPU is created, and once in VmRun if the core it runs on was never seen. The log line rescan: the rendezvous reached N CPUs says whether the late cores answer.
Tested on a Ryzen 7 5800H, macOS 15.8.1, with rhv-info hv svmlimit 1 (new, debugging: makes the SVM code forget cores 1 and up, the state from the issue) and rhv-info hv rescan: rescan brings back 15 cores, selftest 16 of 16; hvf-smoke passes from that state; Docker Desktop hello-world; Parallels Windows 10 cold boot in 21 s with the keyboard working; a VirtualBox 7.2.22 VM boots; and svmlimit 1 while the Parallels VM runs: VmRun rescans and the guest keeps going. Not tested on Tahoe itself: whether the late cores answer there is what the log line will show.
Install: unpack, ./rhv kext --native, reboot, ./rhv doctor, ./rhv autostart install, then ./rhv parallels native. Keep a working EFI without the kext.
RyzenHV 0.7.3: the TPR shadow in native mode, VirtualBox 7.x, a keyboard fix for restored VMs
0.7.3: the TPR shadow in native mode, VirtualBox 7.x, a keyboard fix for restored Parallels VMs
The kext now offers the TPR shadow by default (to every client except HyperKit). Windows changes its interrupt priority through CR8 all the time, and without the VMX "use TPR shadow" control every such access is a VM exit: most of the exits of a Windows boot. With it, on a Ryzen 7 5800H and macOS 15.8.1:
- Parallels Desktop 26.5.0 in native mode (
./rhv parallels native): a cold boot of Windows 10 (4 vCPUs) reaches the point where the guest tools answer in about 20 s, was about 90 s. - VirtualBox 7.x (new, experimental): VirtualBox 7 has no kernel driver on macOS and runs through Hypervisor.framework, so it now runs on the kext's native mode. With 7.2.22 an EFI VM with 2 vCPUs boots the Windows 10 installer and reaches its disk page in about a minute; without the shadow it did not get past the first screen in minutes. Its log says
Turtle execution mode(hv_vm_space_*are not implemented yet), so it is below full speed. No full installation onto a disk has been run yet.
Turn the shadow off with the boot-arg rhv_tpr_shadow=0, or for the VMs created from then on with rhv-info hv tpr 0 (rhv-info hv shows whether it is on). Also in the kext: the task priority round-trips as the 8-bit HV_X86_TPR for every client but HyperKit (it was Parallels only), hv_vmx_vcpu_set_apic_address answers success, and for VMX control words a client is told the real limits (bits that must or may be 1) like hv_vmx_read_capability does; HyperKit keeps its old answer.
Keyboard in a native Parallels VM restored from a saved state now works: the monitor's "armed" flag is saved with the VM, while its second flag is per process, so the stand-in library arms the monitor until both are set.
Tested on this build (the kext in the archive is the one that was tested): Docker Desktop hello-world and alpine (16 vCPUs); Parallels Windows 10: cold boot, keyboard (Ctrl+Esc through prlctl send-key-event), suspend and resume; VirtualBox as above; hvf-smoke (public API, passes; its stage 3 now tolerates the external-interrupt exits that Hypervisor.framework may return at any time).
Known problem: prlctl suspend hung twice when the Parallels Desktop app was not running (only its background service): the state files were written, the VM stayed "suspending" and its process could not exit until a reboot. With the app open, suspend and resume worked every time. The cause is not known; keep the app open or shut the VM down. See docs/NATIVE.md.
VirtualBox 6.x is a different story: it loads its own driver, which wants to switch AMD-V on itself and stops with VERR_SVM_IN_USE while the kext keeps EFER.SVME on every core (issue #2). Use 7.x.
Install: unpack, ./rhv kext --native, reboot, ./rhv doctor, ./rhv autostart install, then ./rhv parallels native. Details in START-HERE.md. Keep a working EFI without the kext.
RyzenHV 0.7.2: the keyboard in native Parallels, a boot service, app updates
0.7.2: the keyboard in native Parallels, a boot service for kern.hv_support, app updates
The keyboard works in a Parallels VM in native mode (./rhv parallels native, see docs/NATIVE.md). Parallels' monitor drops every key until the guest writes 0 to port 0x80, which Parallels' own firmware does only under Parallels' own hypervisor. The stand-in library now wraps hv_vcpu_run and hv_vcpu_run_until in libMonitor's imports (the monitor uses the second) and calls the monitor's own port handler with 0: on the first guest access to the keyboard controller, and once a second while the flag is still clear (a VM restored from a saved state never touches the keyboard controller again). Verified on a Ryzen 7 5800H, macOS 15.8.1, Windows 10 guest on 4 vCPUs: keys sent with prlctl send-key-event (Ctrl+Esc opens the Start menu) reach the guest after a cold boot and after a resume. Not tested: typing in the VM window, other keyboard layouts. Suspend and resume of a native VM also worked in several cycles.
./rhv autostart install (also a button in the app): a launchd service that turns kern.hv_support on at every boot, so Parallels no longer falls back to its own engine after a restart. It copies rhv-info to /usr/local/libexec/ryzenhv (owned by root) and writes /Library/LaunchDaemons/com.overlorddev.ryzenhv.hvsysctl.plist; ./rhv autostart remove undoes it. Installed and run on the author's machine; a real boot with it has not been observed yet.
The app (RyzenHV-0.7.2-app-macos-x86_64.zip): a new "Automatic start" page and an "Enable, native mode" button on the Parallels page. It builds, and it was started against this bundle and stayed running; its buttons were not clicked. The Install button runs the same command that was run through the password dialog. The app is ad-hoc signed: after a browser download run xattr -dr com.apple.quarantine RyzenHV.app.
The kext is unchanged since 0.7.1 (the same code, constants and data, checked section by section; it still reports 0.7.1). So the guard against the VMRUN panic from issue #1 is the same one, and still not tested on macOS 26.
Plan for what is left to make everything native (TPR shadow for speed, the Parallels window, Mac sleep/wake, no wrapper in /Applications): docs/ROADMAP.md, phase 5. Install: unpack, ./rhv kext --native, reboot, ./rhv doctor, ./rhv autostart install, ./rhv parallels native. Details in START-HERE.md. Keep a working EFI without the kext.
RyzenHV 0.7.1: Parallels in native mode (experimental), a check against a VMRUN panic
0.7.1: Parallels in native mode (experimental), a check against a VMRUN panic, a clearer doctor
Parallels Desktop 26.5.0 now also runs in native mode. With the kext in native mode (./rhv kext --native, reboot, rhv-info hv sysctl 1) run ./rhv parallels native: Parallels then uses Apple's own Hypervisor.framework and the kext, and only its CPU-vendor check is patched in memory by a small stand-in library (no hv_* call is replaced). Tested on a Ryzen 7 5800H, macOS 15.8.1, with a Windows 10 (LTSC 1809) guest: it boots to the desktop on 1 and on 4 vCPUs, Parallels Tools and the network work, no kext errors. Experimental, read docs/NATIVE.md: only Windows 10 was tried; keyboard input is probably not working in this mode yet (the shim route, ./rhv parallels, is unchanged and has it); a boot is about two to three times slower than with the shim (no TPR shadow); sleep/wake, 3D, snapshots and long runs are untested; rhv-info hv sysctl 1 is needed after every reboot.
Issue #1 (kernel panic at rhv_svm_vmrun on macOS 26.7.1 with a Ryzen 9 5900X): before every VMRUN the kext now reads EFER.SVME and VM_HSAVE_PA on the CPU it is about to run on and restores them, or refuses the run with a log line, instead of a #UD panic at CLGI. Not reproduced and not tested on macOS 26: only the "nothing is wrong" path has run here. If it still panics, please send rhv-info log and sudo rhv-info selftest.
./rhv doctor now says when it is run from a git checkout instead of the unpacked release archive (no VERSION, bin/, qemu/), instead of blaming the kext or QEMU.
Also in the kext: the commpage that hv_vmx_tsc_clock spins on is filled in, XSAVE images with XSTATE_BV wider than XCR0 are cut, and for Parallels only: hypervisor hidden and an Intel-style topology in CPUID, the 8-bit task priority round-trips into V_TPR, the LAPIC page is not mapped. Docker Desktop native mode was re-checked on the build (hello-world, alpine).
The release kext has the same code, constants and data as the one tested on the hardware; only the version string and build time differ (checked section by section). A few INFO log lines are new (the first exits of a non-HyperKit VM and its interrupt injections); they will be quieter in the next version.
Install: unpack, ./rhv kext (or --native), reboot, ./rhv doctor. Details in START-HERE.md. Keep a working EFI without the kext.
RyzenHV 0.7.0: native mode (experimental)
0.7.0: native mode (experimental, opt-in)
With the boot-arg rhv_hv=1 (./rhv kext --native adds it) the kext registers with xnu in the place of AppleHV, so the real, unmodified
Hypervisor.framework talks to it. Docker Desktop 4.97.0 (Intel build) runs with Docker's own files: no shim, no wrappers, nothing re-signed, nothing changed in Docker.app.
./rhv docker-desktop only switches Docker to HyperKit in its settings.
Tested on a Ryzen 7 5800H, macOS 15.8.1, OpenCore: the engine starts, hello-world, 30 containers at once, builds, pulls, 16 busy vCPUs, parallel 2 GB disk writes, memory tests; no panic, error counters 0.
QEMU with -accel hvf also boots Linux natively (after rhv-info hv sysctl 1, which the kext does by decoding the kernel's own hv_get_support).
How HyperKit's two CPU checks (the GenuineIntel vendor check and verify_gla) are handled: when com.docker.hyper... creates its VM, the kext finds those two branches by their bytes in that process and changes them in memory, once. Another Docker build is left alone and the kext log says so. Needs AMFI relaxed (amfi_get_out_of_my_way=0x1).
Read docs/NATIVE.md before using it. Known and not closed: a race between hv_vm_map and hv_vm_destroy in two threads, a stale vCPU target after exec() with a live VM, no entitlement check (with rhv_allow_users=1 any local user can create a VM), hv_vcpu_run_until's deadline ignored, sleep/wake and multi-hour runs untested, rhv_hv_sysctl=1 at boot untested. Parallels is not native yet: use the shim (./rhv parallels).
The release kext differs from the one that was tested live only by removed debug logging.
Without rhv_hv=1 the kext behaves exactly like 0.6. Keep a working EFI without the kext.
Install: unpack, ./rhv kext --native, reboot, ./rhv doctor, ./rhv docker-desktop get (if needed), ./rhv docker-desktop, open -a Docker. Details in START-HERE.md.