Skip to content
Merged
Show file tree
Hide file tree
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
10 changes: 5 additions & 5 deletions bin/fetch_coreboot_crossgcc_archive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,19 @@ PKG_BASENAME="$(basename "$PKG_CKSUM_FILE" .cksum)"
# broke all the iasl links - coreboot 90753398).
case "$PKG_NAME" in
gmp)
PKG_BASEURL="https://ftpmirror.gnu.org/gmp/"
PKG_BASEURL="https://mirrors.kernel.org/gnu/gmp/"
;;
mpfr)
PKG_BASEURL="https://ftpmirror.gnu.org/mpfr/"
PKG_BASEURL="https://mirrors.kernel.org/gnu/mpfr/"
;;
mpc)
PKG_BASEURL="https://ftpmirror.gnu.org/mpc/"
PKG_BASEURL="https://mirrors.kernel.org/gnu/mpc/"
;;
gcc)
PKG_BASEURL="https://ftpmirror.gnu.org/gcc/gcc-$(delete_prefix_suffix "$PKG_BASENAME" gcc- .tar.xz)/"
PKG_BASEURL="https://mirrors.kernel.org/gnu/gcc/gcc-$(delete_prefix_suffix "$PKG_BASENAME" gcc- .tar.xz)/"
;;
binutils)
PKG_BASEURL="https://ftpmirror.gnu.org/binutils/"
PKG_BASEURL="https://mirrors.kernel.org/gnu/binutils/"
;;
nasm)
PKG_BASEURL="https://www.nasm.us/pub/nasm/releasebuilds/$(delete_prefix_suffix "$PKG_BASENAME" nasm- .tar.bz2)/"
Expand Down
108 changes: 108 additions & 0 deletions bin/fetch_musl_cross_make_archive.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#! /usr/bin/env bash
set -eo pipefail

# Pre-seed musl-cross-make's component tarballs into the packages directory
# so they are cached alongside all other module tarballs, picked up by
# Purism's package mirror sync, and available for CI cache layers.
#
# usage:
# $0 <musl-cross-make-dir> <pkgs-dir>
# $0 --help
#
# Reads component versions and archive names from the musl-cross-make
# source tree (Makefile defaults + hashes/*.sha1), then downloads each
# tarball via fetch_source_archive.sh.
# Uses fetch_source_archive.sh, so the Purism mirrors are used
# as fallback and WGET can override the path to wget.

usage() {
cat <<USAGE_END
usage:
$0 <musl-cross-make-dir> <pkgs-dir>
$0 --help

Reads component versions and archive names from a musl-cross-make
source tree (Makefile defaults + hashes/*.sha1), then downloads each
tarball via fetch_source_archive.sh (primary -> Purism mirror fallback).

Uses fetch_source_archive.sh, so the Purism mirrors are used
as fallback and WGET can override the path to wget.
USAGE_END
}

if [ "$#" -lt 2 ]; then
usage
exit 1
fi

MCM_DIR="$(realpath "$1")"
PKGS_DIR="$(realpath "$2")" # ensure absolute paths
BIN_DIR="$(dirname "${BASH_SOURCE[0]}")"

# Find a glob pattern that matches exactly one file, failing with a
# distinct message for no matches vs. multiple matches.
single() {
if [ "$#" -eq 1 ]; then
if [ -f "$1" ]; then
echo "$1"
return 0
fi
else
echo "multiple unexpected matches for glob:" "$@" >&2
exit 1
fi
echo "$1: no matches" >&2
exit 1
}

# Extract a variable from the musl-cross-make Makefile.
# Returns the value of KEY = <value>, or empty string if not found.
make_var() {
grep -E "^$1[[:space:]]*=" "$MCM_DIR/Makefile" | head -1 \
| sed "s/^$1[[:space:]]*=[[:space:]]*//"
}

# Resolve the archive name for a component from its hashes file.
# The hashes directory contains files named <prefix>-<version>.tar.*.sha1
# (glob tolerates both .tar.gz and .tar.xz suffixes).
# single() guarantees exactly one match; basename strips the .sha1 suffix
# to give the archive filename.
component_archive() { # $1 = prefix (gcc, binutils, ...), $2 = version
basename "$(single "$MCM_DIR/hashes/$1-$2.tar."*.sha1)" .sha1
}

# Download a tarball via fetch_source_archive.sh.
# Digests are SHA-1 (40 chars); fetch_source_archive.sh auto-detects that.
# fetch_source_archive.sh applies the Purism mirror fallback
# keyed on the basename of the destination file.
fetch() { # $1 = url_base, $2 = filename, $3 = sha1_digest
"$BIN_DIR/fetch_source_archive.sh" "$1$2" "$PKGS_DIR/$2" "$3"
}

# GNU component versions come from the musl-cross-make Makefile defaults
# and feed component_archive() to resolve the archive filenames.
V_BINUTILS=$(make_var BINUTILS_VER)
V_GCC=$(make_var GCC_VER)
V_GMP=$(make_var GMP_VER)
V_MPC=$(make_var MPC_VER)
V_MPFR=$(make_var MPFR_VER)
V_MUSL=$(make_var MUSL_VER)
V_LINUX=$(make_var LINUX_VER)

# SHA-1 digests are read from hashes/*.sha1 files (format: "digest filename").
# cut extracts the first field. component_archive() maps version to filename.

# GNU tarballs: use mirrors.kernel.org directly.
# ftpmirror.gnu.org is a redirector that frequently returns 502.
GNU_BASE="https://mirrors.kernel.org/gnu"

# Fetch each component from its upstream source.
# binutils, gcc, gmp, mpc, mpfr come from GNU mirrors.
fetch "$GNU_BASE/binutils/" "$(component_archive binutils "$V_BINUTILS")" "$(cut -d' ' -f1 "$MCM_DIR/hashes/$(component_archive binutils "$V_BINUTILS").sha1")"
fetch "$GNU_BASE/gcc/gcc-$V_GCC/" "$(component_archive gcc "$V_GCC")" "$(cut -d' ' -f1 "$MCM_DIR/hashes/$(component_archive gcc "$V_GCC").sha1")"
fetch "$GNU_BASE/gmp/" "$(component_archive gmp "$V_GMP")" "$(cut -d' ' -f1 "$MCM_DIR/hashes/$(component_archive gmp "$V_GMP").sha1")"
fetch "$GNU_BASE/mpc/" "$(component_archive mpc "$V_MPC")" "$(cut -d' ' -f1 "$MCM_DIR/hashes/$(component_archive mpc "$V_MPC").sha1")"
fetch "$GNU_BASE/mpfr/" "$(component_archive mpfr "$V_MPFR")" "$(cut -d' ' -f1 "$MCM_DIR/hashes/$(component_archive mpfr "$V_MPFR").sha1")"
# musl and Linux headers come from non-GNU hosts.
fetch "https://musl.libc.org/releases/" "$(component_archive musl "$V_MUSL")" "$(cut -d' ' -f1 "$MCM_DIR/hashes/$(component_archive musl "$V_MUSL").sha1")"
fetch "https://ftp.barfooze.de/pub/sabotage/tarballs/" "$(component_archive linux "$V_LINUX")" "$(cut -d' ' -f1 "$MCM_DIR/hashes/$(component_archive linux "$V_LINUX").sha1")"
18 changes: 15 additions & 3 deletions bin/fetch_source_archive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ esac
download() {
local download_url
download_url="$1"
if ! "$WGET" -O "$TMP_FILE" "$download_url"; then
# --timeout=30: bail fast on hung downloads (default 900s)
# --tries=3: retry transient failures
# -4: prefer IPv4, avoid IPv6 stalls (issue #2086)
if ! "$WGET" -O "$TMP_FILE" \
--timeout=30 --tries=3 -4 \
"$download_url"; then
echo "Failed to download $download_url" >&2
elif ! echo "$DIGEST $TMP_FILE" | "$SHASUM" --check -; then
echo "File from $download_url does not match expected digest" >&2
Expand All @@ -66,19 +71,26 @@ download() {

# If the file exists already and the digest is correct, use the cached copy.
if [ -f "$FILE" ] && (echo "$DIGEST $FILE" | "$SHASUM" --check -); then
echo "$(date -Iseconds) CACHED file=$(basename "$FILE")" \
>>"${MIRROR_LOG:-build/mirror_fallbacks.log}"
echo "File $FILE is already cached" >&2
exit 0
fi

rm -f "$FILE" "$TMP_FILE"

# Try the primary source
download "$URL" && exit 0
if download "$URL"; then
echo "$(date -Iseconds) PRIMARY file=$(basename "$FILE") url=$URL" \
>>"${MIRROR_LOG:-build/mirror_fallbacks.log}"
echo "Downloaded from primary: $URL" >&2
exit 0
fi

# Log mirror fallback for developer awareness
MIRROR_LOG="${MIRROR_LOG:-build/mirror_fallbacks.log}"
mkdir -p "$(dirname "$MIRROR_LOG")"
echo "$(date -Iseconds) MIRROR_FALLBACK primary=$URL" >>"$MIRROR_LOG"
echo "$(date -Iseconds) MIRROR_FALLBACK file=$(basename "$FILE") primary=$URL" >>"$MIRROR_LOG"

# Shuffle the mirrors so we try each equally
readarray -t BACKUP_MIRRORS < <(shuf -e "${BACKUP_MIRRORS[@]}")
Expand Down
3 changes: 2 additions & 1 deletion doc/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ The top-level `Makefile` orchestrates:
6. `data.cpio` — data files
- Final ROM image: coreboot ROM with Linux + initramfs payload embedded

Reproducible builds are achieved via Nix-pinned Docker images. See [docker.md](docker.md).
Reproducible builds are achieved via Nix-pinned Docker images (see [docker.md](docker.md))
and deterministic compiler flags (see [reproducible-builds.md](reproducible-builds.md)).
The CI pipeline's workspace and cache behavior is documented in
[circleci.md](circleci.md).

Expand Down
2 changes: 2 additions & 0 deletions doc/build-freshness.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Build Freshness Debugging Guide

See also: [reproducible-builds.md](reproducible-builds.md) for verifying ROM reproducibility.

## The Problem

Changes to source files in `initrd/` or other build dependencies were not being packed into `initrd.cpio.xz`, causing stale artifacts in the final ROM. The test system showed old commit hashes in `/tmp/config` even after rebuilding.
Expand Down
9 changes: 9 additions & 0 deletions doc/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ environment. Docker images are built with Nix since
[PR #1661](https://github.com/linuxboot/heads/pull/1661).

See also: [General reproducible-build notes](../README.md#general-notes-on-reproducible-builds),
[Reproducible build practices](reproducible-builds.md),
[QEMU testing](qemu.md), [CircleCI pipeline notes](circleci.md).

---
Expand Down Expand Up @@ -235,6 +236,14 @@ USB token (for example `scdaemon` or `pcscd`). The wrapper will warn and, on int
shells, give a **3-second abort window** before attempting to kill those processes to free
the token. Set `HEADS_DISABLE_USB=1` to opt out of this automatic cleanup.

For fully unattended builds (script/non-interactive shell), combine with
`script` to provide the pseudo-TTY that docker_repro.sh's `-ti` requires:

HEADS_DISABLE_USB=1 script -qec './docker_repro.sh make BOARD=...' /dev/null

Both `HEADS_DISABLE_USB=1` and `script` are unnecessary when running from
an interactive terminal.

```bash
HEADS_DISABLE_USB=1 ./docker_repro.sh make BOARD=qemu-coreboot-fbwhiptail-tpm2 run
```
Expand Down
61 changes: 48 additions & 13 deletions doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,53 @@

Quick reference: read the relevant doc when working on a topic.

## Build System & CI

| File | What it covers |
|------|----------------|
| `build-artifacts.md` | ROM filenames, update-package zip layout, LVFS conventions |
| `build-freshness.md` | Why rebuilds produce stale artifacts and how to force a full rebuild |
| `circleci.md` | CI pipeline: job dependency graph, cache layers, workspace persistence |
| `docker.md` | Docker-based build environment with pinned, reproducible images |
| `modules.md` | Module system: toolchain and bin modules, inclusion rules, sentinel chain |
| `patches.md` | Creating and maintaining source patches for upstream packages |
| `prerequisites.md` | Tools and libraries needed before building Heads |
| `reproducible-builds.md` | Deterministic build flags and verifying ROM hashes against CI |

## Architecture & Boot Flow

| File | What it covers |
|------|----------------|
| `architecture.md` | System layout: coreboot → Linux → initramfs, config hierarchy |
| `boot-process.md` | Boot flow stages, ISO boot steps, [OK]/[~]/[X] progress markers |
| `iso_boot.md` | ISO kernel parameters: which framework uses each option |
| `kexec_handoff.md` | Kernel kexec handoff: screen_info, EBDA, sysfb/simpledrm/vesadrm |

## Security, TPM & Keys

| File | What it covers |
|------|----------------|
| `configuring-keys.md` | Setting up GPG keys for signing firmware updates |
| `gpg.md` | GPG tool operation for firmware signing and verification |
| `hotp.md` | HOTP-based remote attestation of firmware state |
| `keys.md` | Key management for firmware signing |
| `security-model.md` | TPM measured boot, trust chain, flash write protection |
| `TPM_GPIO_Reset_Approaches.md` | Eight approaches for resetting TPM via GPIO |
| `TPM_GPIO_Reset_Vulnerability.md` | TPM GPIO reset vulnerability analysis |
| `tpm.md` | TPM 1.2 and 2.0 operation details |
| `wp-notes.md` | Flash write protection: PR0 chipset locking, WP# pin, runtime chain |

## Development & Reference

| File | What it covers |
|------|----------------|
| `architecture.md` | System architecture: coreboot -> kernel -> initrd, build system, config hierarchy |
| `boot-process.md` | Boot flow stages, ISO boot steps (1-7), [OK]/[~]/[X] marker legend |
| `busybox_perks.md` | GNU vs BusyBox command differences for all tools used in initrd scripts |
| `docker.md` | Docker-based build environment |
| `logging.md` | Log levels (STATUS, WARN, NOTE, INFO, DEBUG, TRACE) usage conventions |
| `modules.md` | Available tools: which are BusyBox applets vs standalone binaries |
| `security-model.md` | TPM, measured boot, trust chain, flash write protection |
| `wp-notes.md` | Flash write protection: PR0 chipset locking, WP# pin, config tables, runtime chain, board coverage |
| `tpm.md` | TPM 1.2 and 2.0 operations |
| `ux-patterns.md` | User interaction patterns (whiptail, CLI menu, confirm dialogs) |
| `iso_boot.md` | ISO boot parameter reference: what each kernel param does and which framework uses it |
| `kexec_handoff.md` | Kexec handoff: screen_info normalization (VLFB), EBDA preservation, sysfb/simpledrm/vesadrm dispatch, driver detection markers, kernel version matrix |
| `patches.md` | Patch creation conventions: naming, multi-patch directories, testing, splitting, forced rebuild after changes |
| `BOARDS_AND_TESTERS.md` | Board EOL/ESU status, CPU generations, tester registry |
| `busybox_perks.md` | GNU vs BusyBox command differences for initrd scripts |
| `config.md` | Board config hierarchy: defconfig, oldconfig, variation-to-defconfig |
| `development.md` | Development environment setup and contribution workflow |
| `faq.md` | Frequently asked questions |
| `logging.md` | Message levels (STATUS, WARN, NOTE, INFO, DEBUG, TRACE) |
| `qemu.md` | QEMU-based board emulation for testing |
| `recovery-shell.md` | Recovery shell usage and diagnostic commands |
| `ux-patterns.md` | User interaction: whiptail dialogs, CLI menus, confirmations |
| `variation-to-defconfig.md` | Converting Kconfig variation files to defconfig format |
13 changes: 13 additions & 0 deletions doc/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,16 @@ The `define_module` function in `Makefile` expands these into the
`.canary` → `.configured` → `.build` chain above. The package name
is the Make target: `make BOARD=... kexec` builds just that package.
```

## Toolchain Modules

### musl-cross-make

The `MUSL_CROSS_ONCE` guard prevents `modules/musl-cross-make` from being
included multiple times.

The cross-compiler is included **early** in the Makefile so
that `$(CROSS)` and `$(heads_cc)` are available before any userland module is
included.

See `doc/circleci.md` for how CI orchestrates toolchain caching across jobs.
Loading