summaryrefslogtreecommitdiff
path: root/make-boot-image.sh
diff options
context:
space:
mode:
Diffstat (limited to 'make-boot-image.sh')
-rwxr-xr-xmake-boot-image.sh331
1 files changed, 331 insertions, 0 deletions
diff --git a/make-boot-image.sh b/make-boot-image.sh
new file mode 100755
index 0000000..032398d
--- /dev/null
+++ b/make-boot-image.sh
@@ -0,0 +1,331 @@
+#!/bin/bash -xe
+
+# Config #
+##########
+WORKDIR=/tmp/work
+DLDIR=./downloads
+OUTDIR=./out
+OUTUSB=/dev/sdb1
+RUN_QEMU=y
+ROOTCMD=sudo
+WGET="wget --no-check-certificate"
+KERNEL_TARBALL_URL=https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.6.tar.xz
+KCONFIGLIB_MAIN_URL=https://raw.githubusercontent.com/ulfalizer/Kconfiglib/7eace27993ad3aa1d6911866d9c60a11f32d36d9/kconfiglib.py
+KCONFIGLIB_PATCH_URL=https://raw.githubusercontent.com/ulfalizer/Kconfiglib/7eace27993ad3aa1d6911866d9c60a11f32d36d9/makefile.patch
+NIC_FIRMWARE_URL=http://fr.archive.ubuntu.com/ubuntu/pool/main/l/linux-firmware/nic-firmware_1.157_all.udeb
+BUSYBOX_BIN_URL=https://busybox.net/downloads/binaries/busybox-x86_64
+PCI_IDS_URL=https://pci-ids.ucw.cz/v2.2/pci.ids
+USB_IDS_URL=https://usb-ids.gowdy.us/usb.ids
+
+# Utilities #
+#############
+# From https://landley.net/writing/rootfs-programming.html
+# Its first argument is the new directory, and the rest of its arguments are executables to copy.
+function mkchroot
+{
+ [ $# -lt 2 ] && return 0
+ dest=$1
+ shift
+ for i in "$@"
+ do
+ # Get an absolute path for the file
+ p=$i
+ [ "${p:0:1}" == "/" ] || p=$(which $i) || true
+ if [ ! -e "$p" ]
+ then echo "mkchoot not found: $i"
+ return 1
+ fi
+ # Skip files that already exist at target.
+ [ -f "$dest/$p" ] && continue
+ # Create destination path
+ d=$(echo "$p" | grep -o '.*/') &&
+ mkdir -p "$dest/$d" &&
+ # Copy file
+ echo ${PS4}cp --dereference --preserve=mode "$p" "$dest/$p" &&
+ cp --dereference --preserve=mode "$p" "$dest/$p" &&
+ # Recursively copy shared libraries' shared libraries.
+ mkchroot "$dest" $(ldd "$p" | egrep -o '/.* ') || return $?
+ done
+}
+
+
+# Environement and dependencies #
+#################################
+[ -d "$WORKDIR" ] || mkdir "$WORKDIR"
+[ -d "$DLDIR" ] || mkdir "$DLDIR"
+[ -d "$OUTDIR" ] || mkdir "$OUTDIR"
+
+if [ ! -e "$WORKDIR/apt-done" ]
+then $ROOTCMD apt-get update
+ # Dependencies of this script
+ $ROOTCMD apt-get build-dep linux-source
+ $ROOTCMD apt-get install wget libncurses5-dev
+ # Optionnally qemu to make some santity checks
+ [ "x$RUN_QEMU" = "xy" ] && $ROOTCMD apt-get install qemu-system-x86
+ # Dependencies to put into the initrd
+ $ROOTCMD apt-get install dmidecode pciutils usbutils lshw sysstat iftop atop
+ $ROOTCMD apt-get install partclone udpcast gdisk efibootmgr tcpdump
+ > "$WORKDIR/apt-done"
+fi
+
+# Initial Ram Disk building (embed in kernel) #
+###############################################
+if [ ! -d "$WORKDIR/initrd" ]
+then mkdir -p "$WORKDIR/initrd/"{bin,dev,etc,mnt,root,proc,root,sbin,sys,run/lock,tmp,var}
+ $ROOTCMD cp -a /dev/{null,console,tty1} "$WORKDIR/initrd/dev/"
+ $ROOTCMD chmod 1777 "$WORKDIR/initrd/run/lock"
+ ln -s "../run" "$WORKDIR/initrd/var/run"
+ ln -s "../run/lock" "$WORKDIR/initrd/var/lock"
+fi
+
+if [ ! -f "$WORKDIR/initrd/bin/busybox" ]
+then [ -f "$DLDIR/busybox" ] || $WGET -O "$DLDIR/busybox" "$BUSYBOX_BIN_URL"
+ cp "$DLDIR/busybox" "$WORKDIR/initrd/bin/busybox"
+ chmod +x "$WORKDIR/initrd/bin/busybox"
+fi
+
+if [ ! -f "$WORKDIR/initrd/etc/keys.bmap" ]
+then $ROOTCMD dumpkeys | $ROOTCMD loadkeys -b > "$WORKDIR/initrd/etc/keys.bmap"
+fi
+
+(
+ set +x
+ PATH="/usr/sbin:/usr/bin:/sbin:/bin"
+ # Diagnostic tools
+ mkchroot "$WORKDIR/initrd" atop dmidecode iftop iostat lshw lspci lsusb mpstat tcpdump
+ # Manpage display
+ mkchroot "$WORKDIR/initrd" strace groff nroff troff grotty gtbl
+ # Cloning tools
+ mkchroot "$WORKDIR/initrd" /usr/sbin/partclone* efibootmgr gdisk udp-receiver
+ # Some dyn-loaded libraries (ldd will not display them)
+ mkchroot "$WORKDIR/initrd" /lib/x86_64-linux-gnu/libusb-1.0.so.0
+)
+
+#if [ ! -L "$WORKDIR/initrd/lib/x86_64-linux-gnu/tls/x86_64" ]
+#then mkdir -p "$WORKDIR/initrd/lib/x86_64-linux-gnu/tls"
+# ln -s "../.." "$WORKDIR/initrd/lib/x86_64-linux-gnu/tls/x86_64"
+#fi
+
+if [ ! -d "$WORKDIR/initrd/usr/man" ]
+then mkdir -p "$WORKDIR"/initrd/usr/man/man{1,8} "$WORKDIR"/initrd/usr/share/groff/1.22.2/font "$WORKDIR/initrd/etc/groff"
+ cp /usr/share/man/man1/{atop.1,iostat,mpstat,strace,udp-receiver}* "$WORKDIR/initrd/usr/man/man1/"
+ cp /usr/share/man/man8/{dmidecode,partclone,efibootmgr,gdisk,iftop,tcpdump}* "$WORKDIR/initrd/usr/man/man8/"
+ cp -r /usr/share/groff/1.22.2/font/devascii "$WORKDIR/initrd/usr/share/groff/1.22.2/font/"
+ cp -r /usr/share/groff/1.22.2/tmac "$WORKDIR/initrd/usr/share/groff/1.22.2/"
+ cp /etc/groff/man.local "$WORKDIR/initrd/usr/share/groff/1.22.2/"
+fi
+
+if [ ! -d "$WORKDIR/initrd/var/lib" ]
+then [ -f "$DLDIR/pci.ids" ] || $WGET -O "$DLDIR/pci.ids" "$PCI_IDS_URL"
+ [ -f "$DLDIR/usb.ids" ] || $WGET -O "$DLDIR/usb.ids" "$USB_IDS_URL"
+ mkdir -p "$WORKDIR/initrd/var/lib/usbutils" "$WORKDIR/initrd/usr/share/misc"
+ cp "$DLDIR/usb.ids" "$WORKDIR/initrd/var/lib/usbutils/"
+ cp "$DLDIR/pci.ids" "$WORKDIR/initrd/usr/share/misc/"
+fi
+
+if [ ! -d "$WORKDIR/initrd/lib/firmware" ]
+then [ -f "$DLDIR/nic-firmware.deb" ] || $WGET -O "$DLDIR/nic-firmware.deb" "$NIC_FIRMWARE_URL"
+ dpkg -x "$DLDIR/nic-firmware.deb" "$WORKDIR/initrd/"
+ find "$WORKDIR/initrd/lib/firmware/" \( -name 'ipw*' -o -name 'brcmfmac*' -o -name '*wifi*' \) -print0 | xargs -r0 rm -v
+fi
+
+cat > "$WORKDIR/initrd/funcs" <<"EOT"
+rescue_shell() {
+ echo "Something went wrong. Dropping to a shell."
+ setsid cttyhack sh
+ sync
+ umount /dev /sys /proc
+ poweroff -d1 -f
+}
+
+tty_prog() {
+ tty=/dev/tty$1; shift
+ while true
+ do
+ echo "(re)spawning $@ on $tty" >$tty
+ setsid sh -c "exec $@ <$tty >$tty 2>&1"
+ sleep 2
+ done
+}
+
+network_up() {
+ ip -oneline link | grep DOWN | cut -d: -f2 | grep -v sit | while read iface
+ do
+ echo ip link set dev $iface up
+ ip link set dev $iface up
+ done
+}
+
+machine_info() {
+ for k in system-manufacturer system-product-name \
+ baseboard-manufacturer baseboard-product-name \
+ bios-version bios-release-date
+ do
+ echo $k: $(dmidecode -s $k)
+ done
+ grep -F MemTotal: /proc/meminfo
+ lspci -nn | cut -d' ' -f2- | sed -ne 's/^Ethernet[^:]*/network-card/p'
+ ip -o l | sed -ne 's/[0-9]*: \([^:]*\):[^\\]*\\\s*link\/ether\s/network-mac-\1: /p'
+ lsusb 2>/dev/null | grep -vE hub$ | cut -d: -f2- | sed 's/^ ID/usb-device:/'
+}
+EOT
+
+cat > "$WORKDIR/initrd/init" <<"EOT"
+#!/bin/busybox sh
+echo "Initrd started"
+# Load helper functions
+. /funcs
+# Trace execution
+set -v
+
+# Setup links for programs supported by busybox
+/bin/busybox --install -s
+
+# Mount pseudo-filesystems
+mount -t proc none /proc || rescue_shell
+mount -t sysfs none /sys || rescue_shell
+mount -t devtmpfs none /dev || rescue_shell
+
+# Load keyboard map
+loadkmap < /etc/keys.bmap || rescue_shell
+
+# Start some debug shells (background)
+for i in 2 3 4 5 6; do tty_prog $i sh & done
+
+# Activate networking interfaces
+network_up
+sleep 8 # PHY link detection + IPv6 Duplicate Address Detection & Autoconf
+
+# Dump EFIvars if available
+efibootmgr -v
+
+# Machine basic informations
+machine_info
+
+# You could press Alt+F2 to have a shell. Remote control on telnet port (TCP 23)
+nc -ll -p 23 -e /bin/sh -i
+
+# Network IP adresses
+ip -o addr show | sed -ne 's/[0-9]*:\s*\(\S*\)\s*inet6*\s\(\S*\)\s.*$/\1: \2/p'
+
+EOT
+chmod +x "$WORKDIR/initrd/init"
+
+
+# Kernel build setup #
+######################
+kernel_tarball=$DLDIR/$(basename $KERNEL_TARBALL_URL)
+[ -f "$kernel_tarball" ] || $WGET -O "$kernel_tarball" "$KERNEL_TARBALL_URL"
+if [ ! -d "$WORKDIR/kernel" ]
+then mkdir "$WORKDIR/kernel"
+ tar xf "$kernel_tarball" --strip-components=1 -C "$WORKDIR/kernel"
+fi
+
+if [ ! -d "$WORKDIR/kernel/scripts/Kconfiglib" ]
+then
+ [ -f "$DLDIR/kconfiglib.py" ] || $WGET -O "$DLDIR/kconfiglib.py" "$KCONFIGLIB_MAIN_URL"
+ [ -f "$DLDIR/makefile.patch" ] || $WGET -O "$DLDIR/makefile.patch" "$KCONFIGLIB_PATCH_URL"
+ mkdir "$WORKDIR/kernel/scripts/Kconfiglib"
+ cp "$DLDIR/kconfiglib.py" "$WORKDIR/kernel/scripts/Kconfiglib/kconfiglib.py"
+ patch -t -p1 -d "$WORKDIR/kernel" < "$DLDIR/makefile.patch"
+fi
+
+cat >"$WORKDIR/kernel/scripts/Kconfiglib/customize.py" <<"EOT"
+#!/usr/bin/env python
+import kconfiglib
+import sys
+
+def sset(sym, value=None):
+ if not sym.is_modifiable():
+ print("%s is not modifiable at all"%(sym.get_name()))
+ return True
+ if value is None and sym.get_type() in [ kconfiglib.BOOL, kconfiglib.TRISTATE ]:
+ value = sym.get_upper_bound()
+ old_value = sym.get_value()
+ if old_value == value:
+ return False
+ print("CONFIG_%s=%s [was: %s]"%(sym.get_name(),value,old_value))
+ sym.set_user_value(value)
+ return True
+
+conf = kconfiglib.Config(sys.argv[1])
+conf.load_config('.config')
+support_xz = conf['KERNEL_XZ'] is not None
+i = 0
+more_work = True
+while more_work and i < 10:
+ more_work = False
+ i += 1
+ print("Kconfiglib/customize.py pass %i"%i)
+
+ for sym in conf.get_symbols():
+ name = sym.get_name()
+ if name in ['DEFAULT_HOSTNAME']:
+ # default is (none) and could make FreeBSD's dhcpd complain because unallowed '()'
+ more_work = sset(sym, 'eficast') or more_work
+
+ if name in ['INITRAMFS_SOURCE']:
+ # embed initrd in the EFI bootable kernel
+ more_work = sset(sym, '../initrd/') or more_work
+
+ if name in ['EFI_STUB', 'EFI_VARS', 'DELL_RBU', 'USB_XHCI_HCD', 'IKCONFIG']:
+ # Make kernel directly loadable by EFI, add USB3, Dell flash...
+ more_work = sset(sym) or more_work
+
+ if name in ['LOGO', 'SUSPEND', 'HIBERNATION', 'CPU_FREQ', 'PCCARD', 'HAMRADIO', 'WIRELESS', 'RFKILL', 'WLAN', 'SOUND', 'NETWORK_FILESYSTEMS', 'KEYS', 'SECURITY', 'VIRTUALIZATION']:
+ more_work = sset(sym, 'n') or more_work
+
+ if support_xz:
+ # Compress everything with XZ if available (slower, smaller)
+ if name in ['KERNEL_XZ']:
+ more_work = sset(sym, 'y') or more_work
+ if name in ['RD_GZIP', 'RD_BZIP2', 'RD_LZMA', 'RD_LZO', 'RD_LZ4']:
+ more_work = sset(sym, 'n') or more_work
+
+ # Following generic actions are meant for features, not choices
+ if not sym.is_choice_symbol():
+
+ # Build all available net/ethernet drivers
+ if sym.is_modifiable() and sym.get_type() in [ kconfiglib.BOOL, kconfiglib.TRISTATE ] \
+ and True in [ ('drivers/net/ethernet' in filename) for (filename,_) in sym.get_def_locations() ]:
+ more_work = sset(sym) or more_work
+
+ # Try to get everything in kernel, not as a module
+ if sym.get_value() == 'm' and sym.get_upper_bound() == 'y':
+ more_work = sset(sym, 'y') or more_work
+
+if i == 10:
+ print("ERROR : can't set some of kernel config symbols after 10 passes")
+ sys.exit(1)
+else:
+ sys.exit( conf.write_config(".config") )
+EOT
+chmod +x "$WORKDIR/kernel/scripts/Kconfiglib/customize.py"
+
+# Kernel build kernel #
+#######################
+(
+ cd "$WORKDIR/kernel"
+ if [ ! -f .config ]
+ then make defconfig
+ make scriptconfig SCRIPT=scripts/Kconfiglib/customize.py
+ fi
+ # Workaround : some kernel version forget to update embed initramfs in certain cases
+ [ -f usr/initramfs_data.cpio.gz ] && rm usr/initramfs_data.cpio.gz
+ make -j8
+)
+# Copy / run result EFI file #
+##############################
+cp "$WORKDIR/kernel/arch/x86/boot/bzImage" "$OUTDIR/BOOTX64.EFI"
+
+if [ -n "$OUTUSB" -a -b "$OUTUSB" ]
+then [ -d "$WORKDIR/mountpoint" ] || mkdir "$WORKDIR/mountpoint"
+ mount | grep -E "^$OUTUSB" -q && $ROOTCMD umount "$OUTUSB"
+ $ROOTCMD mount "$OUTUSB" "$WORKDIR/mountpoint"
+ [ -d "$WORKDIR/mountpoint/BOOT/EFI" ] || $ROOTCMD mkdir -p "$WORKDIR/mountpoint/EFI/BOOT"
+ $ROOTCMD cp "$OUTDIR/BOOTX64.EFI" "$WORKDIR/mountpoint/EFI/BOOT"
+ $ROOTCMD umount "$WORKDIR/mountpoint"
+fi
+
+[ "x$RUN_QEMU" == "xy" ] && qemu-system-x86_64 -kernel "$OUTDIR/BOOTX64.EFI"
+