From ae9d3b7909b92ba7e09978ea9e31157f5f198887 Mon Sep 17 00:00:00 2001 From: "Nicholas S. Castellano" Date: Tue, 12 Dec 2023 17:00:58 -0500 Subject: [PATCH] Script for manipulating UEFI settings Will be used to add UEFI boot management features to ES, as discussed in #9227 --- .../core/batocera-scripts/batocera-scripts.mk | 8 + .../batocera-scripts/scripts/batocera-efi | 150 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100755 package/batocera/core/batocera-scripts/scripts/batocera-efi diff --git a/package/batocera/core/batocera-scripts/batocera-scripts.mk b/package/batocera/core/batocera-scripts/batocera-scripts.mk index 402a4524e78..6a8e9470e52 100644 --- a/package/batocera/core/batocera-scripts/batocera-scripts.mk +++ b/package/batocera/core/batocera-scripts/batocera-scripts.mk @@ -27,6 +27,10 @@ ifeq ($(BR2_PACKAGE_BATOCERA_TARGET_SM8250),y) BATOCERA_SCRIPTS_POST_INSTALL_TARGET_HOOKS += BATOCERA_SCRIPTS_INSTALL_QCOM endif +ifeq ($(BR2_PACKAGE_EFIBOOTMGR),y) + BATOCERA_SCRIPTS_POST_INSTALL_TARGET_HOOKS += BATOCERA_SCRIPTS_INSTALL_EFI +endif + define BATOCERA_SCRIPTS_INSTALL_TARGET_CMDS mkdir -p $(TARGET_DIR)/usr/lib/python$(PYTHON3_VERSION_MAJOR) mkdir -p $(TARGET_DIR)/usr/bin @@ -90,4 +94,8 @@ define BATOCERA_SCRIPTS_INSTALL_ROCKCHIP install -m 0755 $(BATOCERA_SCRIPTS_PATH)/scripts/batocera-rockchip-suspend $(TARGET_DIR)/usr/bin/ endef +define BATOCERA_SCRIPTS_INSTALL_EFI + install -m 0755 $(BATOCERA_SCRIPTS_PATH)/scripts/batocera-efi $(TARGET_DIR)/usr/bin/batocera-efi +endef + $(eval $(generic-package)) diff --git a/package/batocera/core/batocera-scripts/scripts/batocera-efi b/package/batocera/core/batocera-scripts/scripts/batocera-efi new file mode 100755 index 00000000000..7b87acdc426 --- /dev/null +++ b/package/batocera/core/batocera-scripts/scripts/batocera-efi @@ -0,0 +1,150 @@ +#!/bin/bash + +do_help() { + echo "$0 check" >&2 + echo "$0 getBootCurrent" >&2 + echo "$0 getBootNext" >&2 + echo "$0 setBootNext XXXX" >&2 + echo "$0 deleteBootNext" >&2 + echo "$0 getBootOrder" >&2 + echo "$0 listBoot" >&2 + echo "$0 listBootAll" >&2 + echo "$0 activateBoot XXXX" >&2 + echo "$0 inactivateBoot XXXX" >&2 + echo "$0 prioritizeBoot XXXX" >&2 +} + +do_getBootCurrent() { + # Get the UEFI boot slot number for the current boot + efibootmgr | sed -n 's/^BootCurrent:\s*\(.*\)/\1/p' +} + +do_getBootNext() { + # Get the UEFI boot slot number for the next boot + efibootmgr | sed -n 's/^BootNext:\s*\(.*\)/\1/p' +} + +do_setBootNext() { + # Set the UEFI boot order override for the next boot + if [ "$1" = "NONE" ] + then + do_deleteBootNext + else + efibootmgr -n "$1" + fi +} + +do_deleteBootNext() { + # Delete any override for the next boot + efibootmgr -N +} + +do_getBootOrder() { + # Get an ordered list of the hexadecimal boot entry numbers, one per line + efibootmgr | sed -n 's/^BootOrder:\s*\(.*\)/\1/p' | sed 's/,/\n/g' +} + +fetchBOOTENTRIES() { + # Set global variable BOOTENTRIES to an unordered list of all BootXXXX UEFI variables + # Value has four TAB-delimited columns + # 1. Boot slot number, four hexadecimal digits from the BootXXXX variable name + # 2. "*" if entry is marked active, " " (space) if inactive. Many UEFI firmwares seems to ignore this and only care about BootOrder + # 3. Boot label + # 4. UEFI boot path + # Yes, this variable really must be exported - it is used in subshells + if [ -z "$BOOTENTRIES" ]; then + export BOOTENTRIES="$(efibootmgr | sed -n 's/^Boot\([0-9A-F][0-9A-F][0-9A-F][0-9A-F]\)\(.\)\s\(.*\)\t/\1\t\2\t\3\t/p')" + fi +} + +do_listBoot() { + # List the boot entries in order of appearance in BootOrder + fetchBOOTENTRIES + do_getBootOrder | + while read ORDER + do + echo "$BOOTENTRIES" | grep "^$ORDER" + done +} + +do_listBootAll() { + # List all boot entries, with those in BootOrder in their order of appearance therein, followed by the remainder in sorted order + fetchBOOTENTRIES + listBoot=$(do_listBoot) + echo "$listBoot" + grep -v -F -f <(echo "$listBoot") <(echo "$BOOTENTRIES") +} + +do_activateBoot() { + # Activate a boot entry + efibootmgr -a -b "$1" +} + +do_inactivateBoot() { + # Inactivate a boot entry + efibootmgr -A -b "$1" +} + +do_prioritizeBoot() { + # Move (or add) a boot entry to the front of BootOrder + export PRIORITIZE="$1" + removeBootOrder="$(do_getBootOrder | grep -v -F "$PRIORITIZE")" + newline=$'\n' + newBootOrder="$(echo "${PRIORITIZE}${newline}${removeBootOrder}" | paste -sd ",")" + efibootmgr -o "$newBootOrder" +} + +if [ ! -d /sys/firmware/efi ]; then + echo "$0: ERROR: UEFI firmware not active." >&2 + exit 1 +fi + +if [ $# -eq 0 ]; then + do_help + exit 1 +fi + +ACTION=$1 +shift + +case "${ACTION}" in + "check") + exit 0 + ;; + "getBootCurrent") + do_getBootCurrent + ;; + "getBootNext") + do_getBootNext + ;; + "setBootNext") + do_setBootNext "$1" + ;; + "deleteBootNext") + do_deleteBootNext + ;; + "getBootOrder") + do_getBootOrder + ;; + "listBoot") + do_listBoot + ;; + "listBootAll") + do_listBootAll + ;; + "activateBoot") + do_activateBoot "$1" + ;; + "inactivateBoot") + do_inactivateBoot "$1" + ;; + "prioritizeBoot") + do_prioritizeBoot "$1" + ;; + *) + do_help + >&2 echo "error: invalid command ${ACTION}" + exit 1 + ;; +esac +exit $?