diff --git a/README.md b/README.md index 799164b..c9c8c3d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,65 @@ +# Rosetta Support for Linux guests + +This fork adds a commandline option `-g ` to specify the name of the directory share tag +used to expose the Rosetta virtiofs directory share to the arm64 Linux guest. The tag can be any name you choose so long +as it conforms to virtiofs naming conventions. + +The virtiofs directory share contains a single linux/arm64 executable named `rosetta`. This executable is an amd64 +emulator which uses the native Rosetta functionality on MacOS to execute amd64 Linux binaries on the arm64 host +running Apple Silicon. + +To actually make use of it in your arm64 Linux guest you must explicitly register a custom binfmt handler in the arm64 +Linux guest by following the installation steps below. + +Example usage of `vftool` with `-g ROSETTA`: +```shell +vftool/build/vftool -k vmlinux -i initrd -g ROSETTA -d root.img -d varlibdocker.img -m 8192 -p 6 -t 0 -a "root=/dev/vda" "$@" +``` + +## PREREQUISITES +The `binfmt-support` Ubuntu package must be installed in the arm64 Linux guest; this package contains the required +`update-binfmts` tool. +```shell +% sudo apt install binfmt-support +``` + +## INSTALLATION +Run these commands in your arm64 Linux guest on every boot: +```shell +% mkdir /tmp/rosetta +% sudo mount -t virtiofs ROSETTA /tmp/rosetta +% sudo /usr/sbin/update-binfmts --install rosetta /tmp/rosetta/rosetta \ + --magic "\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" \ + --credentials yes --preserve no --fix-binary yes +``` + +The token `ROSETTA` in the `mount` command above MUST MATCH the tag name given to vftool `-g` commandline option. + +You may see this error on first use of `update-binfmts`; ignore it and repeat the command and it should succeed. +``` +update-binfmts: warning: unable to close /proc/sys/fs/binfmt_misc/register: No such file or directory +update-binfmts: warning: unable to enable binary format rosetta +update-binfmts: exiting due to previous errors +``` + +If you intend to use `docker` in the arm64 Linux guest to run containers with the `linux/amd64` platform, it's a good +idea to set this environment variable in your MacOS host for the MacOS `docker` client to use as a default: + +```shell +export DOCKER_DEFAULT_PLATFORM=linux/amd64 +``` + +This environment variable could also be specified in the `/lib/systemd/system/docker.service` systemd unit file on the +arm64 Linux guest by adding this line to the `[Service]` stanza: + +```ini +Environment=DOCKER_DEFAULT_PLATFORM=linux/amd64 +``` + +## Original README follows + +--- # Virtualization.framework tool (vftool) Here lies a _really minimalist_ and very noddy command-line wrapper to run VMs in the macOS Big Sur Virtualization.framework. diff --git a/vftool/main.m b/vftool/main.m index 2e1f528..ee512f1 100644 --- a/vftool/main.m +++ b/vftool/main.m @@ -96,7 +96,8 @@ static int createPty(bool waitForConnection) NSString *initrd_path, struct disc_info *dinfo, unsigned int num_discs, - NSString *bridged_eth) + NSString *bridged_eth, + NSString *rosetta_tag) { /* **************************************************************** */ /* Linux bootloader setup: @@ -210,6 +211,27 @@ static int createPty(bool waitForConnection) [conf setStorageDevices:discs]; + // expose the Rosetta directory share as value of rosetta_tag NSString: + if (rosetta_tag) { + NSError *validationError; + if (![VZVirtioFileSystemDeviceConfiguration validateTag:rosetta_tag error:&validationError]) { + // Handle validation error here. + NSLog(@"-- Configuration validation failure! %@\n", validationError); + return nil; + } + + VZLinuxRosettaDirectoryShare *rosettaDirectoryShare = [[VZLinuxRosettaDirectoryShare alloc] initWithError:&validationError]; + if (validationError) { + NSLog(@"-- Configuration validation failure! %@\n", validationError); + return nil; + } + + VZVirtioFileSystemDeviceConfiguration *fileSystemDevice = [[VZVirtioFileSystemDeviceConfiguration alloc] initWithTag:rosetta_tag]; + fileSystemDevice.share = rosettaDirectoryShare; + + conf.directorySharingDevices = @[fileSystemDevice]; + } + return conf; } @@ -228,6 +250,7 @@ static void usage(const char *me) "\t-p (Default 1)\n" "\t-m (Default 512MB)\n" "\t-t (0 = stdio, 1 = pty (default))\n" + "\t-g \n" "\n\tSpecify multiple discs with multiple -d/-c options, in order (max %d)\n", me, MAX_DISCS); } @@ -242,6 +265,7 @@ int main(int argc, char *argv[]) NSString *disc_path = NULL; NSString *cdrom_path = NULL; NSString *eth_if = NULL; + NSString *rosetta_tag = NULL; unsigned int cpus = 0; unsigned int mem = 0; unsigned int tty_type = 1; @@ -250,7 +274,7 @@ int main(int argc, char *argv[]) unsigned int num_discs = 0; int ch; - while ((ch = getopt(argc, argv, "k:a:i:d:c:b:p:m:t:h")) != -1) { + while ((ch = getopt(argc, argv, "k:a:i:d:c:b:p:m:t:g:h")) != -1) { switch (ch) { case 'k': kern_path = [NSString stringWithUTF8String:optarg]; @@ -289,6 +313,9 @@ int main(int argc, char *argv[]) return 1; } break; + case 'g': + rosetta_tag = [NSString stringWithUTF8String:optarg]; + break; case 'h': default: @@ -323,7 +350,8 @@ int main(int argc, char *argv[]) VZVirtualMachineConfiguration *conf = getVMConfig(mem, cpus, tty_type, cmdline, kern_path, initrd_path, dinfo, num_discs, - eth_if); + eth_if, + rosetta_tag); if (!conf) { NSLog(@"Couldn't create configuration for VM.\n");