diff --git a/boards/librem13v2.config b/boards/librem13v2.config index 1b6a5333..15eacb54 100644 --- a/boards/librem13v2.config +++ b/boards/librem13v2.config @@ -9,19 +9,21 @@ CONFIG_KEXEC=y CONFIG_UTIL_LINUX=y CONFIG_LVM2=y CONFIG_MBEDTLS=y +CONFIG_NEWT=y CONFIG_PCIUTILS=y CONFIG_POPT=y CONFIG_QRENCODE=y +CONFIG_SLANG=y CONFIG_TPMTOTP=y CONFIG_LINUX_USB=y export CONFIG_TPM=y -export CONFIG_BOOTSCRIPT=/bin/generic-init - +export CONFIG_BOOTSCRIPT=/bin/gui-init export CONFIG_BOOT_REQ_HASH=n export CONFIG_BOOT_REQ_ROLLBACK=n -export CONFIG_BOOT_KERNEL_ADD="intel_iommu=on" +export CONFIG_BOOT_KERNEL_ADD="intel_iommu=on intel_iommu=igfx_off" export CONFIG_BOOT_KERNEL_REMOVE="quiet" export CONFIG_BOOT_DEV="/dev/sda1" +export CONFIG_BOOT_GUI_MENU_NAME="Purism Librem 13v2 Heads Boot Menu" export CONFIG_USB_BOOT_DEV="/dev/sdb1" diff --git a/initrd/bin/gui-init b/initrd/bin/gui-init new file mode 100755 index 00000000..252462f1 --- /dev/null +++ b/initrd/bin/gui-init @@ -0,0 +1,127 @@ +#!/bin/sh +# Boot from a local disk installation + +CONFIG_BOOT_GUI_MENU_NAME='Heads Boot Menu' + +. /etc/functions +. /etc/config + +mount_boot() +{ + # Mount local disk if it is not already mounted + if ! grep -q /boot /proc/mounts ; then + mount -o ro /boot \ + || recovery "Unable to mount /boot" + fi +} + + +last_half=X +while true; do + MAIN_MENU_OPTIONS="" + unset totp_confirm + # update the TOTP code every thirty seconds + date=`date "+%Y-%m-%d %H:%M:%S"` + seconds=`date "+%s"` + half=`expr \( $seconds % 60 \) / 30` + if [ "$CONFIG_TPM" = n ]; then + TOTP="NO TPM" + elif [ "$half" != "$last_half" ]; then + last_half=$half; + TOTP=`unseal-totp` + if [ $? -ne 0 ]; then + whiptail --clear --title "ERROR: TOTP Generation Failed!" \ + --menu "ERROR: Heads couldn't generate the TOTP code.\n\nIf you have just reflashed your BIOS, you will need to generate a new TOTP secret.\n\nIf you have not just reflashed your BIOS, THIS COULD INDICATE TAMPERING!\n\nHow would you like to proceed?" 20 60 4 \ + 'g' ' Generate new TOTP secret' \ + 'i' ' Ignore error and continue to default boot menu' \ + 'x' ' Exit to recovery shell' \ + 2>/tmp/whiptail || recovery "GUI menu failed" + + totp_confirm=$(cat /tmp/whiptail) + fi + fi + + if [ "$totp_confirm" = "i" -o -z "$totp_confirm" ]; then + whiptail --clear --title "$CONFIG_BOOT_GUI_MENU_NAME" \ + --menu "$date\nTOTP code: $TOTP" 20 60 8 \ + 'y' ' Default boot' \ + 'r' ' TOTP does not match, refresh code' \ + 'n' ' TOTP does not match after refresh, troubleshoot' \ + 'm' ' Show OS boot menu' \ + 'u' ' USB boot' \ + 'g' ' Generate new TOTP secret' \ + 'x' ' Exit to recovery shell' \ + 2>/tmp/whiptail || recovery "GUI menu failed" + + totp_confirm=$(cat /tmp/whiptail) + fi + + if [ "$totp_confirm" = "x" ]; then + recovery "User requested recovery shell" + fi + + if [ "$totp_confirm" = "r" ]; then + continue + fi + + if [ "$totp_confirm" = "n" ]; then + if (whiptail --title "TOTP code mismatched" \ + --yesno "TOTP code mismatches could indicate either TPM tampering or clock drift:\n\nTo correct clock drift: 'date -s HH:MM:SS'\nand save it to the RTC: 'hwclock -w'\nthen reboot and try again.\n\nWould you like to exit to a recovery console?" 30 60) then + echo "" + echo "To correct clock drift: 'date -s HH:MM:SS'" + echo "and save it to the RTC: 'hwclock -w'" + echo "then reboot and try again" + echo "" + recovery "TOTP mismatch" + else + continue + fi + fi + + if [ "$totp_confirm" = "u" ]; then + exec /bin/usb-init + continue + fi + + if [ "$totp_confirm" = "g" ]; then + if (whiptail --title 'Generate new TOTP secret' \ + --yesno "This will erase your old secret and replace it with a new one!\n\nDo you want to proceed?" 16 60) then + echo "Scan the QR code to add the new TOTP secret" + /bin/seal-totp + echo "Once you have scanned the QR code, hit Enter to reboot" + read + /bin/reboot + else + echo "Returning to the main menu" + fi + continue + fi + + if [ "$totp_confirm" = "m" ]; then + # Try to select a kernel from the menu + mount_boot + kexec-select-boot -m -b /boot -c "grub.cfg" -g + continue + fi + + if [ "$totp_confirm" = "y" -o -n "$totp_confirm" ]; then + # Try to boot the default + mount_boot + DEFAULT_FILE=`find /boot/kexec_default.*.txt 2>/dev/null | head -1` + if [ -r "$DEFAULT_FILE" ]; then + kexec-select-boot -b /boot -c "grub.cfg" \ + || recovery "Failed default boot" + else + if (whiptail --title 'No Default Boot Option Configured' \ + --yesno "There is no default boot option configured yet. Would you like to load a menu of boot options? Otherwise you will return to the main menu." 16 60) then + kexec-select-boot -m -b /boot -c "grub.cfg" -g + else + echo "Returning to the main menu" + fi + continue + fi + fi + +done + +recovery "Something failed during boot" diff --git a/initrd/bin/kexec-select-boot b/initrd/bin/kexec-select-boot index 64e57173..8471ace5 100755 --- a/initrd/bin/kexec-select-boot +++ b/initrd/bin/kexec-select-boot @@ -12,7 +12,8 @@ valid_hash="n" valid_global_hash="n" valid_rollback="n" force_menu="n" -while getopts "b:d:p:a:r:c:uim" arg; do +gui_menu="n" +while getopts "b:d:p:a:r:c:uimg" arg; do case $arg in b) bootdir="$OPTARG" ;; d) paramsdev="$OPTARG" ;; @@ -23,6 +24,7 @@ while getopts "b:d:p:a:r:c:uim" arg; do u) unique="y" ;; m) force_menu="y" ;; i) valid_hash="y"; valid_rollback="y" ;; + g) gui_menu="y" ;; esac done @@ -80,6 +82,24 @@ get_menu_option() { if [ $num_options -eq 1 -a $first_menu = "y" ]; then option_index=1 + elif [ "$gui_menu" = "y" ]; then + MENU_OPTIONS="" + n=0 + while read option + do + parse_option + n=`expr $n + 1` + name=$(echo $name | tr " " "_") + kernel=$(echo $kernel | cut -f2 -d " ") + MENU_OPTIONS="$MENU_OPTIONS $n ${name}_[$kernel]" + done < $TMP_MENU_FILE + + whiptail --clear --title "Select your boot option" \ + --menu "Choose the boot option [1-$n, a to abort]:" 20 120 8 \ + -- $MENU_OPTIONS \ + 2>/tmp/whiptail || die "Aborting boot attempt" + + option_index=$(cat /tmp/whiptail) else echo "+++ Select your boot option:" n=0 @@ -105,14 +125,23 @@ get_menu_option() { } confirm_menu_option() { - echo "+++ Please confirm the boot details for $name:" - echo $option + if [ "$gui_menu" = "y" ]; then + whiptail --clear --title "Confirm boot details" \ + --menu "Confirm the boot details for $name:\n\n$option\n\n" 20 120 8 \ + -- 'y' "Boot $name" 'd' "Make $name the default" \ + 2>/tmp/whiptail || die "Aborting boot attempt" - read \ - -n 1 \ - -p "Confirm selection by pressing 'y', make default with 'd': " \ - option_confirm - echo + option_confirm=$(cat /tmp/whiptail) + else + echo "+++ Please confirm the boot details for $name:" + echo $option + + read \ + -n 1 \ + -p "Confirm selection by pressing 'y', make default with 'd': " \ + option_confirm + echo + fi } parse_option() {