Skip to content

Instantly share code, notes, and snippets.

@satmandu
Last active September 25, 2024 03:44
Show Gist options
  • Save satmandu/a507c59d84737f6d29ff353395819d51 to your computer and use it in GitHub Desktop.
Save satmandu/a507c59d84737f6d29ff353395819d51 to your computer and use it in GitHub Desktop.
Make arm64 deb packages for the offical Raspberry Pi Foundation arm64 kernels, tested with ubuntu 23.04
#!/bin/bash -x
# make_arm64_rpi_kernel_debs.sh
# Builds arm64 debian packages from the CURRENT rpi firmware repository kernel which is installed by:
# sudo rpi-update
# This runs on an arm64 host with arm64 compilation tools...
# or with some sort of cross-compilation setup.
# Debs are put in $workdir/build
#
# This will NOT work in Raspbian unless you have an arm64 compilation
# environment setup. Appears to work on
# Raspberry Pi OS (64 bit) beta test version
#
#
#
# Install packages you should probably have if you are needing to install kernel headers.
arch=$(uname -m)
if [[ $arch == 'aarch64' ]]; then
echo ""
else
echo "This needs to be run when booted into 64-bit mode."
exit 1
fi
# sudo apt install -f -y build-essential flex gawk bison libssl-dev bc dkms autoconf libtool || (sudo apt install -f -y || true)
workdir="${HOME}/workdir"
[[ ! -d "$workdir" ]] && ( mkdir -p "$workdir" || exit 1)
[[ ! -d "$workdir"/tmp ]] && ( mkdir -p "$workdir"/tmp || exit 1)
[[ ! -d "$workdir"/build ]] && ( mkdir -p "$workdir"/build || exit 1)
echo "workdir is ${workdir}"
tmpdir=$(mktemp -d deb_XXXX -p "$workdir"/tmp)
echo "tmpdir is ${tmpdir}"
dhpath="$tmpdir/headers"
dipath="$tmpdir/image"
src_temp=$(mktemp -d rpi_src_XXXi -p "$workdir"/tmp)
git_base="https://github.com/raspberrypi/rpi-firmware"
git_branch="master"
FIRMWARE_REV=$(git ls-remote "https://github.com/raspberrypi/rpi-firmware" refs/heads/$git_branch | awk '{print $1}')
cd "$src_temp" && curl -OLf https://github.com/raspberrypi/rpi-firmware/raw/$git_branch/git_hash
KERNEL_REV=$(cat "$src_temp"/git_hash)
SHORT_HASH=$(echo ${KERNEL_REV:0:7})
setup_git_fw() {
if [[ -d "$workdir/rpi-firmware" ]]; then
( sudo rm -rf "$workdir"/rpi-firmware.old || true )
( sudo mv "$workdir"/rpi-firmware "$workdir"/rpi-firmware.old || true )
( sudo rm -rf "$workdir"/rpi-firmware.old || true )
fi
cd "$workdir" && git clone --depth=1 -b $git_branch $git_base
}
update_git_fw() {
[[ ! -d "$workdir/rpi-firmware" ]] && setup_git_fw
( cd "$workdir"/rpi-firmware && git fetch && git reset --hard origin/$git_branch ) || setup_git_fw
cd "$workdir"/rpi-firmware && git config pull.ff only
cd "$workdir"/rpi-firmware && git pull
#cd "$workdir"/rpi-firmware && git_hash=$(git rev-parse origin/$git_branch)
}
check_zfs() {
# Install zfs prerequisites
sudo apt install -f -y autoconf libtool uuid-dev libudev-dev \
libssl-dev zlib1g-dev libaio-dev libattr1-dev python3 python3-dev \
python3-setuptools autoconf automake libtool gawk dkms libblkid-dev \
uuid-dev libudev-dev libssl-dev libelf-dev python3-cffi libffi-dev || true
}
make_headers_deb_files() {
installed_size_headers=$(du -a "$dhpath" | tail -n 1 | awk '{print $1}')
mkdir -p "$dhpath"/DEBIAN
chmod 777 "$dhpath"/DEBIAN
cat <<-EOF | dd status=none of="$dhpath"/DEBIAN/control
Source: linux-$kver
Section: kernel
Priority: optional
Maintainer: root <root@$SHORT_HASH>
Standards-Version: 4.1.3
Homepage: http://www.kernel.org/
Package: linux-headers-$kver
Architecture: all
Version: $kver-1
Depends: build-essential, flex, bison, bc
Installed-Size: $installed_size_headers
Description: Linux kernel headers for $kver on arm64
This package provides kernel header files for $kver on arm64
built from:
https://github.com/raspberrypi/linux/tree/$FIRMWARE_REV
This is useful for people who need to build external modules
EOF
cat <<-EOF | dd status=none of="$dhpath"/DEBIAN/preinst
#!/bin/sh
set -e
version=$kver
if [ "\$1" = abort-upgrade ]; then
exit 0
fi
if [ "\$1" = install ]; then
mkdir -p /lib/modules/\$version
mkdir -p /usr/src/linux-headers-\$version || true
cd /lib/modules/\$version && ln -snrvf /usr/src/linux-headers-\$version build
fi
if [ -d /etc/kernel/header_preinst.d ]; then
DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
--arg=\$image_path /etc/kernel/header_preinst.d
fi
exit 0
EOF
chmod +x "$dhpath"/DEBIAN/preinst
cat <<-EOF | dd status=none of="$dhpath"/DEBIAN/postinst
#!/bin/bash
set -e
version=$kver
[[ -f /etc/environment ]] && . /etc/environment
if [ "\$1" != configure ]; then
exit 0
fi
if [ -d /etc/kernel/header_postinst.d ]; then
DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
/etc/kernel/header_postinst.d
fi
exit 0
EOF
chmod +x "$dhpath"/DEBIAN/postinst
chmod -R 0755 "$dhpath"/DEBIAN
cd "$tmpdir" && sudo nice -n 20 dpkg-deb -b headers/
sudo mv "$tmpdir"/headers.deb "$workdir"/build/linux-headers-"${kver}"_all.deb
}
make_image_deb_files() {
installed_size_image=$(du -a "$dipath" | tail -n 1 | awk '{print $1}')
mkdir -p "$dipath"/DEBIAN
chmod 777 "$dipath"/DEBIAN
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/control
Package: linux-image-$kver
Source: linux-$kver
Version: $kver-1
Architecture: arm64
Maintainer: root <root@$SHORT_HASH>
Installed-Size: $installed_size_image
Section: kernel
Priority: optional
Homepage: http://www.kernel.org/
Description: Linux kernel, version $kver
This package contains the Linux kernel, modules and corresponding other
files, version: $kver.
EOF
cat <<-EOFF | dd status=none of="$dipath"/DEBIAN/postinst
#!/bin/bash
set -e
version=$kver
image_path=/boot/vmlinuz-\$version
bootfsmount=\$(mount | grep boot | awk '{print \$3}')
[[ \$(echo \$bootfsmount | wc -w) == "1" ]] && BOOTFS=\${bootfsmount}
BOOTFS=\${BOOTFS:-/boot}
# Install kernel (This avoids an issue if /boot is fat32.)
mount -o remount,rw /boot 2>/dev/null || true
cp /usr/share/rpikernelhack/vmlinuz-"$kver" \$image_path || true
# If custom kernel= line is being used don't replace kernel8.img,
# overlays, or dtb files.
if ! vcgencmd get_config str | grep -q kernel ; then
cp /usr/share/rpikernelhack/vmlinuz-"$kver" /boot/kernel8.img
fi
cp /usr/lib/linux-image-"$kver"/broadcom/*.dtb \$BOOTFS/
cp /usr/lib/linux-image-"$kver"/overlays/* \$BOOTFS/overlays/
# This is needed to keep flash-kernel from throwing an error.
cp /usr/lib/linux-image-"$kver"/broadcom/*.dtb /etc/flash-kernel/dtbs/
# Make sure flash-kernel db allows for any kernel flavor
if ! grep -q 'Kernel-Flavors: any' /etc/flash-kernel/db ; then
mkdir -p /etc/flash-kernel/
cat <<FLASHDBRPI4 >> /etc/flash-kernel/db
Machine: Raspberry Pi 4 Model B
Machine: Raspberry Pi 4 Model B Rev 1.1
Machine: Raspberry Pi 4 Model B Rev 1.2
Machine: Raspberry Pi 4 Model B Rev 1.4
Machine: Raspberry Pi Compute Module 4 Rev 1.0
Machine: Raspberry Pi 400 Rev 1.0
Machine: Raspberry Pi 400 Rev 1.1
Machine: Raspberry Pi *
Kernel-Flavors: any
FLASHDBRPI4
fi
#
# When we install linux-image we have to run kernel postinst.d support to
# generate the initramfs, create links etc. Should it have an associated
# linux-image-extra package and we install that we also need to run kernel
# postinst.d, to regenerate the initramfs. If we are installing both at the
# same time, we necessarily trigger kernel postinst.d twice. As this includes
# rebuilding the initramfs and reconfiguring the boot loader this is very time
# consuming.
#
# Similarly for removal when we remove the linux-image-extra package we need to
# run kernel postinst.d handling in order to pare down the initramfs to
# linux-image contents only. When we remove the linux-image need to remove the
# now redundant initramfs. If we are removing both at the same time, then
# we will rebuilt the initramfs and then immediatly remove it.
#
# Switches to using a trigger against the linux-image package for all
# postinst.d and postrm.d handling. On installation postinst.d gets triggered
# twice once by linux-image and once by linux-image-extra. As triggers are
# non-cumulative we will only run this processing once. When removing both
# packages we will trigger postinst.d from linux-image-extra and then in
# linux-image postrm.d we effectivly ignore the pending trigger and simply run
# the postrm.d. This prevents us from rebuilding the initramfs.
#
if [ "\$1" = triggered ]; then
trigger=/usr/lib/linux/triggers/\$version
if [ -f "\$trigger" ]; then
sh "\$trigger"
rm -f "\$trigger"
fi
exit 0
fi
if [ "\$1" != configure ]; then
exit 0
fi
depmod \$version
if [ -f /lib/modules/\$version/.fresh-install ]; then
change=install
else
change=upgrade
fi
# linux-update-symlinks \$change \$version \$image_path
rm -f /lib/modules/\$version/.fresh-install
if [ -d /etc/kernel/postinst.d ]; then
mkdir -p /usr/lib/linux/triggers
cat - >/usr/lib/linux/triggers/\$version <<EOF
DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
--arg=\$image_path /etc/kernel/postinst.d
EOF
dpkg-trigger --no-await linux-update-\$version
fi
exit 0
EOFF
chmod +x "$dipath"/DEBIAN/postinst
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/triggers
interest linux-update-$kver
EOF
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/postrm
#!/bin/sh
set -e
version=$kver
image_path=/boot/vmlinuz-\$version
rm -f /lib/modules/\$version/.fresh-install
#if [ "\$1" != upgrade ] && command -v linux-update-symlinks >/dev/null; then
# linux-update-symlinks remove \$version \$image_path
#fi
if [ -d /etc/kernel/postrm.d ]; then
# We cannot trigger ourselves as at the end of this we will no longer
# exist and can no longer respond to the trigger. The trigger would
# then become lost. Therefore we clear any pending trigger and apply
# postrm directly.
if [ -f /usr/lib/linux/triggers/\$version ]; then
echo "\$0 ... removing pending trigger"
rm -f /usr/lib/linux/triggers/\$version
fi
DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
--arg=\$image_path /etc/kernel/postrm.d
fi
if [ "\$1" = purge ]; then
for extra_file in modules.dep modules.isapnpmap modules.pcimap \\
modules.usbmap modules.parportmap \\
modules.generic_string modules.ieee1394map \\
modules.ieee1394map modules.pnpbiosmap \\
modules.alias modules.ccwmap modules.inputmap \\
modules.symbols modules.ofmap \\
modules.seriomap modules.\\*.bin \\
modules.softdep modules.devname; do
eval rm -f /lib/modules/\$version/\$extra_file
done
rmdir /lib/modules/\$version || true
fi
exit 0
EOF
chmod +x "$dipath"/DEBIAN/postrm
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/preinst
#!/bin/sh
set -e
version=$kver
image_path=/boot/vmlinuz-\$version
if [ "\$1" = abort-upgrade ]; then
exit 0
fi
if [ "\$1" = install ]; then
# Create a flag file for postinst
mkdir -p /lib/modules/\$version
touch /lib/modules/\$version/.fresh-install
fi
if [ -d /etc/kernel/preinst.d ]; then
DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
--arg=\$image_path /etc/kernel/preinst.d
fi
if [ ! -e /lib/modules/\$version/build ]; then
mkdir -p /usr/src/linux-headers-\$version || true
cd /lib/modules/\$version && ln -snrvf /usr/src/linux-headers-\$version build || true
fi
exit 0
EOF
chmod +x "$dipath"/DEBIAN/preinst
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/prerm
#!/bin/sh
set -e
version=$kver
image_path=/boot/vmlinuz-\$version
if [ "\$1" != remove ]; then
exit 0
fi
linux-check-removal \$version
if [ -d /etc/kernel/prerm.d ]; then
DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
--arg=\$image_path /etc/kernel/prerm.d
fi
exit 0
EOF
chmod +x "$dipath"/DEBIAN/prerm
chmod -R 0755 "$dipath"/DEBIAN
cd "$tmpdir" && sudo nice -n 20 dpkg-deb -b image/
sudo mv "$tmpdir"/image.deb "$workdir"/build/linux-image-"${kver}"_arm64.deb
}
make_debs() {
cd "$src_temp" && curl -L https://github.com/raspberrypi/linux/archive/"${KERNEL_REV}".tar.gz >rpi-linux.tar.gz
cd "$src_temp" && curl --retry 3 -OL "https://github.com/raspberrypi/rpi-firmware/raw/${FIRMWARE_REV}/Module8.symvers"
mv $src_temp/Module8.symvers $src_temp/Module.symvers
kver=$(find "$workdir"/rpi-firmware/modules/ -type d -name '*v8+' -printf "%P\n")
l=$kver
# Build kernel header package
# Adapted from scripts/package/builddeb
mkdir -p $src_temp/header_tmp/debian
cd $src_temp/header_tmp && tar --strip-components 1 -xf "${src_temp}"/rpi-linux.tar.gz
SRCARCH=arm64
(cd $src_temp/header_tmp; cp $src_temp/header_tmp/arch/arm64/configs/bcm2711_defconfig $src_temp/header_tmp/.config) # copy .config manually to be where it's expected to be
cd "$src_temp/header_tmp" && (yes "" | sudo make oldconfig)
mkdir -p "$dhpath"/boot
cp "$src_temp/header_tmp"/.config "$dhpath"/boot/config-"${kver}"
cd "$src_temp/header_tmp" && (yes "" | sudo make modules_prepare) && sudo chown -R `id -u` .
#cd "$src_temp/header_tmp" && (yes "" | sudo make scripts) && sudo chown -R `id -u` .
(cd $src_temp/header_tmp; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$src_temp/header_tmp/debian/hdrsrcfiles"
(cd $src_temp/header_tmp; find arch/*/include include scripts -type f -o -type l) >> "$src_temp/header_tmp/debian/hdrsrcfiles"
(cd $src_temp/header_tmp; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$src_temp/header_tmp/debian/hdrsrcfiles"
(cd $src_temp/header_tmp; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$src_temp/header_tmp/debian/hdrsrcfiles"
(cd $src_temp/header_tmp; find tools/objtool -type f -executable) >> "$src_temp/header_tmp/debian/hdrobjfiles"
(cd $src_temp/header_tmp; find arch/$SRCARCH/include modules.builtin.modinfo Module.symvers include scripts -type f) >> "$src_temp/header_tmp/debian/hdrobjfiles"
(cd $src_temp/header_tmp; find scripts/gcc-plugins -name \*.so -o -name gcc-common.h) >> "$src_temp/header_tmp/debian/hdrobjfiles"
destdir="$dhpath"/usr/src/linux-headers-$kver
mkdir -p "$destdir"
(cd $src_temp/header_tmp; tar -c -f - -T -) < "$src_temp/header_tmp/debian/hdrsrcfiles" | (cd $destdir; tar -xf -)
(cd $src_temp/header_tmp; tar -c -f - -T -) < "$src_temp/header_tmp/debian/hdrobjfiles" | (cd $destdir; tar -xf -)
(cd $src_temp/header_tmp; cp $src_temp/header_tmp/arch/arm64/configs/bcm2711_defconfig $destdir/.config) # copy .config manually to be where it's expected to be
rm -rf "$src_temp/header_tmp/debian/hdrsrcfiles" "$src_temp/header_tmp/debian/hdrobjfiles"
cp "$src_temp"/Module.symvers "$destdir"/Module.symvers
make_headers_deb_files
mkdir -p "$dipath"/usr/share/rpikernelhack/
cp "$workdir"/rpi-firmware/kernel8.img "$dipath"/usr/share/rpikernelhack/vmlinuz-"$l"
mkdir -p "$dipath"/lib/modules/
cp -r "$workdir"/rpi-firmware/modules/"$l" "$dipath"/lib/modules/
mkdir -p "$dipath"/usr/lib/linux-image-"$l"/broadcom && mkdir -p "$dipath"/usr/lib/linux-image-"$l"/overlays
cp -f "$workdir"/rpi-firmware/*.dtb "$dipath"/usr/lib/linux-image-"$l"/broadcom/
cp -f "$workdir"/rpi-firmware/overlays/* "$dipath"/usr/lib/linux-image-"$l"/overlays/
[[ ! -e "$dipath/lib/firmware/$l/device-tree" ]] && mkdir -p "$dipath"/lib/firmware/"$l"/device-tree
make_image_deb_files
# Clean up.
cd "$workdir"
sudo rm -rf "$src_temp"
sudo rm -rf "$tmpdir"
}
install_headers() {
if [[ $(uname -m) == "aarch64" ]]; then
bootfsmount=$(mount | grep boot | awk '{print $3}')
[[ $(echo $bootfsmount | wc -w) == "1" ]] && BOOTFS=${bootfsmount}
BOOTFS=${BOOTFS:-/boot}
sudo mount -o remount,rw $BOOTFS
fi
sudo nice -n 20 dpkg -i "$workdir"/build/linux-headers-"${kver}"*.deb || sudo apt install -f -y
}
install_image() {
if [[ $(uname -m) == "aarch64" ]]; then
bootfsmount=$(mount | grep boot | awk '{print $3}')
[[ $(echo $bootfsmount | wc -w) == "1" ]] && BOOTFS=${bootfsmount}
BOOTFS=${BOOTFS:-/boot}
sudo mount -o remount,rw $BOOTFS
fi
sudo nice -n 20 dpkg -i "$workdir"/build/linux-image-"${kver}"*.deb || sudo apt install -f -y
}
update_git_fw
make_debs
mkdir -p "$workdir"/kernel-test
cp "$workdir"/build/linux-image-"${kver}"*.deb "$workdir"/kernel-test/
cp "$workdir"/build/linux-headers-"${kver}"*.deb "$workdir"/kernel-test/
install_headers
install_image
#sudo flash-image --force ${kver}
#trap '' HUP
#if [[ $(uname -m) == "aarch64" ]]; then
#bootfsmount=$(mount | grep boot | awk '{print $3}')
#[[ $(echo $bootfsmount | wc -w) == "1" ]] && BOOTFS=${bootfsmount}
#BOOTFS=${BOOTFS:-/boot}
#sudo mount -o remount,rw $BOOTFS
#fi
#mkdir "$workdir"/bin
#curl -Lf https://github.com/raspberrypi/rpi-update/raw/master/rpi-update -o "$workdir"/bin/rpi-update && chmod +x "$workdir"/bin/rpi-update
#sudo touch $BOOTFS/kernel7l.img && sudo WANT_32BIT=0 WANT_64BIT=1 WANT_PI4=1 SKIP_WARNING=1 BOOT_PATH=$BOOTFS ROOT_PATH=/ BRANCH=master "$workdir"/bin/rpi-update
echo "done."
@benni-tec
Copy link

benni-tec commented Mar 24, 2022

Hey, this script seems to do what I need. I want to install v4l2-loopback but 'am missing header files.

As I understand it this script builds headers for the most current version. My problem is that uname -r shows I'm running 5.10.103-v8+ however the script builds headers for 5.10.73-v8+ which to me seems like a lower version.

Is this a bug or does this mean the script is outdated?
Any help would be greatly appriciated!

Secondly I was wondering, if it is relativly simple to build these headers shouldn't it be possible to make these available through a raspberrypi-kernel-headers style package for 64-bit raspbian?

EDIT: welp I'm an idiot. I didn't install the image.deb along with the headers. v4l2loopback now shows up in modprobe. However the raspberrypi-camera is gone. Anyway I belive this isn't really the solution to my problem since I think I just changed kernels (which is an older version than before)

@satmandu
Copy link
Author

Here is my current version, which builds the 5.15 kernel images...

#!/bin/bash -x
# make_arm64_rpi_kernel_debs.sh
# Builds arm64 debian packages from the CURRENT rpi firmware repository kernel which is installed by:
# sudo rpi-update
# This runs on an arm64 host with arm64 compilation tools... 
# or with some sort of cross-compilation setup.
# Debs are put in $workdir/build
#
# This will NOT work in Raspbian unless you have an arm64 compilation
# environment setup. Appears to work on
# Raspberry Pi OS (64 bit) beta test version
#
#
#
# Install packages you should probably have if you are needing to install kernel headers.
arch=$(uname -m)
if [[ $arch == 'aarch64' ]]; then
    echo ""
else 
    echo "This needs to be run when booted into 64-bit mode."
    exit 1
fi

# sudo apt install -f -y build-essential flex gawk bison libssl-dev bc dkms autoconf libtool   || (sudo apt install -f -y || true)
workdir="${HOME}/workdir"
[[ ! -d "$workdir" ]] && ( mkdir -p "$workdir" || exit 1)
[[ ! -d "$workdir"/tmp ]] && ( mkdir -p "$workdir"/tmp || exit 1)
[[ ! -d "$workdir"/build ]] && ( mkdir -p "$workdir"/build || exit 1)
echo "workdir is ${workdir}"

tmpdir=$(mktemp -d deb_XXXX -p "$workdir"/tmp)
echo "tmpdir is ${tmpdir}"
dhpath="$tmpdir/headers"
dipath="$tmpdir/image"
src_temp=$(mktemp -d rpi_src_XXXi -p "$workdir"/tmp)

git_base="https://github.com/raspberrypi/rpi-firmware"
git_branch="master" 

FIRMWARE_REV=$(git ls-remote "https://github.com/raspberrypi/rpi-firmware" refs/heads/$git_branch | awk '{print $1}')
cd "$src_temp" && curl -OLf https://github.com/raspberrypi/rpi-firmware/raw/$git_branch/git_hash
KERNEL_REV=$(cat "$src_temp"/git_hash)
SHORT_HASH=$(echo ${KERNEL_REV:0:7})

setup_git_fw() {
if [[ -d "$workdir/rpi-firmware" ]]; then
    (  sudo rm -rf "$workdir"/rpi-firmware.old || true )
    (  sudo mv "$workdir"/rpi-firmware "$workdir"/rpi-firmware.old || true )
    (  sudo rm -rf "$workdir"/rpi-firmware.old || true )
fi
    cd "$workdir" && git clone --depth=1 -b $git_branch $git_base
}

update_git_fw() {
[[ ! -d "$workdir/rpi-firmware" ]] && setup_git_fw

( cd "$workdir"/rpi-firmware && git fetch && git reset --hard origin/$git_branch ) || setup_git_fw
    cd "$workdir"/rpi-firmware && git config pull.ff only
    cd "$workdir"/rpi-firmware && git pull
    #cd "$workdir"/rpi-firmware && git_hash=$(git rev-parse origin/$git_branch)
}

check_zfs() {
        # Install zfs prerequisites
        sudo apt install -f -y  autoconf libtool  uuid-dev libudev-dev \
    libssl-dev zlib1g-dev libaio-dev libattr1-dev python3 python3-dev \
    python3-setuptools autoconf automake libtool gawk dkms libblkid-dev \
    uuid-dev libudev-dev libssl-dev libelf-dev python3-cffi libffi-dev || true
    
}

make_headers_deb_files() {
installed_size_headers=$(du -a "$dhpath" | tail -n 1 | awk '{print $1}')
mkdir -p "$dhpath"/DEBIAN
chmod 777 "$dhpath"/DEBIAN
cat <<-EOF | dd status=none of="$dhpath"/DEBIAN/control
Source: linux-$kver
Section: kernel
Priority: optional
Maintainer: root <root@$SHORT_HASH>
Standards-Version: 4.1.3
Homepage: http://www.kernel.org/
Package: linux-headers-$kver
Architecture: all
Version: $kver-1
Depends: build-essential, flex, bison, bc
Installed-Size: $installed_size_headers
Description: Linux kernel headers for $kver on arm64
 This package provides kernel header files for $kver on arm64
 built from:
 https://github.com/raspberrypi/linux/tree/$FIRMWARE_REV
 This is useful for people who need to build external modules
EOF
cat <<-EOF | dd status=none of="$dhpath"/DEBIAN/preinst
#!/bin/sh
set -e

version=$kver

if [ "\$1" = abort-upgrade ]; then
    exit 0
fi

if [ "\$1" = install ]; then
    mkdir -p /lib/modules/\$version
    mkdir -p /usr/src/linux-headers-\$version || true
    cd /lib/modules/\$version && ln -snrvf /usr/src/linux-headers-\$version build
fi

if [ -d /etc/kernel/header_preinst.d ]; then
    DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
          --arg=\$image_path /etc/kernel/header_preinst.d
fi


exit 0
EOF
chmod +x "$dhpath"/DEBIAN/preinst
cat <<-EOF | dd status=none of="$dhpath"/DEBIAN/postinst
#!/bin/bash

set -e

version=$kver
[[ -f /etc/environment ]] && . /etc/environment
if [ "\$1" != configure ]; then
    exit 0
fi




if [ -d /etc/kernel/header_postinst.d ]; then
    DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
                /etc/kernel/header_postinst.d
fi


exit 0
EOF
chmod +x "$dhpath"/DEBIAN/postinst
chmod -R 0755 "$dhpath"/DEBIAN
cd "$tmpdir" && sudo nice -n 20 dpkg-deb -b headers/
sudo mv "$tmpdir"/headers.deb "$workdir"/build/linux-headers-"${kver}"_all.deb
}

make_image_deb_files() {
installed_size_image=$(du -a "$dipath" | tail -n 1 | awk '{print $1}')
mkdir -p "$dipath"/DEBIAN
chmod 777 "$dipath"/DEBIAN
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/control
Package: linux-image-$kver
Source: linux-$kver
Version: $kver-1
Architecture: arm64
Maintainer: root <root@$SHORT_HASH>
Installed-Size: $installed_size_image
Section: kernel
Priority: optional
Homepage: http://www.kernel.org/
Description: Linux kernel, version $kver
 This package contains the Linux kernel, modules and corresponding other
 files, version: $kver.
EOF
cat <<-EOFF | dd status=none of="$dipath"/DEBIAN/postinst
#!/bin/sh
set -e

version=$kver
image_path=/boot/vmlinuz-\$version

# Install kernel (This avoids an issue if /boot is fat32.)
mount -o remount,rw /boot 2>/dev/null || true
cp /usr/share/rpikernelhack/vmlinuz-"$kver" \$image_path || true
# If custom kernel= line is being used don't replace kernel8.img,
# overlays, or dtb files.
if ! vcgencmd get_config str | grep -q kernel ; then
    cp /usr/share/rpikernelhack/vmlinuz-"$kver" /boot/kernel8.img
    cp /usr/lib/linux-image-"$kver"/broadcom/*.dtb /boot/
    cp /usr/lib/linux-image-"$kver"/overlays/* /boot/overlays/
fi



#
# When we install linux-image we have to run kernel postinst.d support to
# generate the initramfs, create links etc.  Should it have an associated
# linux-image-extra package and we install that we also need to run kernel
# postinst.d, to regenerate the initramfs.  If we are installing both at the
# same time, we necessarily trigger kernel postinst.d twice. As this includes
# rebuilding the initramfs and reconfiguring the boot loader this is very time
# consuming.
#
# Similarly for removal when we remove the linux-image-extra package we need to
# run kernel postinst.d handling in order to pare down the initramfs to
# linux-image contents only.  When we remove the linux-image need to remove the
# now redundant initramfs.  If we are removing both at the same time, then
# we will rebuilt the initramfs and then immediatly remove it.
#
# Switches to using a trigger against the linux-image package for all
# postinst.d and postrm.d handling.  On installation postinst.d gets triggered
# twice once by linux-image and once by linux-image-extra.  As triggers are
# non-cumulative we will only run this processing once.  When removing both
# packages we will trigger postinst.d from linux-image-extra and then in
# linux-image postrm.d we effectivly ignore the pending trigger and simply run
# the postrm.d.  This prevents us from rebuilding the initramfs.
#
if [ "\$1" = triggered ]; then
    trigger=/usr/lib/linux/triggers/\$version
    if [ -f "\$trigger" ]; then
    sh "\$trigger"
    rm -f "\$trigger"
    fi
    exit 0
fi

if [ "\$1" != configure ]; then
    exit 0
fi

depmod \$version

if [ -f /lib/modules/\$version/.fresh-install ]; then
    change=install
else
    change=upgrade
fi
# linux-update-symlinks \$change \$version \$image_path
rm -f /lib/modules/\$version/.fresh-install

if [ -d /etc/kernel/postinst.d ]; then
    mkdir -p /usr/lib/linux/triggers
    cat - >/usr/lib/linux/triggers/\$version <<EOF
DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
      --arg=\$image_path /etc/kernel/postinst.d
EOF
    dpkg-trigger --no-await linux-update-\$version
fi

exit 0

EOFF
chmod +x "$dipath"/DEBIAN/postinst

cat <<-EOF | dd status=none of="$dipath"/DEBIAN/triggers
interest linux-update-$kver
EOF

cat <<-EOF | dd status=none of="$dipath"/DEBIAN/postrm
#!/bin/sh
set -e

version=$kver
image_path=/boot/vmlinuz-\$version

rm -f /lib/modules/\$version/.fresh-install

#if [ "\$1" != upgrade ] && command -v linux-update-symlinks >/dev/null; then
#    linux-update-symlinks remove \$version \$image_path
#fi

if [ -d /etc/kernel/postrm.d ]; then
    # We cannot trigger ourselves as at the end of this we will no longer
    # exist and can no longer respond to the trigger.  The trigger would
    # then become lost.  Therefore we clear any pending trigger and apply
    # postrm directly.
    if [ -f /usr/lib/linux/triggers/\$version ]; then
    echo "\$0 ... removing pending trigger"
    rm -f /usr/lib/linux/triggers/\$version
    fi
    DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
          --arg=\$image_path /etc/kernel/postrm.d
fi

if [ "\$1" = purge ]; then
    for extra_file in modules.dep modules.isapnpmap modules.pcimap \\
                      modules.usbmap modules.parportmap \\
                      modules.generic_string modules.ieee1394map \\
                      modules.ieee1394map modules.pnpbiosmap \\
                      modules.alias modules.ccwmap modules.inputmap \\
                      modules.symbols modules.ofmap \\
                      modules.seriomap modules.\\*.bin \\
              modules.softdep modules.devname; do
    eval rm -f /lib/modules/\$version/\$extra_file
    done
    rmdir /lib/modules/\$version || true
fi

exit 0
EOF
chmod +x "$dipath"/DEBIAN/postrm
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/preinst
#!/bin/sh
set -e

version=$kver
image_path=/boot/vmlinuz-\$version

if [ "\$1" = abort-upgrade ]; then
    exit 0
fi

if [ "\$1" = install ]; then
    # Create a flag file for postinst
    mkdir -p /lib/modules/\$version
    touch /lib/modules/\$version/.fresh-install
fi

if [ -d /etc/kernel/preinst.d ]; then
    DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
          --arg=\$image_path /etc/kernel/preinst.d
fi

if [ ! -e /lib/modules/\$version/build ]; then
    mkdir -p /usr/src/linux-headers-\$version || true
    cd /lib/modules/\$version && ln -snrvf /usr/src/linux-headers-\$version build || true
fi

exit 0
EOF
chmod +x "$dipath"/DEBIAN/preinst
cat <<-EOF | dd status=none of="$dipath"/DEBIAN/prerm
#!/bin/sh
set -e

version=$kver
image_path=/boot/vmlinuz-\$version

if [ "\$1" != remove ]; then
    exit 0
fi

linux-check-removal \$version

if [ -d /etc/kernel/prerm.d ]; then
    DEB_MAINT_PARAMS="\$*" run-parts --report --exit-on-error --arg=\$version \\
          --arg=\$image_path /etc/kernel/prerm.d
fi

exit 0
EOF
chmod +x "$dipath"/DEBIAN/prerm
chmod -R 0755 "$dipath"/DEBIAN
cd "$tmpdir" && sudo nice -n 20 dpkg-deb -b image/
sudo mv "$tmpdir"/image.deb "$workdir"/build/linux-image-"${kver}"_arm64.deb
}

make_debs() {
    cd "$src_temp" && curl -L https://github.com/raspberrypi/linux/archive/"${KERNEL_REV}".tar.gz >rpi-linux.tar.gz
    cd "$src_temp" && curl --retry 3 -OL "https://github.com/raspberrypi/rpi-firmware/raw/${FIRMWARE_REV}/Module8.symvers"
    mv $src_temp/Module8.symvers $src_temp/Module.symvers
    kver=$(find "$workdir"/rpi-firmware/modules/ -type d -name '*v8+' -printf "%P\n")
    l=$kver
    
    # Build kernel header package
    # Adapted from scripts/package/builddeb
    mkdir -p $src_temp/header_tmp/debian
    cd $src_temp/header_tmp && tar --strip-components 1 -xf "${src_temp}"/rpi-linux.tar.gz
    SRCARCH=arm64
    (cd $src_temp/header_tmp; cp $src_temp/header_tmp/arch/arm64/configs/bcm2711_defconfig $src_temp/header_tmp/.config) # copy .config manually to be where it's expected to be
    cd "$src_temp/header_tmp" && (yes "" | sudo make modules_prepare) && sudo chown -R `id -u` .
    #cd "$src_temp/header_tmp" && (yes "" | sudo make scripts) && sudo chown -R `id -u` .
    (cd $src_temp/header_tmp; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$src_temp/header_tmp/debian/hdrsrcfiles"
    (cd $src_temp/header_tmp; find arch/*/include include scripts -type f -o -type l) >> "$src_temp/header_tmp/debian/hdrsrcfiles"
    (cd $src_temp/header_tmp; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$src_temp/header_tmp/debian/hdrsrcfiles"
    (cd $src_temp/header_tmp; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$src_temp/header_tmp/debian/hdrsrcfiles"
    (cd $src_temp/header_tmp; find tools/objtool -type f -executable) >> "$src_temp/header_tmp/debian/hdrobjfiles"
    
    (cd $src_temp/header_tmp; find arch/$SRCARCH/include modules.builtin.modinfo Module.symvers include scripts -type f) >> "$src_temp/header_tmp/debian/hdrobjfiles"
    (cd $src_temp/header_tmp; find scripts/gcc-plugins -name \*.so -o -name gcc-common.h) >> "$src_temp/header_tmp/debian/hdrobjfiles"
    destdir="$dhpath"/usr/src/linux-headers-$kver
    mkdir -p "$destdir"
    (cd $src_temp/header_tmp; tar -c -f - -T -) < "$src_temp/header_tmp/debian/hdrsrcfiles" | (cd $destdir; tar -xf -)
    (cd $src_temp/header_tmp; tar -c -f - -T -) < "$src_temp/header_tmp/debian/hdrobjfiles" | (cd $destdir; tar -xf -)
    (cd $src_temp/header_tmp; cp $src_temp/header_tmp/arch/arm64/configs/bcm2711_defconfig $destdir/.config) # copy .config manually to be where it's expected to be
    rm -rf "$src_temp/header_tmp/debian/hdrsrcfiles" "$src_temp/header_tmp/debian/hdrobjfiles"
    cp "$src_temp"/Module.symvers "$destdir"/Module.symvers
    
    make_headers_deb_files

    mkdir -p "$dipath"/usr/share/rpikernelhack/
    cp "$workdir"/rpi-firmware/kernel8.img "$dipath"/usr/share/rpikernelhack/vmlinuz-"$l"
    mkdir -p "$dipath"/lib/modules/
    cp -r "$workdir"/rpi-firmware/modules/"$l" "$dipath"/lib/modules/
    mkdir -p "$dipath"/usr/lib/linux-image-"$l"/broadcom && mkdir -p "$dipath"/usr/lib/linux-image-"$l"/overlays   
    cp -f "$workdir"/rpi-firmware/*.dtb "$dipath"/usr/lib/linux-image-"$l"/broadcom/
    cp -f "$workdir"/rpi-firmware/overlays/* "$dipath"/usr/lib/linux-image-"$l"/overlays/
    [[ ! -e "$dipath/lib/firmware/$l/device-tree" ]] && mkdir -p "$dipath"/lib/firmware/"$l"/device-tree
    
    make_image_deb_files
    
    # Clean up.
    cd "$workdir"
    sudo rm -rf "$src_temp"
    sudo rm -rf "$tmpdir"
}

install_headers() {
if [[ $(uname -m) == "aarch64" ]]; then
bootfsmount=$(mount | grep boot | awk '{print $3}')
[[ $(echo $bootfsmount | wc -w) == "1" ]] && BOOTFS=${bootfsmount}
BOOTFS=${BOOTFS:-/boot}
sudo mount -o remount,rw $BOOTFS
fi
sudo nice -n 20 dpkg -i "$workdir"/build/linux-headers-"${kver}"*.deb || sudo apt install -f -y
}
install_image() {
	if [[ $(uname -m) == "aarch64" ]]; then
		bootfsmount=$(mount | grep boot | awk '{print $3}')
		[[ $(echo $bootfsmount | wc -w) == "1" ]] && BOOTFS=${bootfsmount}
		BOOTFS=${BOOTFS:-/boot}
		sudo mount -o remount,rw $BOOTFS
	fi
	sudo nice -n 20 dpkg -i "$workdir"/build/linux-image-"${kver}"*.deb || sudo apt install -f -y
}

update_git_fw
make_debs
install_headers
install_image
sudo flash-image --force ${kver} 
echo "done."

@alphafox02
Copy link

alphafox02 commented May 30, 2022

@satmandu Would you script be okay to generate the image/headers/tools etc for use in a Ubuntu aarch64 20.04 build running on a Pi4? I've been keeping a look out for a 5.15 kernel to come to 20.04 aarch64 like how it's coming to the x86_64 version, but so far all I see is 5.4

I installed a 5.15 kernel from Ubuntu 22.04 aarch64 for testing, which is fine, but the headers/tools can't be installed to do a dependency being to low a version in 20.04.

I have your script running now, so I guess I'll see what happens. I'm not sure how different a Pi OS Kernel vs a Ubuntu aarch64 kernel.

edit: I think I answered my own question as the script doesn't appear to work. It states the following "Ignoring old or unknown version 5.15.43-v8+ (latest is 5.15.0-1008-raspi)" towards the end.

@satmandu
Copy link
Author

Here is the current version I use with Ubuntu 22.04:

https://paste.ubuntu.com/p/SWF2nRX92c/

@satmandu
Copy link
Author

@alphafox02 I updated the script to the version I use for generating kernels for Ubuntu 22.04.

@alphafox02
Copy link

I’ll check it out here shortly. I’m super curious to see if it’ll work on 20.04 Ubuntu aarch64. Thank you for sharing.

@alphafox02
Copy link

@satmandu both the kernel and headers built and installed and no immediate problem booting. Should I be looking for a way to build the Linux-modules/Linux/modules-extra and Linux-raspi-tools/Linux-tools that typically accompany the kernel and header install on the Pi w/ aarch64 20.04?

@satmandu
Copy link
Author

@alphafox02 I have never bothered with those packages.

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