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

2021/03/11-progress-report: Fix broken links #50

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions content/blog/2021/03/11-progress-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ m1n1 traces its past to [mini](https://github.com/fail0verflow/mini), which is a

What does that have to do with an Apple Silicon bootloader, you ask? Well, mini was really just a very simple piece of software that runs on bare-metal 32-bit ARM systems without any external libraries or dependencies. It makes for a nice, simple base on which to build bare-metal code, so we ported it to AArch64 and Apple Silicon and renamed it to m1n1. But more importantly, mini and m1n1 have a trick up their sleeves: thanks to mini's legacy as firmware running on a *separate* processor that needs to be controlled from the main CPU, and from past experiments with Wii hardware research, it has a built-in RPC proxy that works over a serial port. This means that you can "remote control" mini and m1n1 from a development computer, in real time. m1n1 lets you play with the M1 hardware using simple Python scripts running on any computer, or even from an [interactive shell](https://github.com/AsahiLinux/docs/wiki/Developer-Quickstart#playground-shell). It would be best described as a hardware experimentation tool that just happens to also feature a Linux bootloader.

This makes for an awesome platform to learn more about the hardware and discover all of Apple's proprietary features. For example, [this script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/fptest.py) tests a special Apple feature that adds support for a some x86-specific floating point configuration bits to their CPUs, which they use to speed up Rosetta x86 emulation. [This script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/find_all_regs.py) searches for all Apple-custom CPU registers and prints their values and their access restrictions. [This script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/hacr_trap_bits.py) automatically figures out how those access restrictions can be customized by an Apple-proprietary hypervisor configuration register. And, of course, [this script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/linux.py) will boot a Linux kernel for you, streamed in straight from the serial port.
This makes for an awesome platform to learn more about the hardware and discover all of Apple's proprietary features. For example, [this script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/experiments/fptest.py) tests a special Apple feature that adds support for a some x86-specific floating point configuration bits to their CPUs, which they use to speed up Rosetta x86 emulation. [This script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/m1n1/find_regs.py) searches for all Apple-custom CPU registers and prints their values and their access restrictions. [This script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/experiments/hacr_trap_bits.py) automatically figures out how those access restrictions can be customized by an Apple-proprietary hypervisor configuration register. And, of course, [this script](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/tools/linux.py) will boot a Linux kernel for you, streamed in straight from the serial port.

Booting an M1 Mac Mini into m1n1 takes about 7 seconds, and all of these scripts can be run interactively without rebooting (until you crash the machine). m1n1 can also [load itself](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/chainload.py), so the development cycle for m1n1 itself is also very fast: you can leave an old version of m1n1 installed with `kmutil` and simply load the most recent one at runtime after a reboot.
Booting an M1 Mac Mini into m1n1 takes about 7 seconds, and all of these scripts can be run interactively without rebooting (until you crash the machine). m1n1 can also [load itself](https://github.com/AsahiLinux/m1n1/blob/main/proxyclient/tools/chainload.py), so the development cycle for m1n1 itself is also very fast: you can leave an old version of m1n1 installed with `kmutil` and simply load the most recent one at runtime after a reboot.

Using m1n1, we've been hard at work documenting Apple’s custom [ARM instructions](https://github.com/AsahiLinux/docs/wiki/HW:Apple-Instructions), Apple-specific [system registers](https://github.com/AsahiLinux/docs/wiki/HW:ARM-System-Registers), hardware such as the [Apple Interrupt Controller](https://github.com/AsahiLinux/docs/wiki/HW:AIC), and more.

Expand Down Expand Up @@ -253,7 +253,7 @@ You see, Apple's first iPhones ran on [Samsung SoCs](https://www.theiphonewiki.c

And so, Linux already has a driver for Samsung UARTs. But there's a catch (of course there's a catch). There isn't a single "Samsung UART". Instead, there are several subtly incompatible variants – and the one that Apple uses is not supported in the Linux Samsung UART driver.

Drivers supporting many variants of the same hardware can get quite messy, and even moreso for drivers as old as this one. Worse, the serial port subsystem in Linux dates back to the earliest versions, and brings with it yet another dimension of cruft: *[beware all ye who read on](https://www.kernel.org/doc/html/latest/driver-api/serial/tty.html)*. And so, the challenge is figuring out how to integrate support for this new UART variant, without making the code *worse*. This means refactoring and cleanup! For example, Linux has an ancient concept of [serial port types](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/serial_core.h) that is exposed to userspace (which means that these types can only ever be added, not removed, as the *userspace* API must remain backwards-compatible), but this is completely at odds with how devices are handled on modern Linux. There is absolutely no reason why userspace should care about what type a serial port is, and if it does it certainly shouldn't use clunky TTY APIs with hardcoded define lists (that is what [sysfs](https://en.wikipedia.org/wiki/Sysfs) is for). Each existing Samsung UART variant had its own port type defined there (and there is even an unused one that was never implemented), but adding yet another one was definitely out of the question... so we refactored the driver to have an internal private notion of the UART variant, unrelated to the port type exposed to userspace. Apple Silicon UARTs just identify themselves as a 16550 to this legacy API, which nobody uses for anything anyway.
Drivers supporting many variants of the same hardware can get quite messy, and even moreso for drivers as old as this one. Worse, the serial port subsystem in Linux dates back to the earliest versions, and brings with it yet another dimension of cruft: *[beware all ye who read on](https://www.kernel.org/doc/html/v5.10/driver-api/serial/tty.html)*. And so, the challenge is figuring out how to integrate support for this new UART variant, without making the code *worse*. This means refactoring and cleanup! For example, Linux has an ancient concept of [serial port types](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/serial_core.h) that is exposed to userspace (which means that these types can only ever be added, not removed, as the *userspace* API must remain backwards-compatible), but this is completely at odds with how devices are handled on modern Linux. There is absolutely no reason why userspace should care about what type a serial port is, and if it does it certainly shouldn't use clunky TTY APIs with hardcoded define lists (that is what [sysfs](https://en.wikipedia.org/wiki/Sysfs) is for). Each existing Samsung UART variant had its own port type defined there (and there is even an unused one that was never implemented), but adding yet another one was definitely out of the question... so we refactored the driver to have an internal private notion of the UART variant, unrelated to the port type exposed to userspace. Apple Silicon UARTs just identify themselves as a 16550 to this legacy API, which nobody uses for anything anyway.

Yet another challenge is how this variant handles interrupts. Older Samsung UARTs had two independent interrupt outputs for transmit and receive, handled separately in the system's interrupt controller. Newer Exynos variants handle this internally, with a little interrupt controller in the UART to handle various interrupt types and deliver them as a single one to the system IRQ controller. The Apple variant also does this, but in an incompatible way with different registers, so separate code paths had to be written for it.

Expand Down