diff options
author | Xiaotian Wu <yetist@gmail.com> | 2022-12-30 18:28:48 +0800 |
---|---|---|
committer | Xiaotian Wu <yetist@gmail.com> | 2023-10-14 20:36:31 +0800 |
commit | 3e92948536c86a25ce4be45c1bf0283cb8eff604 (patch) | |
tree | 5b8b4e471e8ac6efc06c3e0dd804e39fb7b6f4a6 | |
parent | b8f91b24e32d0dbf4de9a3d3e12ca38040a79908 (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-- | functions | 73 |
1 files changed, 73 insertions, 0 deletions
@@ -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' |