├── README.md ├── eudyptula-boot ├── flake.lock ├── flake.nix └── minimal-configuration /README.md: -------------------------------------------------------------------------------- 1 | # eudyptula-boot 2 | 3 | `eudyptula-boot` boots a Linux kernel in a VM without a dedicated root 4 | filesystem. The root filesystem is the underlying root filesystem (or 5 | some pre-built chroot). This is a convenient way to do quick tests 6 | with a custom kernel. 7 | 8 | The name comes from [Eudyptula][] which is a genus for penguins. This 9 | is also the name of a [challenge for the Linux kernel][]. 10 | 11 | This utility is aimed at development only. This is a hack. It relies 12 | on AUFS/overlayfs and 9P to build the root filesystem from the running 13 | system. 14 | 15 | [Eudyptula]: http://en.wikipedia.org/wiki/Eudyptula 16 | [challenge for the Linux kernel]: http://eudyptula-challenge.org/ 17 | 18 | Also see 19 | [this blog post](http://vincent.bernat.ch/en/blog/2014-eudyptula-boot) 20 | for a quick presentation of this tool. 21 | 22 | ## Usage 23 | 24 | It is preferable to have a kernel with AUFS or OverlayFS 25 | enabled. Ubuntu and Debian kernels are patched to support AUFS. Since 26 | 3.18, vanilla kernels have OverlayFS built-in. Ubuntu kernels also 27 | come with OverlayFS support. Check you have one of those options: 28 | 29 | CONFIG_AUFS_FS=y 30 | CONFIG_OVERLAY_FS=y 31 | CONFIG_OVERLAYFS_FS=y 32 | 33 | Ensure you have the following options enabled (as a module or builtin): 34 | 35 | CONFIG_9P_FS=y 36 | CONFIG_NET_9P=y 37 | CONFIG_NET_9P_VIRTIO=y 38 | CONFIG_VIRTIO=y 39 | CONFIG_VIRTIO_PCI=y 40 | CONFIG_VIRTIO_CONSOLE=y 41 | 42 | To get a somewhat minimal configuration, have a look at the 43 | `minimal-configuration` script. 44 | 45 | Once compiled, the kernel needs to be installed in some work directory: 46 | 47 | $ make modules_install install INSTALL_MOD_PATH=$WORK INSTALL_PATH=$WORK 48 | 49 | Then, boot your kernel with: 50 | 51 | $ eudyptula-boot --kernel $WORK/vmlinuz-3.15.0~rc5-02950-g7e61329b0c26 52 | 53 | Use `--help` to get additional available options. 54 | 55 | Before booting the kernel, the path to GDB socket will be 56 | displayed. You can use it by running gdb on `vmlinux` (which is 57 | somewhere in the source tree): 58 | 59 | $ gdb vmlinux 60 | GNU gdb (GDB) 7.4.1-debian 61 | Reading symbols from /home/bernat/src/linux/vmlinux...done. 62 | (gdb) target remote /path/to/vm-eudyptula-gdb.pipe 63 | Remote debugging using /path/to/vm-eudyptula-gdb.pipe 64 | native_safe_halt () at /home/bernat/src/linux/arch/x86/include/asm/irqflags.h:50 65 | 50 } 66 | (gdb) 67 | 68 | If you have modules, you also need to manually load debug symbols for 69 | them. In guest: 70 | 71 | $ grep . /sys/module/vxlan/sections/{.text,.data,.bss} 72 | /sys/module/vxlan/sections/.text:0xffffffffc0370000 73 | /sys/module/vxlan/sections/.data:0xffffffffc0378000 74 | /sys/module/vxlan/sections/.bss:0xffffffffc0378900 75 | 76 | In GDB: 77 | 78 | (gdb) add-symbol-file /usr/lib/debug/lib/modules/$(uname -r)/kernel/drivers/net/vxlan.ko \ 79 | 0xffffffffc0370000 \ 80 | -s .data 0xffffffffc0378000 \ 81 | -s .bss 0xffffffffc0378900 82 | 83 | This can be automated with `lx-symbols` command if you source 84 | `vmlinux-gdb.py` from a compiled kernel. 85 | 86 | A serial port is also exported. It can be convenient for remote 87 | debugging of userland processes. More details can be found in this 88 | [blog post][] (which also covers debugging the kernel). 89 | 90 | [blog post]: http://vincent.bernat.ch/en/blog/2012-network-lab-kvm 91 | 92 | QEMU monitor is also attached to a UNIX socket. You can use the 93 | following command to interact with it: 94 | 95 | $ socat - UNIX:/path/to/vm-eudyptula-console.pipe 96 | QEMU 2.0.0 monitor - type 'help' for more information 97 | (qemu) 98 | 99 | You can also get something similar to [guestfish][]: 100 | 101 | $ eudyptula-boot --qemu="-drive file=someimage.qcow2,media=disk,if=virtio" 102 | 103 | With `--extra-gettys`, you can allocate additional consoles. To access 104 | one of them, use: 105 | 106 | $ socat STDIO,echo=0,icanon=0 UNIX:/tmp/tmp.oCshB5ryj4/getty-1.pipe 107 | 108 | [guestfish]: http://libguestfs.org/guestfish.1.html 109 | 110 | ## Usage with Nix 111 | 112 | You can also run `eudyptula-boot` with the following command if you have Nix 113 | installed: 114 | 115 | $ nix run github:vincentbernat/eudyptula-boot 116 | 117 | If you want to add arguments, separate them with `--`: 118 | 119 | $ nix run github:vincentbernat/eudyptula-boot -- --net -m 4G 120 | 121 | To run `minimal-configuration`, use: 122 | 123 | $ nix run github:vincentbernat/eudyptula-boot#minimal-configuration 124 | 125 | You can also get a shell with the tools to hack around the kernel: 126 | 127 | $ nix develop github:vincentbernat/eudyptula-boot#kernel-dev 128 | 129 | ## Alternatives 130 | 131 | Similar projects exist: 132 | 133 | - https://github.com/g2p/vido 134 | - https://git.kernel.org/cgit/utils/kernel/virtme/virtme.git/ 135 | -------------------------------------------------------------------------------- /eudyptula-boot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright (c) 2014 Vincent Bernat 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | # 17 | # Some parts are licensed under GPL-2.0. 18 | 19 | set -e 20 | 21 | QEMU_SYSTEM=${QEMU_SYSTEM:="qemu-system-$(uname -m)"} 22 | 23 | ESC="$(printf '\033')" 24 | if [ -t 1 ] && [ -z "$noterm" ]; then 25 | NORMAL="${ESC}[0m" 26 | RED="${ESC}[31;1m" 27 | GREEN="${ESC}[32;1m" 28 | YELLOW="${ESC}[33;1m" 29 | BLUE="${ESC}[34;1m" 30 | BEGINNING="$(printf '\015\033')[K" 31 | else 32 | BEGINNING="\n" 33 | fi 34 | 35 | log_begin_msg () { 36 | [ -n "$SILENT" ] || { 37 | >&2 printf "${BEGINNING}" 38 | >&2 printf "${BLUE}[…]${NORMAL} $1${BLUE}...${NORMAL} " 39 | } 40 | } 41 | log_ok_msg () { 42 | [ -n "$SILENT" ] || { 43 | >&2 printf "${BEGINNING}" 44 | >&2 echo "$GREEN[✔]$NORMAL $1." 45 | } 46 | } 47 | log_warn_msg () { 48 | [ -n "$SILENT" ] || { 49 | >&2 printf "${BEGINNING}" 50 | >&2 echo "$YELLOW[⚡]$NORMAL $1!" 51 | } 52 | } 53 | log_error_msg () { 54 | >&2 printf "${BEGINNING}" 55 | >&2 echo "$RED[✘]$NORMAL $1!" 56 | exit 1 57 | } 58 | log_info_msg () { 59 | [ -n "$SILENT" ] || { 60 | >&2 printf "${BEGINNING}" 61 | >&2 echo "$BLUE[∗]$NORMAL $1." 62 | } 63 | } 64 | 65 | usage() { 66 | >&2 cat < /dev/null | strings -20 | \ 108 | grep ^Linux.version; then 109 | return 0 110 | fi 111 | done 112 | command -v ${cmd%% *} 2> /dev/null > /dev/null || \ 113 | log_warn_msg "Command \`$cmd' not found to uncompress $KERNEL" 114 | return 1 115 | } 116 | 117 | check_kernel_version() { 118 | log_begin_msg "Checking kernel version" 119 | [ -f "$KERNEL" ] || log_error_msg "Unable to find kernel $KERNEL" 120 | [ -r "$KERNEL" ] || log_error_msg "Kernel $KERNEL is not readable.\n Try \`setfacl -m u:$USER:r $KERNEL'" 121 | 122 | # A recent version of `file` is able to extract the 123 | # information. Since it is not widely available, let use some hack 124 | # method. See scripts/extract-vmlinux for patterns. 125 | VERSION=$(false \ 126 | || _check_kernel_version gunzip '\037\213\010' xy \ 127 | || _check_kernel_version unxz '\3757zXZ\000' abcde \ 128 | || _check_kernel_version bunzip2 'BZh' xy \ 129 | || _check_kernel_version unlzma '\135\0\0\0' xxx \ 130 | || _check_kernel_version 'lzop -d' '\211\114\132' xy \ 131 | || _check_kernel_version 'lz4 -d' '\002!L\030' xxx \ 132 | || _check_kernel_version unzstd '(\265/\375' xxx \ 133 | || true) 134 | VERSION="${VERSION#Linux version }" 135 | VERSION="${VERSION%% *}" 136 | [ -n "$VERSION" ] || \ 137 | log_error_msg "Unable to determine version for $KERNEL" 138 | log_ok_msg "Found kernel $VERSION" 139 | } 140 | 141 | _extract_kernel_configuration() { 142 | # Adapted from https://github.com/torvalds/linux/blob/master/scripts/extract-ikconfig 143 | # SPDX-License-Identifier: GPL-2.0 144 | kernel="$1" 145 | config="$TMP/kernel-configuration" 146 | cf1='IKCFG_ST\037\213\010' 147 | cf2='0123456789' 148 | pos=$(tr "$cf1\n$cf2" "\n$cf2=" < "$kernel" | grep -abo "^$cf2") 149 | [ -n $pos ] || return 1 150 | pos=${pos%%:*} 151 | tail -c+$(($pos+8)) "$kernel" | zcat > "$config" 2> /dev/null 152 | [ $? != 1 ] || { 153 | rm -f "$config" 154 | return 1 155 | } 156 | } 157 | 158 | _extract_compressed_kernel_configuration() { 159 | # Adapted from https://github.com/torvalds/linux/blob/master/scripts/extract-ikconfig 160 | # SPDX-License-Identifier: GPL-2.0 161 | kernel="$1" 162 | cmd="$2" 163 | sig1="$3" 164 | sig2="$4" 165 | poss=$(tr "${sig1}\n${sig2}" "\n${sig2}=" < "$kernel" | grep -abo "^${sig2}" || true) 166 | [ -n "$poss" ] || return 1 167 | for pos in $poss; do 168 | pos=${pos%%:*} 169 | tail -c+$pos "$kernel" | $cmd > $TMP/compressed-kernel-configuration 2> /dev/null 170 | ! _extract_kernel_configuration $TMP/compressed-kernel-configuration || return 0 171 | done 172 | command -v ${cmd%% *} 2> /dev/null > /dev/null || \ 173 | log_warn_msg "Command \`$cmd' not found to uncompress $kernel" 174 | return 1 175 | } 176 | 177 | check_kernel_configuration() { 178 | log_begin_msg "Check kernel configuration" 179 | SERIAL=isa-serial 180 | CONFIG="$(dirname $KERNEL)/config-$VERSION" 181 | if [ ! -f "$CONFIG" ]; then 182 | # Handle IKCONFIG case 183 | for obj in $KERNEL ${MODULES+$MODULES/kernel/kernel/configs.ko*}; do 184 | [ -f "$obj" ] || continue 185 | false \ 186 | || _extract_kernel_configuration "$obj" \ 187 | || _extract_compressed_kernel_configuration "$obj" gunzip '\037\213\010' xy \ 188 | || _extract_compressed_kernel_configuration "$obj" unxz '\3757zXZ\000' abcde \ 189 | || _extract_compressed_kernel_configuration "$obj" bunzip2 'BZh' xy \ 190 | || _extract_compressed_kernel_configuration "$obj" unlzma '\135\0\0\0' xxx \ 191 | || _extract_compressed_kernel_configuration "$obj" 'lzop -d' '\211\114\132' xy \ 192 | || _extract_compressed_kernel_configuration "$obj" 'lz4 -d' '\002!L\030' xxx \ 193 | || _extract_compressed_kernel_configuration "$obj" unzstd '(\265/\375' xxx \ 194 | || continue 195 | break 196 | done 197 | [ ! -f "$TMP/kernel-configuration" ] || CONFIG="$TMP/kernel-configuration" 198 | fi 199 | [ -f "$CONFIG" ] || { 200 | log_warn_msg "Unable to find configuration file $CONFIG" 201 | return 202 | } 203 | while read el; do 204 | grep -qx "CONFIG_$el" $CONFIG || log_error_msg "Kernel not configured with CONFIG_$el" 205 | done < /dev/null > /dev/null || log_error_msg "Busybox is not installed" 268 | command -v ${QEMU_SYSTEM} 2> /dev/null > /dev/null || log_error_msg "${QEMU_SYSTEM} is not installed" 269 | command -v strings 2> /dev/null > /dev/null || log_error_msg "strings is not installed (binutils package)" 270 | log_ok_msg "All dependencies are met" 271 | } 272 | 273 | setup_tmp () { 274 | TMP=$(mktemp -d) 275 | trap "rm -rf $TMP" EXIT 276 | log_info_msg "TMP is $TMP" 277 | } 278 | 279 | setup_initrd () { 280 | log_begin_msg "Build initrd" 281 | DESTDIR=$TMP/initrd 282 | mkdir -p $DESTDIR 283 | 284 | # Copy busybox and insmod. 285 | # insmod from busybox does not support compressed module yet. Fixed in: 286 | # https://git.busybox.net/busybox/commit/modutils/modprobe-small.c?id=af5277f883e8fc2e0236aa9ecc5115ecaffd0ccb 287 | bins="busybox insmod" 288 | for bin in $bins; do 289 | install -D "$(command -v $bin)" ${DESTDIR}/bin/$bin 290 | 291 | # First, get the loader and copy it (unless static binary) 292 | objcopy -O binary -j .interp "$(command -v $bin)" $TMP/interp 293 | [ -s $TMP/interp ] || continue 294 | 295 | ld=$(tr -d '\000' < $TMP/interp) 296 | [ -f "${DESTDIR}/$ld" ] || install -D "$ld" "${DESTDIR}/$ld" 297 | 298 | # Then, use it to get the other libs 299 | for x in $(LD_TRACE_LOADED_OBJECTS=1 $ld "$(command -v $bin)" 2> /dev/null | sed -e ' 300 | /\//!d; 301 | /linux-gate/d; 302 | /=>/ {s/.*=>[[:blank:]]*\([^[:blank:]]*\).*/\1/}; 303 | s/[[:blank:]]*\([^[:blank:]]*\) (.*)/\1/' 2>/dev/null); do 304 | [ -f "${DESTDIR}/$x" ] || install -D "$x" "${DESTDIR}/$x" 305 | done 306 | done 307 | 308 | # Configure busybox 309 | ${DESTDIR}/bin/busybox --install ${DESTDIR}/bin 310 | 311 | # Add modules 312 | [ -z "$MODULES" ] || { 313 | modules="9pnet_virtio 9p virtio_pci virtio_net" 314 | [ -z "$UNION" ] || modules="$modules $UNION" 315 | for mod in $modules; do 316 | base=${MODULES}/../../.. 317 | cmd="modprobe --all --set-version=${VERSION} -d ${base} --ignore-install --quiet --show-depends $mod" 318 | $cmd > /dev/null || { 319 | depmod -b ${base} ${VERSION} 2> /dev/null && $cmd > /dev/null || { 320 | log_warn_msg "Unable to find module $mod" 321 | log_begin_msg "Continue building initrd" 322 | } 323 | } 324 | $cmd | while read prefix kmod options ; do 325 | [ "${prefix}" = "insmod" ] || continue 326 | grep -qFw "$kmod" ${DESTDIR}/modules 2> /dev/null || { 327 | install -D "$kmod" "${DESTDIR}/${kmod}" 328 | echo /bin/insmod $kmod $options >> ${DESTDIR}/modules 329 | } 330 | done 331 | done 332 | } 333 | 334 | # Copy this program 335 | cp "$PROGNAME" ${DESTDIR}/init 336 | 337 | # Create /tmp 338 | mkdir -p ${DESTDIR}/tmp 339 | 340 | # Build initrd 341 | (cd "${DESTDIR}" && find . | cpio --quiet -R 0:0 -o -H newc) | gzip > $TMP/initrd.gz 342 | 343 | log_ok_msg "initrd built in $TMP/initrd.gz" 344 | } 345 | 346 | start_vm () { 347 | name=$(echo eudyptula-${VERSION} | tr '.' '-') 348 | log_info_msg "Start VM $name" 349 | 350 | if [ -e /dev/kvm ] && ${QEMU_SYSTEM} -accel help | grep -qwFx kvm; then 351 | KVM="-enable-kvm" 352 | log_info_msg "KVM is active" 353 | else 354 | KVM="" 355 | log_info_msg "KVM is not available" 356 | fi 357 | 358 | # Configuration settings 359 | mkdir "$TMP/config" 360 | case $PWD in 361 | $HOME*) echo "${PWD#$HOME/}" > "$TMP/config/pwd" ;; 362 | *) echo "$PWD" > "$TMP/config/pwd" ;; 363 | esac 364 | echo "$TERM" > "$TMP/config/term" 365 | echo "$SHELL" > "$TMP/config/shell" 366 | echo "$name" > "$TMP/config/uts" 367 | [ -z "$PID1" ] || touch "$TMP/config/pid1" 368 | [ -z "$RW" ] || touch "$TMP/config/rw" 369 | [ -z "$RO" ] || touch "$TMP/config/ro" 370 | [ -z "$FSHELL" ] || touch "$TMP/config/fshell" 371 | [ -z "$UNION" ] || echo "$UNION" > "$TMP/config/union" 372 | [ -z "$CUSER" ] || echo "$CUSER" > "$TMP/config/user" 373 | [ -z "$EXTRA_GETTYS" ] || echo "$EXTRA_GETTYS" > "$TMP/config/gettys" 374 | [ $# -eq 0 ] || echo "$@" > "$TMP/config/exec" 375 | 376 | # Kernel command-line 377 | append="console=${CONSOLE:-ttyS0} panic=1 8250.nr_uarts=4 nokaslr $CMDLINE" 378 | [ -t 1 ] || append="$append noterm=1" 379 | [ -z "$SILENT" ] || append="$append SILENT=1 loglevel=3" 380 | [ -n "$VERBOSE" ] || append="$append quiet" 381 | 382 | # qemu command-line 383 | qemu="" 384 | [ -z "$MEM" ] || qemu="$qemu -m $MEM" 385 | [ -z "$CONSOLE" ] || { 386 | qemu="$qemu -chardev socket,id=charserial2,path=$TMP/vm-$name-kernel.pipe,server=on,wait=on" 387 | qemu="$qemu -device ${SERIAL},chardev=charserial2,id=serial2" 388 | } 389 | [ -z "$EXTRA_GETTYS" ] || { 390 | qemu="$qemu -device virtio-serial" 391 | for i in $(seq $EXTRA_GETTYS); do 392 | qemu="$qemu -chardev socket,id=getty$i,server=on,wait=off,path=$TMP/getty-$i.pipe" 393 | qemu="$qemu -device virtconsole,name=console.$((i-1)),chardev=getty$i" 394 | done 395 | } 396 | [ x"$NET" != x"1" ] || { 397 | mac=50:54:00:00:00:42 398 | qemu="$qemu -netdev user,id=internet" 399 | qemu="$qemu -device virtio-net-pci,mac=$mac,netdev=internet,id=internet-dev" 400 | } 401 | qemu="$qemu $QEMU" 402 | # /root is mounted with version 9p2000.u to allow access to /dev, 403 | # /sys and to mount new partitions over them. This is not the case 404 | # for 9p2000.L. 405 | cat < "$TMP/vm-$name.exec" 406 | #!/bin/sh 407 | echo \$\$ > $TMP/config/pid 408 | exec ${QEMU_SYSTEM} \ 409 | ${KVM} \ 410 | -cpu max \ 411 | -no-user-config -nodefaults \ 412 | -display none \ 413 | -device virtio-rng \ 414 | \ 415 | -chardev stdio,id=charserial0,signal=off \ 416 | -device ${SERIAL},chardev=charserial0,id=serial0 \ 417 | -chardev socket,id=charserial1,path=$TMP/vm-$name-serial.pipe,server=on,wait=off \ 418 | -device ${SERIAL},chardev=charserial1,id=serial1 \ 419 | \ 420 | -chardev socket,id=con0,path=$TMP/vm-$name-console.pipe,server=on,wait=off \ 421 | -mon chardev=con0,mode=readline \ 422 | \ 423 | -fsdev local,security_model=passthrough,id=fsdev-root,path=${ROOT},multidevs=remap \ 424 | -device virtio-9p-pci,id=fs-root,fsdev=fsdev-root,mount_tag=rootshare \ 425 | -fsdev local,security_model=none,id=fsdev-home,path=${HOME},multidevs=remap \ 426 | -device virtio-9p-pci,id=fs-home,fsdev=fsdev-home,mount_tag=homeshare \ 427 | -fsdev local,security_model=none,id=fsdev-modules,path=${MODULES}/..,readonly=on \ 428 | -device virtio-9p-pci,id=fs-modules,fsdev=fsdev-modules,mount_tag=moduleshare \ 429 | -fsdev local,security_model=passthrough,id=fsdev-config,path=$TMP/config \ 430 | -device virtio-9p-pci,id=fs-config,fsdev=fsdev-config,mount_tag=configshare \ 431 | \ 432 | -gdb unix:$TMP/vm-$name-gdb.pipe,server=on,wait=off \ 433 | -no-reboot \ 434 | -kernel $KERNEL \ 435 | -initrd $TMP/initrd.gz \ 436 | -append "$append" \ 437 | \ 438 | $qemu 439 | EOF 440 | log_info_msg "monitor listening on $TMP/vm-$name-console.pipe" 441 | log_info_msg "ttyS1 listening on $TMP/vm-$name-serial.pipe" 442 | log_info_msg "GDB server gdb -ex='target remote $TMP/vm-$name-gdb.pipe'" 443 | [ -z "$EXTRA_GETTYS" ] || { 444 | for i in $(seq $EXTRA_GETTYS); do 445 | log_info_msg "Getty $i listening on $TMP/getty-$i.pipe" 446 | done 447 | } 448 | [ -z "$CONSOLE" ] || { 449 | log_info_msg "ttyS2 listening on $TMP/vm-$name-kernel.pipe" 450 | log_warn_msg "You must connect with 'socat STDIO UNIX:$TMP/vm-$name-kernel.pipe'" 451 | } 452 | chmod +x "$TMP/vm-$name.exec" 453 | "$TMP/vm-$name.exec" 454 | log_info_msg "VM terminated" 455 | } 456 | 457 | # FSM 458 | export STATE=${STATE:-BEGIN} 459 | case $$,$STATE in 460 | 1,BEGIN) 461 | # In initrd 462 | log_info_msg "initrd started" 463 | export PATH=/usr/local/bin:/usr/bin:/bin:/sbin:/usr/local/sbin:/usr/sbin:/nix/var/nix/profiles/system/sw/bin 464 | export HOME=/root 465 | 466 | [ ! -f /modules ] || { 467 | log_info_msg "Loading modules" 468 | . /modules 469 | } 470 | 471 | log_begin_msg "Load configuration" 472 | mount -n -t tmpfs tmpfs /tmp -o rw 473 | mkdir /tmp/config 474 | mount -n -t 9p configshare /tmp/config -o trans=virtio,version=9p2000.u,access=any,msize=104857600,rw,cache=loose || \ 475 | log_error_msg "Unable to load configuration" 476 | 477 | # Various config stuff 478 | hostname "$(cat /tmp/config/uts)" 479 | [ ! -f /tmp/config/pid1 ] || export PID1=1 480 | [ ! -f /tmp/config/rw ] || export RW=1 481 | [ ! -f /tmp/config/ro ] || export RO=1 482 | [ ! -f /tmp/config/fshell ] || export FSHELL=1 483 | [ ! -f /tmp/config/union ] || export UNION="$(cat /tmp/config/union)" 484 | [ ! -f /tmp/config/user ] || export CUSER="$(cat /tmp/config/user)" 485 | export TERM=$(cat /tmp/config/term) 486 | export SHELL=$(cat /tmp/config/shell) 487 | unset SHLVL 488 | log_ok_msg "Configuration loaded" 489 | 490 | log_begin_msg "Setup root file system" 491 | mkdir /tmp/target 492 | mkdir /tmp/target/ro 493 | mkdir /tmp/target/overlay 494 | case $RW,$RO in 495 | ,) 496 | mkdir /tmp/target/rw 497 | mount -n -t 9p rootshare /tmp/target/ro -o trans=virtio,version=9p2000.u,msize=104857600,ro,cache=loose 498 | mount -n -t tmpfs tmpfs /tmp/target/rw -o rw 499 | mkdir /tmp/target/rw/workdir 500 | mkdir /tmp/target/rw/upperdir 501 | set -- $UNION 502 | while [ $# -gt 0 ]; do 503 | case $1 in 504 | aufs) 505 | ! mount -n -t aufs aufs /tmp/target/overlay \ 506 | -o noxino,noatime,dirs=/tmp/target/rw/upperdir:/tmp/target/ro=ro 2> /dev/null || break 507 | log_warn_msg "Unable to use AUFS" 508 | ;; 509 | overlayfs) 510 | # Pre-3.18 511 | ! mount -n -t $1 overlayfs /tmp/target/overlay \ 512 | -o lowerdir=/tmp/target/ro,upperdir=/tmp/target/rw/upperdir,noatime \ 513 | 2> /dev/null || break 514 | log_warn_msg "Unable to use overlayfs" 515 | ;; 516 | overlay) 517 | # 3.18+ 518 | ! mount -n -t $1 overlayfs /tmp/target/overlay \ 519 | -o lowerdir=/tmp/target/ro,upperdir=/tmp/target/rw/upperdir,workdir=/tmp/target/rw/workdir,noatime \ 520 | 2> /dev/null || break 521 | log_warn_msg "Unable to use overlayfs" 522 | ;; 523 | esac 524 | shift 525 | done 526 | [ $# -gt 0 ] || \ 527 | mount -n --bind /tmp/target/ro /tmp/target/overlay 528 | log_ok_msg "Root file system setup" 529 | ;; 530 | 1,) 531 | mount -n -t 9p rootshare /tmp/target/overlay -o trans=virtio,version=9p2000.u,msize=104857600,rw,cache=loose 532 | ;; 533 | ,1) 534 | mount -n -t 9p rootshare /tmp/target/overlay -o trans=virtio,version=9p2000.u,msize=104857600,ro,cache=loose 535 | ;; 536 | *) 537 | log_error_msg "Dunno if root FS should be RO or RW (ro=$RO,rw=$RW)" 538 | ;; 539 | esac 540 | 541 | log_begin_msg "Clean /tmp and /run" 542 | for fs in /run /var/run /var/tmp /var/log /tmp; do 543 | if [ -d /tmp/target/overlay$fs ] && [ ! -h /tmp/target/overlay$fs ]; then 544 | mount -n -t tmpfs tmpfs /tmp/target/overlay$fs -o rw,nosuid,nodev 545 | fi 546 | done 547 | log_ok_msg "/tmp, /run and others are clean" 548 | 549 | mkdir /tmp/target/overlay/tmp/config 550 | mount -n --bind /tmp/config /tmp/target/overlay/tmp/config 551 | 552 | log_info_msg "Change root" 553 | export STATE=CHROOTED 554 | cp /init /tmp/target/overlay/tmp 555 | if command -v switch_root > /dev/null 2> /dev/null; then 556 | exec switch_root /tmp/target/overlay /tmp/init 557 | else 558 | exec chroot /tmp/target/overlay /tmp/init 559 | fi 560 | ;; 561 | 562 | 1,CHROOTED) 563 | log_begin_msg "Setup /proc and /sys" 564 | mount -n -t proc proc /proc 565 | mount -n -t sysfs sys /sys 566 | mount -n -t debugfs debugfs /sys/kernel/debug 2> /dev/null || true 567 | mount -n -t configfs configfs /sys/kernel/config 2> /dev/null || true 568 | log_ok_msg "/proc and /sys setup" 569 | 570 | if [ -z "$CUSER" ]; then 571 | log_begin_msg "Mount /root" 572 | mount -n -t 9p homeshare /root -o trans=virtio,version=9p2000.L,access=0,msize=104857600,rw,cache=mmap || \ 573 | log_error_msg "Unable to mount /root" 574 | log_ok_msg "/root mounted" 575 | else 576 | export HOME=$(getent passwd $CUSER | awk -F: '{print $6}') 577 | log_begin_msg "Mount $HOME" 578 | mount -n -t 9p homeshare $HOME -o trans=virtio,version=9p2000.L,access=any,msize=104857600,rw,cache=mmap || \ 579 | log_error_msg "Unable to mount $HOME" 580 | log_ok_msg "$HOME mounted" 581 | fi 582 | log_begin_msg "Mount /lib/modules" 583 | mkdir -p /lib/modules 584 | mount -n -t 9p moduleshare /lib/modules -o trans=virtio,version=9p2000.L,access=0,msize=104857600,ro,cache=loose || \ 585 | log_error_msg "Unable to mount /lib/modules" 586 | log_ok_msg "/lib/modules mounted" 587 | 588 | echo 3 > /proc/sys/vm/drop_caches 589 | 590 | log_begin_msg "Starting udev" 591 | udev_log=err 592 | mount -n -o size=10M,mode=0755 -t devtmpfs devtmpfs /dev 593 | mkdir /dev/shm 594 | mount -t tmpfs tmpfs /dev/shm 595 | udevadm info --cleanup-db 596 | for udev in $(dirname $(readlink -f $(command -v udevadm 2> /dev/null)))/../lib/systemd/systemd-udevd $(command -v udevd 2> /dev/null); do 597 | [ ! -x $udev ] || break 598 | done 599 | $udev --daemon 600 | udevadm trigger --action=add 601 | udevadm settle 602 | mkdir -p /dev/pts 603 | mount -n -t devpts devpts /dev/pts 2> /dev/null || true 604 | ln -sf /proc/self/fd /dev/fd 605 | log_ok_msg "udev started" 606 | 607 | sysctl -q -w kernel.panic_on_oops=1 608 | 609 | log_begin_msg "Configure network" 610 | ip link set up dev lo 611 | for iface in /sys/class/net/*; do 612 | if [ x"$(cat "$iface/address")" = x"50:54:00:00:00:42" ]; then 613 | # We don't use DHCP as the root filesystem may be read-only 614 | ip link set up dev "${iface##*/}" 615 | ip addr add 10.0.2.14/24 dev "${iface##*/}" 616 | ip route add default via 10.0.2.2 617 | if [ -L /etc/resolv.conf ]; then 618 | # /etc/resolv.conf is a symlink, assume it points to /run 619 | mkdir -p "$(dirname "$(readlink -m /etc/resolv.conf)")" 620 | echo "nameserver 10.0.2.3" > "$(readlink -m /etc/resolv.conf)" 621 | else 622 | # root may be read-only, use a bind mount 623 | echo "nameserver 10.0.2.3" > /tmp/resolv.conf 624 | mount -n --bind /tmp/resolv.conf /etc/resolv.conf 625 | fi 626 | break 627 | fi 628 | iface= 629 | done 630 | log_ok_msg "Network configured${iface:+ (${iface##*/})}" 631 | 632 | # Switch to the appropriate directory we were in 633 | cd $HOME 634 | cd $(cat /tmp/config/pwd) 2> /dev/null || true 635 | 636 | # Do we have an exec share? 637 | if [ -f /tmp/config/exec ]; then 638 | if [ -z "$FSHELL" ]; then 639 | # Don't execute in a shell 640 | ret=0 641 | ${PID1:+exec} ${CUSER:+chroot --userspec=${CUSER} /} sh -c "cd $PWD && . /tmp/config/exec" || ret=$? 642 | echo $ret > /tmp/config/ret 643 | echo b > /proc/sysrq-trigger 644 | else 645 | sh /tmp/config/exec 646 | fi 647 | fi 648 | 649 | [ -z "$CUSER" ] || [ ! -x /usr/bin/sudo ] || { 650 | log_begin_msg "Configuring sudo" 651 | echo "$CUSER ALL=(ALL) NOPASSWD: ALL" > /tmp/sudoers 652 | mount --bind /tmp/sudoers /etc/sudoers 653 | log_ok_msg "sudo configured for $CUSER" 654 | } 655 | 656 | log_info_msg "Setup terminal" 657 | export STATE=GETTY 658 | [ ! -f /tmp/config/gettys ] || { 659 | for i in $(seq $(cat /tmp/config/gettys)); do 660 | while true; do agetty -n -L hvc$((i-1)) -a root -l /tmp/init -i 115200 $TERM ; done & 661 | done 662 | } 663 | exec setsid agetty -n -L ttyS0 -a root -l /tmp/init -i 115200 $TERM 664 | ;; 665 | 666 | *,GETTY) 667 | log_begin_msg "Setup terminal size" 668 | previous=$(stty -g) 669 | stty raw -echo min 0 time 5 670 | printf '\0337\033[r\033[999;999H\033[6n\0338' > /dev/tty 671 | IFS='[;R' read -r _ rows cols _ < /dev/tty || true 672 | stty "$previous" 673 | if [ -n "$cols" ] && [ -n "$rows" ]; then 674 | stty cols "$cols" rows "$rows" 675 | log_ok_msg "Terminal size is $cols×$rows" 676 | else 677 | log_warn_msg "Unknown terminal size" 678 | fi 679 | 680 | log_info_msg "QEMU PID is $(cat /tmp/config/pid)" 681 | log_info_msg "Spawning a shell" 682 | export SSH_TTY=$(tty) 683 | for SHELL in $SHELL /bin/bash /bin/sh; do 684 | [ ! -x $SHELL ] || break 685 | done 686 | ret=0 687 | ${PID1:+exec} ${CUSER:+chroot --userspec=${CUSER} /} sh -c "cd $PWD && exec ${SHELL} -i" || ret=$? 688 | case $$ in 689 | 1) 690 | echo $ret > /tmp/config/ret 691 | echo b > /proc/sysrq-trigger 692 | ;; 693 | *) 694 | exit $ret 695 | ;; 696 | esac 697 | ;; 698 | 699 | *,BEGIN) 700 | # Initial state 701 | PROGNAME="$(readlink -f "$0")" 702 | ARGS="$(getopt -n eudyptula-boot \ 703 | -o +hsk:r:c:m:u1wov2 \ 704 | --longoptions help,silent,kernel:,root:,cmdline:,qemu:,mem:,extra-gettys:,user,net,network,pid1,readwrite,readonly,force,shell,verbose,ttyS2 \ 705 | -- "$@")" || \ 706 | log_error_msg "Invalid option, use --help for more information" 707 | eval set -- "$ARGS" 708 | while true; do 709 | case "$1" in 710 | -h | --help) 711 | usage 712 | exit 0 713 | ;; 714 | -s | --silent) 715 | SILENT=1 716 | shift 717 | ;; 718 | -v | --verbose) 719 | VERBOSE=1 720 | shift 721 | ;; 722 | -2 | --ttyS2) 723 | CONSOLE=ttyS2 724 | shift 725 | ;; 726 | -k | --kernel) 727 | KERNEL="$(readlink -f "$2")" 728 | shift 2 729 | ;; 730 | -r | --root) 731 | ROOT="$(readlink -f "$2")" 732 | shift 2 733 | ;; 734 | -w | --readwrite) 735 | RW=1 736 | shift 737 | ;; 738 | -o | --readonly) 739 | RO=1 740 | shift 741 | ;; 742 | -c | --cmdline) 743 | CMDLINE="$2" 744 | shift 2 745 | ;; 746 | --qemu) 747 | QEMU="$QEMU $2" 748 | shift 2 749 | ;; 750 | -m | --mem) 751 | MEM="$2" 752 | shift 2 753 | ;; 754 | -u | --user) 755 | CUSER="$(id -nu)" 756 | shift 1 757 | ;; 758 | --net|--network) 759 | NET=1 760 | shift 761 | ;; 762 | -1 | --pid1) 763 | PID1=1 764 | shift 765 | ;; 766 | --shell) 767 | FSHELL=1 768 | shift 769 | ;; 770 | --force) 771 | DANGEROUS=1 772 | shift 773 | ;; 774 | --extra-gettys) 775 | EXTRA_GETTYS="$2" 776 | shift 2 777 | ;; 778 | -- ) 779 | shift 780 | break 781 | ;; 782 | * ) 783 | log_error_msg "Unknown argument \`$1'" 784 | usage 785 | exit 1 786 | ;; 787 | esac 788 | done 789 | [ -z "$RW" ] || [ -z "$RO" ] || \ 790 | log_error_msg "Use of \`--readwrite' and \`--readonly' are exclusive" 791 | [ -n "$DANGEROUS" ] || [ -z "$RW" ] || [ -n "$ROOT" ] || \ 792 | log_error_msg "Use of \`--readwrite' without \`--root' is too dangerous" 793 | [ -n "$DANGEROUS" ] || [ $(id -u) != 0 ] || \ 794 | log_error_msg "You should not run this as root" 795 | 796 | KERNEL="${KERNEL:-/boot/vmlinuz-$(uname -r)}" 797 | ROOT="${ROOT:-/}" 798 | PATH="$PATH":/usr/local/sbin:/usr/sbin:/sbin 799 | 800 | check_dependencies 801 | setup_tmp 802 | check_kernel 803 | setup_initrd 804 | start_vm "$@" 805 | ret=255 806 | [ ! -f $TMP/config/ret ] || ret="$(cat $TMP/config/ret)" 807 | exit $ret 808 | ;; 809 | esac 810 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1731533236, 9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1736420959, 24 | "narHash": "sha256-dMGNa5UwdtowEqQac+Dr0d2tFO/60ckVgdhZU9q2E2o=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "32af3611f6f05655ca166a0b1f47b57c762b5192", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "id": "nixpkgs", 32 | "type": "indirect" 33 | } 34 | }, 35 | "root": { 36 | "inputs": { 37 | "flake-utils": "flake-utils", 38 | "nixpkgs": "nixpkgs" 39 | } 40 | }, 41 | "systems": { 42 | "locked": { 43 | "lastModified": 1681028828, 44 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 45 | "owner": "nix-systems", 46 | "repo": "default", 47 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 48 | "type": "github" 49 | }, 50 | "original": { 51 | "owner": "nix-systems", 52 | "repo": "default", 53 | "type": "github" 54 | } 55 | } 56 | }, 57 | "root": "root", 58 | "version": 7 59 | } 60 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "nixpkgs"; 4 | flake-utils.url = "github:numtide/flake-utils"; 5 | }; 6 | outputs = { self, nixpkgs, flake-utils }: 7 | flake-utils.lib.eachDefaultSystem (system: 8 | let 9 | pkgs = import nixpkgs { 10 | inherit system; 11 | }; 12 | eudyptula-boot-deps = with pkgs; [ 13 | (busybox.override { enableAppletSymlinks = false; }) 14 | coreutils 15 | qemu_kvm 16 | bintools 17 | ]; 18 | minimal-configuration-deps = with pkgs; [ 19 | coreutils 20 | gnumake 21 | ]; 22 | in 23 | { 24 | packages = rec { 25 | eudyptula-boot = pkgs.writeShellApplication { 26 | name = "eudyptula-boot"; 27 | runtimeInputs = eudyptula-boot-deps; 28 | text = ./eudyptula-boot; 29 | }; 30 | minimal-configuration = pkgs.writeShellApplication { 31 | name = "minimal-configuration"; 32 | runtimeInputs = minimal-configuration-deps; 33 | text = ./minimal-configuration; 34 | }; 35 | default = eudyptula-boot; 36 | }; 37 | devShells = rec { 38 | eudyptula-boot = pkgs.mkShell { 39 | name = "eudyptula-boot"; 40 | nativeBuildInputs = eudyptula-boot-deps ++ minimal-configuration-deps; 41 | }; 42 | kernel-dev = pkgs.mkShell { 43 | name = "kernel-dev"; 44 | nativeBuildInputs = [ 45 | self.packages.${system}.eudyptula-boot 46 | self.packages.${system}.minimal-configuration 47 | pkgs.linux.nativeBuildInputs 48 | pkgs.ncurses 49 | pkgs.pkg-config 50 | ]; 51 | }; 52 | default = eudyptula-boot; 53 | }; 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /minimal-configuration: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Build a minimal .config. To be executed from the root of the kernel 4 | # sources. 5 | 6 | set -e 7 | 8 | cat < .config 9 | CONFIG_SHMEM=y 10 | CONFIG_TMPFS=y 11 | CONFIG_OVERLAY_FS=y 12 | CONFIG_SYSFS=y 13 | CONFIG_PROC_FS=y 14 | CONFIG_DEVTMPFS=y 15 | CONFIG_BLK_DEV_INITRD=y 16 | CONFIG_RD_GZIP=y 17 | CONFIG_SERIAL_8250=y 18 | CONFIG_SERIAL_8250_CONSOLE=y 19 | CONFIG_PRINTK=y 20 | CONFIG_EARLY_PRINTK=y 21 | CONFIG_BINFMT_SCRIPT=y 22 | CONFIG_64BIT=y 23 | CONFIG_x86_64=y 24 | CONFIG_UNIX=y 25 | CONFIG_MAGIC_SYSRQ=y 26 | CONFIG_FUTEX=y 27 | CONFIG_MULTIUSER=y 28 | CONFIG_FILE_LOCKING=y 29 | CONFIG_VIRTIO_CONSOLE=y 30 | CONFIG_POSIX_TIMERS=y 31 | CONFIG_MODULE_UNLOAD=y 32 | CONFIG_IKCONFIG=y 33 | EOF 34 | 35 | # Some flavours 36 | while [ $# -ge 1 ]; do 37 | case $1 in 38 | network) 39 | # Some base network stuff 40 | cat <> .config 41 | CONFIG_PACKET=y 42 | CONFIG_UNIX=y 43 | CONFIG_IP_ADVANCED_ROUTER=y 44 | CONFIG_IP_MULTIPLE_TABLES=y 45 | CONFIG_IP_ROUTE_MULTIPATH=y 46 | CONFIG_IP_FIB_TRIE_STATS=y 47 | CONFIG_IPV6=y 48 | CONFIG_IPV6_MULTIPLE_TABLES=y 49 | CONFIG_DUMMY=y 50 | CONFIG_VETH=y 51 | CONFIG_VLAN_8021Q=y 52 | EOF 53 | ;; 54 | rocker) 55 | cat <> .config 56 | CONFIG_NET_SWITCHDEV=y 57 | CONFIG_BRIDGE=y 58 | CONFIG_ROCKER=y 59 | EOF 60 | ;; 61 | netfilter) 62 | # Netfilter 63 | cat <> .config 64 | CONFIG_NETFILTER=y 65 | CONFIG_NETFILTER_ADVANCED=y 66 | CONFIG_NETFILTER_INGRESS=y 67 | CONFIG_NETFILTER_NETLINK=y 68 | CONFIG_NETFILTER_NETLINK_ACCT=y 69 | CONFIG_NETFILTER_NETLINK_QUEUE=y 70 | CONFIG_NETFILTER_NETLINK_LOG=y 71 | CONFIG_NETFILTER_SYNPROXY=y 72 | CONFIG_NETFILTER_XTABLES=y 73 | CONFIG_NETFILTER_XT_MARK=y 74 | CONFIG_NETFILTER_XT_CONNMARK=y 75 | CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y 76 | CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set 77 | CONFIG_NETFILTER_XT_TARGET_CONNMARK=y 78 | CONFIG_NETFILTER_XT_TARGET_CT=y 79 | CONFIG_NETFILTER_XT_TARGET_DSCP is not set 80 | CONFIG_NETFILTER_XT_TARGET_HL=y 81 | CONFIG_NETFILTER_XT_TARGET_HMARK is not set 82 | CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set 83 | CONFIG_NETFILTER_XT_TARGET_LOG=y 84 | CONFIG_NETFILTER_XT_TARGET_MARK=y 85 | CONFIG_NETFILTER_XT_NAT=y 86 | CONFIG_NETFILTER_XT_TARGET_NETMAP=y 87 | CONFIG_NETFILTER_XT_TARGET_NFLOG=y 88 | CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y 89 | CONFIG_NETFILTER_XT_TARGET_NOTRACK=y 90 | CONFIG_NETFILTER_XT_TARGET_RATEEST=y 91 | CONFIG_NETFILTER_XT_TARGET_REDIRECT=y 92 | CONFIG_NETFILTER_XT_TARGET_TEE=y 93 | CONFIG_NETFILTER_XT_TARGET_TPROXY=y 94 | CONFIG_NETFILTER_XT_TARGET_TRACE=y 95 | CONFIG_NETFILTER_XT_TARGET_TCPMSS=y 96 | CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y 97 | CONFIG_NETFILTER_XT_MATCH_BPF=y 98 | CONFIG_NETFILTER_XT_MATCH_CLUSTER=y 99 | CONFIG_NETFILTER_XT_MATCH_COMMENT=y 100 | CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y 101 | CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y 102 | CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y 103 | CONFIG_NETFILTER_XT_MATCH_CONNMARK=y 104 | CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y 105 | CONFIG_NETFILTER_XT_MATCH_CPU=y 106 | CONFIG_NETFILTER_XT_MATCH_DCCP=y 107 | CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y 108 | CONFIG_NETFILTER_XT_MATCH_DSCP=y 109 | CONFIG_NETFILTER_XT_MATCH_ECN=y 110 | CONFIG_NETFILTER_XT_MATCH_ESP=y 111 | CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y 112 | CONFIG_NETFILTER_XT_MATCH_HELPER=y 113 | CONFIG_NETFILTER_XT_MATCH_HL=y 114 | CONFIG_NETFILTER_XT_MATCH_IPCOMP=y 115 | CONFIG_NETFILTER_XT_MATCH_IPRANGE=y 116 | CONFIG_NETFILTER_XT_MATCH_L2TP=y 117 | CONFIG_NETFILTER_XT_MATCH_LENGTH=y 118 | CONFIG_NETFILTER_XT_MATCH_LIMIT=y 119 | CONFIG_NETFILTER_XT_MATCH_MAC=y 120 | CONFIG_NETFILTER_XT_MATCH_MARK=y 121 | CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y 122 | CONFIG_NETFILTER_XT_MATCH_NFACCT=y 123 | CONFIG_NETFILTER_XT_MATCH_OSF=y 124 | CONFIG_NETFILTER_XT_MATCH_OWNER=y 125 | CONFIG_NETFILTER_XT_MATCH_POLICY=y 126 | CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y 127 | CONFIG_NETFILTER_XT_MATCH_QUOTA=y 128 | CONFIG_NETFILTER_XT_MATCH_RATEEST=y 129 | CONFIG_NETFILTER_XT_MATCH_REALM=y 130 | CONFIG_NETFILTER_XT_MATCH_RECENT=y 131 | CONFIG_NETFILTER_XT_MATCH_SCTP=y 132 | CONFIG_NETFILTER_XT_MATCH_SOCKET=y 133 | CONFIG_NETFILTER_XT_MATCH_STATE=y 134 | CONFIG_NETFILTER_XT_MATCH_STATISTIC=y 135 | CONFIG_NETFILTER_XT_MATCH_STRING=y 136 | CONFIG_NETFILTER_XT_MATCH_TCPMSS=y 137 | CONFIG_NETFILTER_XT_MATCH_TIME=y 138 | CONFIG_NETFILTER_XT_MATCH_U32=y 139 | 140 | CONFIG_NF_CONNTRACK=y 141 | CONFIG_NF_LOG_COMMON=y 142 | CONFIG_NF_CONNTRACK_MARK=y 143 | CONFIG_NF_CONNTRACK_PROCFS=y 144 | CONFIG_NF_CONNTRACK_LABELS=y 145 | CONFIG_NF_NAT=y 146 | CONFIG_NF_NAT_NEEDED=y 147 | CONFIG_NF_NAT_REDIRECT=y 148 | CONFIG_NETFILTER_XT_TARGET_NFLOG=y 149 | CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y 150 | CONFIG_NETFILTER_XT_MATCH_NFACCT=y 151 | CONFIG_NF_DEFRAG_IPV4=y 152 | CONFIG_NF_CONNTRACK_IPV4=y 153 | CONFIG_NF_CONNTRACK_PROC_COMPAT=y 154 | CONFIG_NF_DUP_IPV4=y 155 | CONFIG_NF_LOG_ARP=y 156 | CONFIG_NF_LOG_IPV4=y 157 | CONFIG_NF_REJECT_IPV4=y 158 | CONFIG_NF_NAT_IPV4=y 159 | CONFIG_NF_NAT_MASQUERADE_IPV4=y 160 | CONFIG_IP_NF_IPTABLES=y 161 | CONFIG_IP_NF_MATCH_AH=y 162 | CONFIG_IP_NF_MATCH_ECN=y 163 | CONFIG_IP_NF_MATCH_RPFILTER=y 164 | CONFIG_IP_NF_MATCH_TTL=y 165 | CONFIG_IP_NF_FILTER=y 166 | CONFIG_IP_NF_TARGET_REJECT=y 167 | CONFIG_IP_NF_TARGET_SYNPROXY=y 168 | CONFIG_IP_NF_NAT=y 169 | CONFIG_IP_NF_TARGET_MASQUERADE=y 170 | CONFIG_IP_NF_TARGET_NETMAP=y 171 | CONFIG_IP_NF_TARGET_REDIRECT=y 172 | CONFIG_IP_NF_MANGLE=y 173 | CONFIG_IP_NF_TARGET_CLUSTERIP=y 174 | CONFIG_IP_NF_TARGET_ECN=y 175 | CONFIG_IP_NF_TARGET_TTL=y 176 | CONFIG_IP_NF_RAW=y 177 | CONFIG_IP_NF_ARPTABLES=y 178 | CONFIG_IP_NF_ARPFILTER=y 179 | CONFIG_IP_NF_ARP_MANGLE=y 180 | CONFIG_NF_DEFRAG_IPV6=y 181 | CONFIG_NF_CONNTRACK_IPV6=y 182 | CONFIG_NF_DUP_IPV6=y 183 | CONFIG_NF_REJECT_IPV6=y 184 | CONFIG_NF_LOG_IPV6=y 185 | CONFIG_NF_NAT_IPV6=y 186 | CONFIG_NF_NAT_MASQUERADE_IPV6=y 187 | CONFIG_IP6_NF_IPTABLES=y 188 | CONFIG_IP6_NF_MATCH_AH=y 189 | CONFIG_IP6_NF_MATCH_EUI64=y 190 | CONFIG_IP6_NF_MATCH_FRAG=y 191 | CONFIG_IP6_NF_MATCH_OPTS=y 192 | CONFIG_IP6_NF_MATCH_HL=y 193 | CONFIG_IP6_NF_MATCH_IPV6HEADER=y 194 | CONFIG_IP6_NF_MATCH_MH=y 195 | CONFIG_IP6_NF_MATCH_RPFILTER=y 196 | CONFIG_IP6_NF_MATCH_RT=y 197 | CONFIG_IP6_NF_TARGET_HL=y 198 | CONFIG_IP6_NF_FILTER=y 199 | CONFIG_IP6_NF_TARGET_REJECT=y 200 | CONFIG_IP6_NF_TARGET_SYNPROXY=y 201 | CONFIG_IP6_NF_MANGLE=y 202 | CONFIG_IP6_NF_RAW=y 203 | CONFIG_IP6_NF_NAT=y 204 | CONFIG_IP6_NF_TARGET_MASQUERADE=y 205 | CONFIG_IP6_NF_TARGET_NPT=y 206 | EOF 207 | ;; 208 | ipsec) 209 | # IPsec support 210 | cat <> .config 211 | CONFIG_NET_IPVTI=y 212 | CONFIG_IPV6_VTI=y 213 | CONFIG_INET_ESP=y 214 | CONFIG_INET6_ESP=y 215 | CONFIG_XFRM=y 216 | CONFIG_XFRM_USER=y 217 | CONFIG_XFRM_STATISTICS=y 218 | CONFIG_INET_XFRM_MODE_TUNNEL=y 219 | CONFIG_INET6_XFRM_MODE_TUNNEL=y 220 | CONFIG_CRYPTO_AES=y 221 | CONFIG_CRYPTO_SHA256=y 222 | CONFIG_CRYPTO_SHA512=y 223 | CONFIG_CRYPTO_SHA1=y 224 | CONFIG_CRYPTO_DH=y 225 | CONFIG_CRYPTO_GCM=y 226 | EOF 227 | ;; 228 | namespace) 229 | # Namespace support 230 | cat <> .config 231 | CONFIG_NAMESPACES=y 232 | CONFIG_UTS_NS=y 233 | CONFIG_IPC_NS=y 234 | CONFIG_USER_NS=y 235 | CONFIG_PID_NS=y 236 | CONFIG_NET_NS=y 237 | EOF 238 | ;; 239 | debug) 240 | # More debugging support. We need modules to get kprobes. 241 | cat <> .config 242 | CONFIG_MODULES=y 243 | CONFIG_STACKTRACE=y 244 | CONFIG_HIST_TRIGGERS=y 245 | CONFIG_STACK_TRACER=y 246 | CONFIG_FUNCTION_TRACER=y 247 | CONFIG_FTRACE_SYSCALLS=y 248 | CONFIG_KPROBES=y 249 | CONFIG_KPROBES_EVENTS=y 250 | CONFIG_BPF_SYSCALL=y 251 | CONFIG_DEBUG_INFO=y 252 | CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y 253 | CONFIG_DEBUG_INFO_BTF=y 254 | CONFIG_DEBUG_INFO_BTF_MODULES=y 255 | CONFIG_GDB_SCRIPTS=y 256 | CONFIG_COREDUMP=y 257 | CONFIG_UNWINDER_FRAME_POINTER=y 258 | EOF 259 | ;; 260 | *) 261 | >&2 echo "Unknown flavour \`$1'" 262 | exit 2 263 | ;; 264 | esac 265 | shift 266 | done 267 | 268 | make kvm_guest.config || make kvmconfig 269 | --------------------------------------------------------------------------------