summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiaotian Wu <yetist@gmail.com>2022-12-30 18:28:48 +0800
committerXiaotian Wu <yetist@gmail.com>2023-10-14 20:36:31 +0800
commit3e92948536c86a25ce4be45c1bf0283cb8eff604 (patch)
tree5b8b4e471e8ac6efc06c3e0dd804e39fb7b6f4a6
parentb8f91b24e32d0dbf4de9a3d3e12ca38040a79908 (diff)
Get kernel version from generic EFI zboot image
This feature was added to the kernel since 6.1 https://elixir.bootlin.com/linux/v6.1/source/drivers/firmware/efi/libstub/Makefile.zboot https://elixir.bootlin.com/linux/v6.1/source/drivers/firmware/efi/libstub/zboot-header.S See discussion [Here](https://lists.gnu.org/archive/html/grub-devel/2022-12/msg00099.html)
-rw-r--r--functions73
1 files changed, 73 insertions, 0 deletions
diff --git a/functions b/functions
index a8c9103..ab929f2 100644
--- a/functions
+++ b/functions
@@ -210,9 +210,71 @@ detect_compression() {
return
fi
+ read -rd '' bytes < <(od -An -j0x04 -t c -N4 "$1" | tr -dc '[:alnum:]')
+ if [[ "$bytes" == 'zimg' ]]; then
+ echo 'zimg'
+ return
+ fi
+
# out of ideas, assuming uncompressed
}
+kver_zimage() {
+ # Generic EFI zboot added since kernel 6.1
+ # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/efi/libstub/Makefile.zboot?h=v6.1
+ # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/efi/libstub/zboot-header.S?h=v6.1
+
+ local kver='' reader start size comp_type
+
+ # Reading 4 bytes from address 0x08 is the starting offset of compressed data
+ start="$(od -An -j0x08 -t u4 -N4 "$1" | tr -dc '[:alnum:]')"
+
+ # Reading 4 bytes from address 0x0c is the size of compressed data,
+ # but it needs to be corrected according to the compressed type.
+ size="$(od -An -j0x0c -t u4 -N4 "$1" | tr -dc '[:alnum:]')"
+
+ # Read 36 bytes (before 0x3c) from address 0x18,
+ # which is a nul-terminated string representing the compressed type.
+ read -rd '' comp_type < <(od -An -j0x18 -t a -N32 "$1" | sed 's/ nul//g' | tr -dc '[:alnum:]')
+
+ [[ "$start" =~ ^[0-9]+$ ]] || return 1
+ [[ "$size" =~ ^[0-9]+$ ]] || return 1
+
+ case "$comp_type" in
+ 'gzip')
+ reader='zcat'
+ ;;
+ 'lz4')
+ reader='lz4cat'
+ size="$((size + 4))"
+ ;;
+ 'lzma')
+ reader='xzcat'
+ size="$((size + 4))"
+ ;;
+ 'lzo')
+ reader="lzop -d"
+ size="$((size + 4))"
+ ;;
+ 'xzkern')
+ reader='xzcat'
+ size="$((size + 4))"
+ ;;
+ 'zstd22')
+ reader='zstdcat'
+ size="$((size + 4))"
+ ;;
+ *)
+ reader="$comp_type"
+ size="$((size + 4))"
+ ;;
+ esac
+
+ read -r _ _ kver _ < <(dd if="$1" bs=1 count="$size" skip="$start" 2>/dev/null | $reader - | grep -m1 -aoE 'Linux version .(\.[-[:alnum:]+]+)+')
+
+ printf '%s' "$kver"
+}
+
kver_generic() {
# For unknown architectures, we can try to grep the uncompressed or gzipped
# image for the boot banner.
@@ -223,6 +285,17 @@ kver_generic() {
# Loosely grep for `linux_banner`:
# https://elixir.bootlin.com/linux/v5.7.2/source/init/version.c#L46
local kver='' reader='cat'
+ local comp_type=''
+
+ comp_type="$(detect_compression "$1")"
+
+ if [[ "$comp_type" == 'zimg' ]]; then
+ # Generic EFI zboot image
+ kver_zimage "$1"
+ return 0
+ elif [[ "$comp_type" == 'gzip' ]]; then
+ reader='zcat'
+ fi
[[ "$(detect_compression "$1")" == 'gzip' ]] && reader='zcat'