#!/bin/bash UPDATED="2024-04-25" DISABLE=1 # disable some options ENABLE=1 # enable some options SECURED=1 # enable/disable security PATCHES=1 # enable/disable patch apply UARCH=1 # apply more uarch patch CLANG=1 # use Clang compiler (if not, use GCC) O3=1 # use -O3 vs -O2 (optimisation) ARCH="x86-64-v4" # target architecture (uarch patch) CONFIGCLOUD=1 # enable cloud 'from' config CONFIGOLD=1 # enable old def config CONFIGMOD=0 # enable all mod config SCRATCH=0 # perform from scratch (remove preexisting content) UNCOMPRESS=1 # perform uncompress if already exist CLEANUP=1 # perform folder cleanup TESTING=0 # add testing options # # Sources: # https://github.com/sn99/Optimizing-linux#compiling-your-kernel # https://wiki.gentoo.org/wiki/Kernel/Optimization # # config-cloud-amd64: # https://packages.debian.org/source/sid/linux # linux-image-6.7.9-cloud-amd64-unsigned # Go down to download section, select amd64 and download deb. # Open .deb with archiver, browse to boot folder and grab 'config-6.7.9-cloud-amd64'. # # more-uarches-for-kernel.patch: # https://github.com/graysky2/kernel_compiler_patch # more-uarches-for-kernel.patch : more-uarches-for-kernel-6.8-rc4+.patch # # # Prerequisites: # sudo apt install build-essential fakeroot dpkg-dev perl libssl-dev bc gnupg dirmngr libncurses-dev libelf-dev flex bison lsb-release rsync dwarves clang llvm lld debhelper # # # In case of usage of uninstall.sh, you must reinstall 'linux-libc-dev' with the version of used kernel # # # To make a diff of different .config file: # diff --side-by-side --suppress-common-lines --ignore-tab-expansion --ignore-trailing-space --ignore-space-change --ignore-blank-lines --text CONFIG1 CONFIG2 # doBuildSystem() { echo "v$UPDATED" } # Display introduction doIntro() { echo if [ $TESTING == 1 ]; then echo "Debian Kernel Builder: $HOSTNAME [TEST]" else echo "Debian Kernel Builder: $HOSTNAME" fi doBuildSystem echo } # Show date/time header doHeader() { NOW=$(date +"%Y/%m/%d %H:%M:%S") echo "- $NOW" echo "" } if [ "$(id -u)" != "0" ]; then doIntro doHeader echo echo "This script must be run as root" 1>&2 echo exit 1 fi LOGNAME=kernel LOGEXT=log LOGFILE="" NPROC=$(nproc) HOSTNAME=$(hostname) SELF=$(realpath $0) SCRIPT=$(basename $SELF) CWD=$(dirname $SELF) CURRENT=$CWD CONFIGS=$CURRENT/configs PATCHES=$CURRENT/patches OPTIONS=$CURRENT/options BRANCH=$1 BRANCH="${BRANCH:=help}" VERSION=$2 VERSION="${VERSION:=help}" STEPS=$3 STEPS="${STEPS:=help}" WORKDIR="" cd $CURRENT # Force sync & flush doSync() { sync echo 3 >/proc/sys/vm/drop_caches } # Display header infos doHead() { doIntro doHeader } # Display help doHelp() { doIntro doHeader if [ $BRANCH != "help" ]; then echo ">>> Unspecified, unknown or invalid option specified!" echo fi echo "Usage: $SCRIPT 'branch' 'version'" echo echo "branch : Main branch (eg. 6.x)" echo "version: Full version tag (eg. 6.6.1)" echo } # Display step infos doEchoStep() { NOW=$(date +"%Y/%m/%d %H:%M:%S") echo "### $NOW - $1" } # Scratch doScratch() { if [ $SCRATCH == 1 ]; then if [ -d $WORKDIR ]; then doEchoStep "Scratch: remove existing content" rm -rf $WORKDIR else doEchoStep "Scratch: existing previous content not found" fi fi } # Download doDownload() { if [[ -d $WORKDIR && -f $WORKDIR/linux-$VERSION.tar.xz ]]; then doEchoStep "$BRANCH/$VERSION already present (don't download)" else mkdir -p $WORKDIR cd $WORKDIR doEchoStep "Download branch '$BRANCH' version '$VERSION'" wget --compression=auto --show-progress --no-verbose --inet4-only https://cdn.kernel.org/pub/linux/kernel/v$BRANCH/linux-$VERSION.tar.sign wget --compression=auto --show-progress --no-verbose --inet4-only https://cdn.kernel.org/pub/linux/kernel/v$BRANCH/linux-$VERSION.tar.xz doSync result=$? if [ ! result==0 ]; then echo ">>> Error in download!" exit 1 fi fi } # Uncompress doPerformUncompress() { cd $WORKDIR doEchoStep "Uncompress" rm -rf linux-$VERSION tar -xaf linux-$VERSION.tar.xz result=$? if [ ! result==0 ]; then echo ">>> Error in uncompress!" exit 1 fi } doUncompress() { if [ -d $WORKDIR ]; then if [ $UNCOMPRESS == 1 ]; then doPerformUncompress else doEchoStep "$BRANCH/$VERSION already present (don't uncompress)" fi else doPerformUncompress fi doSync } # Clean folder doCleanup() { if [ $CLEANUP == 1 ]; then cd $WORKDIR doEchoStep "Cleanup" if [ "$CLANG" == "1" ]; then make -j${NPROC} LLVM=1 CC="ccache clang" distclean else make -j${NPROC} CC="ccache gcc" distclean fi result=$? if [ ! result==0 ]; then echo ">>> Error in cleanup!" exit 1 fi fi } # Copy .config from cloud kernel doConfigCloud() { if [ $CONFIGCLOUD == 1 ]; then cd $WORKDIR doEchoStep "Copy cloud kernel .config" if [ -f .config ]; then cp .config .config.cloud.before fi cp $CONFIGS/cloud-amd64 .config result=$? if [ ! result==0 ]; then echo ">>> Error in cloud kernel .config copy!" exit 1 fi cp .config .config.cloud.after fi } # Generate .config from old kernel doOldOne() { if [ $CONFIGOLD == 1 ]; then cd $WORKDIR doEchoStep "Generate config from old kernel .config" if [ -f .config ]; then cp .config .config.old.before fi if [ "$CLANG" == "1" ]; then make -j${NPROC} LLVM=1 CC="ccache clang" olddefconfig else make -j${NPROC} CC="ccache gcc" olddefconfig fi result=$? if [ ! result==0 ]; then echo ">>> Error in generate .config!" exit 1 fi cp .config .config.old.after fi } # Define all modules not included in kernel doAllMods() { if [ $CONFIGMOD == 1 ]; then cd $WORKDIR doEchoStep "Set all modules to be 'module'" if [ -f .config ]; then cp .config .config.mod.before fi if [ "$CLANG" == "1" ]; then make -j${NPROC} LLVM=1 CC="ccache clang" allmodconfig else make -j${NPROC} CC="ccache gcc" allmodconfig fi result=$? if [ ! result==0 ]; then echo ">>> Error in set all modules not in kernel!" exit 1 fi cp .config .config.mod.after fi } # Define permissions (user/group) to first user created (default 1000) doPermissions() { cd $WORKDIR doEchoStep "Define user/group" chown -R 1000:1000 $CURRENT/build/$BRANCH/$VERSION/. result=$? if [ ! result==0 ]; then echo ">>> Error in chown!" exit 1 fi doSync } # Strip signature doStripSig() { cd $WORKDIR doEchoStep "Remove signature/keys" if [ -f .config ]; then cp .config .config.stripsig.before fi ./scripts/config --disable MODULE_SIG_ALL ./scripts/config --set-str CONFIG_MODULE_SIG_KEY "" ./scripts/config --set-str CONFIG_SYSTEM_TRUSTED_KEY "" ./scripts/config --set-str CONFIG_SYSTEM_REVOCATION_KEYS "" result=$? if [ ! result==0 ]; then echo ">>> Error in chown!" exit 1 fi cp .config .config.stripsig.after } # Strip debug informations doStripDebug() { cd $WORKDIR doEchoStep "Remove debug informations" if [ -f .config ]; then cp .config .config.stripdebug.before fi ./scripts/config --disable DEBUG_INFO ./scripts/config --enable DEBUG_INFO_NONE result=$? if [ ! result==0 ]; then echo ">>> Error in chown!" exit 1 fi cp .config .config.stripdebug.after } # Apply more patchs doApplyPatches() { if [ $PATCHES == 1 ]; then if [ $UARCH == 1 ] && [ -f $PATCHES/more-uarches.patch ]; then cd $WORKDIR doEchoStep "Apply 'uarches' patch" if [ -f .config ]; then cp .config .config.uarches.before fi patch -p1 <$PATCHES/more-uarches.patch result=$? if [ ! result==0 ]; then echo ">>> Error in 'uarches'!" exit 1 fi cp .config .config.uarches.after fi fi } # Exexcute './scripts/config' from file input doScriptsConfigFile() { SWITCH=$1 FILE=$2 while read -r option; do ./scripts/config --${SWITCH} $option done <"$FILE" } # Generate defaults options for this kernel doDefaultsDisable() { if [ $DISABLE == 1 ]; then doEchoStep "Options: disable" if [ -f .config ]; then cp .config .config.disable.before fi doScriptsConfigFile disable $OPTIONS/disable.txt cp .config .config.disable.after fi } doDefaultsEnable() { if [ $ENABLE == 1 ]; then doEchoStep "Options: enable" if [ -f .config ]; then cp .config .config.enable.before fi if [ "$CLANG" == "1" ]; then doScriptsConfigFile enable $OPTIONS/clang.txt fi doScriptsConfigFile enable $OPTIONS/enable.txt case ${ARCH} in "x86-64-v2") ./scripts/config --enable CONFIG_GENERIC_CPU2 ;; "x86-64-v3") ./scripts/config --enable CONFIG_GENERIC_CPU3 ;; "x86-64-v4") ./scripts/config --enable CONFIG_GENERIC_CPU4 ;; esac cp .config .config.enable.after fi } doDefaultMitigations() { if [ -f .config ]; then cp .config .config.mitigations.before fi if [ $SECURED == 0 ]; then doEchoStep "Options: secured OFF" doScriptsConfigFile disable $OPTIONS/unsecured.txt else doEchoStep "Options: secured ON" doScriptsConfigFile enable $OPTIONS/secured.txt fi cp .config .config.mitigations.after } doDefaultsTesting() { if [ $TESTING == 1 ]; then doEchoStep "Options: testings activated..." if [ -f .config ]; then cp .config .config.testing.before fi ./scripts/config --set-str CONFIG_LOCALVERSION '-test' cp .config .config.testing.after fi } doDefaults() { cd $WORKDIR if [ -f .config ]; then cp .config .config.default.before fi doApplyPatches doEchoStep "Define options" if [ "$CLANG" == "1" ]; then ./scripts/config --set-str CONFIG_LOCALVERSION '-clang' else ./scripts/config --set-str CONFIG_LOCALVERSION '-gcc' fi doDefaultsDisable doDefaultsEnable doDefaultMitigations doDefaultsTesting cp .config .config.default.after } # Edit .config doEditSettings() { cd $WORKDIR doEchoStep "Settings tuning!" if [ -f .config ]; then cp .config .config.edit.before fi if [ "$CLANG" == "1" ]; then make -j${NPROC} LLVM=1 CC="ccache clang" menuconfig else make -j${NPROC} CC="ccache gcc" menuconfig fi result=$? if [ ! result==0 ]; then echo ">>> Error in settings edit!" exit 1 fi cp .config .config.edit.after } doGenerateUninstall() { # remove old files READY=$CURRENT/build/$BRANCH/$VERSION/ready mkdir -p $READY rm -rf $READY/*.* if ls $WORKDIR/../*.deb 1>/dev/null 2>&1; then # find .deb packages and generate # uninstall commands # package name PACKAGES= TAG="_$VERSION_amd64.deb" search_dir=$WORKDIR/../ for entry in "$search_dir"/*.deb; do name="${entry##*/}" pname=${name//$TAG/} if [ ! "$pname" == "linux-libc-dev" ]; then PACKAGES="$PACKAGES $pname" fi echo "$name" >>$READY/packages.log done # move files to destination folder mv -f $WORKDIR/../*.deb $READY/ # prepare uninstall script cat <<-EOF >${READY}/uninstall.sh #!/bin/bash # ${UPDATED} apt remove --purge ${PACKAGES} sudo sync exit 0 EOF # generate install script cat <<-EOF >${READY}/install.sh #!/bin/bash # ${UPDATED} echo 'blacklist pcspkr' > /etc/modprobe.d/pcspkr.conf sudo dpkg -i *.deb sudo sync exit 0 EOF # Set execution attribute chmod +x $READY/*.sh else echo ">>> No packages have been created!" exit 1 fi # setup execution rights on packages chown -R root:root $READY/. } # Print compilation end informations doEnding() { clear doHead doEchoStep "Generated packages :" echo cat $CURRENT/build/$BRANCH/$VERSION/ready/packages.log echo echo "In folder: $CURRENT/build/$BRANCH/$VERSION/ready" doSync } # Perform effective compilation doCompile() { cd $WORKDIR doStripSig doStripDebug if [ $O3 == 1 ]; then GCCO="3" else GCCO="2" fi doEchoStep "Compilation time... Be patient!" if [ "$CLANG" == "1" ]; then doEchoStep "Compiler: CLANG" else doEchoStep "Compiler: GCC" fi export MAKEFLAGS="-j$((NPROC + 1)) -l${NPROC} -Wno-error" export CFLAGS="-march=${ARCH} -O${GCCO} -flto -pipe -msse -msse2 -msse3 -mmmx" export CXXFLAGS="${CFLAGS}" export KCFLAGS="-march=${ARCH} -O${GCCO}" export KCPPFLAGS="${KCFLAGS}" set CONFIG_SITE=/etc/dpkg-cross/cross-config.amd64 set DEB_BUILD_OPTIONS=nocheck doEchoStep "MAKEFLAGS: $MAKEFLAGS" doEchoStep "CFLAGS: $CFLAGS" doEchoStep "CXXFLAGS: $CXXFLAGS" doEchoStep "KCFLAGS: $KCFLAGS" doEchoStep "KCPPFLAGS: $KCPPFLAGS" doEchoStep "make bindeb-pkg" if [ "$CLANG" == "1" ]; then make \ -j${NPROC} \ LLVM=1 LLVM_IAS=1 \ CC='ccache clang' \ HOSTCC='ccache clang' \ bindeb-pkg \ LOCALVERSION=-"$(dpkg --print-architecture)" \ KDEB_PKGVERSION="$(make kernelversion)" else make \ -j${NPROC} \ CC='ccache gcc' \ bindeb-pkg \ LOCALVERSION=-"$(dpkg --print-architecture)" \ KDEB_PKGVERSION="$(make kernelversion)" fi result=$? doEchoStep "make bindeb-pkg: $result" if [ ! result==0 ]; then echo ">>> Error in 'make bindeb-pkg'!" exit 1 fi doGenerateUninstall doEnding doSync } # Proceed for Kernel build doKernel() { WORKDIR=$CURRENT/build/$BRANCH/$VERSION doScratch if [ ! -d $WORKDIR ]; then mkdir -p $WORKDIR fi LOGFILE=$WORKDIR/$LOGNAME.$LOGEXT if [ -f $LOGFILE ]; then rm -rf $LOGFILE fi touch $LOGFILE if [ "$STEPS" != "compile" ]; then doDownload > >(tee -a $LOGFILE) 2>&1 doUncompress > >(tee -a $LOGFILE) 2>&1 fi WORKDIR=$WORKDIR/linux-$VERSION doCleanup > >(tee -a $LOGFILE) 2>&1 doConfigCloud > >(tee -a $LOGFILE) 2>&1 doOldOne > >(tee -a $LOGFILE) 2>&1 doAllMods > >(tee -a $LOGFILE) 2>&1 doDefaults > >(tee -a $LOGFILE) 2>&1 doPermissions > >(tee -a $LOGFILE) 2>&1 doEditSettings while true; do read -p "Do you wish to run compile? " yn case $yn in [Yy]*) doCompile > >(tee -a $LOGFILE) 2>&1 break ;; [Nn]*) exit ;; *) echo "Please answer yes or no." ;; esac done } # Entrypoint of operations if [[ -z $BRANCH || "$BRANCH" == "help" || -z $VERSION || "$VERSION" == "help" ]]; then doHelp exit 1 else clear doHead doKernel fi exit 0