How to Build A Custom Linux Kernel For Qemu (2015 Edition)

Preparation

First, create a workspace:

$ mkdir $HOME/teeny-linux
$ TOP=$HOME/teeny-linux

Our entire system will be composed of exactly two packages: the Linux kernel and Busybox. Download and extract them now:

$ cd $TOP
$ curl https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.0.3.tar.xz | tar xJf -
$ curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf -

Busybox Userland

The first thing we’ll do is create a minimal userland based on the ever-useful busybox tool. After building busybox, we’ll throw it in a minimal filesystem hierarchy and package it up in an initramfs using cpio.

Let’s go configure busybox now:

$ cd $TOP/busybox-1.23.2
$ mkdir -pv ../obj/busybox-x86
$ make O=../obj/busybox-x86 defconfig

(Note: in the busybox build system, O= means “place build output here”. This allows you to host multiple different configurations out of the same source tree. The Linux kernel follows a similar convention.)

This gives us a basic starting point. We’re going to take the easy way out here and just statically link busybox in order to avoid fiddling with shared libraries. We’ll need to use busybox’s menuconfig interface to enable static linking:

$ make O=../obj/busybox-x86 menuconfig

type /, search for “static”. You’ll see that the option is located at:

-> Busybox Settings
  -> Build Options
[ ] Build BusyBox as a static binary (no shared libs)
-> Networking Utilities
    -> inetd (INETD [=n])

Go to that location, select it, save, and exit.

Now build busybox:

$ cd ../obj/busybox-x86
$ make -j2
$ make install

So far so good. With a statically-linked busybox in hand we can build the directory structure for our initramfs:

$ mkdir -p $TOP/initramfs/x86-busybox
$ cd $TOP/initramfs/x86-busybox
$ mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}
$ cp -av $TOP/obj/busybox-x86/_install/* .

Of course, there’s a lot missing from this skeleton hierarachy that will cause a lot of applications to break (no /etc/passwd, for example), but it’s enough to boot to a shell, so we’ll live with it for the sake of brevity. If you want to flesh it out more you can refer to these sections of Linux From Scratch.

One absolutely critical piece of our userland that’s still missing is an init program. We’ll just write a tiny shell script and use it as our init:

$ vim init

And enter the following:

#!/bin/sh

mount -t proc none /proc
mount -t sysfs none /sys

echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"

exec /bin/sh

and make it executable:

$ chmod +x init

The Gentoo wiki’s Custom Initramfs page is a great reference for building a minimalistic initramfs if you’d like to learn more.

We’re now ready to cpio everything up:

$ find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 > $TOP/obj/initramfs-busybox-x86.cpio.gz

We now have a minimal userland in $TOP/obj/initramfs-busybox-x86.cpio.gz that we can pass to qemu as an initrd (using the -initrd option). But before we can do that we need a kernel…

Linux Kernel

  • ./arch/x86/configs/my_x86_64_defconfig
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_FHANDLE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_CGROUPS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_OSF_PARTITION=y
CONFIG_AMIGA_PARTITION=y
CONFIG_MAC_PARTITION=y
CONFIG_BSD_DISKLABEL=y
CONFIG_MINIX_SUBPARTITION=y
CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SGI_PARTITION=y
CONFIG_SUN_PARTITION=y
CONFIG_KARMA_PARTITION=y
CONFIG_EFI_PARTITION=y
CONFIG_SMP=y
CONFIG_CALGARY_IOMMU=y
CONFIG_NR_CPUS=64
CONFIG_SCHED_SMT=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
CONFIG_X86_MCE=y
CONFIG_MICROCODE=y
CONFIG_MICROCODE_AMD=y
CONFIG_X86_MSR=y
CONFIG_X86_CPUID=y
CONFIG_NUMA=y
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
# CONFIG_MTRR_SANITIZER is not set
CONFIG_EFI=y
CONFIG_HZ_1000=y
CONFIG_KEXEC=y
CONFIG_CRASH_DUMP=y
# CONFIG_COMPAT_VDSO is not set
CONFIG_HIBERNATION=y
CONFIG_PM_DEBUG=y
CONFIG_PM_TRACE_RTC=y
CONFIG_ACPI_DOCK=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_X86_ACPI_CPUFREQ=y
CONFIG_PCI_MMCONFIG=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCCARD=y
CONFIG_YENTA=y
CONFIG_HOTPLUG_PCI=y
CONFIG_BINFMT_MISC=y
CONFIG_IA32_EMULATION=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_DIAG is not set
CONFIG_TCP_CONG_ADVANCED=y
# CONFIG_TCP_CONG_BIC is not set
# CONFIG_TCP_CONG_WESTWOOD is not set
# CONFIG_TCP_CONG_HTCP is not set
CONFIG_TCP_MD5SIG=y
CONFIG_IPV6=y
CONFIG_INET6_AH=y
CONFIG_INET6_ESP=y
CONFIG_NETLABEL=y
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_ADVANCED is not set
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_CONNTRACK_IRC=y
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CT_NETLINK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NF_CONNTRACK_IPV4=y
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_REJECT=y
CONFIG_IP_NF_TARGET_ULOG=y
CONFIG_NF_NAT=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_IP_NF_MANGLE=y
CONFIG_NF_CONNTRACK_IPV6=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MATCH_IPV6HEADER=y
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_MANGLE=y
CONFIG_NET_SCHED=y
CONFIG_NET_EMATCH=y
CONFIG_NET_CLS_ACT=y
CONFIG_HAMRADIO=y
CONFIG_CFG80211=y
CONFIG_MAC80211=y
CONFIG_MAC80211_LEDS=y
CONFIG_RFKILL=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DEBUG_DEVRES=y
CONFIG_CONNECTOR=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_ATA_PIIX=y
CONFIG_PATA_AMD=y
CONFIG_PATA_OLDPIIX=y
CONFIG_PATA_SCH=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_MIRROR=y
CONFIG_DM_ZERO=y
CONFIG_MACINTOSH_DRIVERS=y
CONFIG_MAC_EMUMOUSEBTN=y
CONFIG_NETDEVICES=y
CONFIG_NETCONSOLE=y
CONFIG_TIGON3=y
CONFIG_NET_TULIP=y
CONFIG_E100=y
CONFIG_E1000=y
CONFIG_SKY2=y
CONFIG_FORCEDETH=y
CONFIG_8139TOO=y
CONFIG_FDDI=y
CONFIG_INPUT_POLLDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TABLET=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_NONSTANDARD=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=32
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_8250_DETECT_IRQ=y
CONFIG_SERIAL_8250_RSA=y
CONFIG_HW_RANDOM=y
# CONFIG_HW_RANDOM_INTEL is not set
# CONFIG_HW_RANDOM_AMD is not set
CONFIG_NVRAM=y
CONFIG_HPET=y
# CONFIG_HPET_MMAP is not set
CONFIG_I2C_I801=y
CONFIG_WATCHDOG=y
CONFIG_AGP=y
CONFIG_AGP_AMD64=y
CONFIG_AGP_INTEL=y
CONFIG_DRM=y
CONFIG_DRM_I915=y
CONFIG_DRM_I915_KMS=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_EFI=y
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_VGACON_SOFT_SCROLLBACK=y
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SEQUENCER=y
CONFIG_SND_SEQ_DUMMY=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
CONFIG_SND_SEQUENCER_OSS=y
CONFIG_SND_HRTIMER=y
CONFIG_SND_HDA_INTEL=y
CONFIG_SND_HDA_HWDEP=y
CONFIG_HIDRAW=y
CONFIG_HID_GYRATION=y
CONFIG_LOGITECH_FF=y
CONFIG_HID_NTRIG=y
CONFIG_HID_PANTHERLORD=y
CONFIG_PANTHERLORD_FF=y
CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
CONFIG_HID_TOPSEED=y
CONFIG_HID_PID=y
CONFIG_USB_HIDDEV=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_MON=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_TT_NEWSCHED=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_PRINTER=y
CONFIG_USB_STORAGE=y
CONFIG_USB_LIBUSUAL=y
CONFIG_EDAC=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_HCTOSYS is not set
CONFIG_DMADEVICES=y
CONFIG_EEEPC_LAPTOP=y
CONFIG_AMD_IOMMU=y
CONFIG_AMD_IOMMU_STATS=y
CONFIG_INTEL_IOMMU=y
# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
CONFIG_EFI_VARS=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
# CONFIG_PRINT_QUOTA_WARNING is not set
CONFIG_QFMT_V2=y
CONFIG_AUTOFS4_FS=y
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_PROC_KCORE=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
CONFIG_EARLY_PRINTK_DBGP=y
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_RODATA_TEST is not set
CONFIG_DEBUG_BOOT_PARAMS=y
CONFIG_OPTIMIZE_INLINING=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_DISABLE=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set

CONFIG_DEBUG_INFO=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_LOW_LEVEL_TRAP=y
CONFIG_FRAME_POINTER=y
CONFIG_8139CP=y
CONFIG_DEBUG_SET_MODULE_RONX=n
CONFIG_DEBUG_RODATA=n


CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y

Basic Kernel Config As a point of comparison, let’s build a kernel using the default x86_64 configuration that ships with the kernel tree. Apply the configuration like so:

$ cd $TOP/linux-4.0.3
$ make O=../obj/linux-x86-basic x86_64_defconfig
$ make O=../obj/linux-x86-basic my_x86_64_defconfig

We can also merge in a few config options that improve performance/functionality of kvm guests with:

$ make O=../obj/linux-x86-basic kvmconfig

The kernel is now configured and ready to build. Go ahead and build it:

$ make O=../obj/linux-x86-basic -j2

Now that we have a kernel and a userland, we’re ready to boot! You can use qemu-system-x86_64 to try out your new system:

$ cd $TOP
$ qemu-system-x86_64 \
    -kernel obj/linux-x86-basic/arch/x86_64/boot/bzImage \
    -initrd obj/initramfs-busybox-x86.cpio.gz \
    -nographic -append "console=ttyS0"

Exit the VM by hitting Ctl-a c then typing “quit” at the qemu monitor shell.

If your host processor and kernel have virtualization extensions you can add the -enable-kvm flag to really speed things up:

$ qemu-system-x86_64 \
    -kernel obj/linux-x86-basic/arch/x86_64/boot/bzImage \
    -initrd obj/initramfs-busybox-x86.cpio.gz \
    -nographic -append "console=ttyS0" -enable-kvm

Smaller Kernel Config

That’s great and all, but if we really just want a tiny system with nothing but busybox on it we can remove a bunch of stuff from our kernel. By trimming down our kernel config we can reduce the size of our kernel image and reduce boot time.

Let’s try using the kernel’s Kbuild defaults as our baseline. The Kbuild defaults are generally quite conservative since Linus Torvalds has declared that in the kernel unless the feature cures cancer, it’s not on by default, as opposed to the x86_64_defconfig which is meant to provide a lot of generally useful features and work on a wide variety of x86 targets.

You can apply this more conservative configuration based on the Kbuild defaults by using the alldefconfig target:

$ cd $TOP/linux-4.0.3
$ make O=../obj/linux-x86-alldefconfig alldefconfig

We need to enable a few more options in order to actually be able to use this configuration.

First, we need to enable a serial driver so that we can get a serial console. Run your preferred kernel configurator (I like nconfig, but you can use menuconfig, xconfig, etc.):

$ make O=../obj/linux-x86-alldefconfig nconfig

Navigate to:

-> Device Drivers
  -> Character devices
    -> Serial drivers

and enable the following options:

[*] 8250/16550 and compatible serial support
[*] Console on 8250/16550 and compatible serial port

We also need to enable initramfs support, so that we can actually boot our userland. Go to:

-> General setup

and select:

[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

You can also deselect all of the decompressors except gzip, since that’s what we’re using.

Finally, enable some features for kvm guests (not actually necessary to get the system booting, but hey):

$ make O=../obj/linux-x86-alldefconfig kvmconfig

And build:

$ make O=../obj/linux-x86-alldefconfig -j2

We now have a much smaller kernel image:

$ (cd $TOP; du -hs obj/linux-x86-*/vmlinux)
18M     obj/linux-x86-basic/vmlinux
6.0M    obj/linux-x86-alldefconfig/vmlinux

Now you can boot the new kernel (with our same userspace):

$ qemu-system-x86_64 \
    -kernel obj/linux-x86-alldefconfig/arch/x86_64/boot/bzImage \
    -initrd obj/initramfs-busybox-x86.cpio.gz \
    -nographic -append "console=ttyS0" -enable-kvm

Not only is it smaller than the last one, but it boots faster too!

Configuration	Boot time (seconds)
x86_64_defconfig + kvmconfig	1.73
alldefconfig + custom stuff + kvmconfig	0.61

Smallest Kernel Config

We saw a 3x decrease in kernel image size and boot time by using a smaller set of default options. But how much smaller and “faster” can we go?

Let’s prune the image down even further by starting with absolutely nothing. The kernel build system has a make target for this: allnoconfig. Let’s create a new configuration based on that:

$ cd $TOP/linux-4.0.3
$ make O=$TOP/obj/linux-x86-allnoconfig allnoconfig

Now everything that can be turned off is turned off. This is as low as it goes without hacking up the kernel source. As one might expect, we have a little more work to do in order to get something that actually boots in qemu, but it’s still not too bad, which is actually pretty incredible. Here are the options you need to turn on:

[*] 64-bit kernel

-> General setup
  -> Configure standard kernel features
[*] Enable support for printk
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

-> Executable file formats / Emulations
[*] Kernel support for ELF binaries
[*] Kernel support for scripts starting with #!

-> Device Drivers
  -> Character devices
[*] Enable TTY

-> Device Drivers
  -> Character devices
    -> Serial drivers
[*] 8250/16550 and compatible serial support
[*]   Console on 8250/16550 and compatible serial port

-> File systems
  -> Pseudo filesystems
[*] /proc file system support
[*] sysfs file system support

In order to keep things truly tiny, we’ll skip make kvmconfig. Build it:

$ make O=../obj/linux-x86-alldefconfig -j2

The resulting image is quite a bit smaller than our last one, and way smaller than the one based on x86_64_defconfig:

$ (cd $TOP; du -hs linux-4.0.3/obj-x86-*/vmlinux)
18M     obj/linux-x86-basic/vmlinux
6.0M    obj/linux-x86-alldefconfig/vmlinux
2.6M    obj/linux-x86-allnoconfig/vmlinux

Adding make kvmconfig increases the image size to 5M, so allnoconfig isn’t actually a huge win in terms of size against alldefconfig.

And boot it:

$ qemu-system-x86_64 \
    -kernel obj/linux-x86-allnoconfig/arch/x86_64/boot/bzImage \
    -initrd obj/initramfs-busybox-x86.cpio.gz \
    -nographic -append "console=ttyS0" -enable-kvm

Our new tiniest kernel boots about twice as fast as the alldefconfig one and about 5x as fast as the one based on x86_64_defconfig. Adding kvmconfig didn’t really affect boot time.

Configuration	Boot time (seconds)
x86_64_defconfig + kvmconfig	1.73
alldefconfig + custom stuff + kvmconfig	0.61
allnoconfig + custom stuff	0.36
allnoconfig + custom stuff + kvmconfig	0.39

Conclusion

The most obvious application for this type of work is in the embedded space. However, I could see how it might also be beneficial in elastic cloud computing to reduce boot times and memory footprint. Please leave a comment if you’re aware of anyone doing this in “the cloud”!

If nothing else it’s an interesting exercise! :)

TOP=`pwd`
echo $TOP

curl https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.1.6.tar.xz | tar xJf -
curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf -
#
## build busybox
cd $TOP/busybox-1.23.2
mkdir -pv ../obj/busybox-x86
make mrproper
make  O=../obj/busybox-x86 defconfig
sed -i 's/.*CONFIG_STATIC.*/CONFIG_STATIC=y/' ../obj/busybox-x86/.config
sed -i 's/.*CONFIG_INETD.*/CONFIG_INETD=n/' ../obj/busybox-x86/.config
make clean
make  O=../obj/busybox-x86 -j12 2>&1 | tee  ../busybox_build.log
make  O=../obj/busybox-x86 install

# initramfs
mkdir -p $TOP/initramfs/x86-busybox
cd $TOP/initramfs/x86-busybox
mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}
cp -av $TOP/obj/busybox-x86/_install/* .

echo "#!/bin/sh" >> init
echo "mount -t proc none /proc" >> init
echo "mount -t sysfs none /sys" >> init
echo 'echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"' >> init
echo "exec /bin/sh" >> init

chmod +x init

find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 > $TOP/obj/initramfs-busybox-x86.cpio.gz

# build kernel
cd $TOP
make -C linux-4.1.6 O=../obj/linux-x86-basic mrproper
make -C linux-4.1.6 O=../obj/linux-x86-basic x86_64_defconfig
make -C linux-4.1.6 O=../obj/linux-x86-basic kvmconfig
sed -i 's/.*CONFIG_EXPERIMENTAL.*/CONFIG_EXPERIMENTAL=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_DEBUG_INFO.*/CONFIG_DEBUG_INFO=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_KGDB.*/CONFIG_KGDB=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_KGDB_LOW_LEVEL_TRAP.*/CONFIG_KGDB_LOW_LEVEL_TRAP=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_FRAME_POINTER.*/CONFIG_FRAME_POINTER=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_MAGIC_SYSRQ.*/CONFIG_MAGIC_SYSRQ=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_8139CP.*/CONFIG_8139CP=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_DEBUG_SET_MODULE_RONX.*/CONFIG_DEBUG_SET_MODULE_RONX=n/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_DEBUG_RODATA.*/CONFIG_DEBUG_RODATA=n/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_MODULE_FORCE_LOAD.*/CONFIG_MODULE_FORCE_LOAD=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_MODULE_UNLOAD.*/CONFIG_MODULE_UNLOAD=y/' obj/linux-x86-basic/.config
sed -i 's/.*CONFIG_MODULE_FORCE_UNLOAD.*/CONFIG_MODULE_FORCE_UNLOAD=y/' obj/linux-x86-basic/.config
yes '' | make -C linux-4.1.6 O=../obj/linux-x86-basic oldconfig
make -C linux-4.1.6 O=../obj/linux-x86-basic clean
time make -C linux-4.1.6 O=../obj/linux-x86-basic -j12 2>&1 | tee kernel_build.log

书籍推荐