1#!/bin/bash 2 3# Clear environment variables by restarting script w/bare minimum passed through 4[ -z "$NOCLEAR" ] && 5 exec env -i NOCLEAR=1 HOME="$HOME" PATH="$PATH" LINUX="$LINUX" \ 6 CROSS_COMPILE="$CROSS_COMPILE" CROSS_SHORT="$CROSS_SHORT" "$0" "$@" 7 8# assign command line NAME=VALUE args to env vars 9while [ $# -ne 0 ] 10do 11 X="${1/=*/}" 12 Y="${1#*=}" 13 [ "${1/=/}" != "$1" ] && eval "export $X=\"\$Y\"" || echo "unknown $i" 14 shift 15done 16 17# If we're cross compiling, set appropriate environment variables. 18if [ -z "$CROSS_COMPILE" ] 19then 20 echo "Building natively" 21 if ! cc --static -xc - -o /dev/null <<< "int main(void) {return 0;}" 22 then 23 echo "Warning: host compiler can't create static binaries." >&2 24 sleep 3 25 fi 26else 27 CROSS_PATH="$(dirname "$(which "${CROSS_COMPILE}cc")")" 28 CROSS_BASE="$(basename "$CROSS_COMPILE")" 29 [ -z "$CROSS_SHORT" ] && CROSS_SHORT="${CROSS_BASE/-*/}" 30 echo "Cross compiling to $CROSS_SHORT" 31 if [ -z "$CROSS_PATH" ] 32 then 33 echo "no ${CROSS_COMPILE}cc in path" >&2 34 exit 1 35 fi 36fi 37 38# set up directories (can override most of these paths on cmdline) 39TOP="$PWD/root" 40[ -z "$BUILD" ] && BUILD="$TOP/build" 41[ -z "$AIRLOCK" ] && AIRLOCK="$TOP/airlock" 42[ -z "$OUTPUT" ] && OUTPUT="$TOP/${CROSS_SHORT:-host}" 43[ -z "$ROOT" ] && ROOT="$OUTPUT/${CROSS_BASE}fs" && rm -rf "$ROOT" 44MYBUILD="$BUILD/${CROSS_BASE:-host-}tmp" 45rm -rf "$MYBUILD" && mkdir -p "$MYBUILD" || exit 1 46 47# Stabilize cross compiling by providing known $PATH contents 48if [ ! -z "$CROSS_COMPILE" ] 49then 50 if [ ! -e "$AIRLOCK/toybox" ] 51 then 52 echo === Create airlock dir 53 54 PREFIX="$AIRLOCK" KCONFIG_CONFIG="$TOP"/.airlock CROSS_COMPILE= \ 55 make clean defconfig toybox install_airlock && 56 rm "$TOP"/.airlock || exit 1 57 fi 58 export PATH="$CROSS_PATH:$AIRLOCK" 59fi 60 61### Create files and directories 62mkdir -p "$ROOT"/{etc,tmp,proc,sys,dev,home,mnt,root,usr/{bin,sbin,lib},var} && 63chmod a+rwxt "$ROOT"/tmp && ln -s usr/{bin,sbin,lib} "$ROOT" || exit 1 64 65# init script. Runs as pid 1 from initramfs to set up and hand off system. 66cat > "$ROOT"/init << 'EOF' && 67#!/bin/sh 68 69export HOME=/home 70export PATH=/bin:/sbin 71 72mountpoint -q proc || mount -t proc proc proc 73mountpoint -q sys || mount -t sysfs sys sys 74if ! mountpoint -q dev 75then 76 mount -t devtmpfs dev dev || mdev -s 77 mkdir -p dev/pts 78 mountpoint -q dev/pts || mount -t devpts dev/pts dev/pts 79fi 80 81if [ $$ -eq 1 ] 82then 83 # Setup networking for QEMU (needs /proc) 84 ifconfig eth0 10.0.2.15 85 route add default gw 10.0.2.2 86 [ "$(date +%s)" -lt 1000 ] && rdate 10.0.2.2 # or time-b.nist.gov 87 [ "$(date +%s)" -lt 10000000 ] && ntpd -nq -p north-america.pool.ntp.org 88 89 [ -z "$CONSOLE" ] && 90 CONSOLE="$(sed -n 's@.* console=\(/dev/\)*\([^ ]*\).*@\2@p' /proc/cmdline)" 91 92 [ -z "$HANDOFF" ] && HANDOFF=/bin/sh && echo Type exit when done. 93 [ -z "$CONSOLE" ] && CONSOLE=console 94 exec /sbin/oneit -c /dev/"$CONSOLE" $HANDOFF 95else 96 /bin/sh 97 umount /dev/pts /dev /sys /proc 98fi 99EOF 100chmod +x "$ROOT"/init && 101 102# /etc/passwd with both kernel special accounts (root and nobody) + guest user 103cat > "$ROOT"/etc/passwd << 'EOF' && 104root::0:0:root:/home/root:/bin/sh 105guest:x:500:500:guest:/home/guest:/bin/sh 106nobody:x:65534:65534:nobody:/proc/self:/dev/null 107EOF 108 109# /etc/group with groups corresponding to each /etc/passwd user 110cat > "$ROOT"/etc/group << 'EOF' && 111root:x:0: 112guest:x:500: 113nobody:x:65534: 114EOF 115 116# /etc/resolv.conf using Google's public nameserver. (We could use QEMU's 117# 10.0.2.2 forwarder here, but this way works in both chroot and QEMU.) 118echo "nameserver 8.8.8.8" > "$ROOT"/etc/resolv.conf || exit 1 119 120# Build toybox 121 122make clean 123if [ -z .config ] 124then 125 make defconfig 126 # Work around musl-libc design flaw. 127 [ "${CROSS_BASE/fdpic//}" != "$CROSS_BASE" ] && 128 sed -i 's/.*\(CONFIG_TOYBOX_MUSL_NOMMU_IS_BROKEN\).*/\1=y/' .config 129else 130 make silentoldconfig 131fi 132LDFLAGS=--static PREFIX="$ROOT" make toybox install || exit 1 133 134# Abort early if no kernel source specified 135if [ -z "$LINUX" ] || [ ! -d "$LINUX/kernel" ] 136then 137 echo 'No $LINUX directory, kernel build skipped.' 138 rmdir "$MYBUILD" "$BUILD" 2>/dev/null 139 exit 0 140fi 141 142# Which architecture are we building a kernel for? 143[ -z "$TARGET" ] && TARGET="${CROSS_BASE/-*/}" 144[ -z "$TARGET" ] && TARGET="$(uname -m)" 145 146# Target-specific info in an (alphabetical order) if/else staircase 147# Each target needs board config, serial console, RTC, ethernet, block device. 148 149if [ "$TARGET" == armv5l ] 150then 151 152 # This could use the same VIRT board as armv7, but let's demonstrate a 153 # different one requiring a separate device tree binary. 154 QEMU="qemu-system-arm -M versatilepb -net nic,model=rtl8139 -net user" 155 KARCH=arm 156 KARGS="console=ttyAMA0" 157 VMLINUX=arch/arm/boot/zImage 158 KERNEL_CONFIG=" 159CONFIG_CPU_ARM926T=y 160CONFIG_MMU=y 161CONFIG_VFP=y 162CONFIG_ARM_THUMB=y 163CONFIG_AEABI=y 164CONFIG_ARCH_VERSATILE=y 165 166# The switch to device-tree-only added this mess 167CONFIG_ATAGS=y 168CONFIG_DEPRECATED_PARAM_STRUCT=y 169CONFIG_ARM_ATAG_DTB_COMPAT=y 170CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND=y 171 172CONFIG_SERIAL_AMBA_PL011=y 173CONFIG_SERIAL_AMBA_PL011_CONSOLE=y 174 175CONFIG_RTC_CLASS=y 176CONFIG_RTC_DRV_PL031=y 177CONFIG_RTC_HCTOSYS=y 178 179CONFIG_PCI=y 180CONFIG_PCI_VERSATILE=y 181CONFIG_BLK_DEV_SD=y 182CONFIG_SCSI=y 183CONFIG_SCSI_LOWLEVEL=y 184CONFIG_SCSI_SYM53C8XX_2=y 185CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 186CONFIG_SCSI_SYM53C8XX_MMIO=y 187 188CONFIG_NET_VENDOR_REALTEK=y 189CONFIG_8139CP=y 190" 191 DTB=arch/arm/boot/dts/versatile-pb.dtb 192elif [ "$TARGET" == armv7l ] || [ "$TARGET" == aarch64 ] 193then 194 if [ "$TARGET" == aarch64 ] 195 then 196 QEMU="qemu-system-aarch64 -M virt -cpu cortex-a57" 197 KARCH=arm64 198 VMLINUX=arch/arm64/boot/Image 199 else 200 QEMU="qemu-system-arm -M virt" 201 KARCH=arm 202 VMLINUX=arch/arm/boot/zImage 203 fi 204 KARGS="console=ttyAMA0" 205 KERNEL_CONFIG=" 206CONFIG_MMU=y 207CONFIG_ARCH_MULTI_V7=y 208CONFIG_ARCH_VIRT=y 209CONFIG_SOC_DRA7XX=y 210CONFIG_ARCH_OMAP2PLUS_TYPICAL=y 211CONFIG_ARCH_ALPINE=y 212CONFIG_ARM_THUMB=y 213CONFIG_VDSO=y 214CONFIG_CPU_IDLE=y 215CONFIG_ARM_CPUIDLE=y 216CONFIG_KERNEL_MODE_NEON=y 217 218CONFIG_SERIAL_AMBA_PL011=y 219CONFIG_SERIAL_AMBA_PL011_CONSOLE=y 220 221CONFIG_RTC_CLASS=y 222CONFIG_RTC_HCTOSYS=y 223CONFIG_RTC_DRV_PL031=y 224 225CONFIG_NET_CORE=y 226CONFIG_VIRTIO_MENU=y 227CONFIG_VIRTIO_NET=y 228 229CONFIG_PCI=y 230CONFIG_PCI_HOST_GENERIC=y 231CONFIG_VIRTIO_BLK=y 232CONFIG_VIRTIO_PCI=y 233CONFIG_VIRTIO_MMIO=y 234 235CONFIG_ATA=y 236CONFIG_ATA_SFF=y 237CONFIG_ATA_BMDMA=y 238CONFIG_ATA_PIIX=y 239 240CONFIG_PATA_PLATFORM=y 241CONFIG_PATA_OF_PLATFORM=y 242CONFIG_ATA_GENERIC=y 243" 244elif [ "$TARGET" == i486 ] || [ "$TARGET" == i686 ] || 245 [ "$TARGET" == x86_64 ] || [ "$TARGET" == x32 ] 246then 247 if [ "$TARGET" == i486 ] 248 then 249 QEMU="qemu-system-i386 -cpu 486 -global fw_cfg.dma_enabled=false" 250 KERNEL_CONFIG="CONFIG_M486=y" 251 elif [ "$TARGET" == i686 ] 252 then 253 QEMU="qemu-system-i386 -cpu pentium3" 254 KERNEL_CONFIG="CONFIG_MPENTIUMII=y" 255 else 256 QEMU=qemu-system-x86_64 257 KERNEL_CONFIG="CONFIG_64BIT=y" 258 [ "$TARGET" == x32 ] && KERNEL_CONFIG="$KERNEL_CONFIG 259CONFIG_X86_X32=y" 260 fi 261 KARCH=x86 262 KARGS="console=ttyS0" 263 VMLINUX=arch/x86/boot/bzImage 264 CONFIG_MPENTIUMII=y 265 KERNEL_CONFIG=" 266$KERNEL_CONFIG 267 268CONFIG_UNWINDER_FRAME_POINTER=y 269 270CONFIG_PCI=y 271CONFIG_BLK_DEV_SD=y 272CONFIG_ATA=y 273CONFIG_ATA_SFF=y 274CONFIG_ATA_BMDMA=y 275CONFIG_ATA_PIIX=y 276 277CONFIG_NET_VENDOR_INTEL=y 278CONFIG_E1000=y 279CONFIG_SERIAL_8250=y 280CONFIG_SERIAL_8250_CONSOLE=y 281CONFIG_RTC_CLASS=y 282" 283elif [ "$TARGET" == mips ] || [ "$TARGET" == mipsel ] 284then 285 QEMU="qemu-system-mips -M malta" 286 KARCH=mips 287 KARGS="console=ttyS0" 288 VMLINUX=vmlinux 289 KERNEL_CONFIG=" 290CONFIG_MIPS_MALTA=y 291CONFIG_CPU_MIPS32_R2=y 292CONFIG_SERIAL_8250=y 293CONFIG_SERIAL_8250_CONSOLE=y 294 295CONFIG_PCI=y 296CONFIG_BLK_DEV_SD=y 297CONFIG_ATA=y 298CONFIG_ATA_SFF=y 299CONFIG_ATA_BMDMA=y 300CONFIG_ATA_PIIX=y 301 302CONFIG_NET_VENDOR_AMD=y 303CONFIG_PCNET32=y 304 305CONFIG_POWER_RESET=y 306CONFIG_POWER_RESET_SYSCON=y 307" 308 [ "$TARGET" == mipsel ] && 309 KERNEL_CONFIG="${KERNEL_CONFIG}CONFIG_CPU_LITTLE_ENDIAN=y" && 310 QEMU="qemu-system-mipsel -M malta" 311elif [ "$TARGET" == powerpc ] 312then 313 KARCH=powerpc 314 QEMU="qemu-system-ppc -M g3beige" 315 KARGS="console=ttyS0" 316 VMLINUX=vmlinux 317 KERNEL_CONFIG=" 318CONFIG_ALTIVEC=y 319CONFIG_PPC_PMAC=y 320CONFIG_PPC_OF_BOOT_TRAMPOLINE=y 321 322CONFIG_IDE=y 323CONFIG_IDE_GD=y 324CONFIG_IDE_GD_ATA=y 325CONFIG_BLK_DEV_IDE_PMAC=y 326CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y 327 328CONFIG_MACINTOSH_DRIVERS=y 329CONFIG_ADB=y 330CONFIG_ADB_CUDA=y 331 332CONFIG_NET_VENDOR_NATSEMI=y 333CONFIG_NET_VENDOR_8390=y 334CONFIG_NE2K_PCI=y 335 336CONFIG_SERIO=y 337CONFIG_SERIAL_PMACZILOG=y 338CONFIG_SERIAL_PMACZILOG_TTYS=y 339CONFIG_SERIAL_PMACZILOG_CONSOLE=y 340CONFIG_BOOTX_TEXT=y 341" 342elif [ "$TARGET" == powerpc64le ] 343then 344 KARCH=powerpc 345 QEMU="qemu-system-ppc64 -M pseries -vga none" 346 KARGS="console=/dev/hvc0" 347 VMLINUX=vmlinux 348 KERNEL_CONFIG="CONFIG_PPC64=y 349CONFIG_PPC_PSERIES=y 350CONFIG_CPU_LITTLE_ENDIAN=y 351CONFIG_PPC_OF_BOOT_TRAMPOLINE=y 352 353CONFIG_BLK_DEV_SD=y 354CONFIG_SCSI_LOWLEVEL=y 355CONFIG_SCSI_IBMVSCSI=y 356CONFIG_ATA=y 357 358CONFIG_NET_VENDOR_IBM=y 359CONFIG_IBMVETH=y 360CONFIG_HVC_CONSOLE=y 361 362# None of this should be necessary 363CONFIG_PPC_TRANSACTIONAL_MEM=y 364CONFIG_PPC_DISABLE_WERROR=y 365CONFIG_SECTION_MISMATCH_WARN_ONLY=y 366" 367elif [ "$TARGET" = s390x ] 368then 369 QEMU="qemu-system-s390x" 370 KARCH=s390 371 VMLINUX=arch/s390/boot/bzImage 372 KERNEL_CONFIG=" 373CONFIG_MARCH_Z900=y 374CONFIG_PACK_STACK=y 375CONFIG_NET_CORE=y 376CONFIG_VIRTIO_NET=y 377CONFIG_VIRTIO_BLK=y 378CONFIG_SCLP_TTY=y 379CONFIG_SCLP_CONSOLE=y 380CONFIG_SCLP_VT220_TTY=y 381CONFIG_SCLP_VT220_CONSOLE=y 382CONFIG_S390_GUEST=y 383" 384elif [ "$TARGET" == sh4 ] 385then 386 QEMU="qemu-system-sh4 -M r2d -serial null -serial mon:stdio" 387 KARCH=sh 388 KARGS="console=ttySC1 noiotrap" 389 VMLINUX=arch/sh/boot/zImage 390 KERNEL_CONFIG=" 391CONFIG_CPU_SUBTYPE_SH7751R=y 392CONFIG_MMU=y 393CONFIG_MEMORY_START=0x0c000000 394CONFIG_VSYSCALL=y 395CONFIG_SH_FPU=y 396CONFIG_SH_RTS7751R2D=y 397CONFIG_RTS7751R2D_PLUS=y 398CONFIG_SERIAL_SH_SCI=y 399CONFIG_SERIAL_SH_SCI_CONSOLE=y 400 401CONFIG_PCI=y 402CONFIG_NET_VENDOR_REALTEK=y 403CONFIG_8139CP=y 404 405CONFIG_PCI=y 406CONFIG_BLK_DEV_SD=y 407CONFIG_ATA=y 408CONFIG_ATA_SFF=y 409CONFIG_ATA_BMDMA=y 410CONFIG_PATA_PLATFORM=y 411 412CONFIG_BINFMT_ELF_FDPIC=y 413CONFIG_BINFMT_FLAT=y 414 415#CONFIG_SPI=y 416#CONFIG_SPI_SH_SCI=y 417#CONFIG_MFD_SM501=y 418 419#CONFIG_RTC_CLASS=y 420#CONFIG_RTC_DRV_R9701=y 421#CONFIG_RTC_DRV_SH=y 422#CONFIG_RTC_HCTOSYS=y 423" 424else 425 echo "Unknown \$TARGET" 426 exit 1 427fi 428 429# Write the miniconfig file 430{ 431 echo "# make ARCH=$KARCH allnoconfig KCONFIG_ALLCONFIG=$TARGET.miniconf" 432 echo "# make ARCH=$KARCH -j \$(nproc)" 433 echo "# boot $VMLINUX" 434 echo 435 echo "$KERNEL_CONFIG" 436 437 # Generic options for all targets 438 439 echo " 440# CONFIG_EMBEDDED is not set 441CONFIG_EARLY_PRINTK=y 442CONFIG_BINFMT_ELF=y 443CONFIG_BINFMT_SCRIPT=y 444CONFIG_NO_HZ=y 445CONFIG_HIGH_RES_TIMERS=y 446 447CONFIG_BLK_DEV=y 448CONFIG_BLK_DEV_INITRD=y 449CONFIG_RD_GZIP=y 450 451CONFIG_BLK_DEV_LOOP=y 452CONFIG_EXT4_FS=y 453CONFIG_EXT4_USE_FOR_EXT2=y 454CONFIG_VFAT_FS=y 455CONFIG_FAT_DEFAULT_UTF8=y 456CONFIG_MISC_FILESYSTEMS=y 457CONFIG_SQUASHFS=y 458CONFIG_SQUASHFS_XATTR=y 459CONFIG_SQUASHFS_ZLIB=y 460CONFIG_DEVTMPFS=y 461CONFIG_DEVTMPFS_MOUNT=y 462CONFIG_TMPFS=y 463CONFIG_TMPFS_POSIX_ACL=y 464 465CONFIG_NET=y 466CONFIG_PACKET=y 467CONFIG_UNIX=y 468CONFIG_INET=y 469CONFIG_IPV6=y 470CONFIG_NETDEVICES=y 471#CONFIG_NET_CORE=y 472#CONFIG_NETCONSOLE=y 473CONFIG_ETHERNET=y 474" 475} > "$OUTPUT/miniconfig-$TARGET" 476 477# Write the qemu launch script 478echo "$QEMU -nographic -no-reboot -m 256" \ 479 "-append \"panic=1 HOST=$TARGET $KARGS\"" \ 480 "-kernel $(basename "$VMLINUX") -initrd ${CROSS_BASE}root.cpio.gz" \ 481 ${DTB:+-dtb "$(basename "$DTB")"} '"$@"' \ 482 > "$OUTPUT/qemu-$TARGET.sh" && 483chmod +x "$OUTPUT/qemu-$TARGET.sh" && 484 485echo "Build linux for $KARCH" 486 487# Snapshot Linux source dir and clean it 488cp -sfR "$LINUX" "$MYBUILD/linux" && pushd "$MYBUILD/linux" > /dev/null || 489 exit 1 490 491# Build kernel 492make distclean && 493make ARCH=$KARCH allnoconfig KCONFIG_ALLCONFIG="$OUTPUT/miniconfig-$TARGET" && 494make ARCH=$KARCH CROSS_COMPILE="$CROSS_COMPILE" -j $(nproc) || exit 1 495 496# If we have a device tree binary, save it for QEMU. 497if [ ! -z "$DTB" ] 498then 499 cp "$DTB" "$OUTPUT/$(basename "$DTB")" || exit 1 500fi 501 502cp "$VMLINUX" "$OUTPUT/$(basename "$VMLINUX")" && cd .. && rm -rf linux && 503 popd || exit 1 504rmdir "$MYBUILD" "$BUILD" 2>/dev/null 505 506# package root filesystem for initramfs. 507# we do it here so module install can add files (not implemented yet) 508echo === create "${CROSS_BASE}root.cpio.gz" 509 510(cd "$ROOT" && find . | cpio -o -H newc | gzip) > \ 511 "$OUTPUT/${CROSS_BASE}root.cpio.gz" 512