kernel/kernel.sh
2024-05-07 15:19:48 +02:00

788 lines
18 KiB
Bash

#!/bin/bash
UPDATED="2024-05-07"
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
#
# Ubuntu:
# sudo apt-get install linux-source
# In kernel sources folder:
# sudo openssl req -x509 -newkey rsa:4096 -keyout certs/mycert.pem -out certs/mycert.pem -nodes -days 3650
# sudo nano .config
# CONFIG_MODULE_SIG_KEY="certs/mycert.pem"
# CONFIG_SYSTEM_TRUSTED_KEYRING=y
# CONFIG_SYSTEM_TRUSTED_KEYS="certs/mycert.pem"
# CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
# CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096
# CONFIG_SECONDARY_TRUSTED_KEYRING=y
# CONFIG_SYSTEM_BLACKLIST_KEYRING=y
# CONFIG_SYSTEM_BLACKLIST_HASH_LIST=""
#
doBuildSystem() {
echo "v$UPDATED"
}
# Get target distribution name
doTargetName() {
case ${TARGET} in
debian)
TARGETNAME="Debian"
;;
ubuntu)
TARGETNAME="Ubuntu"
;;
esac
}
# Display introduction
doIntro() {
echo
doTargetName
if [ $TESTING == 1 ]; then
echo "$TARGETNAME Kernel Builder: $HOSTNAME [TEST]"
else
echo "$TARGETNAME 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
CERTS=$CURRENT/certs
BRANCH=$1
BRANCH="${BRANCH:=help}"
VERSION=$2
VERSION="${VERSION:=help}"
TARGET=$3
TARGET="${TARGET:=debian}"
WORKDIR=""
REVISION=1
cd $CURRENT
# Perform specific distribution adjustments
doTarget() {
case ${TARGET} in
ubuntu)
DISABLE=0
PATCHES=0
UARCH=0
ARCH="native"
CONFIGCLOUD=0
CONFIGMOD=0
CONFIGOLD=1
SCRATCH=0
;;
*)
;;
esac
}
# Perform adaptation bases on target specificity
doTargetAdapt() {
cd $WORKDIR
doTargetName
case ${TARGET} in
ubuntu)
doEchoStep "Adaptation for: ${TARGETNAME}"
doEchoStep " - Certificates generation"
openssl req -x509 -newkey rsa:4096 -keyout certs/zogg.pem -out certs/zogg.pem -nodes -days 3650 -config $CERTS/zogg.cnf
doEchoStep " - Options override"
./scripts/config --set-str CONFIG_MODULE_SIG_KEY "certs/zogg.pem"
./scripts/config --enable CONFIG_SYSTEM_TRUSTED_KEYRING
./scripts/config --set-str CONFIG_SYSTEM_TRUSTED_KEYS "certs/zogg.pem"
./scripts/config --enable CONFIG_SYSTEM_EXTRA_CERTIFICATE
./scripts/config --set-val CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE 4096
./scripts/config --enable CONFIG_SECONDARY_TRUSTED_KEYRING
./scripts/config --enable CONFIG_SYSTEM_BLACKLIST_KEYRING
./scripts/config --set-str CONFIG_SYSTEM_BLACKLIST_HASH_LIST ""
export CC="x86_64-pc-linux-gnu"
;;
*)
;;
esac
}
# 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' 'target'"
echo
echo "branch : Main branch (eg. 6.x) [*]"
echo "version: Full version tag (eg. 6.6.1) [*]"
echo "target: Target distribution (eg. debian/default, ubuntu)"
echo
echo " [*] : parameter required"
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
SEC="-unsecure"
if [ "$SECURED" == "1" ]; then
SEC="-secure"
fi
doEchoStep "Define options"
if [ "$CLANG" == "1" ]; then
./scripts/config --set-str CONFIG_LOCALVERSION "${SEC}-clang"
else
./scripts/config --set-str CONFIG_LOCALVERSION "${SEC}-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}-${REVISION}_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
if [ -f ../revision.log ]; then
REVISION="`head -1 ../revision.log`"
REVISION=$((REVISION+1))
fi
echo $REVISION > ../revision.log
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)-${REVISION}"
else
make \
-j${NPROC} \
CC='ccache gcc' \
bindeb-pkg \
LOCALVERSION=-"$(dpkg --print-architecture)" \
KDEB_PKGVERSION="$(make kernelversion)-${REVISION}"
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
doTarget
doScratch
if [ ! -d $WORKDIR ]; then
mkdir -p $WORKDIR
fi
LOGFILE=$WORKDIR/$LOGNAME.$LOGEXT
if [ -f $LOGFILE ]; then
rm -rf $LOGFILE
fi
touch $LOGFILE
doDownload > >(tee -a $LOGFILE) 2>&1
doUncompress > >(tee -a $LOGFILE) 2>&1
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
doTargetAdapt > >(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