Skip to content


Linux on the M1, with GPU acceleration

M12 min read

Apple recently released new MacBook Pros using their incredible M1 (Pro|Max) chips.

Those chips are really impressive. However, MacBooks ship with macOS, an operating system several of us consider much less impressive.

Let's run Linux on them!

Table of Contents

MacBook Pro M1 showing glxgears and neofetch applications running under

MacBook Pro 2021 showing glxgears and neofetch running in virtualized ArchLinux.



The Asahi Linux project is working really hard on bringing a first class Linux experience to the M1 hardware.

Looking on their most recent progress report reveals it has come a lot of way already.

The lack of accelerated graphics and overall driver situation, especially on the laptop models, sadly disqualify it as a daily driver for the time being.


QEMU to the rescue! More specifically, UTM provides a version of QEMU specifically tailored towards M1 Macs (along with fancy GUI).

Most importantly, it ships a virtual graphics mode virtio-ramfb-gl, enabling accelerated graphics on most modern Linux out of the box.


We are going to use the following:

DeviceMacBook Pro 2021
OS (Host)macOS 12.0
OS (VM)ArchLinux ARM
HypervisorUTM v2.4.0

Preparing ArchLinux ARM

Unlike the official ArchLinux project, ArchLinux ARM does not come with a USB installer. Instead, we are going to create a bootable disk ourselves.

Requirements: fdisk, kpartx, qemu-img, bsdtar. Suggested to use any other Linux machine for the following.

Installation procedure based on this Gist. The following is very concise and intended for experienced Arch users.

$: normal user, #: root user

0. Download

In some suitable folder run:

1$ curl -LO
1. Disk

First, partition and mount a new image:

1$ qemu-img create alarm.img 32G
3$ fdisk alarm.img
4 then create the following:
5 - gpt partition table
6 - 200MB+ EFI partition
7 - root partition (rest of disk)
9# kpartx -av alarm.img
10# mkfs.vfat /dev/mapper/loopXp1
11# mkfs.ext4 /dev/mapper/loopXp2
13# mount /dev/mapper/loopXp2 /mnt
14# mkdir /mnt/boot
15# mount /dev/mapper/loopXp1 /mnt/boot
2. OS

Next, extract ArchLinux ARM onto it:

1# bsdtar -xpf ArchLinuxARM-aarch64-latest.tar.gz -C /mnt

Correctly set disk UUIDs in /etc/fstab (use blkid to get yours):

1/dev/disk/by-uuid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX / ext4 defaults 0 0
2/dev/disk/by-uuid/XXXX-XXXX /boot vfat defaults 0 0

Because we cannot set EFIVARS in advance, we need to use a fallback /boot/startup.nsh (fill in your ext4 UUID):

1Image root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw initrd=\initramfs-linux.img
3. Finish

First, unmount:

1# umount -R /mnt
2# kpartx -d alarm.img

Then, convert to .qcow2 (much smaller):

1$ qemu-img convert -O qcow2 alarm.img alarm.qcow2

Transfer that .qcow2 to your M1 Mac then.

VM creation

Continue now on your M1 Mac.

Open UTM, create a new VM (from scratch) and set the following:

CPUCortex A72
Cores8 (# performance cores)

Import Drive, then select your alarm.qcow2

TypeFull Graphics
Retina Modeyes

UTM supports other hardware accelerated GPU types apart from virtio-ramfb-gl, but in my testing they either did not boot at all, or had worse performance.


Power up the VM, it should drop into the UEFI shell, but boot Linux shortly after.

Login as root:root. Linux is basically installed by this point, but some setup is still left:

1# pacman-key --init
2# pacman-key --populate archlinuxarm
3# pacman -Syu

To avoid relying on the the UEFI startup.nsh fallback, setup a bootloader using EFIVARS:

1# efibootmgr --disk /dev/vda --part 1 --create --label "Arch Linux ARM" --loader /Image --unicode 'root=UUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw initrd=\initramfs-linux.img' --verbose

Above uses the EFISTUB functionality of the Linux kernel. Alternatives include systemd-boot, grub2, etc. and work perfectly fine as well.

By this point, ArchLinux ARM is installed. As always, consider following the General Recommendations and setup the system to your liking.

i3 desktop

Obviously we need a desktop enviroment to actually use this. I prefer i3, but choose whatever you like:

1# pacman -S i3 xorg-server xorg-init
2$ startx

There are no special drivers required, X11 works out of the box.

A bit of .xinitrc is needed though:

1# load system wide xinit
2if [ -d /etc/X11/xinit/xinitrc.d ] ; then
3 for f in /etc/X11/xinit/xinitrc.d/?*.sh ; do
4 [ -x "$f" ] && . "$f"
5 done
6 unset f
9# screen layout
11xrandr --newmode $modename 493.75 3024 3264 3592 4160 1910 1913 1923 1979 -hsync +vsync
12xrandr --addmode Virtual-1 $modename
13xrandr --output Virtual-1 --mode $modename
15# HiDPI
16xrdb -merge ~/.Xresources
18# start i3
19exec i3


The MacBook Pro 2021 uses a display with a whopping 3024x1964 pixels and 254 dpi. To avoid everything being incredibly small, the following appears to work well:

1Xft.dpi = 192

1export GDK_SCALE=2
2export GDK_DPI_SCALE=0.5


It's fast! Like, really. Consider these Geekbench scores:

Native (macOS)LinuxCost %

But what about the GPU? I did not find any benchmarking tool that runs on both operating systems, but I compared the fps of the WebGL Aquarium:

# FishNative (macOS)Linux

As expected for a virtualized GPU, performance decreases quite a lot.

However, we did not come for 3D intensive tasks, but for some OpenGL to smoothly browse the web and watch the one or another YouTube video.

And it does that perfectly fine at 60fps, without any noticeable slowdown!