#!/bin/bash -e
 
#---------------------------------------------------------------------

# Filename: build-kernel.sh
# Purpose:  Builds a Linux kernel
# License:  BSD-style (for this file only)
# Revision: 250228

#---------------------------------------------------------------------

# Warning:  This script will delete the directory "/usr/src/linux", if
# it exists, and will  subsequently put a symlink at that location re-
# gardless.

#---------------------------------------------------------------------

MODFLAG=no
if [ "x$1" == "x--mod" ]; then MODFLAG=yes; fi
if [ "x$1" == "x-mod"  ]; then MODFLAG=yes; fi
if [ "x$1" == "xmod"   ]; then MODFLAG=yes; fi

RUNFLAG=no
if [ "x$1" == "x--run" ]; then RUNFLAG=yes; fi
if [ "x$1" == "x-run"  ]; then RUNFLAG=yes; fi
if [ "x$1" == "xrun"   ]; then RUNFLAG=yes; fi

if [ "x$MODFLAG" = "xyes" ]; then
    RUNFLAG=yes
fi

# CFGLOCAL should end with -32 for 32-bit or -64 for 64-bit. Addition-
# ally, CFGLOCAL should match CONFIG_LOCALVERSION in the kernel ".con-
# fig" file.

CFGLOCAL="-250228-64"
KERNFILE=kernel$CFGLOCAL
KERNXDIR=/kernelsbuilt/$KERNFILE
XWD=`pwd`

#---------------------------------------------------------------------

BITS=`echo $CFGLOCAL | sed -e 's/.*-//'`

if [ "@$LACSMPJOBS" \!= "@" ]; then
    cat << END
LACSMPJOBS (requested number of parallel build processes) has been set
externally to: $LACSMPJOBS
END
fi

MAKECMD=""
if [ "@$BITS" == "@32" ]; then
    NP=`getconf _NPROCESSORS_ONLN`
#   MAKECMD="make -j$NP ARCH=i386 CFLAGS=-m32"
    MAKECMD="smpmake -m32"
fi
if [ "@$BITS" == "@64" ]; then
    MAKECMD="smpmake"
fi
if [ "@$MAKECMD" == "@" ]; then
    cat << END
Error:
CFGLOCAL should end with -32 for 32-bit or -64 for 64-bit. Additional-
ly,  CFGLOCAL should match CONFIG_LOCALVERSION in the kernel ".config"
file.
END
    exit 1
fi

#---------------------------------------------------------------------

if [ "x$RUNFLAG" = "xno" ]; then
    cat << END
1. This script  builds a  4.14.X (or above) to  6.X Intel-based  Linux
kernel.

It  can  build a 64-bit kernel on a  64-bit box or a  32-bit kernel on
a 32-bit or 64-bit box.

#---------------------------------------------------------------------

2 To start,  unpack a previously-prepared Laclin kernel source tarball
source tarball in some directory.

The directory must *not* be located under "/usr".

As a related note,  if  the  directory  "/usr/src/linux" exists,  this
script will delete it.

The  tarball used  should be a  tarball prepared  by  "prepare-kernel-
sources.sh" as opposed to a standard Linux kernel source tarball.

It's  recommended  that  the  following additional conditions  be met.
However,  they're optional except for the fact that a lot of free disk
is needed in the filesystem used.

* The directory used should be named "/ram"
* "/ram" should be mounted as tmpfs; i.e., as virtual memory
* "/ram" should have at least 4 GB free

The "unpack" should create a directory with a name similar to "kernel-
210126-64".

#---------------------------------------------------------------------

3 This script  should be  executed in the  "kernel-..." directory men-
tioned previously.

The directory in question should contain a kernel source tree, includ-
ing, at the top level, the usual "arch" and "block" directories.

#---------------------------------------------------------------------

4. An  appropriate kernel ".config" file should be present in the top-
level directory. The "prepare-..." script should have placed one there
previously.

#---------------------------------------------------------------------

5. In the ".config" file, CONFIG_LOCALVERSION should be set to double-
quote, dash, a 6-digit date, dash, 32 or 64 to indicate 32 or 64 bits,
double-quote.

For example:

    CONFIG_LOCALVERSION="$CFGLOCAL"

CONFIG_LOCALVERSION_AUTO shouldn't be set:

    # CONFIG_LOCALVERSION_AUTO is not set

#---------------------------------------------------------------------

6. To build  a kernel,  go to the directory containing ".config", this
script,  and the kernel's "arch" and "block"  directories  and execute
the following command:

    bash ./build-kernel.sh --run >& build.log

#---------------------------------------------------------------------

7. If a "build" is successful, the following file should be created:

    arch/x86/boot/bzImage

The  path  shown  here is relative  to  the  directory  that  contains
".config".

#---------------------------------------------------------------------

8. If  a "build" is successful, this script  also installs kernel mod-
ules in the appropriate "/lib/modules" subdirectory.

#---------------------------------------------------------------------

9. Typical past build times:

Dell Inspiron 6400 2.0 GHz Intel Duo 7200 2 GB RAM: 1.0  hours
HP EliteBook 8560w (2011) i7 4x2 32 GB RAM:         1.0  hours
Same subsequent to cool-down safety measures:       1.75 hours

#---------------------------------------------------------------------

Post-build steps are as follows:

10. Select a kernel-file name of the following form:

    KERNFILE=kernel$CFGLOCAL

The  part after  "kernel" here should be the same as the value of CON-
FIG_LOCALVERSION.

It should  end with  "-64" for a 64-bit kernel and  "-32" for a 32-bit
kernel.

#---------------------------------------------------------------------

11. Copy the following file  to the appropriate directory on your GRUB
(or other) boot partition:

    arch/x86/boot/bzImage

Give the copy the name selected in the preceding step.

If the local distro needs a copy somewhere else (for example, for "re-
master" purposes), create that copy as well.

For example (destinations will be different on your system):

    cp arch/x86/boot/bzImage /boot/$KERNFILE
    cp arch/x86/boot/bzImage /mnt/sda1/boot/$KERNFILE

#---------------------------------------------------------------------

12. Edit your  GRUB (or other)  boot configuration file(s)  to reflect
the presence of the file.

#---------------------------------------------------------------------

13. This script tries to do the following for you:

13.1. Build  the kernel file and associated modules.  Install the mod-
ules.

13.2. Move the kernel "build" tree to: /kernelsbuilt/$KERNFILE

13.3. Fix some symlinks:

    mkdir -p          /usr/src
    rm    -fr         /usr/src/linux
    ln -nsf $KERNXDIR /usr/src/linux

    cd /lib/modules/*$CFGLOCAL/
    ln -nsf $KERNXDIR build
    ln -nsf build source

The  part after  "*" here  should be the same as the  value of CONFIG_
LOCALVERSION.

13.4. Make a backup copy of the new kernel's "/lib/modules/*$CFGLOCAL"
directory.

#---------------------------------------------------------------------

14. Reboot using the new kernel.

#---------------------------------------------------------------------

15. Rebuild  the  system's  "glibc*" package.  Generate  userland-type
kernel header files  and  move them into place in the current "glibc*"
package.

The  "glibc*"  rebuild procedure  may take care of the latter step for
you.

#---------------------------------------------------------------------

16. Rebuild packages  that depend in  a strict manner  on the  kernel.
These include, for example:

    fuse298  fuse300  qemu  vboxose5

END
    exit 1
fi

#---------------------------------------------------------------------
#                           main procedure
#---------------------------------------------------------------------

ISUSR=`pwd | grep /usr/ | wc -l`

if [ "x$ISUSR" == "x1" ]; then
    echo Error: Do not run this script anywhere under /usr/
    echo See instructions in the script
    exit 1
fi

#---------------------------------------------------------------------

# export LACSLOWDOWN=0.76
export LACSMPTRIES=8
export FORCECFLAGS64=yes

gcc --version
gcc -dumpmachine

#---------------------------------------------------------------------

if [ "x$MODFLAG" = "xno" ]; then
echo ============================== `date` initial setup
rm -fr arch/*/boot/bzImage

echo ============================== `date` $MAKECMD bzImage
$MAKECMD bzImage            || exit 1

echo ============================== `date` $MAKECMD modules
$MAKECMD modules            || exit 1
fi

echo ============================== `date` $MAKECMD modules_install
$MAKECMD modules_install    || exit 1

# Note: The "make firmware_install" step is no longer required.

#---------------------------------------------------------------------
#                  move "build" directory out of RAM
#---------------------------------------------------------------------

if [ \! -f ./vmlinux ]; then
    echo Internal error: Something is wrong
    exit 1
fi

XDIR=`pwd`
ISRAM=`pwd | grep /ram/ | wc -l`

if [ "x$MODFLAG" = "xno" ]; then
if [ "x$ISRAM" == "x1" ]; then
    echo ISRAM yes

    cd /                || exit 1
    echo " 001"
    rm -fr   $KERNXDIR  || exit 1
    echo " 002"
    mv $XDIR $KERNXDIR  || exit 1
    echo " 003"
    cd       $KERNXDIR  || exit 1

    echo Moved build directory to $KERNXDIR
else
    echo ISRAM no XDIR=$XDIR ISRAM=$ISRAM
fi
fi

#---------------------------------------------------------------------
#                        set up some symlinks
#---------------------------------------------------------------------

# If we're cross-building a 32-bit kernel on a 64-bit box,  some inte-
# gration with the build box is skipped.

OKAY=true
if [ "x$MODFLAG" = "xno" ]; then
    if [ "@$BITS" == "@32" ]; then
        UM=`uname -m`
        if [ "@$UM"   == "@x86_64" ]; then
            OKAY=false
        fi
    fi
fi

#---------------------------------------------------------------------

if [ "@$OKAY" == "@true"   ]; then
    XDIR=`pwd`

    mkdir -p      /usr/src          || exit 1
    rm    -fr     /usr/src/linux    || exit 1
    ln -nsf $XDIR /usr/src/linux    || exit 1

    cd /lib/modules/*$CFGLOCAL      || exit 1
    MDIR=`pwd`
    ln -nsf $XDIR build             || exit 1
    ln -nsf build source            || exit 1
    cd ..
    rm -fr       $MDIR.original     || exit 1
    cp -a  $MDIR $MDIR.original     || exit 1

    cd $XDIR                        || exit 1
fi

#---------------------------------------------------------------------

if [ "x$MODFLAG" = "xyes" ]; then
    mkdir -p /boot                  || exit 1
    cp -p arch/x86/boot/bzImage \
          /boot/$KERNFILE           || exit 1
fi

#---------------------------------------------------------------------
#                             wrap it up
#---------------------------------------------------------------------

echo ============================== `date` Results:
ls -l arch/x86/boot/bzImage || exit 1

cat << END
Done. For post-install steps,  see the instructions in the script file
usage text section.
END

exit 0                          # "Success" exit