Files
s390-tools/netboot/mk-s390image
Marc Hartmayer 128e5f86fe netboot: Add longer kernel command lines support
Since Linux commit 5ecb2da660ab ("s390: support command lines longer
than 896 bytes") the s390x kernel supports longer command lines than 896
bytes. The indication of the maximum size is stored in a new field at
address 0x10430, older kernels without the support store a value of 0
there so in that case fallback to the old maximum length of 896.

In addition, use the checked size as limit to copy in the 'dd' call.
This prevents Linux kernel corruption in case the parmline has changed
in between.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/194
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2025-12-01 13:45:36 +01:00

209 lines
4.6 KiB
Bash
Executable File

#!/bin/bash
#
# netboot - PXE-style boot for KVM on s390
#
# Sample script to build a single s390 boot image consisting of
# kernel, an initial ramdisk and kernel parameters from
# individual components. Note that bash is required to run this script!
#
# Sample invocation:
#
# ./mk-s390image /boot/image -r /boot/initrd image
#
# The resulting image can be used to build a bootable
# ISO or as firmware image for KVM.
#
# Copyright IBM Corp. 2017
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
# Offsets
OFFS_INITRD_START_BYTES=66568
OFFS_INITRD_SIZE_BYTES=66576
OFFS_COMMANDLINE_MAX_SIZE_BYTES=66608
OFFS_COMMANDLINE_BYTES=66688
LEGACY_MAX_PARMFILE_SIZE=896
# Variables
cmd=$(basename -- "$0")
kernel=
ramdisk=
parmfile=
image=
binval=
success=no
# Cleanup on exit
# shellcheck disable=SC2317
cleanup()
{
if [ -n "$binval" ]
then
rm -f -- "$binval"
fi
if [ -n "$image" ] && [ "$success" = no ]
then
rm -- "$image"
fi
}
trap cleanup EXIT
# Usage
usage()
{
cat <<-EOF
Usage: $cmd KERNEL BOOT_IMAGE [-r RAMDISK] [-p PARMFILE]
Build an s390 image BOOT_IMAGE suitable for CD/tape/network boot or as a
KVM firmware image using a stripped Linux kernel file KERNEL.
OPTIONS
-p Use PARMFILE with kernel parameters in the image
-r Include RAMDISK in the image
-h Print this help, then exit
-v Print version information, then exit
EOF
}
printversion()
{
cat <<-EOD
$cmd: version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2017
EOD
}
# Convert decimal number to big endian doubleword
dec2be64()
{
local num=$1
local b
local i
for i in $(seq 1 8)
do
b="\\x$(printf '%x' "$((num % 256))")$b"
num=$((num / 256)) || true
done
printf '%b' "$b"
}
max_kernel_cmdline_size()
{
local __kernel=$1 size v
size_be="$(od -A n -j "${OFFS_COMMANDLINE_MAX_SIZE_BYTES}" -N 8 -t uL -- "$__kernel")"
# If little endian then swap bytes
if (("$(printf '\1' | od -dAn)" == 1)); then
v="$(printf '%016x0' "$size_be")"
size="0x${v:14:2}${v:12:2}${v:10:2}${v:8:2}${v:6:2}${v:4:2}${v:2:2}${v:0:2}"
else
size="$size_be"
fi
if ((size == 0)); then
size="${LEGACY_MAX_PARMFILE_SIZE}"
fi
# Use arithmetic expression to remove leading and trailing whitespace.
printf '%s' "$((size))"
}
# Do the image build
dobuild()
{
local i
local kernel_size
local ramdisk_size
local ramdisk_offset
local parmfile_size
# check whether all specified files exist
for i in $kernel $ramdisk $parmfile
do
if [ ! -f "$i" ]
then
echo "$cmd: File $i not found" >&2
return 1
fi
done
if ! file -b -- "$(readlink -f -- "$kernel")" | grep "Linux S390" > /dev/null
then
echo "$cmd: Unrecognized file format for $kernel" >&2
return 1
fi
# from now on we SHOULD only fail on disk shortage
# or file permissions, let the shell handle that
set -e
# copy over kernel padded with zeroes to page boundary
dd if="$kernel" of="$image" bs=4096 conv=sync status=none
# append ramdisk if specified
if [ "$ramdisk" != "" ]
then
ramdisk_size=$(du -b -L -- "$ramdisk" | cut -f1)
# shellcheck disable=SC2034
kernel_size=$(du -b -L -- "$kernel" | cut -f1)
ramdisk_offset=$(du -b -L -- "$image" | cut -f1)
cat -- "$ramdisk" >> "$image"
binval=$(mktemp)
dec2be64 "$ramdisk_offset" > "$binval"
dd seek=$OFFS_INITRD_START_BYTES if="$binval" of="$image" bs=1 \
count=8 conv=notrunc status=none
dec2be64 "$ramdisk_size" > "$binval"
dd seek=$OFFS_INITRD_SIZE_BYTES if="$binval" of="$image" bs=1 \
count=8 conv=notrunc status=none
fi
# set cmdline
if [ "$parmfile" != "" ]
then
max_parmfile_size=$(max_kernel_cmdline_size "$kernel")
parmfile_size=$(du -b -L -- "$parmfile" | cut -f1)
if (( parmfile_size <= max_parmfile_size ));
then
# Clear any previous parameters
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 count="$max_parmfile_size" \
if=/dev/zero of="$image" conv=notrunc status=none
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 count="$parmfile_size" \
if="$parmfile" of="$image" conv=notrunc status=none
else
echo "$cmd: Size $parmfile_size of $parmfile exceeds command line limit of $max_parmfile_size bytes" >&2
return 1
fi
fi
# we've done it
success=yes
}
# check args and build
# shellcheck disable=SC2086,SC2048
if args=$(getopt "r:p:hv" $*)
then
# shellcheck disable=SC2086
set -- $args
while [ "$1" != "" ]
do
case $1 in
-r) ramdisk=$2; shift 2;;
-p) parmfile=$2; shift 2;;
-h) usage; exit 0;;
-v) printversion; exit 0;;
--) shift; break;;
*) echo "$cmd: Unexpected argument $1, exiting..." >&2; exit 1;;
esac
done
fi
if [ $# = 2 ]
then
kernel=$1
image=$2
dobuild
exit 0
fi
# something wasn't right
usage >&2
exit 1