What works / doesn’t work?
- 10G Ethernet: Works.
- WiFi: Can’t find wireless card.
- Audio: Neither HDMI nor onboard audio works.
- USB Audio: Works. If you use Apple USB-C to 3.5mm dongle, connect your headphones / speakers to the dongle first before plugging the dongle into Mac Mini.
- USB3: Degraded speed on type C ports – Operates at 300Mbit/s. Type A ports are fully functional.
- Graphics: fbcon / kmscon works without issue. Can start GUI with llvmpipe and is in fact fast enough to run gnome.
- Built-in NVME drive: Block device nodes exist. My system is not deployed on the internal SSD. Actual usuability and performance remain untested.
Devices and Software
- A linux host where you build the kernel and the bootloader.
- A M1 Mac Mini. Mine has 10Gbit ethernet.
- A USB drive to serve as a makeshift root device.
- A USB-something to USB-C 3.0 cable for sideloading kernel and initrd.
- A USB keyboard hooked on the Mac Mini.
- GCC toolchain targetting at least arm64-noneabi. If your distro doesn’t have a cross compiler toolchain, grab one from Linaro. At the time of writing I’m using GCC 12 unstable snapshot 2021.11-1.
- M1N1 bootloader. Grab from Asahi GitHub. At the time of writing, m1n1 is at commit
660d7482b9f8d9e99fc6414bc366623d092c3229
. To use 10G ethernet, also apply patch in PR125. - Linux kernel 5.16 RC1. Clone or download a tarball snapshot.
- Apply patches in Janne Grunau’s PKGBUILD to the kernel source.
- Apply the patch that resets PCIe devices for proper bring up at startup.
- Apply the patch that sets the PCIe link speed.
- Apply the patch that nudges the 10G Ethernet card to use the right MAC address.
- My kernel configuration (add whatever you need)
- AOSC OS arm64 root filesystem tarball. Grab from repo.aosc.io and dump onto a USB thumb drive formatted to ext4. Other distros should technically work, though initrd / boot command line options may vary.
Compiling
Build the kernel first. Make sure environment variable is set:
ARCH
=arm64
CROSS_COMPILE
= the path of the cross compiler tool chain.INSTALL_MOD_PATH=
/usr in the thumbdrive root file system.
Verify you have arch/arm64/boot/Image.gz
, arch/arm64/boot/dts/apple/t8103-j274.dtb
. Run make modules_install
and make sure the kernel modules are correctly stored at <thumbdrive>/usr/lib/modules/<version-localversion>
.
There’s no good way to generate an initrd
without messing around with QEMU userspace emulation or going to another arm64 Linux machine. Since we are already in a chroot, you may configure root passwords, hostname / timezone and other stuff in there as well. See a random Stack Exchange post on how to do this.
Building m1n1 is very straight forward. Modify the first line in Makefile and set ARCH
to ${CROSS_COMPILE}
, then follow README at https://github.com/AsahiLinux/m1n1. Find compiled m1n1.macho
in build/
.
Follow AsahiLinux Dev Quick Start to provision disk space from Mac OS, transfer m1n1.macho
to 1TR and use kmutil
to use m1n1 as a custom boot object, connect Mac Mini to build host with a USB cable.
Sideloading Kernel and Initrd
m1n1
has a bunch of python scripts to interact with a Mac running m1n1. When the Mac mini is connected to the Linux PC it should appear as a USB serial device, something like /dev/ttyACM0
.
Set environment variable M1N1DEVICE
to /dev/ttyACM0
. Invoke proxyclient/tools/linux.py
to sideload a kernel like this:
python3 linux.py \
-b 'root=/dev/sda1 rw earlycon console=tty0' \
${kernel_source}/arch/arm64/boot/Image.gz \
${kernel_source}/arch/arm64/boot/dts/apple/t8103-j274.dtb \
/path/to/initramfs-5.16.0-rc1-cth-m1+.img
Bootable m1n1 + Kernel Payload
Use the following command to concatenate m1n1 and other stuff used to boot:
cat m1n1.macho \
<(echo 'boot-args=root=/dev/sda1 rw earlycon console=tty0') \
${kernel_source}/arch/arm64/boot/Image.gz \
${kernel_source}/arch/arm64/boot/dts/apple/t8103-j274.dtb \
/path/to/initramfs-5.16.0-rc1-cth-m1+.img \
> /tmp/m1n1+kernel.macho
The combined boot object can be used to boot directly into Linux without another PC.
Notes
Booting from iSCSI
At boot pass parameters root=UUID=XXXX ip=dhcp rd.iscsi.initiator=iqn.<host-iqn:identifier> netroot=iscsi:<server-ip>::::iqn.<server-iqn:target>
instead of a normal root=/dev/XXX
. Also make sure your dracut.conf
includes appropriate modules:
add_dracutmodules+=" iscsi lvm "
# I am using LVM on iSCSI. Ignore if just using normal GPT
install_items+=" /usr/bin/lsusb /usr/bin/lspci /usr/bin/iperf3 "
# Add additional files as you wish
I have effectively included as many core system utilities as possible in case I need to operate on the root device before leaving initrd.
HDCP everywhere under Mac OS / 1TR
Due to lack of desk space and monitors, my Mac mini is hooked up to an HDMI capture card. If your capture card can’t terminate HDCP encryption, anything the Mac Mini displays when running Mac OS / 1TR will be unviewable over the capture device even when there are no “copyrighted” contents being displayed at all. (Dammit. Apple. Why?)
Once M1N1 loads, the capture card should report non-HDCP encrypted content. After Linux kernel taking over the framebuffer, HDMI capture will remain unencrypted and functional.