Skip to content

Instantly share code, notes, and snippets.

@smx-smx
Last active June 30, 2024 01:08
Show Gist options
  • Save smx-smx/d9898756eb0f2cecc9ef8437f96a7191 to your computer and use it in GitHub Desktop.
Save smx-smx/d9898756eb0f2cecc9ef8437f96a7191 to your computer and use it in GitHub Desktop.
z270 coreboot

ASRock Z270 Extreme 4

This page describes how to run coreboot on the ASRock Z270 Extreme4.

Flashing coreboot

Internal programming

The main SPI flash can be accessed using flashrom. By default, only the BIOS region of the flash is writable. If you wish to change any other region, such as the Management Engine or firmware descriptor, then an external programmer is required (unless you find a clever way around the flash protection). More information about this here.

External programming - introduction

There are 2 flash chip on this board, one for the "main" BIOS and one for recovery. Both are 16 MiB socketed DIP-8 chips. Both are Macronix MX25L12873F, whose datasheet can be found here. The chips is located to the bottom right-hand side of the board.

There are 2 undocumented headers on the board that can be used to interact with these chips. They were pre-populated on my board, so no soldering was required.

One of them is BIOS_PH, which exposes the SPI bus to talk to the flash.

This header can be found in the lower right part of the board, between the PC Speaker connector and the COM header (and right below the flash chips)

bios headers

The other one is a jumper labelled D_BIOS_TEST1 and located on the top right edge of BIOS_PH (it can be seen in the picture).

This jumper is a manual selector between the primary flash chip and the secondary flash chip.

NOTE: this jumper is not described at all in the manual! during normal operations, switching between primary and secondary flash is typically controlled by the board's "Embedded Controller", aka the Nuvoton N76E885 chip located on the bottom left corner, next to the RGB_LED header.

N76E885

This is an Intel 8051 microcontroller which has several functions, such as:

  • Controlling the RGB LEDs
  • Switching between primary and secondary bios chip on multiple boot failures

Bridging the D_BIOS_TEST1 jumper changes the Chip Select between the 2 chips, just like the Microcontroller would.

NOTE: there are actually 2 RED LEDs next to the Bios chips. Switching between the primary and secondary bios chip will also alternate between the 2 LEDs.

External programming - setup

The following picture shows the pinout of BIOS_PH and a setup with a Raspberry PI Gen 1 used as the flasher:

pinout

NOTE: RSMRST# MUST be driven to GND in order to keep Intel ME in reset and prevent it from running. Otherwise, it will interfere with the flash chip (to read its own code from the ME region) and it will be impossible to read/write reliably.

NOTE: from personal experimentation, it's more reliable to flash the board with an external power supply rather than using the standby power from the ATX PSU. However, the board has no back-current protection. 3.3v must be supplied via VCC, and will travel all the way to the PCH and the 5v rail. This could be observed by my RGB keyboard turning on with a faint light. This excessive load causes a voltage drop which also makes the flash chip undetectable. As a workaround, disconnect any USB device when reading/writing the flash.

NOTE: if you want to operate on the primary flash chip, the D_BIOS_TEST1 jumper should be OPEN. If you want to operate on the secondary flash chip, bridge the contacts.

NOTE: after flashing the chip, you might experience a strange sitation where the PC will refuse to boot and the power button won't function. Unplugging and replugging the ATX PSU won't have any effect and the board appears bricked.

The power button is handled by Intel ME, which is always running on Standby. Therefore, make sure that RSMRST# is no longer connected to GND so that Intel ME is no longer stuck in reset and is free to run.

If the PC is still not booting, Don't panic! and keep on reading.

This situation can happen if Intel ME gets a chance to run before RSMRST# is driven low and the power was detected unstable, or if Intel ME encountered a crash (both of which can happen when supplying external power and accessing the SPI bus). A special flag will then be written to the CMOS storage, supposedly by Intel ME, which will then disable itself until CMOS is cleared.

To clear it, you need to locate the Clear CMOS jumper and switch it from the default 1-2 position to 2-3. Wait a couple seconds, and put it back to 1-2. Alternatively, remove the coin battery and wait a couple seconds.

The power button should now be back in order and the system will boot with the newly flashed BIOS.

External programming - flashing coreboot

The setup explained previously allows us to dual boot with AMI and Coreboot. The recommended chip to flash coreboot to is the secondary/recovery chip.

This is because, at boot time, AMIBios will check the active BIOS chip by asking the Nuvoton EC. If it detects that it's running from the secondary bios chip, it will launch a non-stoppable recovery program that will:

  • read the contents of the current (recovery) chip to RAM
  • ask to the Nuvoton EC (via SMBus) to switch to the primary bios chip
  • write the RAM contents to the newly selected chip, thus restoring it
  • reboot to the primary chip

This means that, if you want to have Amibios be usable, the only way besides patching it in order to skip said auto-recovery is to run it from the primary chip, so that the code won't trigger.

Otherwise, if you flash coreboot to the primary bios chip and boot fails for 3 consecutive attempts for whatever reason, the EC will switch to the secondary chip and AMIBios will then erase coreboot from the primary chip, which is not ideal.

To flash coreboot to the secondary bios chip, bridge D_BIOS_TEST1.

Unplug the PC Power supply and setup the connection to your Raspberry PI.

Paste the following in setgpio.sh and run it in order to configure WPn and HOLDn:

#!/usr/bin/env bash
set -x

mode="out"
for pin in 24 23; do
        echo $pin > /sys/class/gpio/unexport
        sleep 0.2
        echo $pin > /sys/class/gpio/export
        sleep 0.2
        echo $mode > /sys/class/gpio/gpio$pin/direction
        sleep 0.2
        echo 1 > /sys/class/gpio/gpio$pin/value
done

Then write the following to flash.sh:

#!/usr/bin/env bash
flashrom \
        -p linux_spi:dev=/dev/spidev0.0,spispeed=20000 \
        -c "MX25L12833F/MX25L12835F/MX25L12845E/MX25L12865E/MX25L12873F" \
        "$@"

You can now use this wrapper script to perform the usual read/write operations.

Switching between primary and secondary bios chips

To switch bios chips, you have the following methods:

  • by manually flipping the D_BIOS_TEST1 jumper
  • by instructing the Nuvoton EC to switch the active bios Chip via an SMBUS command (more details later)
  • by having boot fail for 3 consecutive times, which will trigger the auto failover code in the EC.

Manually switching through SMBus

The Nuvoton EC is listening on the I2C bus at address 0x6a. This can be observed through i2cdetect:

# i2cdetect -l
i2c-1    i2c           i915 gmbus dpc                      I2C adapter
i2c-2    i2c           i915 gmbus dpb                      I2C adapter
i2c-3    i2c           i915 gmbus dpd                      I2C adapter
i2c-4    i2c           AUX A/DDI E/PHY E                   I2C adapter

# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         08 -- -- -- -- -- -- -- 
10: -- -- -- -- 14 15 -- -- -- 19 -- 1b -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: 30 31 32 -- 34 35 UU UU -- -- -- -- -- -- -- -- 
40: 40 -- -- -- 44 -- -- -- -- -- -- -- -- -- -- -- 
50: UU UU UU UU -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- 6a -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

The active bios chip is stored in register/address 0x6a. It can be read:

# i2cget -y 0 0x6a 0x50 s
0x01

or written to:

# i2cset -y 0 0x6a 0x50 [chip id] s

where chip id can be either 0 or 1

NOTE: the EC will only react to a block write (indicated by s in the i2cset command)

Single byte read/write will NOT work.

Since i wanted to be able to do this from Windows, i made an experimental/incomplete modification to chipsec in order to add SMBus block commands. You can find it here: https://github.com/smx-smx/chipsec/commit/9883c535264030979d301b1587ab6f4bfb96b379

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment