#!/usr/bin/env zsh # shellcheck shell=bash # Copyright (c) 2016-2021 Ivan J. # This file is part of libdevuansdk # # This source code is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this source code. If not, see . build_metal_dist() { fn build_metal_dist req=(arch) req+=(workdir strapdir disk_name) ckreq || return 1 notice "installing complete dist" act "add release symlink to debootstrap scripts." if [[ ! -f /usr/share/debootstrap/scripts/${release} ]]; then ln -sf /usr/share/debootstrap/scripts/ceres \ /usr/share/debootstrap/scripts/${release} fi image_partition_disk_zfs || { zerr; wrapup } image_format_partitions_zfs || { zerr; wrapup } bootstrap_complete_base-wrapper || { zerr; wrapup } blend_preinst || { zerr; wrapup } blend_postinst || { zerr; wrapup } } build_image_dist() { fn build_image_dist req=(arch size parted_type) case "$parted_type" in gpt) req+=(gpt_boot gpt_root) ;; dos) req+=(parted_boot parted_root) ;; *) die "Unknown parted_type: $parted_type. Supported is gpt|dos." zerr; return 1 ;; esac req+=(workdir strapdir image_name) ckreq || return 1 notice "building complete dist image" act "$image_name" bootstrap_complete_base || { zerr; wrapup } blend_preinst || { zerr; wrapup } image_prepare_raw || { zerr; wrapup } image_partition_raw_${parted_type} || { zerr; wrapup } build_kernel_${arch} || { zerr; wrapup } blend_postinst || { zerr; wrapup } rsync_to_raw_image || { zerr; wrapup } image_pack_dist || { zerr; wrapup } } build_arm_dist() { fn build_arm_dist req=(workdir strapdir os arch size parted_type) case "$parted_type" in gpt) req+=(gpt_boot gpt_root) ;; dos) req+=(parted_boot parted_root) ;; *) die "Unknown parted_type: $parted_type. Supported is gpt|dos." zerr; return 1 ;; esac ckreq || return 1 notice "Building complete Arm image(s)" bootstrap_complete_base-wrapper || { zerr; return 1; } blend_preinst || { zerr; return 1; } image_prepare_raw || { zerr; return 1; } image_connect_raw || { zerr; return 1; } image_partition_raw_${parted_type} || { zerr; return 1; } image_format_partitions || { zerr; return 1; } build_kernel_${arch} || { zerr; return 1; } image_mount || { zerr; return 1; } strapdir_to_image || { zerr; return 1; } blend_postinst || { zerr; return 1; } image_umount || { zerr; return 1; } image_disconnect_raw || { zerr; return 1; } image_pack_dist || { zerr; return 1; } clean_strapdir || { zerr; return 1; } } copy-root-overlay() { fn copy-root-overlay "(override)" req=(strapdir device_name bootpart_partuuid R) ckreq || return 1 [[ -d $R/extra/generic-root ]] && notice "copying generic-root" && \ sudo cp -rfv $R/extra/generic-root/* $strapdir sudo sed -e "s/{{{BOOTFS}}}/$bootfs/" -i "$strapdir/etc/fstab" sudo sed -e "s/\/dev\/mmcblk0p1/PARTUUID=$bootpart_partuuid/" -i "$strapdir/etc/fstab" [[ -d $R/extra/$device_name ]] && \ notice "copying ${device_name}-root" && \ sudo cp -rfv $R/extra/$device_name/* $strapdir return 0 } # Overide the post 'debootstrap stage 2' placeholder function of zlib/debootstrap # bootstrap_complete_base. # The default is just to return 0 blend_bootstrap_setup() { fn blend_bootstrap_setup "noop" return 0 } # the local bootstrap wrapper just adds an options variable # via an alias to the debootstrap command bootstrap_complete_base-wrapper() { mkdir -p "$debootstrap_cache" alias debootstrap='debootstrap \ --cache-dir="$debootstrap_cache" \ --exclude="$debootstrap_purge_packages" \ ${debootstrap_options}' bootstrap_complete_base } image_partition_raw_gpt() { fn image_partition_raw_gpt req=(workdir image_name gpt_boot gpt_root bootpart_partuuid rootpart_partuuid) ckreq || return 1 notice "partitioning raw gpt image..." notice "workdir: $workdir" notice "image_name: $image_name" notice "gpt_boot: $gpt_boot" notice "gpt_root: $gpt_root" parted $workdir/${image_name}.img --script -- mklabel gpt || zerr cgpt repair $workdir/${image_name}.img cgpt create -z $workdir/${image_name}.img || zerr cgpt create $workdir/${image_name}.img || zerr notice 'cgpt add -i 1 -t kernel -b ${gpt_boot[1]} \ -s ${gpt_boot[2]} \ -l kernel -S 1 -T 5 -P 10 $workdir/${image_name}.img' notice "cgpt add -i 1 -t kernel -b ${gpt_boot[1]} \ -s ${gpt_boot[2]} \ -l kernel -S 1 -T 5 -P 10 $workdir/${image_name}.img" cgpt add -i 1 -t kernel -b ${gpt_boot[1]} \ -s ${gpt_boot[2]} \ -l kernel -S 1 -T 5 -P 10 $workdir/${image_name}.img notice 'cgpt add -i 2 -t data -b ${gpt_root[1]} \ -s $(expr $(cgpt show $workdir/${image_name}.img | \ awk "/Sec GPT table/ {print $1}") - ${gpt_root[1]}) \ -l Root $workdir/${image_name}.img' notice "cgpt add -i 2 -t data -b ${gpt_root[1]} \ -s $(expr $(cgpt show $workdir/${image_name}.img | \ awk '/Sec GPT table/ {print $1}') - ${gpt_root[1]}) \ -l Root $workdir/${image_name}.img" cgpt add -i 2 -t data -b ${gpt_root[1]} \ -s $(expr $(cgpt show $workdir/${image_name}.img | \ awk '/Sec GPT table/ {print $1}') - ${gpt_root[1]}) \ -l Root $workdir/${image_name}.img findloopdev bootpart="${loopdevice}p1" rootpart="${loopdevice}p2" bootpart_partuuid=$(blkid -s PARTUUID -o value ${bootpart}) rootpart_partuuid=$(blkid -s PARTUUID -o value ${rootpart}) image_format_partitions } ## Override the helper function: # takes the 'apt-get -f' out of the loop so that dependency provided by other # debs can be resolved. # inside the loop it just uninstalls the deb because of unfullfilled deps. install-custdebs() { fn install-custdebs "(override)" req=(R strapdir custom_deb_packages) ckreq || return 1 sudo mkdir -p ${strapdir}/debs sudo cp $R/extra/custom-packages/*.deb ${strapdir}/debs/ cat <<-EOF | sudo tee ${strapdir}/install-debs >/dev/null #!/bin/sh cd /debs for deb in ${custom_deb_packages}; do dpkg -i \$deb done apt-get --yes --force-yes -f install cd / apt-get --yes --force-yes autoremove #rm -rf /debs EOF chroot-script -d install-debs } ## Added function: # In the style of install-custdebs above but for a collection of arbitrary # scripts placed in a # directory alongside the blend custom debs called automate. # The scripts are copied from the blends scripts directory to extra/custom-scripts # in blend_preinst() above. # Called after install-customdebs because some need checkinstall which disappears # from archives. install-custscripts() { fn install-custscripts req=(R strapdir custom_scripts) ckreq || return 1 sudo mkdir -p ${strapdir}/var/tmp/automate sudo cp $R/extra/custom-scripts/*.sh ${strapdir}/var/tmp/automate/ cat <<-EOF | sudo tee ${strapdir}/install-scripts >/dev/null #!/bin/sh cd /var/tmp/automate for script in ${custom_scripts}; do touch \${script}.log bash \$script done apt-get --yes --force-yes -f install cd / apt-get --yes --force-yes autoremove #rm -rf /var/tmp/automate EOF chroot-script -d install-scripts } copy-kernel-config() { fn copy-kernel-config "(override)" req=(device_name gitbranch) ckreq || return 1 notice "copying available ${gitbranch} kernel config for ${device_name}" notice "cp -f $R/boards/kernel-configs/${device_name}.config_${gitbranch} \ $R/tmp/kernels/$device_name/${device_name}-linux_$gitbranch/.config" cp -f $R/boards/kernel-configs/${device_name}.config_${gitbranch} \ $R/tmp/kernels/$device_name/${device_name}-linux_$gitbranch/.config } ## Override the helper function: # Allow an alternative skel directory, defaults to /etc/skel add-user() { fn add-user req=(strapdir username userpass user_shell) ckreq || return 1 notice "adding user $user:$pass using $skel and shell $default_shell" cat <<-EOF | sudo tee ${strapdir}/add-user >/dev/null #!/bin/sh set -x if [ $(id -u ${username} 2>&1 >/dev/null) ]; then echo "user not present, creating account." sudo useradd --create-home \ --shell $usershell \ --groups $usergroups \ --password $(openssl passwd -1 $userpass) \ --skel ${user_skel:-/etc/skel} \ $username echo "${username}:${userpass}" | chpasswd usermod -a -G ${user_groups} ${username} if grep -q "${user_shell}" /etc/shells; then usermod --shell "${user_shell}" "${username}" else echo "${user_shell} is not available, leaving unchanged." fi fi EOF chroot-script add-user || { zerr; return 0; } } ## apt related functions # point apt at a local apt-proxy like apt-cacher-ng enable_apt-proxy() { fn enable_apt-proxy req=(strapdir apt_proxy) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/add_apt-proxy #!/bin/sh cat > '/etc/apt/apt.conf.d/02proxy' << 'FOE' Acquire::http { Proxy "${apt_proxy}"; }; FOE EOF chroot-script add_apt-proxy || zerr } disable_apt-proxy() { fn disable_apt-proxy req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/del_apt-proxy #!/bin/sh rm -f /etc/apt/apt.conf.d/02proxy EOF chroot-script del_apt-proxy || zerr } # When the release changes its suite (ie. from stable to oldstable) by default # apt asks for explicite acceptance, which you might not want in your image, turn # this on and off. enable_apt-allow-releaseinfo-change() { fn enable_apt-allow-releaseinfo-change req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/add_apt-releaseinfo-change #!/bin/sh cat > '/etc/apt/apt.conf.d/10no-check-valid-until' << 'FOE' Acquire::AllowReleaseInfoChange::Suite "true"; FOE EOF chroot-script add_apt-releaseinfo-change || zerr } disable_apt-allow-releaseinfo-change() { fn disable_apt-allow-releaseinfo-change req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/del_apt-allow-releaseinfo-change #!/bin/sh # rm -f /etc/apt/apt.conf.d/10no-check-valid-until EOF chroot-script del_apt-allow-releaseinfo-change || zerr } # apt checks the valid-util and refuses to install from repositories that are too # old, which you might not want if building an old release, turn this on or off. disable_apt-valid-until() { fn disable_apt-valid-until req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/add_apt-check-valid #!/bin/sh cat > '/etc/apt/apt.conf.d/10no-check-valid-until' << 'FOE' Acquire::Check-Valid-Until "false"; FOE EOF chroot-script add_apt-check-valid || zerr } enable_apt-valid-until() { fn enable_apt-valid-until req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/del_apt-check-valid #!/bin/sh rm -f /etc/apt/apt.conf.d/10no-check-valid-until EOF chroot-script del_apt-check-valid || zerr } # Overide the sdk version of this function to prevent deletion prior to unpacking # the cpio as we have mountpoints in place when installing to hardrive. bootstrap_cpio_unpack() { fn bootstrap_cpio_unpack "$*" req=(_bootstrap_cpio strapdir) local _bootstrap_cpio="$1" ckreq || return 1 notice "Unpacking bootstrap cpio archive: $_bootstrap_cpio" #sudo rm -rf "${strapdir}"/* pushd "$strapdir" || { zerr; return 1; } zcat "$_bootstrap_cpio" | sudo cpio -idmn --format=newc || { zerr; return 1; } popd sudo mkdir -p "$strapdir"/{boot,dev,proc,sys} } image_partition_disk_zfs() { fn image_partition_disk_zfs req=(strapdir disk_name efi_start efi_part_size swap_part_size boot_part_size available_disks) ckreq || return 1 notice "partitioning disks" # See: https://didrocks.fr/2020/06/11/zfs-focus-on-ubuntu-20.04-lts-zsys-partition-layout/ for disk in "${available_disks[@]}"; do local TARGET="/dev/disk/by-id/${disk}" act "partitioning ${TARGET}" /sbin/sgdisk --zap-all ${TARGET} act "Partition 1 - Create partition using start and end values for partitioning the 'Bios boot' partition." FIRST_USABLE_SECTOR=34 ((ENDSECTOR = ${efi_start} - 1)) /sbin/sgdisk --print --set-alignment=1 --new=1:${FIRST_USABLE_SECTOR}:${ENDSECTOR} ${TARGET} /sbin/sgdisk --print --change-name=1:"BIOS_Boot_Partition" --typecode=1:EF02 ${TARGET} act "Partition 2 - Create partition using start and end values for partitioning the 'EFI' partition." STARTSECTOR=${efi_start} /sbin/sgdisk --print --set-alignment=${STARTSECTOR} --mbrtogpt --new=2:${STARTSECTOR}:+${efi_part_size} ${TARGET} /sbin/sgdisk --print --change-name=2:"EFI_System_Partition" --typecode=2:EF00 ${TARGET} act "Partition 3 - Create partition using start and end values for partitioning the 'swap' partition." STARTSECTOR=`/sbin/sgdisk --first-in-largest ${TARGET}|sed -sn 2p` /sbin/sgdisk --print --new=3:${STARTSECTOR}:+${swap_part_size} ${TARGET} /sbin/sgdisk --print --change-name=3:"Linux_swap" --typecode=3:8200 ${TARGET} act "Partition 4 - upto 2GB partition for boot." STARTSECTOR=`/sbin/sgdisk --first-in-largest ${TARGET}|sed -sn 2p` /sbin/sgdisk --print --new=4:${STARTSECTOR}:+${boot_part_size} ${TARGET} /sbin/sgdisk --print --change-name=4:boot --typecode=4:BE00 ${TARGET} act "Partition 5 - the main partition for root." /sbin/sgdisk --print --largest-new=5 ${TARGET} /sbin/sgdisk --print --change-name=5:root --typecode=5:BF00 ${TARGET} act "Reread the current partition tables with partprobe." # the second drive fails to update the kernel until reboot so added 2> partprobe ${TARGET} 2>/dev/null || true #partx --update ${TARGET} #kpartx -a ${TARGET} #hdparm -z ${TARGET} #blockdev --rereadept ${TARGET} #udevadm trigger --subsystem-match=block; udevadm settle --exit-if-exists=/dev/${TARGET}-part5 #echo 1 > /sys/block/sdX/device/rescan done } image_format_partitions_zfs() { fn image_format_partitions_zfs req=(disk_name available_disks efi_partitions swap_partitions root_part_number boot_part_number rpool_name bpool_name zpool_cache_dir strapdir) ckreq || return 1 act "format available efi partitions to vfat." for efi_partition in "${efi_partitions[@]}"; do act "format the efi partition to vfat." mkfs.fat -F32 ${efi_partition} done act "mkswap on available swap partitions." for swap_partition in "${swap_partitions[@]}"; do notice "making swap on ${swap_partition}" mkswap ${swap_partition} done notice "formatting zfs partitions..." # for disk in "${available_disks[@]}"; do # gdisk -l /dev/disk/by-id/${disk} # done act "udev is slow recognizing new partitions so trigger sleep for 10 seconds" sleep 10 # create a separate boot pool for /boot with the features limited to only # those that GRUB supports allowing the root pool to use any/all features. if [[ ${raid} == "mirror" ]]; then mirror_disk=${available_disks[2]}; fi act "create the zfs boot pool" #zpool create -f -m none \ zpool create -f \ -o cachefile=${zpool_cache_dir}/zpool.cache \ -o ashift=${ashift} -d \ -o feature@async_destroy=enabled \ -o feature@bookmarks=enabled \ -o feature@embedded_data=enabled \ -o feature@empty_bpobj=enabled \ -o feature@enabled_txg=enabled \ -o feature@extensible_dataset=enabled \ -o feature@filesystem_limits=enabled \ -o feature@hole_birth=enabled \ -o feature@large_blocks=enabled \ -o feature@lz4_compress=enabled \ -o feature@spacemap_histogram=enabled \ -o feature@zpool_checkpoint=enabled \ -O acltype=posixacl \ -O canmount=off \ -O compression=lz4 \ -O devices=off \ -O normalization=formD \ -O relatime=on \ -O xattr=sa \ -O mountpoint=legacy -o altroot=${strapdir} \ ${bpool_name} ${raid} /dev/disk/by-id/${disk_name}-part${boot_part_number} /dev/disk/by-id/${mirror_disk}-part${boot_part_number} act "create the zfs root pool" zpool create -f \ -o cachefile=${zpool_cache_dir}/zpool.cache \ -o ashift=${ashift} \ -O acltype=posixacl \ -O canmount=off \ -O compression=lz4 \ -O dnodesize=auto \ -O normalization=formD \ -O relatime=on \ -O xattr=sa \ -O mountpoint=/ -o altroot=${strapdir} \ ${rpool_name} ${raid} /dev/disk/by-id/${disk_name}-part${root_part_number} /dev/disk/by-id/${mirror_disk}-part${root_part_number} ## Physical swap used instead. # act "create the zfs zvol for swap" # zfs create -V ${swap_part_size} -b $(getconf PAGESIZE) \ # -o compression=zle \ # -o logbias=throughput \ # -o sync=always \ # -o primarycache=metadata \ # -o secondarycache=none \ # -o com.sun:auto-snapshot=false \ # ${rpool_name}/swap # mkswap -f -L "Linux swap" /dev/zvol/${rpool_name}/swap notice "zfs system installation" act "create filesystem datasets to act as containers" zfs create -o canmount=off -o mountpoint=none ${rpool_name}/ROOT zfs create -o canmount=off -o mountpoint=none ${bpool_name}/BOOT act "create filesystem datasets for the root and boot filesystems" # Create the initial boot environment and mount ${rpool_name} at /${rpool_name} zfs create -o canmount=noauto -o mountpoint=/ ${rpool_name}/ROOT/${root_name} zfs mount ${rpool_name}/ROOT/${root_name} #zfs create -o canmount=noauto -o mountpoint=/boot ${bpool_name}/BOOT/${root_name} zfs create -o mountpoint=/boot ${bpool_name}/BOOT/${root_name} ## At this point rpool directory is created in the workdir # zfs set mountpoint=/${rpool_name} ${rpool_name} TMP_EXEC_STATE=on VAR_TMP_EXEC_STATE=on notice "create datasets" act "create zfs datasets for $rpool_name" zfs create -o mountpoint=/home ${rpool_name}/home zfs create -o mountpoint=/root ${rpool_name}/home/root zfs create -o mountpoint=/space ${rpool_name}/space zfs create -o mountpoint=/opt ${rpool_name}/opt zfs create -o mountpoint=/srv ${rpool_name}/srv zfs create -o mountpoint=/usr \ -o canmount=off \ ${rpool_name}/usr zfs create -o mountpoint=/usr/share ${rpool_name}/usr/share zfs create -o mountpoint=/usr/local ${rpool_name}/usr/local zfs create -o mountpoint=/tmp \ -o setuid=off \ -o exec=${TMP_EXEC_STATE} \ -o com.sun:autosnapshot=false \ ${rpool_name}/tmp zfs create -o mountpoint=/var \ -o canmount=off \ ${rpool_name}/var zfs create -o mountpoint=/var/lib ${rpool_name}/var/lib zfs create -o mountpoint=/var/lib/virt ${rpool_name}/var/lib/virt zfs create -o mountpoint=/var/tmp \ -o setuid=off \ -o com.sun:auto-snapshot=false \ -o exec=${VAR_TMP_EXEC_STATE} \ ${rpool_name}/var/tmp zfs create -o mountpoint=/var/cache \ -o com.sun:auto-snapshot=false \ ${rpool_name}/var/cache zfs create \ -o mountpoint=/var/lib/docker \ -o com.sun:autosnapshot=false \ ${rpool_name}/docker zfs create -o mountpoint=/var/log ${rpool_name}/var/log zfs create -o mountpoint=/var/snap ${rpool_name}/var/snap zfs create -o mountpoint=/var/spool ${rpool_name}/var/spool zfs create -o mountpoint=/var/www ${rpool_name}/var/www zfs list -t all -o name,type,mountpoint,compress,exec,setuid,atime,relatime chmod 700 ${strapdir}/root chmod 1777 ${strapdir}/tmp #chmod 1777 ${strapdir}/var/tmp act "mount the efi partition on ${grub_mount} before debootstrap." mkdir -p ${strapdir}${grub_mount} mount /dev/disk/by-id/${disk_name}-part${efi_part_number} -t vfat ${strapdir}${grub_mount} act "create zpool cache file" mkdir -p ${strapdir}/etc/zfs cp ${zpool_cache_dir}/zpool.cache ${strapdir}/etc/zfs/ } use_swap_partition() { fn use_swap_partition req=(swap_partitions) ckreq || return 1 for swap_partition in "${swap_partitions[@]}"; do act "Using swapon on ${swap_partition}" swapon ${swap_partition} done } image_zfs_mount() { fn image_zfs_mount req=(strapdir disk_name rpool_name bpool_name grub_mount) ckreq || return 1 notice "image_zfs_mount" act "importing zfs pools without mounting the filesystem" zpool import -N -R ${strapdir} ${rpool_name} zpool import -N -R ${strapdir} ${bpool_name} if [[ -n $encrypt ]]; then act "loading encryption keys of ZFS datasets from imported pools" zfs load-key -a fi act "mounting zfs datasets" zfs mount -v ${rpool_name}/ROOT/${root_name} zfs mount -v ${bpool_name}/BOOT/${root_name} zfs mount -v -a act "mount efi partition to /boot/grub" mkdir -p ${strapdir}${grub_mount} mount /dev/disk/by-id/${disk_name}-part${efi_part_number} -t vfat ${strapdir}${grub_mount} act "mount system directories" devprocsys mount ${strapdir} } image_zfs_umount() { fn image_zfs_umount req=(workdir strapdir rpool_name bpool_name) ckreq || return 1 notice "umount system directories" devprocsys umount ${strapdir} act "reaping chroot processes" PREFIX=${strapdir} FOUND=0 reap() { for ROOT in /proc/*/root; do LINK=$(readlink $ROOT) if [[ "x${LINK}" != "x" ]]; then if [[ "x${LINK:0:${#PREFIX}}" = "x${PREFIX}" ]]; then PID=$(basename $(dirname "$ROOT")) act "this process is in the chroot... $PID" kill -9 "$PID" FOUND=1 fi fi done } reap if [[ "x$FOUND" = "x1" ]]; then reap fi act "umount efi partition" efi_path=/dev/disk/by-id/${disk_name}-part${efi_part_number} if [[ $(/bin/mountpoint -q -- ${efi_path}) ]]; then umount --lazy ${efi_path} fi act "umount zfs partitions" COUNT=0 while grep -q "$PREFIX" /proc/mounts; do COUNT=$(($COUNT+1)) if [ $COUNT -ge 20 ]; then echo "failed to umount $PREFIX" if [ -x /usr/bin/lsof ]; then /usr/bin/lsof "$PREFIX" fi exit 1 fi grep "$PREFIX" /proc/mounts | \ cut -d\ -f2 | LANG=C sort -r | xargs -r -n 1 umount || sleep 1 done act "export zfs pools." zpool export ${bpool_name} zpool export ${rpool_name} } get_selections() { fn get_selections req=(strapdir blend_release_path) ckreq || return 1 notice "generating package list files to ${blend_release_path}" pushd "${blend_release_path}" dpkg --get-selections > packages.list debconf-get-selections > debconf-settings.list update-alternatives --get-selections > /var/tmp/alternatives-settings.list /usr/bin/apt-mark showauto > pkgs_auto.lst /usr/bin/apt-mark showmanual > pkgs_manual.lst popd } set_selections() { fn set_selections req=(strapdir blend_release_path) ckreq || return 1 pushd "${blend_release_path}" notice "copying set selections related files to ${strapdir}/var/tmp" if [[ -f ./packages.list ]]; then cp ./packages.list ${strapdir}/var/tmp else act "no package.list found in ${blend_release_path} " exit 0 fi if [[ -f ./debconf-settings.list ]]; then cp ./debconf-settings.list ${strapdir}/var/tmp else act "no debconf-settings.list found in ${blend_release_path} " exit 0 fi if [[ -f ./alternatives-settings.list ]]; then cp ./alternatives-settings.list ${strapdir}/var/tmp else act "no alternatives-settings.list found in ${blend_release_path} " exit 0 fi if [[ -f ./pkgs_auto.lst ]]; then cp ./pkgs_auto.lst ${strapdir}/var/tmp else act "no pkgs_auto.lst found in ${blend_release_path}" fi if [[ -f ./pkgs_auto.lst ]]; then cp ./pkgs_manual.lst ${strapdir}/var/tmp else act "no pkgs_manual.lst found in ${blend_release_path}" fi popd notice "upgrading using dselect" cat <<-EOF | sudo tee "$strapdir/install-set-selections" >/dev/null #!/bin/sh dpkg --set-selections 2>&1 < /var/tmp/packages.list debconfig-set-selections 2>&1 < /var/tmp/debconf-settings.list update-alternatives --set-selections 2>&1 < /var/tmp/alternatives-settings.list apt-get -y -u dselect-upgrade if [[ -f /var/tmp/pkgs_auto.lst ]]; then apt-mark auto $(cat /var/tmp/pkgs_auto.lst) fi if [[ -f /var/tmp/pkgs_manual.lst ]]; then apt-mark manual $(cat /var/tmp/pkgs_manual.lst) fi EOF chroot-script -d install-set-selections || { zerr; return 1; } } enablessh() { fn enablessh req=(strapdir) ckreq || return 1 notice "enabling ssh access without password." act "Use ssh-copy-id default@192.168.1.x to login on reboot." act "adding or creating keys (place keys in /etc/ssh/ssh_host_rsa_key.pub)" cat <<-EOF | sudo tee "$strapdir/etc/rc.local" >/dev/null #!/bin/sh # rc.local for base images [ -f /etc/ssh/ssh_host_rsa_key.pub ] || ssh-keygen -A exit 0 EOF sudo chmod +x "$strapdir/etc/rc.local" cat <<-EOF | sudo tee "$strapdir/enablessh" >/dev/null #!/usr/bin/env zsh set -x ; exec 2>${PWD}/enablessh.log config_file="/etc/ssh/sshd_config" typeset -A rules rules=( "LoginGraceTime" "1m" "PermitRootLogin" "yes" "PasswordAuthentication" "no" "AllowUsers" "${username}" ) EOF cat <<-'EOF' | sudo tee -a "$strapdir/enablessh" >/dev/null for rule in "${(@k)rules}"; do regex="s/^#\?\(${rule}\s*\).*$/\1 ${rules[${rule}]}/" sed -i "${regex}" ${config_file}; done EOF chroot-script -d enablessh || { zerr; return 1; } } install_kernel_headers() { fn install_kernel_headers req=(strapdir kernel_version arch) ckreq || return 1 # could go in blends/devuan-desktop-live/config $extra_packages and # remove headers in blends/devuan-desktop-live/chimaera/config $purge_packages notice "install kernel headers" cat <<-EOF | sudo tee "$strapdir/install-kernel-headers" >/dev/null #!/bin/sh apt-get install -y linux-image-${kernel_version}-${arch} apt-get install -y linux-headers-${kernel_version}-${arch} apt-get -y -f install EOF chroot-script -d install-kernel-headers || { zerr; return 1; } } install_zfs() { fn install_zfs req=(strapdir rpool_name bpool_name root_name grubversion) ckreq || return 1 act "install zfs to the $strapdir" act "install the zfs packages in the correct order before dselect upgrade" cat <<-EOF | sudo tee "$strapdir/install-zfs" >/dev/null #!/bin/sh apt-get remove -y live-config && apt-get -y autoremove apt-get install -y dh-autoreconf apt-get install -y zfs-dkms zfs-initramfs zfsnap zfsutils-linux ${grubversion} busybox console-setup apt-get -y -f install # add nouveau graphics setting before updating initramfs: add to the grub commandline with update-initramfs -u # zfs_autoimport_disable is now compiled as set to 1/true by default # At module load 0=read zpool.cache 1=do not read zpool.cache #echo '# https://openzfs.github.io/openzfs-docs/Performance and Tuning/Module Parameters.html' > /etc/modprobe.d/zfs.conf #echo 'options zfs zfs_autoimport_disable=0' >> /etc/modprobe.d/zfs.conf echo 'options zfs l2arc_write_max=50331648' >> /etc/modprobe.d/zfs.conf echo 'options zfs l2arc_write_boost=100663296' >> /etc/modprobe.d/zfs.conf # Additional datasets to /etc/default/zfs not created under ROOT sed -i "s/#ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\"/" /etc/default/zfs # sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/home\"/" /etc/default/zfs sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/space\"/" /etc/default/zfs sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/tmp\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/opt\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/usr_share\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/usr_local\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_lib\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_lib_docker\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_lib_virt\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_tmp\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/usr\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var\"/" /etc/default/zfs EOF chroot-script -d install-zfs || { zerr; return 1; } } install_grub(){ fn install_grub req=(strapdir disk_name efi_partitions swap_part_number rpool_name bpool_name root_name grub_mount grub_theme grub_gfxmode) ckreq || return 1 notice "installing grub." act "move the grub theme to the grub partition, stops 'update-alternatives desktop-grub-theme' from working." mkdir -p /boot/grub/grub-themes cp -a /usr/share/desktop-base/grub-themes/${grub_theme} /boot/grub/grub-themes/ act "replace the pool name detection with zdb command in /etc/grub.d/10_linux." sed -i "s|rpool=.*|rpool=\`zdb -l \${GRUB_DEVICE} \| grep -E '[[:blank:]]name' \| cut -d\\\' -f 2\`|" $strapdir/etc/grub.d/10_linux act "change the grub kernel commandline" cat <<-EOF | sudo tee "$strapdir/write-default-grub" >/dev/null #!/bin/sh set -x # GRUB_CMDLINE_LINUX_DEFAULT="quiet resume=/dev/zvol/rpool/swap radeon:modeset=1 i915:modeset=1 cgroup_enable=memory swapaccount=1 net.ifnames=0 # set boot filesystem - duplicated by grub but misses rpool_name when grub-probe fails to read filesystem type. sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 zfs=${rpool_name}\"|" /etc/default/grub # set swap as the resume partition. sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 resume=/dev/disk/by-id/${disk_name}-part${swap_part_number}\"|" /etc/default/grub # set root - Not needed as the kernel and root are set before /etc/default/grub is added #sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 root=ZFS=${rpool_name}\/ROOT\/${root_name}\"|" /etc/default/grub # init_on_alloc=1 is a security hardening mechanism preventing a class of security issues from being exploitable. # init_on_alloc=1 causes big performance regression for zfs: ubuntu +bug/1862822 sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 init_on_alloc=0\"|" /etc/default/grub # enable udev "info" logging for block devices sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 rd.log.block=info\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 cgroup_enable=memory\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 swapaccount=1\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 net.ifnames=0\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 nouveau.modeset=1\"|" /etc/default/grub #sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 i915.modeset=1\"|" /etc/default/grub #sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 radeon.modeset=1\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 noplymouth nosplash\"|" /etc/default/grub sed -i '/^#GRUB_DISABLE_LINUX_UUID=.*/ s/.*/&\nGRUB_DISABLE_LINUX_UUID=true/' /etc/default/grub sed -i '/^#GRUB_TIMEOUT=.*/ s/.*/&\nGRUB_RECORDFAIL_TIMEOUT=5/' /etc/default/grub #sed -i "s|^#GRUB_DISABLE_LINUX_UUID=\"\(.*\)\"|GRUB_DISABLE_LINUX_UUID=\"\1 true\"|" /etc/default/grub echo "" >> /etc/default/grub echo "# Preload modules so that they are not missed." >> /etc/default/grub echo "GRUB_PRELOAD_MODULES=part_gpt" >> /etc/default/grub sed -i "s|^\(GRUB_GFXMODE=\).*|\1\"$grub_gfxmode\"|" /etc/default/grub sed -i '/^GRUB_GFXMODE=.*/ s/.*/&\nGRUB_GFXPAYLOAD_LINUX=\"keep\"/' /etc/default/grub sed -i "s|^\(GRUB_THEME=\).&|\1\"/boot/grub/grub-themes/${grub_theme}/theme.txt\"|" /etc/default/grub # debug grub sed -i "s/quiet//" /etc/default/grub #sed -i "s/#GRUB_TERMINAL/GRUB_TERMINAL/" /etc/default/grub EOF chroot-script -d write-default-grub || { zerr; return 1; } #umount -q ${strapdir}${grub_mount} if [[ -v $efi ]]; then mkdir -p ${grub_mount} act "write grub-efi to available efi partitions." for efi_partition in "${efi_partitions[@]}"; do notice "writing to efi partitions: ${efi_partitions}" if ! /bin/mountpoint -q "${strapdir}${grub_mount}"; then act "mount the primary disks efi partition under ${grub_mount}" mount ${disk_path}/${disk_name}-part${efi_part_number} ${strapdir}${grub_mount} else notice "the mountpoint ${grub_mount} already in use. Skipping mount operation." fi cat <<-EOF | sudo tee ${strapdir}/update-grub_${disk_name} > /dev/null #!/bin/sh echo "populate the ${grub_mount} with update-grub." grub-mkconfig -o ${grub_mount}/grub.cfg echo "install grub to disk name ${disk_name}, efi partition ${efi_partition}" grub-install --target=${grub_efi_target} \ --no-uefi-secure-boot \ --efi-directory=${grub_mount} \ --bootloader-id="Devuan ${release} (RAID disk ${disk_name})" \ --recheck \ --no-floppy EOF chroot-script -d update-grub_${disk_name} || { zerr; return 1; } umount ${strapdir}${grub_mount} done else mkdir -p ${grub_mount} act "write grub to available efi partitions." for disk_name in "${available_disks[@]}"; do notice "writing grub to available ${disk_name}:" if ! /bin/mountpoint -q "${strapdir}${grub_mount}"; then act "mount the primary disks efi partition under ${grub_mount}" mount ${disk_path}/${disk_name}-part${efi_part_number} ${strapdir}${grub_mount} else notice "The mount point ${grub_mount} is already in use. Skipping mount operation." fi cat <<-EOF | sudo tee ${strapdir}/update-grub_${disk_name} > /dev/null #!/bin/sh echo "populate the ${grub_mount} with update-grub." grub-mkconfig -o ${grub_mount}/grub.cfg echo "install grub-pc to ${disk_name}" grub-install --target=i386-pc /dev/disk/by-id/${disk_name} EOF chroot-script -d update-grub_${disk_name} || { zerr; return 1; } umount ${strapdir}${grub_mount} done fi } dpkg-version() { fn dpkg--version req=(R strapdir) ckreq || return 1 chroot-script bash -c "dpkg-query --show --showformat "\${Version}\n" dpkg" } apt-version() { fn apt-version req=(R strapdir) ckreq || return 1 chroot-script bash -c "dpkg-query --show --showformat "\${Version}\n" apt" } install_u-boot(){ fn install_u-boot req=(strapdir disk_name efi_partitions swap_part_number rpool_name bpool_name root_name grub_mount) ckreq || return 1 # When installing to metal we will install the os plus grub as usual and # then boot grub from u-boot written to SPI. # u-boot gets build as a part of the board definition in arm-sdk. We add # zfs support there in case we wish to boot the kernel directly later. # https://github.com/sigmaris/u-boot/wiki/RockPro64-boot-sequence # notice "installing u-boot to SPI." # The RK3399 Boot ROM will look for code with an ID block header for: # SPI flash at offset 0 bytes # eMMC at offset 0x8000 bytes (64 sectors, a sector is 0x200 bytes) # SDcard at offset 0x8000 bytes (64 sectors, a sector is 0x200 bytes) # this is where we write the idbloader.img (containing U-Boot TPL & SPL) # For SPI it must be written in rkspi format using the U-Boot mkimage tool. cat /proc/device-tree/model # Pine64 RockPro64 v2.0 cat /proc/device-tree/compatible # pine64,rockpro64-v2.0pine64,rockpro64rockchip,rk3399 cat /proc/mtd # dev: size erasesize name # mtd0: 00060000 00001000 "u-boot-spl" # mtd1: 00398000 00001000 "u-boot" # mtd2: 00008000 00001000 "u-boot-env" # mtd3: 00c00000 00001000 "user" lsmtd # DEVICE MAJ:MIN NAME TYPE SIZE # mtd0 90:0 u-boot-spl nor 384K # mtd1 90:2 u-boot nor 3.6M # mtd2 90:4 u-boot-env nor 32K # mtd3 90:6 user nor 12M mtdinfo # Count of MTD devices: 4 # Present MTD devices: mtd0, mtd1, mtd2, mtd3 # Sysfs interface supported: yes sudo mtdinfo /dev/mtd0 # mtd0 # Name: u-boot-spl # Type: nor # Eraseblock size: 4096 bytes, 4.0 KiB # Amount of eraseblocks: 96 (393216 bytes, 384.0 KiB) # Minimum input/output unit size: 1 byte # Sub-page size: 1 byte # Character device major/minor: 90:0 # Bad blocks are allowed: false # Device is writable: true sudo mtd_debug info /dev/mtd0 # mtd.type = MTD_NORFLASH # mtd.flags = MTD_CAP_NORFLASH # mtd.size = 393216 (384K) # mtd.erasesize = 4096 (4K) # mtd.writesize = 1 # mtd.oobsize = 0 # regions = 0 build_atf(){ fn build_atf req=(strapdir atf_branch atfgit compiler) ckreq || return 1 notice "Build arm-trusted-firmware bl31.elf for rk3399." git config --global user.name 'Build Robot' git config --global user.email 'noemail@example.com' git clone --depth 1 -b "$atf_branch" "$atfgit" "$R/tmp/kernels/arm-trusted-firmware" || zerr pushd "$R/tmp/kernels/arm-trusted-firmware" #git am ../atf-rk3399-baudrate.patch make realclean make -j$(nproc) CROSS_COMPILE=$compile PLAT=rk3399 DEBUG=1 bl31 || zerr popd act "Publish arm-trusted-firmware bl31.elf" mkdir -p "$R/dist" cp "$R/tmp/kernels/arm-trusted-firmware/build/rk3399/debug/bl31/bl31.elf" "$R/dist" } build_uboot(){ fn build_u-boot req=(strapdir ubootgit uboot_branch MAKEOPTS) ckreq || return 1 defconfig=rockpro64-rk3399_defconfig img1type=rksd # Rockchip SD Boot Image img1name=idbloader.img img2name=u-boot.itb artifact=u-boot notice "Build u-boot" "FIXME: AUTOBOOT was too chatty at the configure stage with these entries do its disabled for now." git clone --depth 1 "$ubootgit" -b "$uboot_branch" "$R/tmp/kernels/u-boot-rockpro64" || zer pushd "$R/tmp/kernels/u-boot-rockpro64" make mrproper make $(defconfig) act "apply local changes to defconfig." "$R/tmp/kernels/rockpro64/rockpro64-linux/scripts/config" --file .config \ --enable CONFIG_CMD_ZFS \ --enable CONFIG_CMD_BOOTMENU \ --enable CONFIG_MENU \ --enable CONFIG_MENU_SHOW \ --enable CONFIG_CFB_CONSOLE_ANSI \ --enable CONFIG_CMD_BOOTEFI \ --enable CONFIG_EFI_LOADER \ --enable CONFIG_EFI_SECURE_BOOT \ --enable CONFIG_CMD_BOOTM \ --enable CONFIG_BOOTM_EFI \ --enable CONFIG_BOOTM_LINUX \ --enable CONFIG_BOOTM_NETBSD \ --enable CONFIG_BLK \ --enable CONFIG_VERSION_VARIABLE \ --enable CONFIG_PARTITIONS \ --enable CONFIG_DM_VIDEO #--enable CONFIG_AUTOBOOT_KEYED \ #--set-val CONFIG_BOOTDELAY 30 act "apply sigmaris changes to defconfig." "$R/tmp/kernels/rockpro64/rockpro64-linux/scripts/config" --file .config \ --enable CONFIG_OF_BOARD_SETUP \ --enable CONFIG_MTD \ --enable CONFIG_CMD_MTDPARTS \ --enable CONFIG_SPL_MMC \ --enable CONFIG_SPL_SPI \ --enable CONFIG_SPI_FLASH_MTD \ --enable CONFIG_SPL_SPI_FLASH_SUPPORT \ --enable CONFIG_NVME \ --enable CONFIG_SCSI \ --enable CONFIG_DM_SCSI \ --enable CONFIG_OF_LIBFDT_OVERLAY \ --enable CONFIG_FDT_FIXUP_PARTITIONS \ --enable CONFIG_SERVERIP_FROM_PROXYDHCP \ --enable CONFIG_AHCI \ --enable CONFIG_SCSI_AHCI \ --enable CONFIG_AHCI_PCI \ --enable CONFIG_DM_KEYBOARD \ --enable CONFIG_LED \ --enable CONFIG_LED_GPIO \ --set-val CONFIG_DEFAULT_DEVICE_TREE "rk3399-rockpro64" \ --set-val CONFIG_SERVERIP_FROM_PROXYDHCP_DELAY_MS 100 \ --set-val CONFIG_MTDIDS_DEFAULT "nor0=spi0.0" \ --set-val CONFIG_MTDPARTS_DEFAULT="mtdparts=spi0.0:384k(u-boot-spl),3680k(u-boot),32k(u-boot-env),-(user)" make -j$(nproc) $MAKEOPTS ARCH=arm CROSS_COMPILE=$compiler || zerr export BL31="$R/tmp/kernels/arm-trusted-firmware/build/rk3399/debug/bl31/bl31.elf" mkdir -p "$R/dist" act "create ${img1type}_${img1name} image file." "$R/tmp/kernels/u-boot-rockpro64/tools/mkimage" \ -n rk3399 \ # set image name -T $(img1type) \ # set image type -d tpl/u-boot-tpl.bin:spl/u-boot-spl.bin \ # use image data from ${img1type}_$(img1name) # idbloader.img act "Publish ${img1type}_${image1name}" cp ${img1type}_$(img1name) "$R/dist" img1type=rkspi # Rockchip SPI Boot Image act "create ${img1type}_${img1name} image file." "$R/tmp/kernels/u-boot-rockpro64/tools/mkimage" \ -n rk3399 \ # set image name -T $(img1type) \ # set image type -d tpl/u-boot-tpl.bin:spl/u-boot-spl.bin \ # use image data from ${img1type}_$(img1name) # idbloader.img act "Publish ${img1type}_${image1name}" cp ${img1type}_$(img1name) "$R/dist" act "Publish ${image2name}" cp u-boot.itb "$R/dist"/$(img2name) # u-boot.itb popd } create_spi_image(){ act "Create single SPI image with u-boot.itb at 0x60000" padsize=$((0x60000 - 1)) img1size=$(wc -c <"$(img1name)") [ $img1size -le $padsize ] || exit 1 dd \ if=/dev/zero \ of=$(img1name) \ conv=notrunc \ bs=1 \ count=1 \ seek=$padsize cat $(img1name) u-boot.itb > "$R/dist"/spi_combined.img create-u-boot-spi-scripts "$R/tmp/kernels/u-boot-rockpro64/tools/mkimage" \ -C none \ # set compression -A arm \ # set architecture -T script \ # set image type -d scripts/flash_spi.cmd \ # use image data fro "$R/dist/flash_spi.scr" } spi_flash_img(){ fn spi_flash_img req=(strapdir) ckreq || return 1 notice "Create SD card image to flash u-boot to SPI" cp "$R/dist/flash_spi.scr boot.scr" cp "$R/dist/spi_combined.img spi_combined.img" dd \ if=/dev/zero \ of=boot.tmp \ bs=1M \ count=16 mkfs.vfat -n u-boot-script boot.tmp mcopy -sm -i boot.tmp boot.scr :: mcopy -sm -i boot.tmp spi_combined.img :: dd \ if=/dev/zero \ of=flash_spi.img \ bs=1M \ count=32 parted -s flash_spi.img mklabel gpt parted -s flash_spi.img unit s mkpart loader1 64 8063 parted -s flash_spi.img unit s mkpart loader2 16384 24575 parted -s flash_spi.img unit s mkpart boot fat16 24576 100% parted -s flash_spi.img set 3 legacy_boot on dd \ if= "$R/tmp/kernels/u-boot-rockpro64/idbloader.img" \ of=flash_spi.img \ conv=notrunc \ seek=64 dd \ if="$R/tmp/kernels/u-boot-rockpro6/u-boot.itb" \ of=flash_spi.img \ conv=notrunc \ seek=16384 dd \ if=boot.tmp \ of=flash_spi.img \ conv=notrunc \ seek=24576 gzip flash_spi.img } set-bootloader(){ fn set-bootloader req=(strapdir) ckreq || return 1 case "$1" in *-rockchip-rock64-*) SD_LOADER="$R/dist/rksd_loader.img" SPI_LOADER="$R/dist/rksd_loader.img" BOARD=rock64 ;; *-rockchip-rockpro64-*) SD_LOADER="$R/dist/rksd_loader.img" SPI_LOADER="$R/dist/rkspi_loader.img" BOARD=rockpro64 ;; *-rockchip-pinebookpro-*) SD_LOADER="$R/dist/rksd_loader.img" SPI_LOADER="$R/dist/rkspi_loader.img" BOARD=pinebookpro ;; *-rockchip-rockpi4b-*) SD_LOADER="$R/dist/rksd_loader.img" SPI_LOADER="$R/dist/rkspi_loader.img" BOARD=rockpi4b ;; *) echo "Cannot detect board from $1." exit 1 ;; esac if ! grep -qi "$BOARD" /proc/device-tree/compatible; then echo "You are currently running on different board:" echo "$(tr -d '\0' < /proc/device-tree/model || true)" echo "It may brick your device or the system unless" echo "you know what are you doing." echo "" fi } bootloader-version(){ fn bootloader-version req=(strapdir) ckreq || return 1 # FIXME: Assumes partitions number p1 or p6 and uses p1 for both version() { local DEVICE="${1/p6/p1}" echo -n "Current version: " if strings "$DEVICE" | grep "^U-Boot [a-z0-9.-]*$"; then echo -n "Board: " strings "$DEVICE" | grep -E "^board=" echo -n "FDT: " strings "$DEVICE" | grep -E "^fdtfile=" else echo "not installed on $DEVICE." fi echo } } upgrade-sd-bootloader(){ fn upgrade-sd-bootloader req=(strapdir SD_LOADER) ckreq || return 1 notice "Upgrading pre-existing bootloader." # FIXME: # extlinux, u-boot, grub, EFI # Assumes u-boot written to a mounted efi partion # Writes the rksd image only to a specific partition number on sd devices. Uses p1 if [[ $(findmnt -M /boot/efi) ]]; then MNT_DEV=$(findmnt /boot/efi -n -o SOURCE) else echo "Error: efi partition not mounted." exit 1 fi # report current version bootloader-version "$MNT_DEV" write_sd() { case "$1" in /dev/mmcblk*p6|/dev/sd*p6|/dev/mapper/loop*p6|/dev/mapper/nvme*p6) dd if="$2" of="${1/p6/p1}" ;; *) echo "Cannot detect boot device ($MNT_DEV)." exit 1 ;; esac } write_sd "$MNT_DEV" "$SD_LOADER" sync } erase-sd-bootloader(){ fn erase-sd-bootloader req=(strapdir) ckreq || return 1 notice "Erasing pre-existing bootloader." # FIXME: Writes/erases a specific partition number on sd devices. Uses p1 MNT_DEV=$(findmnt /boot/efi -n -o SOURCE) # report current version bootloader-version "$MNT_DEV" write_sd() { case "$1" in /dev/mmcblk*p6|/dev/sd*p6|/dev/mapper/loop*p6|/dev/mapper/nvme*p6) dd \ if="$2" \ of="${1/p6/p1}" ;; *) echo "Cannot detect boot device ($MNT_DEV)." exit 1 ;; esac } write_sd "$MNT_DEV" "/dev/zero" sync } write-emmc-flash(){ fn write-emmc-flash req=(strapdir) ckreq || return 1 notice "Writing u-boot to emmc." for blkdevice in $(ls -d /dev/mmcblk* | sed -n -E '/mmcblk[0-9]+$/ p' ); do if [[ -f /sys/block/${blkdevice##*/}/device/type ]]; then if [[ $(< /sys/block/${blkdevice##*/}/device/type) == MMC ]]; then emmc_blkdevice=${blkdevice} fi fi done MNT_DEV=$(findmnt / -n -o SOURCE) MNT_DEV=${MNT_DEV%p[0-9]*} if [[ "$MNT_DEV" == $emmc_blkdevice* ]]; then echo "Cannot write when running from eMMC, use: $0 --force." exit 1 fi # When booting from sdcard: # the card appears as /dev/mmcblk1 and # the emmc appears as /dev/mmcblk2 pushd "$R/tmp/kernels/u-boot-rockpro64" dd \ if="$R/dist/rksd_idbloader.img" \ of=/dev/${emmc_blkdevice} \ seek=64 dd \ if="$R/dist/u-boot.itb" \ of=/dev/${emmc_blkdevice} \ seek=16384 popd } erase-spi-flash(){ fn erase-spi-flash req=(strapdir) ckreq || return 1 notice "Erasing spi flash." # FIXME: Assumes contents of spi labels, we don't have 'loader' so fails. # mtd0: 00060000 00001000 "u-boot-spl" # mtd1: 00398000 00001000 "u-boot" # mtd2: 00008000 00001000 "u-boot-env" # mtd3: 00c00000 00001000 "user" if ! MTD=$(grep \"loader\" /proc/mtd | cut -d: -f1); then echo "loader partition on MTD is not found" return 1 fi # report current version bootloader-version "/dev/${MTD/mtd/mtdblock}" flash_erase "/dev/$MTD" 0 0 } write-spi-flash(){ fn write-spi-flash req=(strapdir) ckreq || return 1 notice "Writing spi flash." version "/dev/${MTD/mtd/mtdblock}" confirm write_nand() { if ! MTD=$(grep \"${1}\" /proc/mtd | cut -d: -f1); then echo "${1} partition on MTD is not found" exit 1 fi echo "Writing /dev/$MTD with content of $2" flash_erase "/dev/$MTD" 0 0 nandwrite "/dev/$MTD" < "$2" } write_nand u-boot-spl "$SPI_LOADER" } } # u-boot menu has been deprecated, extlinux.conf is used instead and uutomatically # updated with u-boot-update from u-boot-menu. see ARM-sdk/BOARDs/rockpro64-ayunfan. create-u-boot-menu(){ fn create-u-boot-menu req=(strapdir) ckreq || return 1 # FIXME: Need to choose a default and fix the other calls cat <<-EOF | tee scripts/boot.cmd > /dev/null setenv bootmenu_0 Boot 1. kernel=bootm 0x82000000 # Set first menu entry setenv bootmenu_1 Boot 2. kernel=bootm 0x83000000 # Set second menu entry setenv bootmenu_2 Reset board=reset # Set third menu entry setenv bootmenu_3 U-Boot boot order=boot # Set fourth menu entry bootmenu 20 # Run bootmenu with autoboot delay 20s u-boot console command sequence: from a android phone setenv bootmenu_0 "Boot LNX ARCH = setenv bootargs 'root=/dev/mmcblk0p7 rootfstype=ext4 rootwait'; \ ext2load mmc 0:2 0x1000000 /boot/zImage; ext2load mmc 0:2 0x2000000 /boot/tegra20-paz00.dtb; bootz 0x1000000 - 0x2000000;" pastbin example setenv bootargs 'mem=214M root=/dev/mmcblk0p2 noinitrd rw rootfstype=ext2 console=ttyS0,115200n8 rootwait' setenv kernelargs 'mem=214M root=/dev/mmcblk0p2 noinitrd rw rootfstype=ext2 console=ttyS0,115200n8 rootwait' saveenv display init force mmcinit 0 fatload mmc 0 0 uzImage.bin textout -1 -1 \"Commands finished. Trying to boot...\" FFFFFF bootm 0 from fat partition fatload mmc 0 0x3000000 uImage fatload mmc 0 0x2A00000 devicetree.dtb bootm 0x3000000 - 0x2A00000 zfs support zfsload [addr] [filename] [bytes] zfsload mmc 2:2 0x30007fc0 /rpool/@/boot/uImage grub from u-boot ext4load mmc 0:1 0x43300000 /boot/grub/arm-uboot/core.img bootm 0x43300000 raspberrypi example setenv kernel_addr_r 2000000 setenv fdt_addr_r 1000000 setenv bootargs 'root=/dev/mmcblk0p7 rootfstype=ext4 rootwait'; \ load mmc 0:2 \$kernel_addr_r /boot/image load mmc 0:2 \$fdt_addr_r boot/dtb/bcm2837-rpi-3-b.dtb from the current spi setenv fdt_addr_r 0x01f00000 setenv kernel_addr_r 0x02080000 setenv devtype scsi setenv devnum 0 setenv distro_bootpart 2 devuan-sdk version - variables set in arm-sdk-boards/(boardname>) setenv kernel_addr_z 0x44080000 setenv kernel_addr_r 0x43000000 setenv fdt_addr_r 0x42000000 setenv ramdisk_addr_r 0x43300000 setenv rootfsaddr 0x43300000 setenv devtype mmc setenv devnum 0 setenv distro_bootpart 1 qemu changes setenv console /dev/ttyS2 setenv root /dev/mmcblk0p2 setenv root /dev/vda2 setenv bootargs "consoleblank=0 root=${root} rw rootwait console=${console},1500000n8 earlycon=uart8250,mmio32,0xff1a0000 console=tty1" setenv bootargs "console=tty0 console=${console} root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4 fbcon=rotate:1" setenv bootargs "console=${console} root=/dev/vda2 mem=128M rdinit=/sbin/init" setenv fdt_addr_r 0xf5f17000 setenv devtype virtio if load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_z} Image.gz; then unzip ${kernel_addr_z} ${kernel_addr_r} if load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} rk3399-rockpro64.dtb; then booti ${kernel_addr_r} - ${fdt_addr_r}; fi; fi armbian: https://github.com/armbian/build/blob/master/config/bootscripts/boot-rockchip64.cmd efi: https://github.com/ARM-software/u-boot/blob/master/doc/README.uefi https://u-boot.readthedocs.io/en/latest/develop/uefi/uefi.html # the efi fat32 partition is mounted under /boot/efi load mmc 0:1 ${fdt_addr_r} rk3399-rockpro64.dtb load mmc 0:1 ${kernel_addr_r} \ /EFI/Devuan\ daedalus\ \(RAID\ disk\ ata-WDC_WD30EZRZ-00WN9B0_WD-WCC4E6RKKRVX\)/grubaa64.efi bootefi ${kernel_addr_r} ${fdt_addr_r} # u-boot, extlinux.conf label linux-5.0.0-rc3 kernel /Image devicetree /sun50i-a64-amarula-relic.dtb append console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait rw => load mmc 0:2 ${fdt_addr_r} boot/dtb 29830 bytes read in 14 ms (2 MiB/s) => load mmc 0:1 ${kernel_addr_r} efi/debian/grubaa64.efi reading efi/debian/grubaa64.efi 120832 bytes read in 7 ms (16.5 MiB/s) => bootefi ${kernel_addr_r} ${fdt_addr_r} efi FIT: => load mmc 0:1 ${kernel_addr_r} image.fit 4620426 bytes read in 83 ms (53.1 MiB/s) => bootm ${kernel_addr_r}#config-grub-nofdt ## Loading kernel from FIT Image at 40400000 ... Using 'config-grub-nofdt' configuration Verifying Hash Integrity ... sha256,rsa2048:dev+ OK Trying 'efi-grub' kernel subimage Description: GRUB EFI Firmware Created: 2019-11-20 8:18:16 UTC Type: Kernel Image (no loading done) Compression: uncompressed Data Start: 0x404000d0 Data Size: 450560 Bytes = 440 KiB Hash algo: sha256 Hash value: 4dbee00021112df618f58b3f7cf5e1595533d543094064b9ce991e8b054a9eec Verifying Hash Integrity ... sha256+ OK XIP Kernel Image (no loading done) ## Transferring control to EFI (at address 404000d0) ... Welcome to GRUB! initramfs example https://armtix.artixlinux.org/info/firefly-rk3399.html mkimage -A arm -T ramdisk -d mkinitramfs-linux.uimg Next, you have to create u-boot script u-boot.cmd with following contents: setenv bootargs "consoleblank=0 root=${console} rw rootwait console=ttyS2,1500000n8 earlycon=uart8250,mmio32,0xff1a0000 console=tty1" load mmc 1:1 ${fdt_addr_r} /dtbs/rockchip/rk3399-firefly.dtb load mmc 1:1 ${kernel_addr_r} /Image load mmc 1:1 ${ramdisk_addr_r} /initramfs-linux.uimg booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r} mkimage -A arm -T ramdisk -d boot.cmd boot.scr EOF "$R/tmp/kernels/u-boot-rockpro64/tools/mkimage" \ -A arm \ # set architechture -O linux \ # set operating system -T script \ # set image type -C none \ # set compression type -a 0 \ # set load address -e 0 \ # set entry point -n "ubootscript" \ # set image name -d scripts/boot.cmd \ # use image data from "$R/dist/boot.scr" } create-u-boot-spi-scripts(){ fn create-u-boot-spi-scripts req=(strapdir) ckreq || return 1 cat <<-'EOF' | tee "$R/tmp/kernels/u-boot-rockpro64/scripts/erase_spi.cmd" > /dev/null setenv blink_work 'led work on; sleep 0.1; led work off; sleep 0.1' setenv blink_diy 'led diy on; sleep 0.1; led diy off; sleep 0.1' echo "Enable SPI Flash now." run blink_work sleep 2 run blink_work sleep 2 run blink_work sleep 2 run blink_work sleep 2 run blink_work sleep 2 if sf probe; then # erase all mtd partitions containing u-boot run blink_work run blink_work run blink_work mtd erase u-boot-spl run blink_work run blink_work run blink_work mtd erase u-boot run blink_work run blink_work run blink_work mtd erase u-boot-env led work on echo "Erased U-Boot from SPI Flash." while true; do sleep 1; done else echo "Error: No SPI flash." # blink both LEDs forever while true; do run blink_diy; run blink_work; done fi EOF cat <<-'EOF' | tee "$R/tmp/kernels/u-boot-rockpro64/scripts/flash-spi.cmd" > /dev/null setenv blink_work 'led work on; sleep 0.1; led work off; sleep 0.1' setenv blink_diy 'led diy on; sleep 0.1; led diy off; sleep 0.1' run blink_work if sf probe; then run blink_work if size ${devtype} ${devnum}:${distro_bootpart} spi_combined.img; then run blink_work load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} spi_combined.img # write flash run blink_work run blink_work run blink_work sf update ${kernel_addr_r} 0 ${filesize} run blink_work run blink_work run blink_work led work on echo "Wrote U-Boot to SPI Flash successfully." while true; do sleep 1; done else echo "Error: Missing spi_combined.img" # blink red LED forever while true; do run blink_diy; sleep 0.1; done fi else echo "Error: No SPI flash." # blink both LEDs forever while true; do run blink_diy; run blink_work; done fi EOF # The procedure if you have idbloader.img and u-boot.itb on an sdcard. cat <<-'EOF' | tee tee "$R/tmp/kernels/u-boot-rockpro64/scripts/load-spi-from-usb.cmd" > /dev/null if ls usb 0:1; then if sf probe; then load usb 0:1 ${fdt_addr_r} idbloader.img sf update ${fdt_addr_r} 0 ${filesize} load usb 0:1 ${fdt_addr_r} u-boot.itb sf update ${fdt_addr_r} 60000 ${filesize} else echo "Error: No SPI flash." # blink both LEDs forever while true; do run blink_diy; run blink_work; done fi else echo "Error: No USB available." fi EOF } create-rockpro64-scripts(){ cat <<-'EOF' | tee /usr/local/sbin/rockpro64_enable_eth_gadget.sh > /dev/null #!/bin/bash set -xe # enable peripheral mode enable_dtoverlay usb0_dwc3_peripheral usb0/dwc3@fe800000 okay \ 'dr_mode="peripheral"' # reload dwc3 echo fe800000.dwc3 > /sys/bus/platform/drivers/dwc3/unbind echo fe800000.dwc3 > /sys/bus/platform/drivers/dwc3/bind # install eth gadget install_gadget RockPro64 fe800000.dwc3 ecm EOF cat <<-'EOF' | tee /usr/local/sbin/rockpro64_disable_otg.sh > /dev/null #!/bin/bash set -x # enable peripheral mode disable_dtoverlay dwc3_peripheral # reload dwc3 echo fe800000.dwc3 > /sys/bus/platform/drivers/dwc3/unbind echo fe800000.dwc3 > /sys/bus/platform/drivers/dwc3/bind # install eth gadget uninstall_gadgets EOF cat <<-'EOF' | tee /usr/local/sbin/rockpro64_reset_emmc.sh > /dev/null #!/bin/bash if [[ "$1" != "--force" ]]; then MNT_DEV=$(findmnt / -n -o SOURCE) if [[ "$MNT_DEV" == /dev/mmcblk1* ]]; then echo "Cannot reset when running from eMMC, use: $0 --force." exit 1 fi fi if [[ -d /sys/bus/platform/drivers/sdhci-arasan/fe330000.sdhci ]]; then echo "Unbinding..." echo fe330000.sdhci > /sys/bus/platform/drivers/sdhci-arasan/unbind fi echo "Binding..." echo fe330000.sdhci > /sys/bus/platform/drivers/sdhci-arasan/bind echo "Finished" EOF cat <<-'EOF' | tee /usr/local/sbin/rockpro64_reset_spi_flash.sh > /dev/null #!/bin/bash if [[ -d /sys/bus/platform/drivers/rockchip-spi/ff1d0000.spi ]]; then echo "Unbinding..." echo ff1d0000.spi > /sys/bus/platform/drivers/rockchip-spi/unbind fi echo "Binding..." echo ff1d0000.spi > /sys/bus/platform/drivers/rockchip-spi/bind echo "Finished" EOF } #----------- #zfs specific commands can be seen in the boot loader prompt using # UBOOT #help # # zfsls - list files in a directory (default /) # zfsload- load binary file from a ZFS file system # #2. To list the files in zfs pool, device or partition, execute # zfsls [POOL/@/dir/file] # For example: # UBOOT #zfsls mmc 0:5 /rpool/@/usr/bin/ # #3. To read and load a file from an ZFS formatted partition to RAM, execute # zfsload [addr] [filename] [bytes] # For example: # UBOOT #zfsload mmc 2:2 0x30007fc0 /rpool/@/boot/uImage #: