Skip to content
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

Add ROSETTA virtiofs directory share exposed to guest linux OS #37

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,65 @@
# Rosetta Support for Linux guests

This fork adds a commandline option `-g <rosetta directory share tag>` 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.
Expand Down
34 changes: 31 additions & 3 deletions vftool/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}

Expand All @@ -228,6 +250,7 @@ static void usage(const char *me)
"\t-p <number of processors> (Default 1)\n"
"\t-m <memory size in MB> (Default 512MB)\n"
"\t-t <tty type> (0 = stdio, 1 = pty (default))\n"
"\t-g <rosetta directory share tag>\n"
"\n\tSpecify multiple discs with multiple -d/-c options, in order (max %d)\n",
me, MAX_DISCS);
}
Expand All @@ -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;
Expand All @@ -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];
Expand Down Expand Up @@ -289,6 +313,9 @@ int main(int argc, char *argv[])
return 1;
}
break;
case 'g':
rosetta_tag = [NSString stringWithUTF8String:optarg];
break;

case 'h':
default:
Expand Down Expand Up @@ -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");
Expand Down