boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

lib-arch.sh (7188B)


      1 # lib-arch.sh — single source for arch + driver setup shared by
      2 # boot/boot.sh, boot/boot{0..6}.sh, lib-pipeline.sh, lib-runscm.sh.
      3 #
      4 # Public entry points (call in this order from a bootN.sh):
      5 #
      6 #     bootlib_init <stage> <arch>     # validate <arch>, cd to repo root,
      7 #                                     # set ARCH/PLATFORM/KERNEL_NAME/
      8 #                                     # MUSL_ARCH/DRIVER/BOOT_STAGE/BOOT_TAG.
      9 #     driver_init [<image-kind>]      # set OUT/STAGE; podman: build IMAGE
     10 #                                     # if missing (image-kind ∈ busybox|
     11 #                                     # empty; default busybox); seed:
     12 #                                     # verify boot6 kernel exists.
     13 #     require_src                     # die if build/$ARCH/src/ missing.
     14 #     require_prev <dir> <name>...    # die if any <dir>/<name> is
     15 #                                     # missing or non-executable.
     16 #     require_file <path> [<hint>]    # die if <path> missing; print a
     17 #                                     # uniform diagnostic with hint.
     18 #
     19 # After bootlib_init, the following shell vars are set/exported:
     20 #   ARCH         input architecture token (aarch64|amd64|riscv64)
     21 #   ROOT         repo root (cwd is set to ROOT)
     22 #   DRIVER       podman|seed (defaults to podman)
     23 #   PLATFORM     linux/<arm64|amd64|riscv64> for podman --platform
     24 #   KERNEL_NAME  Image (aarch64) | kernel.elf (amd64,riscv64)
     25 #   MUSL_ARCH    aarch64 | x86_64 | riscv64
     26 #   BOOT_TAG     "<stage>/<driver>/<arch>" for log prefixes
     27 #   BOOT_STAGE   stage name as passed in (boot0|boot1|...)
     28 #
     29 # After driver_init (boot stages only — prep-* skip it):
     30 #   OUT          build/$ARCH/$DRIVER/$BOOT_STAGE       (stage output dir)
     31 #   STAGE        build/$ARCH/$DRIVER/.$BOOT_STAGE-stage (scratch staging dir)
     32 #   podman:  IMAGE
     33 #   seed:    KERNEL_IMAGE, EXTRACT, SEED_ARCH
     34 
     35 bootlib_init() {
     36     _stage=$1; _arch=${2:-}
     37     [ -n "$_stage" ] || { echo "lib-arch: bootlib_init: stage required" >&2; exit 2; }
     38     case "$_arch" in
     39         aarch64|amd64|riscv64) ;;
     40         *) echo "usage: $0 <aarch64|amd64|riscv64>" >&2; exit 2 ;;
     41     esac
     42     ARCH=$_arch
     43     ROOT=$(cd "$(dirname "$0")/.." && pwd)
     44     cd "$ROOT"
     45     DRIVER=${DRIVER:-podman}
     46     case "$DRIVER" in
     47         podman|seed) ;;
     48         *) echo "[$_stage/$DRIVER/$ARCH] unknown DRIVER=$DRIVER (expected podman|seed)" >&2; exit 2 ;;
     49     esac
     50     BOOT_STAGE=$_stage
     51     BOOT_TAG="$_stage/$DRIVER/$ARCH"
     52     BOOT_T0=$(date +%s)
     53     case "$ARCH" in
     54         aarch64) PLATFORM=linux/arm64;   KERNEL_NAME=Image;      MUSL_ARCH=aarch64 ;;
     55         amd64)   PLATFORM=linux/amd64;   KERNEL_NAME=kernel.elf; MUSL_ARCH=x86_64  ;;
     56         riscv64) PLATFORM=linux/riscv64; KERNEL_NAME=kernel.elf; MUSL_ARCH=riscv64 ;;
     57     esac
     58     export ARCH ROOT DRIVER PLATFORM KERNEL_NAME MUSL_ARCH BOOT_TAG BOOT_STAGE BOOT_T0
     59     trap _bootlib_finish EXIT
     60 }
     61 
     62 # _bootlib_finish — EXIT trap installed by bootlib_init. Prints
     63 # `[$BOOT_TAG] done in Xs (cum Ys)` (or `failed after Xs` on error).
     64 # On success, records the elapsed time so later stages can sum the
     65 # chain. Cumulative = sum of all per-stage .timing files relevant to
     66 # the current $ARCH/$DRIVER.
     67 _bootlib_finish() {
     68     _exit=$?
     69     [ -n "${BOOT_T0:-}" ] || return 0
     70     _elapsed=$(( $(date +%s) - BOOT_T0 ))
     71     if [ "$_exit" != 0 ]; then
     72         echo "[$BOOT_TAG] failed after ${_elapsed}s (exit=$_exit)" >&2
     73         return 0
     74     fi
     75     # Record this stage's time. Boot stages have OUT (set by driver_init);
     76     # the orchestrator (BOOT_STAGE=boot) doesn't write — its time would
     77     # double-count. Other stages without OUT (prep-src) write
     78     # to a per-arch sidecar dir.
     79     if [ "$BOOT_STAGE" != boot ]; then
     80         if [ -n "${OUT:-}" ] && [ -d "$OUT" ]; then
     81             echo "$_elapsed" > "$OUT/.timing"
     82         elif [ -d "build/$ARCH" ]; then
     83             mkdir -p "build/$ARCH/.timings"
     84             echo "$_elapsed" > "build/$ARCH/.timings/$BOOT_STAGE"
     85         fi
     86     fi
     87     # Cumulative: sum boot-stage timings for this driver + driver-
     88     # independent prep timings. Glob may not match — guard each path.
     89     _cum=0
     90     for _f in \
     91         "build/$ARCH/$DRIVER"/*/.timing \
     92         "build/$ARCH/.timings"/*
     93     do
     94         [ -f "$_f" ] || continue
     95         _v=$(cat "$_f" 2>/dev/null) || continue
     96         case "$_v" in *[!0-9]*|'') continue ;; esac
     97         _cum=$((_cum + _v))
     98     done
     99     echo "[$BOOT_TAG] done in ${_elapsed}s (cum ${_cum}s)"
    100 }
    101 
    102 driver_init() {
    103     _image_kind=${1:-busybox}
    104     case "$_image_kind" in
    105         busybox|empty) ;;
    106         *) echo "[$BOOT_TAG] driver_init: image-kind must be busybox|empty (got $_image_kind)" >&2; exit 2 ;;
    107     esac
    108     OUT=build/$ARCH/$DRIVER/$BOOT_STAGE
    109     STAGE=build/$ARCH/$DRIVER/.$BOOT_STAGE-stage
    110     export OUT STAGE
    111     case "$DRIVER" in
    112         podman)
    113             IMAGE=boot2-$_image_kind:$ARCH
    114             if ! podman image exists "$IMAGE"; then
    115                 echo "[$BOOT_TAG] building $IMAGE"
    116                 # Containerfile.empty drops /etc resolver state etc.; no-cache
    117                 # avoids a stale layer surviving an upstream tag bump.
    118                 _no_cache=
    119                 [ "$_image_kind" = empty ] && _no_cache=--no-cache
    120                 podman build $_no_cache --platform "$PLATFORM" -t "$IMAGE" \
    121                     -f boot/containers/Containerfile.$_image_kind boot/containers/
    122             fi
    123             export IMAGE
    124             ;;
    125         seed)
    126             # DRIVER=seed always consumes the podman-built boot6 kernel —
    127             # tcc3 is platform-agnostic but we settled on a single canonical
    128             # build location to reduce surface area.
    129             KERNEL_IMAGE=$ROOT/build/$ARCH/podman/boot6/$KERNEL_NAME
    130             EXTRACT=$ROOT/seed-kernel/scripts/extract-blk.sh
    131             [ -f "$KERNEL_IMAGE" ] || {
    132                 echo "[$BOOT_TAG] missing $KERNEL_IMAGE — run ./boot/boot.sh $ARCH (default DRIVER=podman) first" >&2
    133                 exit 1
    134             }
    135             export KERNEL_IMAGE EXTRACT
    136             export SEED_ARCH=$ARCH
    137             ;;
    138     esac
    139 }
    140 
    141 require_prev() {
    142     _dir=$1; shift
    143     for _n in "$@"; do
    144         [ -x "$_dir/$_n" ] || {
    145             _stage_name=$(basename "$_dir")
    146             case "$_stage_name" in
    147                 boot*) _hint="run boot/$_stage_name.sh $ARCH" ;;
    148                 *)     _hint="rebuild $_dir" ;;
    149             esac
    150             echo "[$BOOT_TAG] missing prerequisite: $_dir/$_n ($_hint)" >&2
    151             exit 1
    152         }
    153     done
    154 }
    155 
    156 # require_src — assert build/$ARCH/src/ exists (the canonical generated
    157 # source tree built by bootprep/prep-src.sh). Every bootN.sh needs it.
    158 require_src() {
    159     [ -d "build/$ARCH/src" ] || {
    160         echo "[$BOOT_TAG] missing build/$ARCH/src — run bootprep/prep-src.sh $ARCH" >&2
    161         exit 1
    162     }
    163 }
    164 
    165 # require_file <path> [<hint>] — assert <path> exists; print a uniform
    166 # "[$BOOT_TAG] missing <path> — <hint>" diagnostic on failure.
    167 require_file() {
    168     _path=$1; _hint=${2:-}
    169     [ -e "$_path" ] || {
    170         if [ -n "$_hint" ]; then
    171             echo "[$BOOT_TAG] missing $_path — $_hint" >&2
    172         else
    173             echo "[$BOOT_TAG] missing $_path" >&2
    174         fi
    175         exit 1
    176     }
    177 }