From a57e131a63b6dac9bad73bed2284c24406598f6f Mon Sep 17 00:00:00 2001 From: Evgeny Zinoviev Date: Wed, 3 Feb 2021 17:21:42 +0300 Subject: Update MacBook Pro 10,1, remove SeaBIOS patch, update README --- README.md | 303 +++++++++++++++++++++++++++++++++++----------- mmga | 31 +---- seabios-macbook-fix.patch | 13 -- 3 files changed, 232 insertions(+), 115 deletions(-) delete mode 100644 seabios-macbook-fix.patch diff --git a/README.md b/README.md index e913c6d..8f7f3b3 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,126 @@ # mmga: Make MacBook Great Again -**mmga** is a script to help flashing coreboot on some MacBook Air and Pro models without using external SPI programmer. -#### Supported models -As of time of writing, following models are supported in coreboot. Other models might be supported in future. -* MacBook Air 4,2 (13'' Mid 2011) (`macbookair4_2`).
**Attention!** See the note below. -* MacBook Air 5,2 (13'' Mid 2012) (`macbookair5_2`) +**mmga** is a script to help flashing coreboot on some MacBook Air and Pro +models without using external SPI programmer. See +[this blog post](https://ch1p.io/coreboot-macbook-internal-flashing/) on how to +do the same manually. + +### Supported devices + +As of time of writing, following devices are supported in coreboot. Other models +might be supported in future. + * MacBook Pro 8,1 (13'' Early 2011) (`macbookpro8_1`) * MacBook Pro 10,1 (15'' Mid 2012 Retina) (`macbookpro10_1`) +* MacBook Air 5,2 (13'' Mid 2012) (`macbookair5_2`) +* MacBook Air 4,2 (13'' Mid 2011) (`macbookair4_2`). + + **Attention!** This model hasn't been tested by me, simply because + I don't have it. There were reports that it doesn't work, and by the nature of + those reports I suggest that coreboot port for MBA 4,2 is somehow broken. + Please don't try to use mmga on 4,2 until it's fixed or confirmed to work. + +iMac 13,1 is a candidate for support too, but [coreboot port](https://review.coreboot.org/c/coreboot/+/38883) +for this device is not actively maintained at the moment and it may fail to build. +I'll add iMac 13,1 support later when it's fixed. -**MacBook Air 4,2** is the only model that hasn't been tested or ported by me, simply because I don't have it. -There were reports that it doesn't work, and by the nature of those reports I suggest that coreboot port for MBA 4,2 is broken. -Please don't try to use mmga on 4,2 until it's fixed. +### System requirements -#### System requirements -* Recent Linux booted with `iomem=relaxed` kernel parameter (needed for internal flashing to work); -* Build dependencies. Here's a list for Ubuntu 16.04: +* Recent Linux distribution booted with `iomem=relaxed` kernel parameter + (required for internal programmer to work); +* Build dependencies. Here's a list for Debian-based distros: ``` # apt install bison build-essential curl flex git gnat libncurses5-dev m4 zlib1g-dev make libpci-dev libusb-1.0-0-dev ``` - On other distros package names might differ. Be sure to install **gnat** prior to building coreboot toolchain. -#### Building flashrom -First of all, grab recent flashrom source tree and build it: + If you plan to use GRUB2 as a payload: + ``` + # apt install libfreetype-dev unifont + ``` + + On other distros package names might differ. Be sure to install **gnat** + prior to building coreboot toolchain. + +### Building flashrom + +First of all, grab recent flashrom sources and build it: ``` $ git clone https://review.coreboot.org/flashrom.git && cd flashrom $ make ``` -Optionally you can install it to `/usr/local/sbin`: + +Optionally, install it to `/usr/local/sbin`: ``` $ sudo make install ``` ## How it works -The firmware is stored on SPI chip. On Intel platforms it consists of various regions: `fd` (Flash Descriptor), `me` (Intel ME), `bios` (the BIOS, or, in case of MacBooks, EFI), and some other (such as `gbe` for Gigabit Ethernet). The most important region in context of this story is FD, the Intel Flash Descriptor. -The **Intel Flash Descriptor** is a data structure stored on the flash chip; it contains information such as space allocated for each region of the flash image (also called a layout), read-write permissions for each region and many more. The Flash Descriptor is located at the **first 4K** of the SPI chip (`0x0000-0x0fff`). +The firmware of the devices covered by this project is stored on SPI chip. It +consists of various regions: `fd` (Flash Descriptor), `me` (Intel ME) and `bios` +(BIOS, or Apple EFI). Sometimes there are more regions, for example there may be +`gbe` region for Gigabit Ethernet or `ec` region with EC firmware, but for now, +let's focus on our MacBooks. -Here's flash chip layout used in MacBook Air 5,2 (which has 8M flash chip), extracted from original firmware dump with ifdtool: +The most important region in context of this story is `fd`, the Intel Flash +Descriptor. + +The Intel Flash Descriptor is a data structure of fixed size (4KB) stored on +the flash chip (resides in `0x0000-0x0fff`), that contains various information +such as space allocated for each region on the flash, access permissions, some +chipset configuration and more. In particular, it contains access permissions +for `fd` and `me` regions. + +This is the flash chip layout used in MacBook Air 5,2 (which has 8 MiB flash chip). +It can be extracted from stock ROM image with `ifdtool`: ``` 00000000:00000fff fd 00190000:007fffff bios 00001000:0018ffff me ``` -As you can see, -- the first region (`0x0000-0x0fff`) is used for a Flash Descriptor (as it always is); -- right next to it (`0x1000-0x18ffff`) Intel ME firmware is stored; -- and the last and largest region (`0x190000-0x7fffff`) is the BIOS, or Apple's EFI in our case. -Normally, the FD should be read-only, but this is not the case with MacBooks. Apparently, Apple's "Think Different" (TM) thing applies to firmware security as well. +Normally, the `fd` and `me` regions should be read-only in production, but this +is not the case with MacBooks. Apparently, Apple's "Think Different" thing +applies to firmware security as well. -You can check access permissions on your MacBook by running `flashrom -p internal` (if it doesn't work, make sure you have booted with `iomem=relaxed` and/or use `-p internal:laptop=force_I_want_a_brick` instead). This is what it shows on MacBook Air 5,2 with latest Mojave firmware updates: -``` -# flashrom -p internal -flashrom v1.1-rc1-3-g4ca575d on Linux 4.9.0-9-amd64 (x86_64) -flashrom is free software, get the source code at https://flashrom.org +Instead, they decided to use SPI Protected Range Registers (PR0-PR4) to set +protection over `fd`, but here they failed again. Due to a bug (I hope), +`0x0000-0x0fff` is not write-protected after cold boot and becomes read-only +only after resuming from S3. -Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns). -No DMI table found. -Found chipset "Intel QS77". -Enabling flash write... SPI Configuration is locked down. -PR0: Warning: 0x00190000-0x0066ffff is read-only. -PR1: Warning: 0x00692000-0x01ffffff is read-only. -At least some flash regions are write protected. For write operations, -you should use a flash layout and include only writable regions. See -manpage for more details. -OK. -Found Micron/Numonyx/ST flash chip "N25Q064..3E" (8192 kB, SPI) mapped at physical address 0x00000000ff800000. -No operations were specified. -``` -As you can see, only the `bios` region is read-only, and not even whole `bios` region, because `0x670000-0x681fff` is writable for some reason: +You can dump PRx protections on your device by running `flashrom -p internal`. +If it doesn't work, make sure to boot with `iomem=relaxed` or try +`-p internal:laptop=force_I_want_a_brick`. + +This is what you should see after a cold boot (and, if so, mmga should work on +your device): ``` PR0: Warning: 0x00190000-0x0066ffff is read-only. PR1: Warning: 0x00692000-0x01ffffff is read-only. ``` -It's interesting that this behavior is reproducible only after cold boot. If you suspend to S3, resume and run flashrom again, `fd` will be read-only: + +And this is after resuming from S3: ``` PR0: Warning: 0x00000000-0x00000fff is read-only. PR1: Warning: 0x00190000-0x0066ffff is read-only. PR2: Warning: 0x00692000-0x01ffffff is read-only. ``` -Looks like a bug in Apple's firmware. Obviously it should always be read-only. -Anyway, that means that after cold boot **`fd` and `me` regions are writable**, and that gives us around 1.5M of writable space. Since we can rewrite FD, we can write a new FD with custom layout. So **the idea is to repartition the flash chip** and flash new bios to a writable space. +So, after cold boot flash descriptor is protected neither by PRx registers nor +by access permission bits on the flash descriptor itself. Under certain +circumstances, **writable flash descriptor allows flashing whole SPI flash** by +using a couple of neat tricks, and that is what mmga script does. -Let's write a new layout (I decided to use `0x00000-0xfffff` region for convenience): +Writable `me` region gives us around 1.5 MiB of writable space. The idea is that +we can shrink ME firmware image with me_cleaner to about ~128 KiB and use the +freed space for a small temporary coreboot image. Writable `fd` gives us ability +to change flash layout and move reset vector. We combine all this, flash modified +regions, then power off (new flash descriptor becomes active on cold boot, so +reboot won't work). Then boot our small temporary coreboot and flash the whole +SPI chip, as there will be no more PRx protections set. So this is a two-stage +process. + +Let's write a new layout: ``` 00000000:00000fff fd 00001000:00020fff me @@ -91,33 +128,51 @@ Let's write a new layout (I decided to use `0x00000-0xfffff` region for convenie 00100000:007fffff pd ``` +In this layout, we allocate 128 KiB for `me` and 892 KiB for `bios`. To fit the +original 1.5 MiB ME image into the 128 KiB region, it has to be truncated with +[me_cleaner](https://github.com/corna/me_cleaner) with `-t` and `-r` arguments, +the size of resulting image is ~92 KiB. We also have to allocate the remaining +`0x100000-0x7fffff` region for *something*, to be able to address and flash it +in future. So we just mark it as `pd`, which is commonly used for "Platform Data". -In this layout, we allocate 128K for `me` and 892K for `bios`. To fit the original 1.5M ME image into the 128K region, it has to be truncated with [me_cleaner](https://github.com/corna/me_cleaner) with `-t` and `-r` arguments, the size of resulting image is ~92K. We also have to allocate the remaining `0x100000-0x7fffff` region for something to be able to address and flash it in future, otherwise flashrom will give us a "Transaction error". So we just mark it as `pd`, which stands for "Platform Data". - -After the new layout is ready, we build small coreboot ROM that fits into the allocated 892K bios region. We do that, then flash **`fd`** (`0x0000-0x0fff`), **`me`** (`0x1000-0x20fff`) and **`bios`** (`0x21000-0xfffff`) according to the new layout. On the next cold boot, coreboot will be loaded from the `0x21000-0xfffff` region, and old firmware, which still resides in `0x190000-0x7fffff`, will be ignored. This is **stage1**. +After the new layout is ready, we build small coreboot ROM that fits into the +allocated 892 KiB bios region. Then we flash **`fd`** (`0x0000-0x0fff`), +**`me`** (`0x1000-0x20fff`) and **`bios`** (`0x21000-0xfffff`) according to the +new layout. On the next cold boot, coreboot will be loaded from the +`0x21000-0xfffff` region, and the old firmware, which still resides in +`0x190000-0x7fffff`, will be ignored. This is **stage1**. -After we boot into just-flashed coreboot, we're able to flash the whole 8M chip, because it's not write-protected anymore. We repartition the chip again, and the new layout looks like this: +After we boot with small temporary coreboot ROM, we're able to flash the whole +8 MiB chip, because there are no more PRx protections set. We repartition the +chip again, and the new layout looks like this: ``` 00000000:00000fff fd 00001000:00020fff me 00021000:007fffff bios ``` -It's almost the same, except that `bios` fills all the remaining space. Then we build coreboot again, flash `fd`, `me` and `bios` and shut down again. On the next cold boot we will have completely corebooted MacBook. This is **stage2**. + +It's almost the same, except that `bios` fills all the remaining space. Then we +build coreboot again, flash `fd`, `me` and `bios` and power off again. On the +next cold boot we will have completely corebooted MacBook. This is **stage2**. ## Usage instructions -The **mmga** script automates steps described above and does all dirty work. -##### Usage: +The **mmga** script automates steps described above and does all the dirty work. + +### Usage: + ``` ./mmga ACTION ``` ##### Options: + ``` -h, --help: show help ``` ##### stage1 actions: + ``` dump: dump flash contents fetch: fetch board tree from Gerrit (if needed) @@ -128,6 +183,7 @@ prepare-stage1: patch IFD, neutralize and truncate ME ``` ##### stage2 actions: + ``` prepare-stage2: patch IFD (if needed) config-stage2: make coreboot config (for manual use) @@ -136,19 +192,57 @@ prepare-stage2: patch IFD (if needed) ``` ##### other actions: + ``` flash-oem: flash OEM firmware back ``` -#### Configuration +### Warning + +You **should** have external means of flashing for a backup, **just in case**. +The procedure described above is quite delicate and error-prone and any mistake +may lead to a brick. In that case, you should have a copy of your original ROM +**on external drive**. Please make a backup of `work/oem/dump.bin` after +running `mmga dump`, or just copy the whole mmga directory. + +These posts may be a little helpful if you ever need to flash externally: + +- [MacBook Air 5,2](https://ch1p.io/coreboot-mba52-flashing/) +- [MacBook Pro 10,1](https://ch1p.io/coreboot-mbp101-flashing/) + +### Choosing the payload + +Currently, SeaBIOS and GRUB are supported by mmga. SeaBIOS supports legacy boot, +it will most probably boot from an old school MBR partition. On the other hand, +it may not boot from GPT (I'm not sure about it, correct me if you know more) +and certainly it will not boot an EFI installation. + +Sometimes GRUB is a better choice, but it all depends on your system. If you are +not sure, do some research before flashing or seek for help. + +It may be a good idea to prepare a USB drive with some live system. I can imagine +a situation where you have chosen the wrong payload and cannot boot into your +system after power off/on cycle to complete the second stage, because, for instance, +SeaBIOS doesn't recognize your partition. In that case, you could try to boot +from live USB to fix your system (if possible) or to complete second stage and +change the payload. + +Of course, in order to do that, you should backup the whole mmga directory after +the completion of the first stage but **before** the reboot. + +### Configuration + Before you start, you have to update variables the `config.inc` file: - **`PAYLOAD`**: which payload to use, supported values are `grub` and `seabios` - **`MODEL`**: put your macbook model here, example: `macbookair5_2` -- **`GRUB_CFG_PATH`**: only if you use `grub` payload; if empty, default grub.cfg will be used +- **`GRUB_CFG_PATH`**: only if you use `grub` payload; if empty, default + `grub.cfg` will be used - **`COREBOOT_PATH`**: path to cloned coreboot repository (see below) - **`FLASHROM`**: path to flashrom binary -- **`FLASHROM_ARGS`**: in case if flashrom detects multiple flash chips, put `"-c CHIP_MODEL"` here -- **`STAGE2_USE_FULL_ME`**: if you want to use original Intel ME image in the final ROM for some reason, set to `1` +- **`FLASHROM_ARGS`**: in case if flashrom detects multiple flash chips, put + `"-c CHIP_MODEL"` here +- **`STAGE2_USE_FULL_ME`**: if you want to use original Intel ME image in the + final ROM for some reason, set to `1` #### stage1 @@ -156,53 +250,114 @@ Get coreboot: ``` $ git clone --recurse-submodules https://review.coreboot.org/coreboot.git && cd coreboot ``` -Build coreboot toolchain. You must have gnat compiler installed as it's required for graphics initialization to work (libgfxinit is written in Ada): + +Build coreboot toolchain. You must have gnat compiler installed, it is required +for graphics initialization (libgfxinit is written in Ada): ``` $ make crossgcc-i386 CPUS=$(nproc) $ make iasl ``` + Dump the flash chip contents: ``` -./mmga dump +# ./mmga dump ``` + +**Create a backup of the stock ROM dump on external drive!** + Create patched FD and neutralize ME: ``` -./mmga prepare-stage1 +$ ./mmga prepare-stage1 ``` -If your board's port hasn't been merged to coreboot master yet or you don't know, run: + +If your board's port hasn't been merged to coreboot master yet or you don't know, +run: ``` -./mmga fetch +$ ./mmga fetch ``` + Create coreboot config and build the ROM: ``` -./mmga build-stage1 +$ ./mmga build-stage1 ``` -(If you're experienced coreboot user or developer, you may want to configure and build coreboot yourself. In that case, run `config-stage1` instead of `build-stage1`. It will create config that you can then copy to `$COREBOOT_PATH`, make your changes and build. Please be aware that `build-stage1` applies SeaBIOS patch and you will have to apply it manually.) + +(If you're experienced coreboot user or developer, you may want to configure and +build coreboot yourself. In that case, run `config-stage1` instead of +`build-stage1`. It will create config that you can then copy to `$COREBOOT_PATH`, +make your changes and build.) Flash it: ``` -./mmga flash-stage1 +# ./mmga flash-stage1 ``` -If it's done and you didn't see any errors, you have to **shutdown** the laptop. It's important: DO NOT REBOOT, shut it down. If you reboot, old FD will still be used and you will boot the Apple's firmware, because it was left untouched in the `0x190000-0x7fffff` region. But since you partly replaced the old `me` region, it may lead to undefined behaviour. So again, do not reboot, shut it down. + +If it's done and there were no errors, you have to **shutdown** the laptop. +Do not reboot, the new flash descriptor is only active after cold boot, so it +won't work and may lead to weird stuff as you've just messed with firmware. Wait +a few seconds and power it back on. #### stage2 -Create patched FD for the next flash: + +Make patched flash descriptor for the next flash: ``` -./mmga prepare-stage2 +$ ./mmga prepare-stage2 ``` -Create new coreboot config and build the ROM (for experienced users, `config-stage2` is also available): + +Create new coreboot config and build the ROM (for experienced users, +`config-stage2` is also available): ``` -./mmga build-stage2 +$ ./mmga build-stage2 ``` + Flash it: ``` -./mmga flash-stage2 +# ./mmga flash-stage2 ``` -This may take a while, please don't interrupt and let it finish. -If you again didn't see any errors after it's done, you have to **shutdown** the laptop again. DO NOT REBOOT, shut it down. It's even more important now: if you reboot, old FD will be used, the one that describes `bios` region as `0x21000-0xfffff`. And since you just flashed `bios` to `0x21000-0x7fffff`, this `0x21000-0xfffff` will most likely just contain `FF`s, so the laptop won't boot and will look like a brick. In that case you will need to press and hold power button for ~10 seconds to hard reset. To avoid all that, just do not reboot, shut it down. +This may take a while, don't interrupt it and let it finish. + +Again, if there were no errors, power off the machine again, wait a few seconds, +and power on. + +## FAQ + +**My device is not listed, will it work?** + +No, but it might be possible to support it. + +**Will macOS continue to work with coreboot?** + +No. It's theoretically possible to turn a corebooted MacBook into a hackintosh +by using TianoCore and Clover or OpenCore. Basically, if you want to use macOS, +don't install coreboot. + +**Switching between iGPU and dGPU on MacBook Pro 10,1** + +Last time I checked, [hacks](https://wiki.archlinux.org/index.php/MacBookPro10,x#Graphics_2) +were needed to use Linux with integrated GPU on this model. It seems that Apple EFI +forces dGPU when OS is not macOS. I've integrated hybrid graphics driver into +coreboot, it automatically switches to the configured GPU and you don't need to +care about it anymore. By default, integrated GPU is used. The setting is stored +in CMOS and you can change it with `nvramtool`. + +Note that to use discrete GPU you need to extract VGA ROM from the stock firmware +dump and add it to CBFS, and configure coreboot to run VGA Option ROMs. + +## TODO + +- Support custom FMAP for larger first-stage `bios` partition +- Support multiple payloads at once +- Support TianoCore as a payload ## Misc -The script was tested on MacBook Air 5,2 and MacBook Pro 10,1. If you have successfully corebooted your macbook with it and it worked, please let me know. If you have any problems, contact me via GitHub issues or by email (see the copyright header in the script). +The script was tested on MacBook Air 5,2, MacBook Pro 8,1 and MacBook Pro 10,1. +If you have successfully corebooted your macbook with it and it worked, please +let me know. + +If you have any problems, contact me via GitHub issues or by email (see the +copyright header in the script). + +## License +GPLv2 \ No newline at end of file diff --git a/mmga b/mmga index 55486bb..77f4f31 100755 --- a/mmga +++ b/mmga @@ -2,7 +2,7 @@ # # mmga: Make MacBook Great Again # -# Copyright (C) 2019 Evgeny Zinoviev +# Copyright (C) 2019, 2021 Evgeny Zinoviev # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ trap 'onerror ${LINENO}' ERR DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" . $DIR/config.inc -VERSION="0.1" +VERSION="0.2" WORK_DIR="$DIR/work" CBOL=$(tput bold) @@ -32,7 +32,7 @@ CYAN=$(tput setaf 6) declare -A BOARD_REFS=( [macbookair5_2]="refs/changes/04/32604/22" [macbookpro8_1]="refs/changes/51/33151/3" - [macbookpro10_1]="refs/changes/73/32673/22" + [macbookpro10_1]="refs/changes/73/32673/30" ) onerror() { @@ -195,8 +195,6 @@ config_write_payload() { echo "CONFIG_PAYLOAD_GRUB2=y" >> "$file" elif [ "$PAYLOAD" == "seabios" ]; then echo "CONFIG_PAYLOAD_SEABIOS=y" >> "$file" - echo "CONFIG_SEABIOS_REVISION=y" >> "$file" - echo "CONFIG_SEABIOS_REVISION_ID=\"macbook-fix\"" >> "$file" fi fi } @@ -231,25 +229,6 @@ coreboot_check_board() { popd >/dev/null } -patch_seabios() { - if [[ "$PAYLOAD" != "seabios" ]]; then - return - fi - pushd "$COREBOOT_PATH/payloads/external/SeaBIOS" >/dev/null - echotitle "Patching SeaBIOS..." - make seabios - cd seabios - if [ $(git branch --list macbook-fix) ]; then - echotitle "SeaBIOS patch already in place, skipping..." - popd >/dev/null - return - fi - git checkout -b macbook-fix - patch -p1 < "$DIR/seabios-macbook-fix.patch" - git commit -am "Fix MacBook USB keyboard" --no-verify - popd >/dev/null -} - get_grub_cfg() { if [ -z "$GRUB_CFG_PATH" ]; then echo "$DIR/grub.cfg" @@ -443,8 +422,6 @@ case "$ACTION" in pushd "$COREBOOT_PATH" >/dev/null make distclean - patch_seabios - echotitle "Building coreboot..." cp "$WORK_DIR/config" "$COREBOOT_PATH/.config" make olddefconfig @@ -526,8 +503,6 @@ case "$ACTION" in pushd "$COREBOOT_PATH" >/dev/null make distclean - patch_seabios - echotitle "Building coreboot..." cp "$WORK_DIR/config" "$COREBOOT_PATH/.config" make olddefconfig diff --git a/seabios-macbook-fix.patch b/seabios-macbook-fix.patch deleted file mode 100644 index d537501..0000000 --- a/seabios-macbook-fix.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/hw/usb-hid.c b/src/hw/usb-hid.c -index fa4d9a2..7d3561c 100644 ---- a/src/hw/usb-hid.c -+++ b/src/hw/usb-hid.c -@@ -59,7 +59,7 @@ usb_kbd_setup(struct usbdevice_s *usbdev - // XXX - this enables the first found keyboard (could be random) - return -1; - -- if (epdesc->wMaxPacketSize != 8) -+ if (epdesc->wMaxPacketSize != 8 && epdesc->wMaxPacketSize != 10) - return -1; - - // Enable "boot" protocol. -- cgit v1.2.3