├── .gitignore ├── LICENSE ├── README.md ├── idemptables ├── kerndev-build ├── kerndev-check ├── kerndev-check-all ├── kerndev-config ├── kerndev-create ├── kerndev-create-foreign ├── kerndev-create-foreign.chroot.sh ├── kerndev-create.chroot.sh ├── kerndev-debug ├── kerndev-defaults.sh ├── kerndev-functions.sh ├── kerndev-install ├── kerndev-module-headers ├── kerndev-nat-launch-subnet.sh ├── kerndev-nat-launch.sh ├── kerndev-qemu-tap-helper.sh ├── kerndev-rebuild ├── kerndev-run ├── kerndev-shared.sh ├── kerndev-update └── kerndev-whose /.gitignore: -------------------------------------------------------------------------------- 1 | .repos 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Lorenzo Stoakes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kernel Development Scripts 2 | 3 | **IMPORTANT:** I recently discovered https://github.com/arighi/virtme-ng which 4 | provides a lot more functionality than these scripts do, I recommend using this 5 | over the scripts. 6 | 7 | These are my kernel development scripts. Some are specific to my setup, others 8 | are more generic. I'm working on making them more generic over time. 9 | 10 | Generally I assume the distro I'm using (Arch Linux.) Additionally you will need 11 | to install appropriate packages, again at some point I will try to document the 12 | required packages. 13 | 14 | The scripts have been expanded to include some rudimentary support for the 15 | aarch64 architecture. To use this functionality, run `kerndev-create aarch64` 16 | (or `kerndev-create-aarch64`) and `kerndev-run aarch64`. 17 | 18 | **WARNING:** This does things as sudo, messes with dnsmasq settings and I 19 | generally take no responsibility if this nukes your system. I've never had 20 | issues arising from it but caveat emptor. 21 | 22 | 23 | ## Acknowledgements 24 | 25 | The qemu networking code is based on [Jakub Klinkovský][lahwaacz]'s 26 | [scripts][lahwaacz-scripts], [qemu-launcher.sh][qemu-launcher.sh] is a good 27 | starting point for this. His code in turn uses [xyne][xyne]'s work. 28 | 29 | The following scripts use this 3rd-party code:- 30 | 31 | * `kerndev-qemu-tap-helper.sh` 32 | * `kerndev-nat-launch.sh` 33 | * `kerndev-nat-launch-subnet.sh` 34 | 35 | ## Scripts 36 | 37 | __NOTE:__ These scripts are interdependent and assume that the they are all on 38 | the `$PATH`. 39 | 40 | __NOTE:__ By convention, files that end in `.sh` are not designed to be 41 | user-runnable, but are instead ran from other scripts. 42 | 43 | ### Maintaining 44 | 45 | * `kerndev-update` - Updates a list of linux trees in specific directories and 46 | on specific branches. This is configured to my personal setup, so you _will_ 47 | need to edit this script to fit your set up. The list of directories and 48 | branches are clearly separated from the actual code that updates so this is a 49 | quick task. 50 | 51 | ### Generating 52 | 53 | * `kerndev-create` - Creates a [qemu][qemu] kernel development environment. The 54 | image is an Arch Linux system. 55 | * `kerndev-build` - Configures and builds the kernel, optionally placing header 56 | and module files into the dev env image. It accepts a single optional argument 57 | which, if provided, specifies a cross-compile target architecture. 58 | * `kerndev-config` - Sets kernel configuration options for the development 59 | environment. 60 | * `kerndev-rebuild` - Same as `kerndev-build` but runs `make mrproper` first. 61 | * `kerndev-install` - Installs header and module files into the dev env 62 | image. This is invoked by `kerndev-build` unless explicitly disabled. 63 | * `kerndev-module-headers` - Generates a stripped version of the kernel source 64 | for building external modules. 65 | 66 | ### Running 67 | 68 | * `kerndev-run` - Runs the kernel development environment with virtio 69 | networking. 70 | * `kerndev-debug` - Connects `gdb` to a running dev env. Debugging config 71 | options are enabled by `kerndev-build` by default. When you run 72 | `kerndev-debug` it runs `gdb` which automatically connects to the qemu 73 | instance. 74 | 75 | __IMPORTANT:__ `gdb` has a big issue with the CPU changing architecture on 76 | startup, so you ought to run `kerndev-run` _before_ `kerndev-debug`. If you 77 | encounter `Remote 'g' packet reply is too long` errors you have triggered this 78 | issue and specifying arch afterwards doesn't seem to fix anything. If you need 79 | to debug early boot code, you'll need to investigate how to work around this 80 | issue :( 81 | 82 | ### Code 83 | 84 | * `kerndev-check` - Runs `checkpatch.pl` against the specified files, ignoring 85 | line length. 86 | * `kerndev-check-all` - Runs `checkpatch.pl` against the specified files. 87 | 88 | [qemu]:http://wiki.qemu.org/Main_Page 89 | 90 | [lahwaacz]:https://github.com/lahwaacz 91 | [lahwaacz-scripts]:https://github.com/lahwaacz/archlinux-dotfiles 92 | [qemu-launcher.sh]:https://github.com/lahwaacz/archlinux-dotfiles/blob/master/Scripts/qemu-launcher.sh 93 | [xyne]:http://xyne.archlinux.ca/notes/network/dhcp_with_dns.html 94 | 95 | ## Required packages 96 | 97 | ``` 98 | bridge-utils 99 | dnsmasq 100 | arch-install-scripts 101 | qemu-system-* 102 | ``` 103 | -------------------------------------------------------------------------------- /idemptables: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # iptables_=/usr/sbin/iptables 4 | iptables_=iptables 5 | 6 | function display_help() 7 | { 8 | cat < 21 | 22 | IPTABLES HELP 23 | HELP 24 | "$iptables_" "$@" 25 | } 26 | 27 | if [[ -z $1 ]] 28 | then 29 | display_help --help 30 | exit 1 31 | fi 32 | 33 | 34 | # Expand short arguments. 35 | inputargs=() 36 | for a_ in "$@" 37 | do 38 | if [[ ${a_:0:1} == '-' ]] \ 39 | && [[ ! -z ${a_:1:1} ]] \ 40 | && [[ ${a_:1:1} != '-' ]] 41 | then 42 | i=1 43 | arg="${a_:i++:1}" 44 | while [[ ! -z $arg ]] 45 | do 46 | inputargs+=("-$arg") 47 | arg="${a_:i++:1}" 48 | done 49 | else 50 | inputargs+=("$a_") 51 | fi 52 | done 53 | 54 | # Collect the input arguments. 55 | i_=0 56 | cargs_=() 57 | args_=() 58 | for a_ in "${inputargs[@]}" 59 | do 60 | args_[i_]="$a_" 61 | # Detect the help flag. 62 | if [[ $a_ == -h ]] || [[ $a_ == --help ]] 63 | then 64 | action_='help' 65 | # Detect append and delete flags and replace them with the check flag in $cargs_ 66 | elif [[ $a_ == -A ]] || [[ $a_ == '--append' ]] 67 | then 68 | if [[ -z $action_ ]] 69 | then 70 | action_='append' 71 | fi 72 | cargs_[i_++]='-C' 73 | elif [[ $a_ == -D ]] || [[ $a_ == '--delete' ]] 74 | then 75 | if [[ -z $action_ ]] 76 | then 77 | action_='delete' 78 | fi 79 | cargs_[i_++]='-C' 80 | else 81 | cargs_[i_++]="$a_" 82 | fi 83 | done 84 | 85 | if [[ -z $action_ ]] 86 | then 87 | "$iptables_" "${args_[@]}" 88 | elif [[ $action_ == 'help' ]] 89 | then 90 | display_help "${args_[@]}" 91 | elif [[ $action_ == 'append' ]] 92 | then 93 | # Append the rule if there is no match. 94 | if ! "$iptables_" "${cargs_[@]}" >/dev/null 2>&1 95 | then 96 | "$iptables_" "${args_[@]}" 97 | fi 98 | elif [[ $action_ == 'delete' ]] 99 | then 100 | # Delete all mathing rules. 101 | while "$iptables_" "${cargs_[@]}" >/dev/null 2>&1 102 | do 103 | "$iptables_" "${args_[@]}" 104 | done 105 | fi 106 | -------------------------------------------------------------------------------- /kerndev-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # NOTE: $cross_compile_prefix will vary depending on your cross-compiler setup. 5 | 6 | # If an argument is provided, it specifies a cross-compile target architecture. 7 | target_arch=${1:-"x86_64"} 8 | 9 | # Sanity checks. 10 | check_linux_dev_path 11 | [[ $EUID = 0 ]] && fatal "Don't run as root, causes file ownership pain" 12 | 13 | case $target_arch in 14 | arm) 15 | # Use aarch64 + backwards compatibility. 16 | ;& 17 | aarch64) 18 | linux_arch="arm64" 19 | cross_compile_prefix="aarch64-linux-gnu-" 20 | ;; 21 | "x86_64") 22 | ;; 23 | *) 24 | fatal "unknown architecture: $target_arch" 25 | ;; 26 | esac 27 | 28 | if [[ "$target_arch" != "x86_64" ]]; then 29 | # Make sure we have cross-compilers. `gcc` check should suffice. 30 | check_exists ${cross_compile_prefix}gcc 31 | 32 | # For now, always force a rebuild. 33 | REBUILD=y 34 | make_opts="ARCH=${linux_arch} CROSS_COMPILE=$cross_compile_prefix" 35 | fi 36 | 37 | # Ref: http://stackoverflow.com/a/6481016 38 | cores=$(grep -c ^processor /proc/cpuinfo) 39 | 40 | push_linux 41 | 42 | echo Configuring kernel... 43 | 44 | source kerndev-config 45 | # Set any new options implied by kerndev-config to default. 46 | mak olddefconfig 47 | 48 | echo Compiling kernel... 49 | # 1 extra thread to account for I/O waiting. 50 | mak -j$((cores + 1)) 51 | 52 | if [[ -z "$DONT_INSTALL" ]]; then 53 | NO_DONE=y sudo -E kerndev-install $target_arch 54 | fi 55 | 56 | pop 57 | 58 | say_done 59 | -------------------------------------------------------------------------------- /kerndev-check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # Since we specify an argument (the switch), we can't just pass $@. 5 | source kerndev-check-all --max-line-length=1000 ${@:-*.[ch]} 6 | -------------------------------------------------------------------------------- /kerndev-check-all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # Default to all .c and .h files in the directory. 5 | args=${@:-*.[ch]} 6 | # Check file (not patch), quiet (unless error), show error types and don't 7 | # bother with a per-file summary. 8 | check_opts="-f -q --show-types --no-summary" 9 | 10 | # Ensure the files exist, if not, die. 11 | for file in $args; do 12 | (! is_opt $file) && [[ ! -f $file ]] && \ 13 | fatal "Can't find $file." 14 | done 15 | 16 | # Perl sometimes outputs spurious error messages on stderr. 17 | $LINUX_DEV_PATH/scripts/checkpatch.pl $check_opts $args 2>/dev/null 18 | -------------------------------------------------------------------------------- /kerndev-config: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | push_linux 5 | 6 | if [[ -n "$REBUILD" ]] || [[ ! -f .config ]]; then 7 | mak mrproper 8 | mak defconfig 9 | fi 10 | 11 | # It isn't always useful to have extra version info :) 12 | kdisable localversion_auto 13 | 14 | # Required for systemd. 15 | kenable fhandle 16 | 17 | # We like devtmpfs. 18 | kenable devtmpfs 19 | 20 | # Disable unneeded wifi interface which spawns spurious debug output. 21 | kdisable cfg80211 22 | 23 | # tun/tap. 24 | kenable tun 25 | 26 | # virtio stuff. 27 | kenable virtio_pci virtio_mmio virtio_blk virtio_net virtio_console \ 28 | virtio_pci_legacy virtio_input virtio_mmio_cmdline_devices 29 | kdisable hw_random_virtio virtio_balloon drm_virtio_gpu crypto_dev_virtio 30 | 31 | # Debugging settings. 32 | kenable debug_info debug_info_dwarf5 gdb_scripts frame_pointer 33 | kdisable debug_info_reduced debug_rodata debug_info_compressed debug_info_split 34 | 35 | # Enable VM debug settings. 36 | kenable debug_vm debug_vm_pgtable 37 | 38 | # Remove irritating debug messages we don't care about. 39 | kdisable debug_stack_usage audit 40 | 41 | # Gain access to /proc/config.gz. 42 | kenable ikconfig ikconfig_proc 43 | 44 | # Avoid legacy hotplug. 45 | # Taken with thanks from http://unix.stackexchange.com/a/116888. 46 | scripts/config --set-str uevent_helper_path "" 47 | 48 | # Pull down PSI information. 49 | kenable psi 50 | kdisable psi_default_disabled 51 | 52 | # Disable STACKPROTECTOR_STRONG to avoid gcc 10 issues as described at 53 | # http://rglinuxtech.com/?p=2694 (seems applicable to kernels around ~5.5). 54 | kdisable stackprotector_strong 55 | 56 | # Enable memcg so we can have mm->owner :) 57 | kenable memcg 58 | 59 | kenable checkpoint_restore mem_soft_dirty mapping_dirty_helpers 60 | 61 | # Optionally enable flags for docker support. 62 | [[ -n "$ENABLE_DOCKER_SUPPORT" ]] && \ 63 | kenable netfilter_advanced dm_thin_provisioning bridge bridge_netfilter \ 64 | devpts_multiple_instances cgroup_device memcg macvlan veth \ 65 | nf_nat_ipv4 nf_nat netfilter_xt_match_{conntrack,addrtype} \ 66 | blk_cgroup blk_dev_throttling cgroup_perf cgroup_hugetlb \ 67 | net_cls_cgroup cfs_bandwidth rt_group_sched netprio_cgroup \ 68 | cgroup_net_prio btrfs_fs 69 | 70 | # Optionally, we are interested in code coverage. 71 | [[ -n "$ENABLE_GCOV" ]] && \ 72 | kenable debug_fs gcov_kernel gcov_format_autodetect gcov_profile_all 73 | 74 | # Userfaultfd is interesting 75 | kenable userfaultfd 76 | 77 | # We want THP. 78 | kenable transparent_hugepage 79 | 80 | # Memory failure useful. 81 | kenable memory_failure 82 | 83 | # Generate test_vmalloc module for testing. 84 | scripts/config --module test_vmalloc 85 | 86 | # Use 16kb pages on arm if set in host system. 87 | zgrep ARM64_16K_PAGES /proc/config.gz &>/dev/null && kenable arm64_16k_pages || true 88 | 89 | # ftrace stuff. 90 | kenable ftrace_syscalls dynamic_ftrace 91 | 92 | # Fault injection stuff. 93 | kenable fault_injection fault_injection_configfs fault_injection_debug_fs failslab 94 | 95 | make olddefconfig 96 | # We don't need modules. 97 | make mod2noconfig || true 98 | 99 | pop 100 | -------------------------------------------------------------------------------- /kerndev-create: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # If an argument is provided, it specifies a cross-compile target architecture. 5 | target_arch=${1:-"x86_64"} 6 | 7 | case $target_arch in 8 | "arm") 9 | exec kerndev-create-foreign arm $@ 10 | exit $? 11 | ;; 12 | "aarch64") 13 | exec kerndev-create-foreign aarch64 $@ 14 | exit $? 15 | ;; 16 | "x86_64") 17 | ;; 18 | *) 19 | fatal Unknown arch $1. 20 | ;; 21 | esac 22 | 23 | # Sanity checks. 24 | [[ ! -f "/etc/arch-release" ]] && \ 25 | fatal This script is designed for arch linux only, sorry! 26 | 27 | check_exists kerndev-create.chroot.sh kerndev-build kerndev-install pacstrap \ 28 | truncate mkfs.ext4 arch-chroot 29 | 30 | [[ -n $USE_EXISTING_IMAGE ]] && [[ ! -f $KERNDEV_PATH/rootfs.img ]] && \ 31 | fatal "can't find existing rootfs image" 32 | 33 | chroot_script_path=$(which kerndev-create.chroot.sh) 34 | 35 | # So many commands need sudo, so just force the issue. 36 | elevate $@ 37 | 38 | # We want access to the underlying user. 39 | [[ -z "$SUDO_USER" ]] && fatal please run this using sudo! 40 | 41 | # If this fails due to being unable to unmount /mnt, mount below will fail so we 42 | # can get away with ||true here. 43 | unmount 44 | 45 | mkdir -p $KERNDEV_PATH 46 | 47 | push_kerndev 48 | 49 | if [[ -z "$USE_EXISTING_IMAGE" ]]; then 50 | echo Creating and formatting rootfs image file... 51 | rm -f rootfs.img 52 | truncate -s $IMAGE_SIZE rootfs.img 53 | mkfs.ext4 -q rootfs.img 54 | else 55 | echo Using existing rootfs... 56 | fi 57 | 58 | mount_image rootfs.img 59 | trap "umount /mnt" EXIT 60 | 61 | if [[ -z "$USE_EXISTING_IMAGE" ]]; then 62 | echo Downloading and installing rootfs into image... 63 | pacstrap /mnt base base-devel &>/dev/null 64 | fi 65 | 66 | echo Running chroot-ed rootfs image config script... 67 | cp $chroot_script_path /mnt/chroot.sh 68 | # Copy ssh keys + config. 69 | cp -R /home/$SUDO_USER/.ssh /mnt/ 70 | arch-chroot /mnt /chroot.sh $SUDO_USER $(id -u $SUDO_USER) $ROOT_PASSWORD 71 | rm /mnt/chroot.sh 72 | # arch-chroot mounts the system's /etc/resolv.conf, so do this outside the 73 | # chroot. 74 | cat >/mnt/etc/resolv.conf <$cov_path <<-EOF 88 | #!/bin/bash 89 | 90 | [[ -z "\$1" ]] && echo "usage: \$(basename \$0) [relative path to source file]" >&2 && exit 1 91 | 92 | # ref: https://goo.gl/rnd6yo 93 | args=\${@:1:-1} 94 | f=\${@: -1} 95 | 96 | local_linux=/home/$SUDO_USER/linux/ 97 | 98 | pushd \$local_linux >/dev/null 99 | sudo gcov \$args -o /sys/kernel/debug/gcov/$LINUX_DEV_PATH/\$(dirname \$f) \$local_linux/\$f 100 | sudo chown $SUDO_USER *.gcov 101 | popd >/dev/null 102 | EOF 103 | chmod +x $cov_path 104 | give_back $cov_path 105 | 106 | pop 107 | fi 108 | 109 | if [[ -n "$ACCESS_CHROOT" ]]; then 110 | echo Entering chroot shell... 111 | arch-chroot /mnt 112 | echo ...chroot shell done! 113 | fi 114 | 115 | # We don't need /mnt any more. 116 | unmount 117 | trap - EXIT 118 | 119 | if [[ -n "$KERNEL_BUILD_ON_CREATE" ]]; then 120 | echo Building linux... 121 | # Install separately so we can update user on progress separately, also this 122 | # means we can run as the user and thus not write root owned files! 123 | NO_DONE=y DONT_INSTALL=y sudo -E -u $SUDO_USER kerndev-build 124 | 125 | echo Installing modules into image... 126 | NO_DONE=y kerndev-install 127 | fi 128 | 129 | pop 130 | 131 | # Pass ownership back to the user. 132 | # Executing this outside of the chroot probably means uids need to be 133 | # synced. TODO: Fix. 134 | give_back $KERNDEV_PATH 135 | 136 | say_done 137 | -------------------------------------------------------------------------------- /kerndev-create-foreign: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # TODO: Duplicates kerndev-create, lots of copy-pasta, de-duplicate!! 5 | 6 | [[ -z "$1" ]] && fatal missing arch. 7 | 8 | target_arch=$1 9 | shift 10 | 11 | case $target_arch in 12 | "arm") 13 | debootstrap_arch="armhf" 14 | binfmt_sig=":arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\ 15 | \x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\ 16 | \xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:" 17 | ;; 18 | "aarch64") 19 | debootstrap_arch="arm64" 20 | binfmt_sig=":aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\ 21 | \x00\x02\x00\xb7:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\ 22 | \xff\xfe\xff\xff:/usr/bin/qemu-aarch64-static:" 23 | ;; 24 | *) 25 | fatal Unknown arch $target_arch. 26 | ;; 27 | esac 28 | 29 | rootfs="rootfs_${target_arch}.img" 30 | binfmt_path="/proc/sys/fs/binfmt_misc" 31 | chroot_path="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" 32 | 33 | # Functions. 34 | 35 | function cleanup() 36 | { 37 | [[ -f $binfmt_path/$target_arch ]] && echo -1 > $binfmt_path/$target_arch 38 | rm -f /mnt/usr/bin/qemu-$target_arch-static 39 | unmount 40 | } 41 | 42 | # Sanity checks. 43 | check_exists debootstrap qemu-system-$target_arch qemu-$target_arch-static 44 | [[ ! -d $binfmt_path ]] && fatal "binfmt not available." 45 | 46 | [[ -n $USE_EXISTING_IMAGE ]] && [[ ! -f $KERNDEV_PATH/$rootfs ]] && \ 47 | fatal "can't find existing rootfs image" 48 | 49 | # So many commands need sudo, so just force the issue. 50 | elevate $@ 51 | 52 | chroot_script_path=$(which kerndev-create-foreign.chroot.sh) 53 | 54 | unmount 55 | 56 | mkdir -p $KERNDEV_PATH 57 | 58 | push_kerndev 59 | 60 | if [[ -z "$USE_EXISTING_IMAGE" ]]; then 61 | echo Creating and formatting rootfs image file... 62 | rm -f $rootfs 63 | truncate -s $IMAGE_SIZE $rootfs 64 | mkfs.ext4 -q $rootfs 65 | fi 66 | 67 | mount_image $rootfs 68 | trap cleanup EXIT 69 | 70 | if [[ -z "$USE_EXISTING_IMAGE" ]]; then 71 | echo "Downloading and installing first stage rootfs into image..." 72 | 73 | debootstrap --arch=$debootstrap_arch --variant=minbase --foreign \ 74 | --include=$DEBIAN_PACKAGES $DEBIAN_VERSION /mnt $DEBIAN_MIRROR \ 75 | >/dev/null 76 | fi 77 | 78 | echo Enabling binfmt for chroot... 79 | cp $(which qemu-${target_arch}-static) /mnt/usr/bin/ 80 | echo "$binfmt_sig" > $binfmt_path/register 81 | 82 | if [[ -z "$USE_EXISTING_IMAGE" ]]; then 83 | echo Entering chroot, downloading and installing second stage rootfs into image... 84 | chroot /mnt /debootstrap/debootstrap --second-stage >/dev/null 85 | fi 86 | 87 | echo Running pre-chroot tasks... 88 | cp $chroot_script_path /mnt/chroot.sh 89 | # Copy ssh keys + config. 90 | cp -R /home/$SUDO_USER/.ssh /mnt/ 91 | 92 | # Git + qemu/arm don't play nice, so clone oh-my-zsh here. 93 | rm -rf /mnt/oh-my-zsh && mkdir /mnt/oh-my-zsh 94 | git clone --depth=1 https://github.com/robbyrussell/oh-my-zsh.git /mnt/oh-my-zsh &>/dev/null 95 | 96 | echo Running chroot-ed rootfs image config script... 97 | arch-chroot /mnt /chroot.sh $SUDO_USER $ROOT_PASSWORD 98 | rm /mnt/chroot.sh 99 | # arch-chroot mounts the system's /etc/resolv.conf, so do this outside the 100 | # chroot. 101 | cat >/mnt/etc/resolv.conf <" >&2 32 | } 33 | 34 | # $1: path of file to set owned by $username. 35 | function give_back() 36 | { 37 | chown -R $username:$username $1 38 | } 39 | 40 | # Sanity checks. 41 | if ! inside_chroot; then 42 | echo not inside chroot! >&2 43 | exit 1 44 | fi 45 | if [[ -z "$username" ]]; then 46 | usage 47 | exit 1 48 | fi 49 | 50 | echo Configuring system... 51 | # We need to define PATH ourselves. 52 | export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin 53 | 54 | # We want to use the network :) 55 | systemctl -q enable dhcpcd 2>/dev/null 56 | 57 | cat > /etc/systemd/network/eth.network </dev/null 64 | 65 | # We assign Google DNS servers (outside this script), so fuck this hook. 66 | echo "nohook resolv.conf" >> /etc/dhcpcd.conf 67 | 68 | # Assign host name. 69 | echo $guest_name > /etc/hostname 70 | grep -v 127.0.0.1 /etc/hosts > /etc/_hosts 71 | echo "127.0.0.1 localhost $guest_name" > /etc/hosts 72 | cat /etc/_hosts >> /etc/hosts 73 | rm /etc/_hosts 74 | 75 | echo Setting up root password... 76 | if [[ -z "$password" ]]; then 77 | # Don't let a typo ruin our day! 78 | while ! passwd; do 79 | echo Try again! 80 | done 81 | else 82 | echo root:$password | chpasswd 83 | fi 84 | 85 | echo Setting up user $username with auto-login... 86 | useradd -m $username -G sudo >/dev/null || true 87 | passwd -d $username >/dev/null 88 | mkdir -p /etc/systemd/system/serial-getty@ttyAMA0.service.d 89 | # I've found xterm works the best. 90 | cat >/etc/systemd/system/serial-getty@ttyAMA0.service.d/autologin.conf <>$user_home/.screenrc </usr/bin/leave <>$user_zshrc </dev/null 137 | 138 | # Failing to sync causes updates to not be written correctly. 139 | echo Syncing changes... 140 | sync 141 | -------------------------------------------------------------------------------- /kerndev-create.chroot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail 3 | 4 | # Configurable variables. 5 | # Console dimensions, adjust to taste, this works well on my screen! 6 | CONSOLE_ROWS=${CONSOLE_ROWS:-50} 7 | CONSOLE_COLS=${CONSOLE_COLS:-200} 8 | 9 | # Passed by calling script. 10 | username=$1 # == $SUDO_USER 11 | uid=$2 # The user ID associated with $username so we can sync bindmount. 12 | password=$3 # Optional, if not provided script will prompt. 13 | 14 | # Functions. 15 | 16 | # Taken from http://unix.stackexchange.com/a/14346. Non-root version didn't work. 17 | function inside_chroot() 18 | { 19 | [[ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]] 20 | } 21 | 22 | function usage() 23 | { 24 | echo "usage: $0 [username] " >&2 25 | } 26 | 27 | # Sanity checks. 28 | if ! inside_chroot; then 29 | echo not inside chroot! >&2 30 | exit 1 31 | fi 32 | if [[ -z "$username" ]]; then 33 | usage 34 | exit 1 35 | fi 36 | 37 | echo Configuring system... 38 | # We want to use the network :) 39 | pacman -S --noconfirm dhcpcd &>/dev/null 40 | systemctl -q enable dhcpcd 41 | # Retrieve wget so we can set it as the transfer command in a moment. 42 | pacman -S --noconfirm wget &>/dev/null 43 | # We assign Google DNS servers (outside this script), so fuck this hook. 44 | echo "nohook resolv.conf" >> /etc/dhcpcd.conf 45 | # No delay for incorrect password reattempt. Pet peeve! 46 | sed -i 's/try_first_pass/try_first_pass nodelay/' /etc/pam.d/system-auth 47 | echo tux > /etc/hostname 48 | # Set up directory for kernel source bindmount. 49 | mkdir -p /src/kernel 50 | 51 | # Now get the packages we want. 52 | echo Installing packages... 53 | pacman -Sy --noconfirm nano strace zsh lsof openssh patch git &>/dev/null 54 | # We don't need the linux package, we link to the kernel via a qemu switch. 55 | pacman -R --noconfirm linux &>/dev/null || true 56 | 57 | echo Setting up root password... 58 | if [[ -z "$password" ]]; then 59 | # Don't let a typo ruin our day! 60 | while ! passwd; do 61 | echo Try again! 62 | done 63 | else 64 | echo root:$password | chpasswd 65 | fi 66 | 67 | echo Setting up user $username with auto-login... 68 | useradd -m $username -u $uid -G wheel >&/dev/null || true 69 | passwd -d $username >/dev/null 70 | echo "%wheel ALL=(ALL) ALL" >> /etc/sudoers 71 | mkdir -p /etc/systemd/system/serial-getty@ttyS0.service.d 72 | mkdir -p /etc/systemd/system/serial-getty@ttyAMA0.service.d 73 | # I've found xterm works the best. 74 | cat >/etc/systemd/system/serial-getty@ttyAMA0.service.d/autologin.conf </etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf </usr/bin/leave <> /etc/fstab 97 | 98 | echo Configuring zsh... 99 | 100 | user_zshrc=/home/$username/.zshrc 101 | 102 | # Install oh-my-zsh 103 | rm -rf /tmp/ls__omz 104 | sudo -u $username git clone https://aur.archlinux.org/oh-my-zsh-git.git /tmp/ls__omz &>/dev/null 105 | cd /tmp/ls__omz 106 | sudo -u $username makepkg -si --noconfirm &>/dev/null 107 | cp /usr/share/oh-my-zsh/zshrc $user_zshrc 108 | sed -i 's/ZSH_THEME=".*"/ZSH_THEME="gallois"/' $user_zshrc 109 | chsh -s /usr/bin/zsh $username >/dev/null 110 | 111 | # For some reason qemu is sending carriage returns... :( fix!! 112 | cat >>$user_zshrc <&2 21 | } 22 | 23 | # Displays parameteters with command name prepended, outputted to stderr, then 24 | # exits with error status. 25 | # $@: message to display. 26 | function fatal() 27 | { 28 | error $@ 29 | exit 1 30 | } 31 | 32 | # Pushes directory onto pushd stack without outputting anything. 33 | # $1: Directory to add to pushd stack. 34 | function push() 35 | { 36 | pushd $1 >/dev/null 37 | } 38 | 39 | # Pops directory off pushd stack without outputting anything. 40 | function pop() 41 | { 42 | popd &>/dev/null || true 43 | } 44 | 45 | # Pushes into linux dev directory (at $LINUX_DEV_PATH), assumes this variable is 46 | # available. 47 | function push_linux() 48 | { 49 | if is_linux_dir; then 50 | path="." 51 | else 52 | path="$LINUX_DEV_PATH" 53 | fi 54 | 55 | push $path 56 | } 57 | 58 | # Pushes into kernel dev directory (at $KERNDEV_PATH), assumes this variable is 59 | # available. 60 | function push_kerndev() 61 | { 62 | push $KERNDEV_PATH 63 | } 64 | 65 | # Replaces the current script with an elevated version of itself. 66 | # If parameters need to be preserved, they need to be passed thorough via $@. 67 | function elevate() 68 | { 69 | if [[ $EUID != 0 ]]; then 70 | exec sudo -E $0 $@ 71 | exit $? 72 | fi 73 | } 74 | 75 | # Checks whether the specified binaries are available on the $PATH. 76 | # $@: Binaries to check. 77 | function check_exists() 78 | { 79 | for file in $@; do 80 | (which $file &>/dev/null) || \ 81 | fatal "Can't find required binary '$file' on path." 82 | done 83 | } 84 | 85 | # Loop mount image file into /mnt. 86 | # $1: Image file to mount, in $KERNDEV_PATH. 87 | function mount_image() 88 | { 89 | mount -o loop $KERNDEV_PATH/$1 /mnt 90 | } 91 | 92 | # Attempt to unmount /mnt, ignore any failures. 93 | function unmount() 94 | { 95 | # This _can_ be dangerous, theoretically, but this is usually shortly 96 | # followed by an attempt at a mount, which if the unmount fails, will 97 | # also fail and end the script with an error. 98 | umount /mnt &>/dev/null || true 99 | } 100 | 101 | # Give ownership of the specified directory to the user (assumes $SUDO_USER is 102 | # available!) 103 | # $1: Directory to 'give back' to user $SUDO_USER. 104 | function give_back() 105 | { 106 | [[ -z "$SUDO_USER" ]] && error "give_back: SUDO_USER not defined." || \ 107 | chown -R $SUDO_USER:$SUDO_USER $1 108 | } 109 | 110 | # Run make with specified arguments and $make_opts. If $VERBOSE is set, output 111 | # to controlling terminal, otherwise redirect to /dev/null. 112 | # $@: make arguments. 113 | function mak() 114 | { 115 | [[ -z $VERBOSE ]] && out="null" || out="tty" 116 | 117 | make $make_opts $@ >/dev/$out 118 | } 119 | 120 | # Determines if the argument is an command-line option. 121 | # $1: Argument. 122 | function is_opt() 123 | { 124 | [[ $1 == -* ]] 125 | } 126 | 127 | # Say we're done, if we're not configured to not do so. 128 | function say_done() 129 | { 130 | [[ -z "$NO_DONE" ]] && echo Done! || true 131 | } 132 | 133 | 134 | # Configure kernel setting to $1 for settings in $@... 135 | function config() 136 | { 137 | choice=$1 138 | shift 139 | 140 | for setting in $@; do 141 | scripts/config --$choice $setting 142 | done 143 | } 144 | 145 | # Enable kernal settings $@... 146 | function kenable() 147 | { 148 | config enable $@ 149 | } 150 | 151 | # Disable kernal settings $@... 152 | function kdisable() 153 | { 154 | config disable $@ 155 | } 156 | 157 | # Outputs the current script directory. 158 | function script_dir() 159 | { 160 | # Source: http://stackoverflow.com/a/246128/6380063 161 | echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 162 | } 163 | 164 | # Check whether $LINUX_DEV_PATH is sane. 165 | function check_linux_dev_path() 166 | { 167 | [[ -d $LINUX_DEV_PATH ]] || fatal "Couldn't find kernel at $LINUX_DEV_PATH." 168 | 169 | is_linux_dir $LINUX_DEV_PATH || \ 170 | fatal "Doesn't look like a linux dev path: $LINUX_DEV_PATH" 171 | } 172 | 173 | # Finds the base linux kernel path of the specified directory contained within a 174 | # kernel directory structure, or if it can't be found just returns the path. 175 | function find_base_linux_path() 176 | { 177 | local path=$1 178 | push $path || fatal "Invalid path $path?!" 179 | 180 | while [[ $PWD != "/" ]] && ! is_linux_dir $PWD; do 181 | cd .. 182 | done 183 | 184 | if [[ $PWD == "/" ]]; then 185 | echo $path 186 | else 187 | echo $PWD 188 | fi 189 | 190 | pop 191 | } 192 | -------------------------------------------------------------------------------- /kerndev-install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # If argument provided it specifies a cross-compile target architecture. 5 | target_arch=${1:-$(uname -m)} 6 | rootfs=rootfs.img 7 | 8 | case $target_arch in 9 | arm) 10 | # Use aarch64 + backwards compatibility. 11 | ;& 12 | aarch64) 13 | linux_arch="arm64" 14 | cross_compile_prefix="aarch64-linux-gnu-" 15 | ;; 16 | x86_64) 17 | kernel_image_path=$LINUX_DEV_PATH/arch/x86/boot/bzImage 18 | 19 | check_linux_dev_path 20 | [[ ! -f $kernel_image_path ]] && \ 21 | fatal "can't find kernel image at $kernel_image_path" 22 | ;; 23 | *) 24 | fatal "unknown architecture: $target_arch" 25 | ;; 26 | esac 27 | 28 | if [[ "$target_arch" != "$(uname -m)" ]]; then 29 | rootfs=rootfs_${target_arch}.img 30 | make_opts="ARCH=${linux_arch} CROSS_COMPILE=$cross_compile_prefix" 31 | fi 32 | 33 | # Sanity checks. 34 | 35 | rootfs_image_path=$KERNDEV_PATH/$rootfs 36 | [[ ! -f $rootfs_image_path ]] && \ 37 | fatal "can't find root fs image at $rootfs_image_path" 38 | 39 | elevate $@ 40 | 41 | push_linux 42 | 43 | unmount 44 | mount_image $rootfs 45 | trap unmount EXIT 46 | 47 | echo Installing headers and modules... 48 | mak headers_install INSTALL_HDR_PATH=/mnt/usr/ 49 | mak modules_install INSTALL_MOD_PATH=/mnt/ 50 | 51 | if [[ -z "$USE_EXISTING_IMAGE" ]] && [[ -n "$ENABLE_GCOV" ]]; then 52 | # We need to copy the linux source code to be able to gcov it. 53 | echo "Copying linux source to image (gcov)..." 54 | 55 | image_linux_dev_path=/mnt/home/$SUDO_USER/linux 56 | 57 | rm -rf $image_linux_dev_path 58 | mkdir $image_linux_dev_path 59 | 60 | # Create dir structure. 61 | find . -type d | xargs -i mkdir -p $image_linux_dev_path/{} 62 | 63 | # Adapted from https://www.kernel.org/doc/Documentation/gcov.txt 64 | # But you need .o files too...? so the docs are wrong? TODO: Investigate... 65 | find -name '*.gcno' -o -name '*.[choS]' -o -type l | \ 66 | xargs -i cp -a {} $image_linux_dev_path/{} 67 | 68 | # Executing this outside of the chroot probably means uids need to be 69 | # synced. TODO: Fix. 70 | give_back $image_linux_dev_path 71 | fi 72 | 73 | pop 74 | 75 | say_done 76 | -------------------------------------------------------------------------------- /kerndev-module-headers: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # Heavily based on PKGBUILD from 5 | # https://www.archlinux.org/packages/core/x86_64/linux/ 6 | 7 | function usage() 8 | { 9 | echo "usage: $(basename $0) [target dir] ">&2 10 | exit 1 11 | } 12 | 13 | # See http://stackoverflow.com/a/4774063 14 | function get_full_path() 15 | { 16 | echo "$( cd "$1" ; pwd -P )" 17 | } 18 | 19 | ([[ -z "$1" ]] || ([[ -f "$1" ]] && [[ ! -d "$1" ]])) && usage 20 | 21 | # Generate if doesn't exist. 22 | install -dm755 $1 23 | 24 | target_dir=$(get_full_path $1) 25 | karch=${2:-x86} 26 | if [[ "$#" -gt 2 ]]; then 27 | shift 2 28 | make_opts="$@" 29 | fi 30 | 31 | karch_dir="arch/$karch" 32 | target_karch_dir="$target_dir/$karch_dir" 33 | 34 | extra_header_dirs="drivers/md net/mac80211 drivers/media/dvb-core include/config/dvb \ 35 | drivers/media/dvb-frontends drivers/media/usb/dvb-usb drivers/media/tuners" 36 | 37 | push_linux 38 | trap pop EXIT 39 | 40 | [[ ! -f .config ]] && fatal "Missing kernel configuration." 41 | [[ ! -f Module.symvers ]] && fatal "Missing Module.symvers, build kernel to generate." 42 | [[ ! -d "$karch_dir" ]] && fatal "Unrecognised karch: $karch" 43 | 44 | echo Running modules_prepare... 45 | make $make_opts modules_prepare >/dev/null 46 | 47 | echo Copying required files... 48 | 49 | for f in .config Makefile kernel/Makefile Module.symvers Documentation/DocBook/Makefile; do 50 | install -D -m644 "$f" "$target_dir/$f" 51 | done 52 | 53 | # Arch Linux copies only specific directories, however the difference is 31M 54 | # vs. 37M (~168k compressed) so for future-proofing I think it's not much more 55 | # of a cost to just copy everything. 56 | find include -mindepth 1 -maxdepth 1 -type d | \ 57 | xargs -I {} cp -a "{}" "$target_dir/include" 58 | 59 | for d in include $extra_header_dirs; do 60 | [[ -d "$d" ]] && mkdir -p "$target_dir/$d" 61 | done 62 | 63 | mkdir -p "$target_karch_dir" 64 | cp -a "$karch_dir/include" "$target_karch_dir" 65 | for h in $(find $karch_dir -iname '*.h'); do 66 | mkdir -p "$target_dir/$(dirname $h)" 67 | cp $h "$target_dir/$h" 68 | done 69 | 70 | cp -a scripts "$target_dir/scripts" 71 | # Don't strip binaries as only makes 200kb difference... 72 | 73 | mkdir -p "$target_karch_dir/kernel" 74 | cp "$karch_dir/Makefile" "$target_karch_dir" 75 | 76 | # May as well always copy these if available. 77 | for f in Makefile_32.cpu kernel/asm-offsets.s; do 78 | p="$karch_dir/$f" 79 | [[ -f $p ]] && cp "$p" "$target_karch_dir/$f" 80 | done 81 | 82 | # Copy in extra headers. Directories already created above. 83 | for d in $extra_header_dirs; do 84 | [[ -d "$d" ]] && cp $d/*.h "$target_dir/$d" 85 | done 86 | 87 | # Specific required files. 88 | mkdir -p "$target_dir/drivers/media/i2c/" 89 | cp drivers/media/i2c/msp3400-driver.h "$target_dir/drivers/media/i2c/" 90 | 91 | # Copy in Kconfig files. 92 | for f in $(find . -name "Kconfig*"); do 93 | mkdir -p "$target_dir/$(dirname $f)" 94 | cp $f "$target_dir/$f" 95 | done 96 | 97 | say_done 98 | -------------------------------------------------------------------------------- /kerndev-nat-launch-subnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail 3 | 4 | function print_launch_subnet_usage() 5 | { 6 | echo "USAGE" 7 | echo " $0 " 8 | cat <<'CONFIG' 9 | 10 | REQUIRED VARIABLES 11 | # The network interface card (NIC) that is connected to the internet or other 12 | # wide area network. 13 | wan_nic="wlan0" 14 | 15 | # The network interface card connected to the subnet. 16 | subnet_nic="eth0" 17 | 18 | # The subnet IP mask. 19 | mask=/24 20 | 21 | # The subnet IP range. 22 | subnet_ip=10.0.0.0$mask 23 | 24 | # The IP of the subnet NIC on the subnet. 25 | server_ip=10.0.0.100$mask 26 | 27 | # The IP tables binary to use. 28 | iptables=/usr/bin/idemptables 29 | 30 | # The dnsmasq arguments - PID and lease files to use. 31 | dnsmasq_pid=/tmp/dhcpd.pid 32 | dnsmasq_lease=/tmp/dhcpd.lease 33 | 34 | # The port of DNS service, see dnsmasq(8) for details. Specify "0" to disable DNS server. 35 | dnsmasq_port=53 36 | 37 | # The DHCP range, see dnsmasq(8) for details. 38 | dnsmasq_dhcp_range="192.168.137.100,192.168.137.200,12h" 39 | 40 | OPTIONAL VARIABLES 41 | # Function or external scripts to run before before and after bringing the 42 | # subnet NIC up or down: pre_up, post_up, pre_down, post_down 43 | 44 | # pre_up as a function: 45 | # function pre_up() 46 | # { 47 | # } 48 | 49 | # pre_up as a script: 50 | # pre_up=/path/to/script 51 | 52 | # ip_forward=0 53 | # The value of /proc/sys/net/ipv4/ip_forward to restore when shutting down 54 | # the subnet. 55 | CONFIG 56 | } 57 | 58 | function launch_subnet() 59 | { 60 | set -e 61 | 62 | if [[ -z $1 ]] 63 | then 64 | print_launch_subnet_usage 65 | exit 1 66 | else 67 | action="$1" 68 | fi 69 | 70 | if [[ -z $wan_nic ]] 71 | then 72 | echo "wan_nic is undefined" 73 | exit 1 74 | fi 75 | 76 | if [[ -z $subnet_nic ]] 77 | then 78 | echo "subnet_nic is undefined" 79 | exit 1 80 | fi 81 | 82 | if [[ -z $mask ]] 83 | then 84 | echo "mask is undefined" 85 | exit 1 86 | fi 87 | 88 | if [[ -z $subnet_ip ]] 89 | then 90 | echo "subnet_ip is undefined" 91 | exit 1 92 | fi 93 | 94 | if [[ -z $server_ip ]] 95 | then 96 | echo "server_ip is undefined" 97 | exit 1 98 | fi 99 | 100 | if [[ -z $iptables ]] 101 | then 102 | echo "iptables is undefined" 103 | exit 1 104 | fi 105 | 106 | if [[ -z $dnsmasq_pid ]] 107 | then 108 | echo "dnsmasq_pid is undefined" 109 | exit 1 110 | fi 111 | 112 | if [[ -z $dnsmasq_lease ]] 113 | then 114 | echo "dnsmasq_lease is undefined" 115 | exit 1 116 | fi 117 | 118 | if [[ -z $dnsmasq_port ]] 119 | then 120 | echo "dnsmasq_port is undefined" 121 | exit 1 122 | fi 123 | 124 | if [[ -z $dnsmasq_dhcp_range ]] 125 | then 126 | echo "dnsmasq_dhcp_range is undefined" 127 | exit 1 128 | fi 129 | 130 | 131 | case "$action" in 132 | up) 133 | 134 | # Enable IP forwarding. 135 | echo 1 > /proc/sys/net/ipv4/ip_forward 136 | 137 | # Open up DNS (53) and DHCP (67) ports on subnet_nic. 138 | "$iptables" -A INPUT -i "$subnet_nic" -s "$subnet_ip" -p tcp --dport 53 -j ACCEPT 139 | "$iptables" -A INPUT -i "$subnet_nic" -s "$subnet_ip" -p udp --dport 53 -j ACCEPT 140 | "$iptables" -A INPUT -i "$subnet_nic" -p udp --dport 67 -j ACCEPT 141 | 142 | # Reply to ICMP (ping) packets so clients can check their connections. 143 | "$iptables" -A INPUT -i "$subnet_nic" -p icmp --icmp-type echo-request -j ACCEPT 144 | #"$iptables" -A OUTPUT -i "$subnet_nic" -p icmp --icmp-type echo-reply -j ACCEPT 145 | 146 | # Allow postrouting to wan_nic (for e.g. internet access on the subnet). 147 | "$iptables" -t nat -A POSTROUTING -s "$subnet_ip" -o "$wan_nic" -j MASQUERADE 148 | 149 | # Enable forwarding from subnet_nic to wan_nic (and back via related and established connections). 150 | "$iptables" -A FORWARD -i "$subnet_nic" -s "$subnet_ip" -o "$wan_nic" -j ACCEPT 151 | "$iptables" -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 152 | 153 | # Bring down subnet_nic, configure it and bring it up again. 154 | if [[ -n $pre_up ]] 155 | then 156 | ip link set dev "$subnet_nic" down 157 | "$pre_up" 158 | fi 159 | ip link set dev "$subnet_nic" up 160 | if [[ -n $post_up ]] 161 | then 162 | "$post_up" 163 | fi 164 | 165 | # Set the static IP for subnet_nic. 166 | ip addr add "$server_ip" dev "$subnet_nic" 167 | 168 | # Ensure the lease file exists. 169 | mkdir -p -- "${dnsmasq_lease%/*}" 170 | [[ -f $dnsmasq_lease ]] || touch "$dnsmasq_lease" 171 | 172 | # Launch the DHCP server 173 | dnsmasq \ 174 | --pid-file="$dnsmasq_pid" \ 175 | --dhcp-leasefile="$dnsmasq_lease" \ 176 | --port="$dnsmasq_port" \ 177 | --interface="$subnet_nic" \ 178 | --except-interface=lo \ 179 | --bind-interfaces \ 180 | --dhcp-range="$dnsmasq_dhcp_range" \ 181 | --dhcp-authoritative \ 182 | --dhcp-option=6,"${server_ip%/*}" 183 | ;; 184 | 185 | down) 186 | # Kill the DHCP server. 187 | if [[ -f $dnsmasq_pid ]] 188 | then 189 | kill $(cat "$dnsmasq_pid") && rm "$dnsmasq_pid" 190 | fi 191 | 192 | if [[ -n $pre_down ]] 193 | then 194 | "$pre_down" 195 | fi 196 | ip addr delete "$server_ip" dev "$subnet_nic" &> /dev/null || true 197 | ip link set dev "$subnet_nic" down 198 | if [[ -n $post_down ]] 199 | then 200 | "$post_down" 201 | fi 202 | 203 | # Undo all of the changes above in reverse order. 204 | "$iptables" -D FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 205 | "$iptables" -D FORWARD -i "$subnet_nic" -s "$subnet_ip" -o "$wan_nic" -j ACCEPT 206 | "$iptables" -t nat -D POSTROUTING -s "$subnet_ip" -o "$wan_nic" -j MASQUERADE 207 | #"$iptables" -D OUTPUT -i "$subnet_nic" -p icmp --icmp-type echo-reply -j ACCEPT 208 | "$iptables" -D INPUT -i "$subnet_nic" -p icmp --icmp-type echo-request -j ACCEPT 209 | "$iptables" -D INPUT -i "$subnet_nic" -p udp --dport 67 -j ACCEPT 210 | "$iptables" -D INPUT -i "$subnet_nic" -s "$subnet_ip" -p udp --dport 53 -j ACCEPT 211 | "$iptables" -D INPUT -i "$subnet_nic" -s "$subnet_ip" -p tcp --dport 53 -j ACCEPT 212 | 213 | 214 | if [[ -n $ip_forward ]] 215 | then 216 | if [[ $ip_forward != $(cat /proc/sys/net/ipv4/ip_forward) ]] 217 | then 218 | echo $ip_forward > /proc/sys/net/ipv4/ip_forward 219 | fi 220 | else 221 | echo 0 > /proc/sys/net/ipv4/ip_forward 222 | fi 223 | ;; 224 | 225 | *) 226 | print_launch_subnet_usage 227 | exit 1 228 | ;; 229 | esac 230 | } 231 | -------------------------------------------------------------------------------- /kerndev-nat-launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail 3 | 4 | # Original author: Xyne 5 | # http://xyne.archlinux.ca/notes/network/dhcp_with_dns.html 6 | 7 | # Via https://stackoverflow.com/a/246128 8 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 9 | 10 | function print_usage() { 11 | echo "usage: $0 " 12 | } 13 | 14 | if [[ $EUID -ne 0 ]]; then 15 | echo "This script must be run as root." >&2 16 | exit 1 17 | fi 18 | 19 | if [[ -z $3 ]]; then 20 | print_usage 21 | exit 1 22 | else 23 | wan_nic="$1" 24 | subnet_nic="$2" 25 | action="$3" 26 | fi 27 | 28 | mask=/24 29 | subnet_ip=192.168.137.0$mask 30 | server_ip=192.168.137.23$mask 31 | iptables=$SCRIPT_DIR/idemptables 32 | dnsmasq_pid=/run/dnsmasq.pid 33 | dnsmasq_lease=/run/dnsmasq.lease 34 | dnsmasq_port=0 35 | dnsmasq_dhcp_range="192.168.137.100,192.168.137.150,6h" 36 | 37 | source kerndev-nat-launch-subnet.sh 38 | 39 | launch_subnet "$action" 40 | -------------------------------------------------------------------------------- /kerndev-qemu-tap-helper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail 3 | 4 | # Author: Jakub Klinkovský (Lahwaacz) 5 | # https://github.com/lahwaacz 6 | 7 | # Modified by Lorenzo Stoakes, with gratitude to Jakub's fine work! 8 | 9 | ########## Functions ########## 10 | 11 | # Uncomment the following line to get debug output. 12 | #DEBUG_OUTPUT=1 13 | function say() 14 | { 15 | [[ -n "$DEBUG_OUTPUT" ]] && echo $@ || true 16 | } 17 | 18 | function error() 19 | { 20 | echo $@ >&2 21 | } 22 | 23 | ## Check if a string represents a network interface 24 | # $1: potential interface name 25 | function is_interface() 26 | { 27 | [[ -d "/sys/class/net/$1" ]] 28 | } 29 | 30 | ## Create new TAP interface 31 | # $1: name of the interface to create 32 | function create_tap() 33 | { 34 | if ! is_interface "$1"; then 35 | say "Creating TAP interface '$1'" 36 | ip tuntap add "$1" mode tap user "$username" 37 | ip link set dev "$1" up 38 | fi 39 | } 40 | 41 | ## Delete TAP interface 42 | # $1: name of the interface to delete 43 | function del_tap() 44 | { 45 | say "Deleting TAP interface '$1'" 46 | ip link set dev "$1" down 47 | ip tuntap del "$1" mode tap 48 | } 49 | 50 | ## Check if the bridge has any interface 51 | # $1: bridge interface name 52 | function bridge_is_empty() 53 | { 54 | [[ $(ls "/sys/class/net/$1/brif" | wc -w) == "0" ]] 55 | } 56 | 57 | ## Create bridge interface if it does not exist 58 | # $1: bridge interface name 59 | function create_br() 60 | { 61 | if is_interface "$1"; then 62 | if [[ ! -d "/sys/class/net/$1/brif" ]]; then 63 | error "Interface '$1' already exists and is not a bridge" 64 | exit 1 65 | fi 66 | else 67 | say "Creating bridge interface '$1'" 68 | brctl addbr "$1" 69 | #ip link add name "$1" type bridge 70 | ip link set dev "$1" up 71 | 72 | # Xyne's excellent script to launch NAT 73 | say "Starting NAT" 74 | kerndev-nat-launch.sh "$wan_nic" "$1" up 75 | fi 76 | } 77 | 78 | ## Delete bridge interface if it exists and has no interface 79 | # $1: bridge interface name 80 | function del_br() 81 | { 82 | if bridge_is_empty "$1"; then 83 | # Xyne's excellent script to kill NAT 84 | say "Stopping NAT" 85 | kerndev-nat-launch.sh "$wan_nic" "$1" down 86 | 87 | say "Deleting bridge interface '$1'" 88 | ip link set dev "$1" down 89 | ip link delete "$1" type bridge 90 | fi 91 | } 92 | 93 | ## Add interface to the bridge 94 | # $1: bridge interface name 95 | # $2: name of the interface to add 96 | function br_add_iface() 97 | { 98 | say "Adding interface '$2' to bridge '$1'" 99 | ip link set dev "$2" promisc on up 100 | ip addr flush dev "$2" scope host #&>/dev/null 101 | ip addr flush dev "$2" scope site #&>/dev/null 102 | ip addr flush dev "$2" scope global #&>/dev/null 103 | #brctl addif $1 $2 104 | ip link set dev "$2" master "$1" 105 | # skip forwarding delay 106 | #bridge link set dev "$2" state 3 107 | #brctl setfd "$2" 0 108 | } 109 | 110 | ## Remove interface from the bridge 111 | # $1: bridge interface name 112 | # $2: name of the interface to remove 113 | function br_rm_iface() 114 | { 115 | say "Removing interface '$2' from bridge '$1'" 116 | ip link set "$2" promisc off down 117 | ip link set dev "$2" nomaster 118 | } 119 | 120 | ########## Main ############### 121 | 122 | function print_qemu_tap_helper_usage() 123 | { 124 | error "usage: $0 " 125 | error " and will be created," 126 | error " NAT from to will be set up" 127 | } 128 | 129 | if [[ $EUID -ne 0 ]]; then 130 | error "This script must be run as root." 131 | exit 1 132 | fi 133 | 134 | if [[ -z $4 ]]; then 135 | print_qemu_tap_helper_usage 136 | exit 1 137 | else 138 | username="$1" 139 | tap_nic="$2" 140 | br_nic="$3" 141 | wan_nic="$4" 142 | action="$5" 143 | fi 144 | 145 | # exit on errors 146 | set -e 147 | 148 | case "$action" in 149 | up) 150 | create_br "$br_nic" 151 | create_tap "$tap_nic" 152 | br_add_iface "$br_nic" "$tap_nic" 153 | ;; 154 | down) 155 | br_rm_iface "$br_nic" "$tap_nic" 156 | del_tap "$tap_nic" 157 | del_br "$br_nic" 158 | ;; 159 | *) 160 | print_qemu_tap_helper_usage 161 | exit 1 162 | ;; 163 | esac 164 | -------------------------------------------------------------------------------- /kerndev-rebuild: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail 3 | 4 | echo Forcing rebuild of kernel... 5 | REBUILD=y source kerndev-build $@ 6 | -------------------------------------------------------------------------------- /kerndev-run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # Networking scripts adapted from 5 | # https://github.com/lahwaacz/archlinux-dotfiles/blob/master/Scripts/qemu-launcher.sh 6 | 7 | # If argument provided it specifies a cross-compile target architecture. 8 | target_arch=${1:-$(uname -m)} 9 | 10 | tap_limit=10 11 | br_nic="qemu-br0" 12 | mac="de:ad:be:ef:f0:0f" 13 | 14 | # Functions. 15 | 16 | function get_tap_name() { 17 | for (( i=0; i < $tap_limit; i++ )); do 18 | local name="tap$i" 19 | if [[ ! -d "/sys/class/net/$name" ]]; then 20 | echo "$name" 21 | break 22 | fi 23 | done 24 | } 25 | 26 | function determine_wan_nic() 27 | { 28 | # Adapted from http://unix.stackexchange.com/a/302613 with love. 29 | ip route ls | grep default | grep -Po '(?<=(dev ))[^ ]+' || true 30 | } 31 | 32 | check_exists brctl dnsmasq 33 | 34 | tap_nic=$(get_tap_name) 35 | 36 | elevate $@ 37 | 38 | # We want access to the underlying user. 39 | [[ -z "$SUDO_USER" ]] && fatal Please run this using sudo! 40 | 41 | # Default to assuming the target_arch is an actual qemu arch. 42 | qemu=qemu-system-${target_arch} 43 | 44 | case $target_arch in 45 | arm) 46 | # Use aarch64 + backwards compatibility. 47 | qemu=qemu-system-aarch64 48 | rootfs_image_path=$KERNDEV_PATH/rootfs_arm.img 49 | ;& 50 | aarch64) 51 | kernel_image_path=$LINUX_DEV_PATH/arch/arm64/boot/Image 52 | 53 | rootfs_image_path=${rootfs_image_path:-$KERNDEV_PATH/rootfs_aarch64.img} 54 | 55 | if [[ "${target_arch}" == "$(uname -m)" ]]; then 56 | rootfs_image_path=$KERNDEV_PATH/rootfs.img 57 | 58 | arch_opts=" 59 | -machine virt 60 | -enable-kvm 61 | -cpu host 62 | -drive if=none,file=$rootfs_image_path,id=vda,format=raw 63 | -device virtio-blk-device,drive=vda" 64 | else 65 | echo $target_arch 66 | arch_opts="-machine virt 67 | -cpu cortex-a57 68 | -machine type=virt,kernel_irqchip=on 69 | -drive if=none,file=$rootfs_image_path,id=vda,format=raw 70 | -device virtio-blk-device,drive=vda" 71 | fi 72 | 73 | arch_append="console=ttyAMA0" 74 | arch_net_opts="-net nic,model=virtio,macaddr=$mac 75 | -netdev tap,ifname=$tap_nic,script=no,downscript=no,id=tap 76 | -device virtio-net-device,netdev=tap" 77 | 78 | ;; 79 | x86_64|icelake) 80 | kernel_image_path=$LINUX_DEV_PATH/arch/x86/boot/bzImage 81 | rootfs_image_path=$KERNDEV_PATH/rootfs.img 82 | 83 | if [[ "$target_arch" == "icelake" ]] || ! lsmod | grep kvm > /dev/null; then 84 | qemu=qemu-system-x86_64 85 | arch_opts="-cpu Icelake-Server 86 | -drive file=$rootfs_image_path,if=virtio,cache=none,format=raw 87 | -boot once=c" 88 | else 89 | # Throttle I/O 90 | # ,throttling.iops-total=1000,throttling.iops-size=4096 91 | 92 | arch_opts="-enable-kvm 93 | -cpu host 94 | -drive file=$rootfs_image_path,if=virtio,cache=none,format=raw 95 | -boot once=c" 96 | fi 97 | 98 | arch_append="console=ttyS0" 99 | arch_net_opts="-net nic,model=virtio,macaddr=$mac 100 | -net tap,ifname=$tap_nic,script=no,downscript=no" 101 | 102 | ;; 103 | *) 104 | fatal "unknown architecture: $target_arch" 105 | ;; 106 | esac 107 | 108 | # '-echr 0x02' moves escape key to C-b to avoid C-a getting nerfed. 109 | shared_opts="-nographic -s -echr 0x02" 110 | # We expose the kernel source as a 9p bindmount to /src/kernel in the guest. 111 | shared_opts+=" -virtfs local,path=$LINUX_DEV_PATH,mount_tag=kernel,security_model=mapped,id=kernel" 112 | # Can add the latter in case heavier log output is required -> console. 113 | shared_append="root=/dev/vda rw earlyprintk=ttyS0 nokaslr no_hash_pointers loglevel=2" #loglevel=7 systemd.journald.forward_to_console=1" 114 | 115 | numa_opts="-smp ${QEMU_CORES} -m ${QEMU_RAM} " 116 | if [[ -n "$USE_NUMA" ]]; then 117 | # Really an experimental and crazy NUMA architecture. 118 | numa_opts+="-object memory-backend-ram,size=15M,id=m0 " 119 | numa_opts+="-numa node,memdev=m0,cpus=1 " 120 | numa_opts+="-object memory-backend-ram,size=3G,id=m1 " 121 | numa_opts+="-numa node,memdev=m1,cpus=2-3 " 122 | numa_opts+="-object memory-backend-ram,size=5105M,id=m2 " 123 | numa_opts+="-numa node,memdev=m2,cpus=4-7" 124 | fi 125 | 126 | wan_nic=$(determine_wan_nic) 127 | if [[ -z "$wan_nic" ]] || ! (zgrep -q CONFIG_BRIDGE= /proc/config.gz 2>/dev/null); then 128 | echo "WARN: Couldn't determine NIC, networking will not work." >&2 129 | unset arch_net_opts 130 | else 131 | kerndev-qemu-tap-helper.sh $SUDO_USER $tap_nic $br_nic $wan_nic up 132 | trap "kerndev-qemu-tap-helper.sh $SUDO_USER $tap_nic $br_nic $wan_nic down" EXIT 133 | fi 134 | 135 | # Possible USB flags: 136 | # -usb \ 137 | # -device usb-ehci,id=ehci \ 138 | # -device usb-mouse,bus=usb-bus.0 \ 139 | 140 | $qemu $shared_opts $numa_opts $arch_opts $arch_net_opts $QEMU_CUSTOM_SETTINGS \ 141 | -kernel $kernel_image_path -append "$shared_append $arch_append" 142 | -------------------------------------------------------------------------------- /kerndev-shared.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail 3 | 4 | source kerndev-functions.sh 5 | source kerndev-defaults.sh 6 | 7 | # Fixup the LINUX_DEV_PATH. 8 | LINUX_DEV_PATH="$(find_base_linux_path $LINUX_DEV_PATH)" 9 | -------------------------------------------------------------------------------- /kerndev-update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | output_format="%-15s\t%s\n" 5 | repos_path="$(script_dir)/.repos" 6 | 7 | # Functions. 8 | 9 | # Enter $1, stash if necessary, and store previous reference in $prevref. 10 | function enterdir() 11 | { 12 | push $1 13 | 14 | prevref=$(git rev-parse --abbrev-ref=strict HEAD) 15 | # If this is 'HEAD', we can't find a matching branch so just use the 16 | # commit hash instead. 17 | [[ "$prevref" == "HEAD" ]] && prevref=$(git rev-parse HEAD) 18 | 19 | changed=$(git status --porcelain) 20 | if [[ -n "$changed" ]]; then 21 | git stash -q --include-untracked 22 | stashed=y 23 | fi 24 | } 25 | 26 | # Resore $prevref, if stashed changes, pop them. 27 | function exitdir() 28 | { 29 | git checkout -q $prevref 30 | 31 | if [[ -n "$stashed" ]]; then 32 | git stash pop -q >/dev/null 33 | unset stashed 34 | fi 35 | 36 | pop 37 | } 38 | 39 | # Update kernel tree. 40 | # 41 | # $1: Directory of kernel tree. 42 | # $2...: Branches to update. 43 | function update() 44 | { 45 | dir=$1 46 | shift 47 | 48 | enterdir $dir 49 | 50 | for branch in $@; do 51 | printf $output_format $branch $PWD 52 | 53 | git checkout --quiet $branch 54 | git pull --quiet --rebase --strategy-option=theirs 55 | done 56 | 57 | exitdir 58 | } 59 | 60 | # The .repos file is of the following format: 61 | 62 | # branch1 branch2 ... branchN 63 | # branch1 branch2 ... branchN 64 | # ... 65 | # branch1 branch2 ... branchN 66 | 67 | [[ -f "$repos_path" ]] || fatal 'Missing .repos' 68 | 69 | echo Updating linux git trees... 70 | 71 | printf $output_format "BRANCH" "DIR" 72 | 73 | while read line; do 74 | update $line 75 | done < "$repos_path" 76 | 77 | say_done 78 | -------------------------------------------------------------------------------- /kerndev-whose: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e; set -o pipefail; source kerndev-shared.sh 3 | 4 | # TODO: Get maintainer for all files in dir if no args? 5 | if [[ -z "$1" ]]; then 6 | echo usage: get_maintainer [[files...]] >&2 7 | exit 1 8 | fi 9 | 10 | function gotoroot() 11 | { 12 | while ! is_linux_dir; do 13 | cd .. 14 | 15 | if [[ $PWD = "/" ]]; then 16 | echo get_maintainer: couldn\'t find linux root >&2 17 | exit 1 18 | fi 19 | done 20 | } 21 | 22 | for file in $@; do 23 | path=$(readlink -f $file) 24 | if [[ ! -f $path ]]; then 25 | echo get_maintainer: no such file: $path >&2 26 | exit 1 27 | fi 28 | 29 | pushd $(dirname $path) > /dev/null 30 | 31 | gotoroot 32 | echo -e "$file\n" 33 | scripts/get_maintainer.pl --subsystem --git -f $path 34 | 35 | popd > /dev/null 36 | done 37 | --------------------------------------------------------------------------------