#!/bin/busybox sh # Copyright 2015 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # # To bootstrap the factory installer on rootfs. This file must be executed as # PID=1 (exec). # Note that this script uses the busybox shell (not bash, not dash). #original: https://chromium.googlesource.com/chromiumos/platform/initramfs/+/refs/heads/main/factory_shim/bootstrap.sh #set -x set +x invoke_terminal() { local tty="$1" local title="$2" shift shift # Copied from factory_installer/factory_shim_service.sh. echo "${title}" >>${tty} setsid sh -c "exec script -afqc '$*' /dev/null <${tty} >>${tty} 2>&1 &" } enable_debug_console() { local tty="$1" echo -e "debug console enabled on ${tty}" invoke_terminal "${tty}" "[Bootstrap Debug Console]" "/bin/busybox sh" } find_rootfs_partitions() { local disks=$(fdisk -l | sed -n "s/Disk \(\/dev\/.*\):.*/\1/p") if [ ! "${disks}" ]; then return 1 fi for disk in $disks; do local partitions=$(fdisk -l $disk | sed -n "s/^[ ]\+\([0-9]\+\).*shimboot_rootfs:\(.*\)$/\1:\2/p") if [ ! "${partitions}" ]; then continue fi for partition in $partitions; do echo "${disk}${partition}" done done } find_chromeos_partitions() { local roota_partitions="$(cgpt find -l ROOT-A)" local rootb_partitions="$(cgpt find -l ROOT-B)" if [ "$roota_partitions" ]; then for partition in $roota_partitions; do echo "${partition}:ChromeOS_ROOT-A:CrOS" done fi if [ "$rootb_partitions" ]; then for partition in $rootb_partitions; do echo "${partition}:ChromeOS_ROOT-B:CrOS" done fi } find_all_partitions() { echo "$(find_chromeos_partitions)" echo "$(find_rootfs_partitions)" } #from original bootstrap.sh move_mounts() { local base_mounts="/sys /proc /dev" local newroot_mnt="$1" for mnt in $base_mounts; do # $mnt is a full path (leading '/'), so no '/' joiner mkdir -p "$newroot_mnt$mnt" mount -n -o move "$mnt" "$newroot_mnt$mnt" done } print_license() { cat << EOF ading2210/shimboot: Boot desktop Linux from a Chrome OS RMA shim. Copyright (C) 2023 ading2210 This program 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 program 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 program. If not, see . EOF } print_selector() { local rootfs_partitions="$1" local i=1 echo "┌──────────────────────┐" echo "│ Shimboot OS Selector │" echo "└──────────────────────┘" if [ "${rootfs_partitions}" ]; then for rootfs_partition in $rootfs_partitions; do #i don't know of a better way to split a string in the busybox shell local part_path=$(echo $rootfs_partition | cut -d ":" -f 1) local part_name=$(echo $rootfs_partition | cut -d ":" -f 2) echo "${i}) ${part_name} on ${part_path}" i=$((i+1)) done else echo "no bootable partitions found. please see the shimboot documentation to mark a partition as bootable." fi echo "q) reboot" echo "s) enter a shell" echo "l) view license" } get_selection() { local rootfs_partitions="$1" local i=1 read -p "Your selection: " selection if [ "$selection" = "q" ]; then echo "rebooting now." reboot -f elif [ "$selection" = "s" ]; then reset enable_debug_console "/dev/pts/0" return 0 elif [ "$selection" = "l" ]; then clear print_license echo read -p "press [enter] to return to the bootloader menu" return 1 fi for rootfs_partition in $rootfs_partitions; do local part_path=$(echo $rootfs_partition | cut -d ":" -f 1) local part_name=$(echo $rootfs_partition | cut -d ":" -f 2) local part_flags=$(echo $rootfs_partition | cut -d ":" -f 3) if [ "$selection" = "$i" ]; then echo "selected $part_path" if [ "$part_flags" = "CrOS" ]; then echo "booting chrome os partition" boot_chromeos $part_path else boot_target $part_path fi return 0 fi i=$((i+1)) done echo "invalid selection" sleep 1 return 1 } contains_word() { local substr="$1" local str="$2" for word in $str; do if [ "$word" = "$substr" ]; then return 0 fi done return 1 } #might be useful in case we need to disable the tpm #currently this causes a kernel panic when we try to boot cros unbind_driver() { local driver_path="$1" local sys_files="$(ls $driver_path)" local excluded_files="bind uevent unbind" for file in $sys_files; do if ! contains_word "$file" "$excluded_files"; then echo "$file" > "${driver_path}/unbind" fi done } unbind_tpm() { unbind_driver "/sys/bus/spi/drivers/tpm_tis_spi" unbind_driver "/sys/bus/pnp/drivers/tpm_tis" unbind_driver "/sys/bus/platform/drivers/tpm_tis" } boot_target() { local target="$1" echo "moving mounts to newroot" mkdir /newroot mount $target /newroot move_mounts /newroot echo "switching root" mkdir -p /newroot/bootloader pivot_root /newroot /newroot/bootloader local tty="/dev/pts/0" exec /sbin/init < "$tty" >> "$tty" 2>&1 } boot_chromeos() { local target="$1" echo "WARNING: this functionality is unfinished and you will only get a bash shell" echo "starting the init system currently does not work and will cause it to hang" sleep 5 echo "mounting target" mkdir /newroot mount -o ro $target /newroot echo "mounting tmpfs" mount -t tmpfs -o mode=1777 none /newroot/tmp mount -t tmpfs -o mode=0555 run /newroot/run mkdir -p -m 0755 /newroot/run/lock echo "moving mounts" move_mounts /newroot echo "switching root" sleep 5 mkdir -p /newroot/tmp/bootloader pivot_root /newroot /newroot/tmp/bootloader local tty="/dev/pts/0" exec /bin/bash < "$tty" >> "$tty" 2>&1 } main() { echo "starting the shimboot bootloader" enable_debug_console "/dev/pts/1" local valid_partitions="$(find_all_partitions)" while true; do clear print_selector "${valid_partitions}" if get_selection "${valid_partitions}"; then break fi done } trap - EXIT main "$@" sleep 1d