mirror of
https://github.com/ps5-linux/ps5-linux-image.git
synced 2026-07-15 21:42:27 +00:00
Initial commit
This commit is contained in:
35
docker/image-builder/Dockerfile
Normal file
35
docker/image-builder/Dockerfile
Normal file
@@ -0,0 +1,35 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# System dependencies for distrobuilder and image creation
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates wget git make gcc libc6-dev build-essential \
|
||||
debootstrap rsync gpg dirmngr squashfs-tools \
|
||||
parted dosfstools e2fsprogs kmod \
|
||||
initramfs-tools fdisk gdisk udev kpartx \
|
||||
xz-utils bzip2 zstd \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Go (Ubuntu 24.04 only has 1.22, distrobuilder needs newer)
|
||||
RUN wget -q https://go.dev/dl/go1.25.6.linux-amd64.tar.gz -O /tmp/go.tar.gz && \
|
||||
tar -C /usr/local -xzf /tmp/go.tar.gz && \
|
||||
rm /tmp/go.tar.gz
|
||||
ENV PATH="/usr/local/go/bin:/root/go/bin:${PATH}"
|
||||
|
||||
# Build distrobuilder from source per upstream instructions
|
||||
RUN mkdir -p /root/go/src/github.com/lxc/ && \
|
||||
cd /root/go/src/github.com/lxc/ && \
|
||||
git clone --depth 1 --branch v3.3.1 https://github.com/lxc/distrobuilder && \
|
||||
cd distrobuilder && \
|
||||
make && \
|
||||
cp /root/go/bin/distrobuilder /usr/local/bin/ && \
|
||||
rm -rf /root/go/src /root/go/pkg
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY docker/image-builder/entrypoint.sh /entrypoint.sh
|
||||
COPY docker/image-builder/entrypoint-multi.sh /entrypoint-multi.sh
|
||||
RUN chmod +x /entrypoint.sh /entrypoint-multi.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
292
docker/image-builder/entrypoint-multi.sh
Normal file
292
docker/image-builder/entrypoint-multi.sh
Normal file
@@ -0,0 +1,292 @@
|
||||
#!/bin/bash
|
||||
# Multi-distro image builder: builds multiple distros into a single
|
||||
# GPT image (shared FAT32 boot + one ext4 rootfs partition per distro).
|
||||
set -ex
|
||||
|
||||
IMG_SIZE="${IMG_SIZE:-32000}"
|
||||
SKIP_CHROOT="${SKIP_CHROOT:-false}"
|
||||
DISTROS="${DISTROS:-ubuntu ubuntu2604 arch alpine}"
|
||||
STAGING="/tmp/build-staging"
|
||||
EFI_LABEL="boot"
|
||||
IMG="/output/ps5-multi.img"
|
||||
NUM_DISTROS=$(echo $DISTROS | wc -w)
|
||||
|
||||
# ======================================================================
|
||||
# Step 1: Build each distro's rootfs via distrobuilder
|
||||
# ======================================================================
|
||||
for DISTRO in $DISTROS; do
|
||||
CHROOT="/build/chroot-${DISTRO}"
|
||||
ROOT_LABEL="$DISTRO"
|
||||
|
||||
if [ "$SKIP_CHROOT" = "true" ] && [ -d "$CHROOT/bin" ]; then
|
||||
echo "=== Skipping $DISTRO chroot build, reusing existing rootfs ==="
|
||||
else
|
||||
echo "=== Building $DISTRO rootfs ==="
|
||||
|
||||
# --- Stage files for distrobuilder's copy generators ---
|
||||
rm -rf "$STAGING"
|
||||
mkdir -p "$STAGING/debs" "$STAGING/pkgs"
|
||||
|
||||
# Use the multi-boot hook instead of the single-distro one
|
||||
cp /repo/distros/shared/zz-update-boot-multi "$STAGING/zz-update-boot"
|
||||
|
||||
# Generate per-distro fstab with partition labels
|
||||
printf 'LABEL=%-14s / ext4 rw,relatime 0 1\nLABEL=%-14s /boot/efi vfat rw,relatime 0 2\n' \
|
||||
"$ROOT_LABEL" "$EFI_LABEL" > "$STAGING/fstab"
|
||||
|
||||
cp /repo/distros/${DISTRO}/grow-rootfs "$STAGING/"
|
||||
cp /repo/distros/${DISTRO}/nm-dns.conf "$STAGING/" 2>/dev/null || true
|
||||
|
||||
case "$DISTRO" in
|
||||
ubuntu*)
|
||||
cp /repo/distros/${DISTRO}/grow-rootfs.service "$STAGING/"
|
||||
cp /kernel-debs/*.deb "$STAGING/debs/"
|
||||
;;
|
||||
alpine)
|
||||
cp /repo/distros/alpine/grow-rootfs.openrc "$STAGING/"
|
||||
;;
|
||||
arch)
|
||||
cp /repo/distros/arch/grow-rootfs.service "$STAGING/"
|
||||
cp /repo/distros/arch/first-boot-setup "$STAGING/"
|
||||
cp /kernel-debs/*.pkg.tar.zst "$STAGING/pkgs/"
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Build rootfs ---
|
||||
rm -rf "$CHROOT"/* "$CHROOT"/.[!.]* 2>/dev/null || true
|
||||
mkdir -p "$CHROOT"
|
||||
|
||||
YAML="/repo/distros/${DISTRO}/image.yaml"
|
||||
distrobuilder build-dir "$YAML" "$CHROOT" --with-post-files --cache-dir /build/cache --cleanup=false
|
||||
|
||||
# --- Post-distrobuilder fixups ---
|
||||
case "$DISTRO" in
|
||||
ubuntu*)
|
||||
rm -f "$CHROOT/etc/resolv.conf"
|
||||
ln -sf /run/systemd/resolve/stub-resolv.conf "$CHROOT/etc/resolv.conf"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Write distro marker
|
||||
echo "$DISTRO" > "$CHROOT/etc/ps5-distro"
|
||||
fi
|
||||
|
||||
# --- Alpine kernel gap: no kernel installed via image.yaml ---
|
||||
# This runs even with --skip-chroot because Alpine's rootfs never includes a kernel;
|
||||
# we must always extract it from the .deb artifacts and generate an initrd.
|
||||
if [ "$DISTRO" = "alpine" ]; then
|
||||
echo "=== Alpine: installing kernel from .deb artifacts ==="
|
||||
|
||||
# Extract modules + vmlinuz from the linux-image .deb
|
||||
ALPINE_STAGING="/tmp/alpine-kernel-staging"
|
||||
rm -rf "$ALPINE_STAGING"
|
||||
mkdir -p "$ALPINE_STAGING"
|
||||
for deb in /kernel-debs/linux-image-*.deb; do
|
||||
[ -f "$deb" ] || continue
|
||||
dpkg-deb -x "$deb" "$ALPINE_STAGING"
|
||||
done
|
||||
|
||||
# Identify kernel version from the extracted .deb before copying
|
||||
KVER=$(ls -1 "$ALPINE_STAGING/lib/modules" 2>/dev/null | head -1)
|
||||
|
||||
if [ -n "$KVER" ]; then
|
||||
# Resolve the real modules path inside the chroot.
|
||||
# Alpine may use usr-merge (/lib -> usr/lib), so we must follow
|
||||
# symlinks to find the actual directory on disk.
|
||||
if [ -L "$CHROOT/lib" ]; then
|
||||
MODDIR="$CHROOT/usr/lib/modules"
|
||||
else
|
||||
MODDIR="$CHROOT/lib/modules"
|
||||
fi
|
||||
mkdir -p "$MODDIR"
|
||||
# Remove any stale modules from a previous build
|
||||
rm -rf "$MODDIR/$KVER"
|
||||
cp -a "$ALPINE_STAGING/lib/modules/$KVER" "$MODDIR/"
|
||||
mkdir -p "$CHROOT/boot"
|
||||
cp "$ALPINE_STAGING/boot/vmlinuz-$KVER" "$CHROOT/boot/vmlinuz-$KVER"
|
||||
echo ">> Alpine: modules copied to $MODDIR/$KVER"
|
||||
ls -la "$MODDIR/"
|
||||
fi
|
||||
rm -rf "$ALPINE_STAGING"
|
||||
|
||||
if [ -n "$KVER" ]; then
|
||||
echo "=== Alpine: generating initrd ==="
|
||||
chroot "$CHROOT" depmod -a "$KVER" 2>/dev/null || true
|
||||
|
||||
# Bind-mount essentials and run mkinitfs inside the alpine chroot
|
||||
mount --bind /dev "$CHROOT/dev"
|
||||
mount --bind /proc "$CHROOT/proc"
|
||||
mount --bind /sys "$CHROOT/sys"
|
||||
chroot "$CHROOT" mkinitfs -k "$KVER" -o "/boot/initrd.img-$KVER" "$KVER" || true
|
||||
umount "$CHROOT/sys" "$CHROOT/proc" "$CHROOT/dev"
|
||||
|
||||
# Populate /boot/efi/ for boot partition assembly
|
||||
mkdir -p "$CHROOT/boot/efi"
|
||||
cp "$CHROOT/boot/vmlinuz-$KVER" "$CHROOT/boot/efi/bzImage"
|
||||
# mkinitfs may output as initramfs-<flavor> — find whatever was generated
|
||||
if [ -f "$CHROOT/boot/initrd.img-$KVER" ]; then
|
||||
cp "$CHROOT/boot/initrd.img-$KVER" "$CHROOT/boot/efi/initrd.img"
|
||||
else
|
||||
# mkinitfs default output: /boot/initramfs-vanilla or similar
|
||||
INITRD=$(ls -1t "$CHROOT"/boot/initramfs-* "$CHROOT"/boot/initrd* 2>/dev/null | head -1)
|
||||
if [ -n "$INITRD" ]; then
|
||||
cp "$INITRD" "$CHROOT/boot/efi/initrd.img"
|
||||
else
|
||||
echo "WARNING: No initrd found for alpine after mkinitfs"
|
||||
fi
|
||||
fi
|
||||
echo ">> Alpine: kernel $KVER staged to boot/efi/"
|
||||
else
|
||||
echo "WARNING: No kernel modules found in .deb for alpine, skipping initrd generation"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# ======================================================================
|
||||
# Step 2: Create GPT image with dynamic partition layout
|
||||
# ======================================================================
|
||||
echo "=== Creating ${IMG_SIZE}MB GPT image ==="
|
||||
TMPIMG="/build/ps5-multi.img"
|
||||
dd if=/dev/zero of="$TMPIMG" bs=1M count=$IMG_SIZE conv=fsync status=progress
|
||||
|
||||
BOOT_END=500 # MiB
|
||||
USABLE=$((IMG_SIZE - BOOT_END))
|
||||
PER_DISTRO=$((USABLE / NUM_DISTROS))
|
||||
|
||||
parted -s "$TMPIMG" mklabel gpt
|
||||
parted -s "$TMPIMG" mkpart primary fat32 1MiB ${BOOT_END}MiB
|
||||
parted -s "$TMPIMG" set 1 esp on
|
||||
|
||||
PART_START=$BOOT_END
|
||||
PART_I=1
|
||||
for DISTRO in $DISTROS; do
|
||||
if [ $PART_I -lt $NUM_DISTROS ]; then
|
||||
PART_END=$((PART_START + PER_DISTRO))
|
||||
parted -s "$TMPIMG" mkpart primary ext4 ${PART_START}MiB ${PART_END}MiB
|
||||
else
|
||||
parted -s "$TMPIMG" mkpart primary ext4 ${PART_START}MiB 100%
|
||||
fi
|
||||
PART_START=$((PART_START + PER_DISTRO))
|
||||
PART_I=$((PART_I + 1))
|
||||
done
|
||||
|
||||
# ======================================================================
|
||||
# Step 3: Setup loop device + format partitions
|
||||
# ======================================================================
|
||||
LOOP_PATH=$(losetup -f)
|
||||
if [ ! -e "$LOOP_PATH" ]; then
|
||||
LOOP_NUM=${LOOP_PATH#/dev/loop}
|
||||
mknod "$LOOP_PATH" b 7 "$LOOP_NUM"
|
||||
fi
|
||||
|
||||
LOOPDEV=$(losetup -f --show "$TMPIMG")
|
||||
kpartx -av "$LOOPDEV"
|
||||
sleep 1
|
||||
|
||||
LOOP_BASE=$(basename "$LOOPDEV")
|
||||
PART_BOOT="/dev/mapper/${LOOP_BASE}p1"
|
||||
|
||||
echo "=== Formatting partitions ==="
|
||||
mkfs.vfat -n "$EFI_LABEL" -F32 "$PART_BOOT"
|
||||
|
||||
PART_NUM=2
|
||||
for DISTRO in $DISTROS; do
|
||||
PART="/dev/mapper/${LOOP_BASE}p${PART_NUM}"
|
||||
mkfs.ext4 -L "$DISTRO" -m 1 "$PART"
|
||||
PART_NUM=$((PART_NUM + 1))
|
||||
done
|
||||
|
||||
# ======================================================================
|
||||
# Step 4: Copy each rootfs to its partition
|
||||
# ======================================================================
|
||||
mkdir -p /tmp/mnt_boot /tmp/mnt_root
|
||||
|
||||
PART_NUM=2
|
||||
for DISTRO in $DISTROS; do
|
||||
echo "=== Copying $DISTRO rootfs ==="
|
||||
PART="/dev/mapper/${LOOP_BASE}p${PART_NUM}"
|
||||
mount "$PART" /tmp/mnt_root
|
||||
cp -a "/build/chroot-${DISTRO}"/* /tmp/mnt_root/
|
||||
sync
|
||||
umount /tmp/mnt_root
|
||||
PART_NUM=$((PART_NUM + 1))
|
||||
done
|
||||
|
||||
# ======================================================================
|
||||
# Step 5: Assemble boot partition
|
||||
# ======================================================================
|
||||
echo "=== Assembling boot partition ==="
|
||||
mount "$PART_BOOT" /tmp/mnt_boot
|
||||
|
||||
# Collect boot files from each distro's chroot.
|
||||
# Prefer /boot/efi/ (populated by fresh builds), fallback to /boot/ (skip-chroot reruns).
|
||||
for DISTRO in $DISTROS; do
|
||||
CHROOT="/build/chroot-${DISTRO}"
|
||||
EFIDIR="$CHROOT/boot/efi"
|
||||
BOOTDIR="$CHROOT/boot"
|
||||
# Find kernel version: look for versioned directories (not 'kernel'), following symlinks
|
||||
MODBASE="$CHROOT/lib/modules"
|
||||
[ -L "$CHROOT/lib" ] && MODBASE="$CHROOT/usr/lib/modules"
|
||||
KVER=$(find "$MODBASE" -maxdepth 1 -mindepth 1 -type d -not -name 'kernel' -printf '%f\n' 2>/dev/null | sort -V | tail -1)
|
||||
|
||||
# Copy bzImage (shared kernel — same for all, just copy once)
|
||||
if [ ! -f /tmp/mnt_boot/bzImage ]; then
|
||||
if [ -f "$EFIDIR/bzImage" ]; then
|
||||
cp "$EFIDIR/bzImage" /tmp/mnt_boot/
|
||||
elif [ -n "$KVER" ] && [ -f "$BOOTDIR/vmlinuz-$KVER" ]; then
|
||||
cp "$BOOTDIR/vmlinuz-$KVER" /tmp/mnt_boot/bzImage
|
||||
fi
|
||||
fi
|
||||
|
||||
# Copy distro-specific initrd
|
||||
if [ -f "$EFIDIR/initrd.img" ]; then
|
||||
cp "$EFIDIR/initrd.img" "/tmp/mnt_boot/initrd-${DISTRO}.img"
|
||||
elif [ -n "$KVER" ] && [ -f "$BOOTDIR/initrd.img-$KVER" ]; then
|
||||
cp "$BOOTDIR/initrd.img-$KVER" "/tmp/mnt_boot/initrd-${DISTRO}.img"
|
||||
elif [ -f "$BOOTDIR/initramfs-vanilla" ]; then
|
||||
# Alpine mkinitfs names its output initramfs-vanilla
|
||||
cp "$BOOTDIR/initramfs-vanilla" "/tmp/mnt_boot/initrd-${DISTRO}.img"
|
||||
fi
|
||||
|
||||
# Clean up /boot/efi contents from the rootfs (they're on the boot partition now)
|
||||
rm -rf "$CHROOT/boot/efi"/*
|
||||
done
|
||||
|
||||
# Ubuntu is default boot — copy its initrd as the generic initrd.img
|
||||
if [ -f /tmp/mnt_boot/initrd-ubuntu.img ]; then
|
||||
cp /tmp/mnt_boot/initrd-ubuntu.img /tmp/mnt_boot/initrd.img
|
||||
fi
|
||||
|
||||
# Generate per-distro cmdline files
|
||||
for DISTRO in $DISTROS; do
|
||||
sed "s|__DISTRO__|${DISTRO}|" /repo/boot/cmdline.txt > "/tmp/mnt_boot/cmdline-${DISTRO}.txt"
|
||||
done
|
||||
|
||||
# Default cmdline points to ubuntu
|
||||
sed "s|__DISTRO__|ubuntu|" /repo/boot/cmdline.txt > /tmp/mnt_boot/cmdline.txt
|
||||
|
||||
# Copy kexec scripts
|
||||
for DISTRO in $DISTROS; do
|
||||
cp "/repo/boot/kexec-${DISTRO}.sh" /tmp/mnt_boot/
|
||||
chmod +x "/tmp/mnt_boot/kexec-${DISTRO}.sh"
|
||||
done
|
||||
|
||||
# Copy vram.txt
|
||||
cp /repo/boot/vram.txt /tmp/mnt_boot/
|
||||
sync
|
||||
|
||||
# ======================================================================
|
||||
# Step 6: Cleanup
|
||||
# ======================================================================
|
||||
umount /tmp/mnt_boot
|
||||
rmdir /tmp/mnt_boot /tmp/mnt_root
|
||||
kpartx -dv "$LOOPDEV"
|
||||
losetup -d "$LOOPDEV"
|
||||
|
||||
mv "$TMPIMG" "$IMG"
|
||||
sync
|
||||
|
||||
echo "========================================"
|
||||
echo "Done! $IMG (${IMG_SIZE}MB) — $(echo $DISTROS | tr ' ' ' + ')"
|
||||
echo "Flash: sudo dd if=$IMG of=/dev/sdX bs=4M status=progress"
|
||||
echo "========================================"
|
||||
175
docker/image-builder/entrypoint.sh
Executable file
175
docker/image-builder/entrypoint.sh
Executable file
@@ -0,0 +1,175 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
DISTRO="${DISTRO:-ubuntu}"
|
||||
IMG_SIZE="${IMG_SIZE:-12000}"
|
||||
SKIP_CHROOT="${SKIP_CHROOT:-false}"
|
||||
STAGING="/tmp/build-staging"
|
||||
ROOT_LABEL="${DISTRO}"
|
||||
EFI_LABEL="boot"
|
||||
CHROOT="/build/chroot"
|
||||
IMG="/output/ps5-${DISTRO}.img"
|
||||
|
||||
if [ "$SKIP_CHROOT" = "true" ] && [ -d "$CHROOT/bin" ]; then
|
||||
echo "=== Reusing cached $DISTRO rootfs ==="
|
||||
else
|
||||
echo "=== Building $DISTRO rootfs ==="
|
||||
# --- Stage files for distrobuilder's copy generators ---
|
||||
rm -rf "$STAGING"
|
||||
mkdir -p "$STAGING/debs"
|
||||
cp /repo/distros/shared/zz-update-boot "$STAGING/"
|
||||
# Generate per-distro fstab with partition labels
|
||||
printf 'LABEL=%-14s / ext4 rw,relatime 0 1\nLABEL=%-14s /boot/efi vfat rw,relatime 0 2\n' \
|
||||
"$ROOT_LABEL" "$EFI_LABEL" > "$STAGING/fstab"
|
||||
cp /repo/distros/${DISTRO}/grow-rootfs "$STAGING/"
|
||||
cp /repo/distros/${DISTRO}/nm-dns.conf "$STAGING/" 2>/dev/null || true
|
||||
|
||||
case "$DISTRO" in
|
||||
ubuntu*)
|
||||
cp /repo/distros/${DISTRO}/grow-rootfs.service "$STAGING/"
|
||||
cp /kernel-debs/*.deb "$STAGING/debs/"
|
||||
;;
|
||||
alpine)
|
||||
cp /repo/distros/alpine/grow-rootfs.openrc "$STAGING/"
|
||||
;;
|
||||
arch)
|
||||
cp /repo/distros/arch/grow-rootfs.service "$STAGING/"
|
||||
cp /repo/distros/arch/first-boot-setup "$STAGING/"
|
||||
mkdir -p "$STAGING/pkgs"
|
||||
cp /kernel-debs/*.pkg.tar.zst "$STAGING/pkgs/"
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Build rootfs ---
|
||||
rm -rf "$CHROOT"/* "$CHROOT"/.[!.]* 2>/dev/null || true
|
||||
|
||||
YAML="/repo/distros/${DISTRO}/image.yaml"
|
||||
distrobuilder build-dir "$YAML" "$CHROOT" --with-post-files --cache-dir /build/cache --cleanup=false
|
||||
fi
|
||||
|
||||
# --- Post-distrobuilder fixups ---
|
||||
case "$DISTRO" in
|
||||
ubuntu*)
|
||||
rm -f "$CHROOT/etc/resolv.conf"
|
||||
ln -sf /run/systemd/resolve/stub-resolv.conf "$CHROOT/etc/resolv.conf"
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Alpine kernel gap: no kernel installed via image.yaml ---
|
||||
# Extract kernel from .deb, copy modules + bzImage, then chroot to run mkinitfs
|
||||
if [ "$DISTRO" = "alpine" ]; then
|
||||
echo "=== Alpine: installing kernel from .deb artifacts ==="
|
||||
|
||||
ALPINE_STAGING="/tmp/alpine-kernel-staging"
|
||||
rm -rf "$ALPINE_STAGING"
|
||||
mkdir -p "$ALPINE_STAGING"
|
||||
for deb in /kernel-debs/linux-image-*.deb; do
|
||||
[ -f "$deb" ] || continue
|
||||
dpkg-deb -x "$deb" "$ALPINE_STAGING"
|
||||
done
|
||||
|
||||
KVER=$(ls -1 "$ALPINE_STAGING/lib/modules" 2>/dev/null | head -1)
|
||||
|
||||
if [ -n "$KVER" ]; then
|
||||
# Resolve the real modules path (Alpine may use usr-merge: /lib -> usr/lib)
|
||||
if [ -L "$CHROOT/lib" ]; then
|
||||
MODDIR="$CHROOT/usr/lib/modules"
|
||||
else
|
||||
MODDIR="$CHROOT/lib/modules"
|
||||
fi
|
||||
mkdir -p "$MODDIR"
|
||||
rm -rf "$MODDIR/$KVER"
|
||||
cp -a "$ALPINE_STAGING/lib/modules/$KVER" "$MODDIR/"
|
||||
mkdir -p "$CHROOT/boot"
|
||||
cp "$ALPINE_STAGING/boot/vmlinuz-$KVER" "$CHROOT/boot/vmlinuz-$KVER"
|
||||
echo ">> Alpine: modules copied to $MODDIR/$KVER"
|
||||
fi
|
||||
rm -rf "$ALPINE_STAGING"
|
||||
|
||||
if [ -n "$KVER" ]; then
|
||||
chroot "$CHROOT" depmod -a "$KVER" 2>/dev/null || true
|
||||
|
||||
mount --bind /dev "$CHROOT/dev"
|
||||
mount --bind /proc "$CHROOT/proc"
|
||||
mount --bind /sys "$CHROOT/sys"
|
||||
chroot "$CHROOT" mkinitfs -k "$KVER" -o "/boot/initrd.img-$KVER" "$KVER" || true
|
||||
umount "$CHROOT/sys" "$CHROOT/proc" "$CHROOT/dev"
|
||||
|
||||
# Populate /boot/efi/ for boot partition assembly
|
||||
mkdir -p "$CHROOT/boot/efi"
|
||||
cp "$CHROOT/boot/vmlinuz-$KVER" "$CHROOT/boot/efi/bzImage"
|
||||
if [ -f "$CHROOT/boot/initrd.img-$KVER" ]; then
|
||||
cp "$CHROOT/boot/initrd.img-$KVER" "$CHROOT/boot/efi/initrd.img"
|
||||
else
|
||||
INITRD=$(ls -1t "$CHROOT"/boot/initramfs-* "$CHROOT"/boot/initrd* 2>/dev/null | head -1)
|
||||
if [ -n "$INITRD" ]; then
|
||||
cp "$INITRD" "$CHROOT/boot/efi/initrd.img"
|
||||
else
|
||||
echo "WARNING: No initrd found for alpine after mkinitfs"
|
||||
fi
|
||||
fi
|
||||
echo ">> Alpine: kernel $KVER staged to boot/efi/"
|
||||
else
|
||||
echo "WARNING: No kernel modules found in .deb for alpine"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Create GPT disk image ---
|
||||
echo "=== Creating ${IMG_SIZE}MB disk image ==="
|
||||
TMPIMG="/build/ps5-${DISTRO}.img"
|
||||
dd if=/dev/zero of="$TMPIMG" bs=1M count=$IMG_SIZE conv=fsync status=progress
|
||||
|
||||
parted -s "$TMPIMG" mklabel gpt
|
||||
parted -s "$TMPIMG" mkpart primary ext4 500MiB 100%
|
||||
parted -s "$TMPIMG" mkpart primary fat32 1MiB 500MiB
|
||||
parted -s "$TMPIMG" set 2 esp on
|
||||
|
||||
# Ensure the free loop device node exists (udev doesn't run inside containers,
|
||||
# so when the kernel allocates a new loop number it may lack a /dev node)
|
||||
LOOP_PATH=$(losetup -f)
|
||||
if [ ! -e "$LOOP_PATH" ]; then
|
||||
LOOP_NUM=${LOOP_PATH#/dev/loop}
|
||||
mknod "$LOOP_PATH" b 7 "$LOOP_NUM"
|
||||
fi
|
||||
|
||||
LOOPDEV=$(losetup -f --show "$TMPIMG")
|
||||
# Use kpartx to create partition device mappings (more reliable in containers)
|
||||
kpartx -av "$LOOPDEV"
|
||||
sleep 1
|
||||
|
||||
# kpartx creates /dev/mapper/loopXp1, /dev/mapper/loopXp2
|
||||
LOOP_BASE=$(basename "$LOOPDEV")
|
||||
PART1="/dev/mapper/${LOOP_BASE}p1"
|
||||
PART2="/dev/mapper/${LOOP_BASE}p2"
|
||||
|
||||
echo "=== Formatting partitions ==="
|
||||
mkfs.ext4 -L "$ROOT_LABEL" -m 1 "$PART1"
|
||||
mkfs.vfat -n "$EFI_LABEL" -F32 "$PART2"
|
||||
|
||||
mkdir -p /tmp/usb_root /tmp/usb_efi
|
||||
mount "$PART1" /tmp/usb_root
|
||||
mount "$PART2" /tmp/usb_efi
|
||||
|
||||
echo "=== Copying rootfs to image ==="
|
||||
cp -a "$CHROOT"/* /tmp/usb_root/
|
||||
sync
|
||||
|
||||
echo "=== Assembling boot partition ==="
|
||||
mv /tmp/usb_root/boot/efi/* /tmp/usb_efi/ 2>/dev/null || true
|
||||
sed "s|__DISTRO__|$ROOT_LABEL|" /repo/boot/cmdline.txt > /tmp/usb_efi/cmdline.txt
|
||||
cp /repo/boot/vram.txt /tmp/usb_efi/
|
||||
sync
|
||||
|
||||
umount /tmp/usb_root /tmp/usb_efi
|
||||
rmdir /tmp/usb_root /tmp/usb_efi
|
||||
kpartx -dv "$LOOPDEV"
|
||||
losetup -d "$LOOPDEV"
|
||||
|
||||
# Move finished image to output volume
|
||||
mv "$TMPIMG" "$IMG"
|
||||
sync
|
||||
|
||||
echo "========================================"
|
||||
echo "Done! $IMG (${IMG_SIZE}MB)"
|
||||
echo "Flash: sudo dd if=$IMG of=/dev/sdX bs=4M status=progress"
|
||||
echo "========================================"
|
||||
16
docker/kernel-builder-arch/Dockerfile
Normal file
16
docker/kernel-builder-arch/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
# Only packaging tools needed — kernel is already compiled
|
||||
RUN pacman -Syu --noconfirm && pacman -S --noconfirm \
|
||||
zstd libarchive && \
|
||||
pacman -Scc --noconfirm
|
||||
|
||||
WORKDIR /out/staging
|
||||
|
||||
# Pre-built artifacts are bind-mounted at /out/staging
|
||||
# Output packages go to /out
|
||||
|
||||
COPY docker/kernel-builder-arch/build.sh /build.sh
|
||||
RUN chmod +x /build.sh
|
||||
|
||||
CMD ["/build.sh"]
|
||||
58
docker/kernel-builder-arch/build.sh
Normal file
58
docker/kernel-builder-arch/build.sh
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# Packages pre-built kernel artifacts as a pacman .pkg.tar.zst.
|
||||
# Runs inside Docker as root; packages manually (makepkg refuses root).
|
||||
# Expects build artifacts staged in /out/staging by the ubuntu build step.
|
||||
set -e
|
||||
|
||||
if [ ! -f /out/staging/boot/bzImage ]; then
|
||||
echo "Error: no staged artifacts in /out/staging — run the kernel build step first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine version from staged modules directory
|
||||
KVER=$(ls /out/staging/lib/modules/)
|
||||
PKGNAME="linux-custom"
|
||||
VERSION=${KVER%%-*}
|
||||
|
||||
echo "==> Packaging kernel $KVER as pacman package"
|
||||
|
||||
STAGING=$(mktemp -d)
|
||||
|
||||
# Copy staged boot artifacts
|
||||
mkdir -p "$STAGING/boot"
|
||||
cp /out/staging/boot/bzImage "$STAGING/boot/vmlinuz-$KVER"
|
||||
cp /out/staging/System.map "$STAGING/boot/System.map-$KVER"
|
||||
cp /out/staging/.config "$STAGING/boot/config-$KVER"
|
||||
|
||||
# Copy pre-installed modules (Arch uses /lib -> /usr/lib)
|
||||
mkdir -p "$STAGING/usr/lib/modules"
|
||||
cp -a "/out/staging/lib/modules/$KVER" "$STAGING/usr/lib/modules/"
|
||||
|
||||
# Create .PKGINFO
|
||||
BUILDDATE=$(date -u +%s)
|
||||
INSTALLED_SIZE=$(du -sb "$STAGING" | awk '{print $1}')
|
||||
cat > "$STAGING/.PKGINFO" << EOF
|
||||
pkgname = $PKGNAME
|
||||
pkgbase = $PKGNAME
|
||||
pkgver = ${VERSION}-1
|
||||
pkgdesc = Custom Linux kernel $KVER for PS5
|
||||
url = https://kernel.org
|
||||
builddate = $BUILDDATE
|
||||
packager = bootstrap_docker
|
||||
size = $INSTALLED_SIZE
|
||||
arch = x86_64
|
||||
license = GPL-2.0-only
|
||||
provides = linux=$VERSION
|
||||
provides = linux-custom=$VERSION
|
||||
EOF
|
||||
|
||||
# Create .MTREE (required by newer pacman)
|
||||
cd "$STAGING"
|
||||
LANG=C bsdtar -czf .MTREE --format=mtree \
|
||||
--options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' \
|
||||
.PKGINFO *
|
||||
|
||||
# Build the package
|
||||
LANG=C bsdtar -cf - .PKGINFO .MTREE * | zstd -c -T0 > "/out/${PKGNAME}-${VERSION}-1-x86_64.pkg.tar.zst"
|
||||
|
||||
echo "==> Done: /out/${PKGNAME}-${VERSION}-1-x86_64.pkg.tar.zst"
|
||||
23
docker/kernel-builder/Dockerfile
Normal file
23
docker/kernel-builder/Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential bc bison flex kmod cpio gawk \
|
||||
libdw-dev libelf-dev libssl-dev \
|
||||
python3 rsync dpkg-dev debhelper zstd \
|
||||
perl git xz-utils ccache \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV PATH="/usr/lib/ccache:${PATH}"
|
||||
ENV CCACHE_DIR=/ccache
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
# Kernel source is bind-mounted at /src
|
||||
# Build artifacts are staged to /out/staging
|
||||
|
||||
COPY docker/kernel-builder/build.sh /build.sh
|
||||
RUN chmod +x /build.sh
|
||||
|
||||
CMD ["/build.sh"]
|
||||
28
docker/kernel-builder/build.sh
Normal file
28
docker/kernel-builder/build.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# Compiles the kernel and stages all artifacts into /out/staging.
|
||||
# Runs inside Docker; kernel source is bind-mounted at /src.
|
||||
set -e
|
||||
|
||||
# Clean host-built tool artifacts that may reference wrong include paths
|
||||
make -C tools/objtool clean 2>/dev/null || true
|
||||
|
||||
make olddefconfig
|
||||
make -j"$(nproc)" bzImage modules
|
||||
|
||||
# Stage all artifacts so downstream packagers don't need to run make
|
||||
echo "=== Staging build artifacts ==="
|
||||
rm -rf /out/staging
|
||||
mkdir -p /out/staging/boot
|
||||
|
||||
cp arch/x86/boot/bzImage /out/staging/boot/
|
||||
cp System.map /out/staging/
|
||||
cp .config /out/staging/
|
||||
|
||||
make modules_install INSTALL_MOD_PATH=/out/staging INSTALL_MOD_STRIP=1
|
||||
|
||||
# Remove dangling symlinks back into the source tree
|
||||
KVER=$(make -s kernelrelease)
|
||||
rm -f "/out/staging/lib/modules/$KVER/build" \
|
||||
"/out/staging/lib/modules/$KVER/source"
|
||||
|
||||
echo "=== Build artifacts staged in /out/staging ==="
|
||||
Reference in New Issue
Block a user