363 lines
9.5 KiB
Bash
Executable File
363 lines
9.5 KiB
Bash
Executable File
#!/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
|
|
Shimboot v1.0.0
|
|
|
|
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 <https://www.gnu.org/licenses/>.
|
|
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 "$TTY1"
|
|
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"
|
|
print_donor_selector "$rootfs_partitions"
|
|
get_donor_selection "$rootfs_partitions" "$part_path"
|
|
else
|
|
boot_target $part_path
|
|
fi
|
|
return 1
|
|
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"
|
|
}
|
|
|
|
copy_progress() {
|
|
local source="$1"
|
|
local destination="$2"
|
|
mkdir -p "$destination"
|
|
tar -cf - -C "${source}" . | pv -f | tar -xf - -C "${destination}"
|
|
}
|
|
|
|
print_donor_selector() {
|
|
local rootfs_partitions="$1"
|
|
local i=1;
|
|
|
|
echo "Choose a partition to copy firmware and modules from:";
|
|
|
|
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 [ "$part_flags" = "CrOS" ]; then
|
|
continue;
|
|
fi
|
|
|
|
echo "${i}) ${part_name} on ${part_path}"
|
|
i=$((i+1))
|
|
done
|
|
}
|
|
|
|
get_donor_selection() {
|
|
local rootfs_partitions="$1"
|
|
local target="$2"
|
|
local i=1;
|
|
read -p "Your selection: " selection
|
|
|
|
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 [ "$part_flags" = "CrOS" ]; then
|
|
continue;
|
|
fi
|
|
|
|
if [ "$selection" = "$i" ]; then
|
|
echo "selected $part_path as the donor partition"
|
|
read -p "would you like to spoof verified mode? this is useful if you're planning on using chrome os while enrolled. (y/n): " use_crossystem
|
|
|
|
if [ "$use_crossystem" = "y" ] || [ "$use_crossystem" = "n" ]; then
|
|
boot_chromeos $target $part_path $use_crossystem
|
|
return 0
|
|
else
|
|
echo "invalid selection"
|
|
sleep 1
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
i=$((i+1))
|
|
done
|
|
|
|
echo "invalid selection"
|
|
sleep 1
|
|
return 1
|
|
}
|
|
|
|
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
|
|
exec /sbin/init < "$TTY1" >> "$TTY1" 2>&1
|
|
}
|
|
|
|
boot_chromeos() {
|
|
local target="$1"
|
|
local donor="$2"
|
|
local use_crossystem="$3"
|
|
|
|
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 "mounting donor partition"
|
|
local donor_mount="/newroot/tmp/donor_mnt"
|
|
local donor_files="/newroot/tmp/donor"
|
|
mkdir -p $donor_mount
|
|
mount -o ro $donor $donor_mount
|
|
|
|
echo "copying modules and firmware to tmpfs (this may take a while)"
|
|
copy_progress $donor_mount/lib/modules $donor_files/lib/modules
|
|
copy_progress $donor_mount/lib/firmware $donor_files/lib/firmware
|
|
mount -o bind $donor_files/lib/modules /newroot/lib/modules
|
|
mount -o bind $donor_files/lib/firmware /newroot/lib/firmware
|
|
umount $donor_mount
|
|
rm -rf $donor_mount
|
|
|
|
if [ -e "/newroot/etc/init/tpm-probe.conf" ]; then
|
|
echo "applying chrome os flex patches"
|
|
mkdir -p /newroot/tmp/empty
|
|
mount -o bind /newroot/tmp/empty /sys/class/tpm
|
|
|
|
cat /newroot/etc/lsb-release | sed "s/DEVICETYPE=OTHER/DEVICETYPE=CHROMEBOOK/" > /newroot/tmp/lsb-release
|
|
mount -o bind /newroot/tmp/lsb-release /newroot/etc/lsb-release
|
|
fi
|
|
|
|
echo "patching chrome os rootfs"
|
|
cat /newroot/etc/ui_use_flags.txt | sed "/reven_branding/d" | sed "/os_install_service/d" > /newroot/tmp/ui_use_flags.txt
|
|
mount -o bind /newroot/tmp/ui_use_flags.txt /newroot/etc/ui_use_flags.txt
|
|
|
|
if [ "$use_crossystem" = "y" ]; then
|
|
echo "patching crossystem"
|
|
cp /opt/crossystem /newroot/tmp/crossystem
|
|
cp /newroot/usr/bin/crossystem /newroot/tmp/crossystem_old
|
|
mount -o bind /newroot/tmp/crossystem /newroot/usr/bin/crossystem
|
|
fi
|
|
|
|
echo "moving mounts"
|
|
move_mounts /newroot
|
|
|
|
echo "switching root"
|
|
mkdir -p /newroot/tmp/bootloader
|
|
pivot_root /newroot /newroot/tmp/bootloader
|
|
|
|
echo "starting init"
|
|
/sbin/modprobe zram
|
|
pkill frecon-lite
|
|
exec /sbin/init < "$TTY1" >> "$TTY1" 2>&1
|
|
}
|
|
|
|
main() {
|
|
echo "starting the shimboot bootloader"
|
|
|
|
enable_debug_console "$TTY2"
|
|
|
|
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
|