-
-
Notifications
You must be signed in to change notification settings - Fork 158
Add Darwin support via vfkit hypervisor #430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
6e7d7cb
16acd1f
67b66af
7e84afe
95a1204
1f4177c
571fd39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Using Rosetta with vfkit on Apple Silicon | ||
|
|
||
| Rosetta support enables running x86_64 (Intel) binaries in your ARM64 Linux VM on Apple Silicon Macs. This is useful for running legacy applications or development tools that haven't been ported to ARM yet. | ||
|
|
||
| ## Requirements | ||
|
|
||
| - Apple Silicon (M1/M2/M3/etc.) Mac | ||
| - macOS with Rosetta installed | ||
| - vfkit hypervisor | ||
|
|
||
| ## Configuration | ||
|
|
||
| Enable Rosetta in your MicroVM configuration: | ||
|
|
||
| ```nix | ||
| { | ||
| microvm = { | ||
| hypervisor = "vfkit"; | ||
| vfkit.rosetta = { | ||
| enable = true; | ||
| # Optional: install Rosetta automatically if missing | ||
| install = true; | ||
| }; | ||
| }; | ||
| } | ||
| ``` | ||
|
|
||
| ## Guest Setup | ||
|
|
||
| After enabling Rosetta, you need to mount the share and configure binfmt in your guest: | ||
|
|
||
| ```nix | ||
| { | ||
| # Mount the Rosetta share | ||
| fileSystems."/mnt/rosetta" = { | ||
| device = "rosetta"; | ||
| fsType = "virtiofs"; | ||
| }; | ||
| # Configure binfmt to use Rosetta for x86_64 binaries | ||
| boot.binfmt.registrations.rosetta = { | ||
| interpreter = "/mnt/rosetta/rosetta"; | ||
| magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00''; | ||
| mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; | ||
| }; | ||
| } | ||
| ``` | ||
luizribeiro marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Testing | ||
|
|
||
| Once configured, you can verify Rosetta is working: | ||
|
|
||
| ```bash | ||
| # Inside the VM | ||
| uname -m | ||
| # Should show: aarch64 | ||
|
|
||
| # Try running an x86_64 binary (if you have one) | ||
| file /path/to/x86_64/binary | ||
| # Should show: ELF 64-bit LSB executable, x86-64 | ||
|
|
||
| /path/to/x86_64/binary | ||
| # Should run successfully via Rosetta | ||
| ``` | ||
luizribeiro marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Options Reference | ||
|
|
||
| | Option | Type | Default | Description | | ||
| |--------|------|---------|-------------| | ||
| | `microvm.vfkit.rosetta.enable` | bool | `false` | Enable Rosetta support | | ||
| | `microvm.vfkit.rosetta.mountTag` | string | `"rosetta"` | Mount tag for the virtiofs share | | ||
| | `microvm.vfkit.rosetta.install` | bool | `false` | Auto-install Rosetta if missing | | ||
| | `microvm.vfkit.rosetta.ignoreIfMissing` | bool | `false` | Continue if Rosetta unavailable | | ||
|
|
||
| ## Limitations | ||
|
|
||
| - Only works on Apple Silicon Macs (M-series chips) | ||
| - vfkit will fail to start on Intel Macs if Rosetta is enabled | ||
| - Performance is slower than native ARM64 execution | ||
| - Not all x86_64 binaries may work perfectly | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -106,18 +106,24 @@ | |||||||||||||
| }; | ||||||||||||||
| } // | ||||||||||||||
| # wrap self.nixosConfigurations in executable packages | ||||||||||||||
| builtins.foldl' (result: systemName: | ||||||||||||||
| let | ||||||||||||||
| nixos = self.nixosConfigurations.${systemName}; | ||||||||||||||
| name = builtins.replaceStrings [ "${system}-" ] [ "" ] systemName; | ||||||||||||||
| inherit (nixos.config.microvm) hypervisor; | ||||||||||||||
| in | ||||||||||||||
| if nixos.pkgs.stdenv.hostPlatform.system == nixpkgs.lib.replaceString "-darwin" "-linux" system | ||||||||||||||
| then result // { | ||||||||||||||
| "${name}" = nixos.config.microvm.runner.${hypervisor}; | ||||||||||||||
| } | ||||||||||||||
| else result | ||||||||||||||
| ) {} (builtins.attrNames self.nixosConfigurations); | ||||||||||||||
| nixpkgs.lib.listToAttrs ( | ||||||||||||||
| nixpkgs.lib.concatMap (configName: | ||||||||||||||
| let | ||||||||||||||
| config = self.nixosConfigurations.${configName}; | ||||||||||||||
| packageName = builtins.replaceStrings [ "${system}-" ] [ "" ] configName; | ||||||||||||||
luizribeiro marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| # Check if this config's guest system matches our current build system | ||||||||||||||
| # (accounting for darwin hosts building linux guests) | ||||||||||||||
| guestSystem = config.pkgs.stdenv.hostPlatform.system; | ||||||||||||||
| buildSystem = nixpkgs.lib.replaceString "-darwin" "-linux" system; | ||||||||||||||
| in | ||||||||||||||
| if guestSystem == buildSystem | ||||||||||||||
| then [{ | ||||||||||||||
| name = packageName; | ||||||||||||||
| value = config.config.microvm.runner.${config.config.microvm.hypervisor}; | ||||||||||||||
| }] | ||||||||||||||
| else [] | ||||||||||||||
luizribeiro marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| ) (builtins.attrNames self.nixosConfigurations) | ||||||||||||||
| ); | ||||||||||||||
|
|
||||||||||||||
| # Takes too much memory in `nix flake show` | ||||||||||||||
| # checks = import ./checks { inherit self nixpkgs system; }; | ||||||||||||||
|
|
@@ -156,7 +162,22 @@ | |||||||||||||
| # currently broken: | ||||||||||||||
| # "crosvm" | ||||||||||||||
| ]; | ||||||||||||||
| hypervisorsWithUserNet = [ "qemu" "kvmtool" ]; | ||||||||||||||
| hypervisorsWithUserNet = [ "qemu" "kvmtool" "vfkit" ]; | ||||||||||||||
| hypervisorsDarwinOnly = [ "vfkit" ]; | ||||||||||||||
| # Hypervisors that work on darwin (qemu via HVF, vfkit natively) | ||||||||||||||
| hypervisorsOnDarwin = [ "qemu" "vfkit" ]; | ||||||||||||||
| hypervisorsWithTap = builtins.filter | ||||||||||||||
| # vfkit supports networking, but does not support tap | ||||||||||||||
| (hv: hv != "vfkit") | ||||||||||||||
| self.lib.hypervisorsWithNetwork; | ||||||||||||||
|
|
||||||||||||||
| isDarwinOnly = hypervisor: builtins.elem hypervisor hypervisorsDarwinOnly; | ||||||||||||||
| isDarwinSystem = system: nixpkgs.lib.hasSuffix "-darwin" system; | ||||||||||||||
| hypervisorSupportsSystem = hypervisor: system: | ||||||||||||||
| if isDarwinSystem system | ||||||||||||||
| then builtins.elem hypervisor hypervisorsOnDarwin | ||||||||||||||
| else !(isDarwinOnly hypervisor); | ||||||||||||||
|
|
||||||||||||||
| makeExample = { system, hypervisor, config ? {} }: | ||||||||||||||
| nixpkgs.lib.nixosSystem { | ||||||||||||||
| system = nixpkgs.lib.replaceString "-darwin" "-linux" system; | ||||||||||||||
|
|
@@ -172,12 +193,21 @@ | |||||||||||||
| nixpkgs.overlays = [ self.overlay ]; | ||||||||||||||
| microvm = { | ||||||||||||||
| inherit hypervisor; | ||||||||||||||
| # share the host's /nix/store if the hypervisor can do 9p | ||||||||||||||
| shares = lib.optional (builtins.elem hypervisor hypervisorsWith9p) { | ||||||||||||||
| tag = "ro-store"; | ||||||||||||||
| source = "/nix/store"; | ||||||||||||||
| mountPoint = "/nix/.ro-store"; | ||||||||||||||
| }; | ||||||||||||||
| # share the host's /nix/store if the hypervisor supports it | ||||||||||||||
| shares = | ||||||||||||||
| if builtins.elem hypervisor hypervisorsWith9p then [{ | ||||||||||||||
| tag = "ro-store"; | ||||||||||||||
| source = "/nix/store"; | ||||||||||||||
| mountPoint = "/nix/.ro-store"; | ||||||||||||||
| proto = "9p"; | ||||||||||||||
| }] | ||||||||||||||
| else if hypervisor == "vfkit" then [{ | ||||||||||||||
| tag = "ro-store"; | ||||||||||||||
| source = "/nix/store"; | ||||||||||||||
| mountPoint = "/nix/.ro-store"; | ||||||||||||||
| proto = "virtiofs"; | ||||||||||||||
| }] | ||||||||||||||
| else []; | ||||||||||||||
| # writableStoreOverlay = "/nix/.rw-store"; | ||||||||||||||
| # volumes = [ { | ||||||||||||||
| # image = "nix-store-overlay.img"; | ||||||||||||||
|
|
@@ -206,22 +236,28 @@ | |||||||||||||
| config | ||||||||||||||
| ]; | ||||||||||||||
| }; | ||||||||||||||
| in | ||||||||||||||
| (builtins.foldl' (results: system: | ||||||||||||||
| builtins.foldl' ({ result, n }: hypervisor: { | ||||||||||||||
| result = result // { | ||||||||||||||
| "${system}-${hypervisor}-example" = makeExample { | ||||||||||||||
| inherit system hypervisor; | ||||||||||||||
| }; | ||||||||||||||
| } // | ||||||||||||||
| nixpkgs.lib.optionalAttrs (builtins.elem hypervisor self.lib.hypervisorsWithNetwork) { | ||||||||||||||
| "${system}-${hypervisor}-example-with-tap" = makeExample { | ||||||||||||||
|
|
||||||||||||||
| basicExamples = nixpkgs.lib.flatten ( | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't work, right? |
||||||||||||||
| builtins.map (system: | ||||||||||||||
| builtins.map (hypervisor: { | ||||||||||||||
luizribeiro marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| name = "${system}-${hypervisor}-example"; | ||||||||||||||
| value = makeExample { inherit system hypervisor; }; | ||||||||||||||
| shouldInclude = hypervisorSupportsSystem hypervisor system; | ||||||||||||||
| }) self.lib.hypervisors | ||||||||||||||
| ) systems | ||||||||||||||
| ); | ||||||||||||||
|
|
||||||||||||||
| tapExamples = nixpkgs.lib.flatten ( | ||||||||||||||
| builtins.map (system: | ||||||||||||||
| nixpkgs.lib.imap1 (idx: hypervisor: { | ||||||||||||||
|
Comment on lines
251
to
253
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as other comment |
||||||||||||||
| name = "${system}-${hypervisor}-example-with-tap"; | ||||||||||||||
| value = makeExample { | ||||||||||||||
| inherit system hypervisor; | ||||||||||||||
| config = _: { | ||||||||||||||
| microvm.interfaces = [ { | ||||||||||||||
| type = "tap"; | ||||||||||||||
| id = "vm-${builtins.substring 0 4 hypervisor}"; | ||||||||||||||
| mac = "02:00:00:01:01:0${toString n}"; | ||||||||||||||
| mac = "02:00:00:01:01:0${toString idx}"; | ||||||||||||||
| } ]; | ||||||||||||||
| networking = { | ||||||||||||||
| interfaces.eth0.useDHCP = true; | ||||||||||||||
|
|
@@ -233,9 +269,14 @@ | |||||||||||||
| }; | ||||||||||||||
| }; | ||||||||||||||
| }; | ||||||||||||||
| }; | ||||||||||||||
| n = n + 1; | ||||||||||||||
| }) results self.lib.hypervisors | ||||||||||||||
| ) { result = {}; n = 1; } systems).result; | ||||||||||||||
| shouldInclude = builtins.elem hypervisor hypervisorsWithTap | ||||||||||||||
| && hypervisorSupportsSystem hypervisor system; | ||||||||||||||
| }) self.lib.hypervisors | ||||||||||||||
| ) systems | ||||||||||||||
| ); | ||||||||||||||
|
|
||||||||||||||
| included = builtins.filter (ex: ex.shouldInclude) (basicExamples ++ tapExamples); | ||||||||||||||
| in | ||||||||||||||
| builtins.listToAttrs (builtins.map ({ name, value, ... }: { inherit name value; }) included); | ||||||||||||||
| }; | ||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ rec { | |
| "kvmtool" | ||
| "stratovirt" | ||
| "alioth" | ||
| "vfkit" | ||
| ]; | ||
|
|
||
| hypervisorsWithNetwork = hypervisors; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.