mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-29 04:25:40 +00:00
Add the framework to build kernel config files from trees of kernel fragments. If no fragment directory is found for the requested kernel version and architecture then revert to looking for a whole prebuilt kernel config file instead. Fixes: #234 Signed-off-by: Graham Whaley <graham.whaley@intel.com>
423 lines
12 KiB
Bash
Executable File
423 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Copyright (c) 2018 Intel Corporation
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
description="
|
|
Description: This script is the *ONLY* to build a kernel for development.
|
|
"
|
|
|
|
set -o errexit
|
|
set -o nounset
|
|
set -o pipefail
|
|
|
|
readonly script_name="$(basename "${BASH_SOURCE[0]}")"
|
|
readonly script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
#project_name
|
|
readonly project_name="kata-containers"
|
|
[ -n "${GOPATH:-}" ] || GOPATH="${HOME}/go"
|
|
# Fetch the first element from GOPATH as working directory
|
|
# as go get only works against the first item in the GOPATH
|
|
GOPATH="${GOPATH%%:*}"
|
|
# Kernel version to be used
|
|
kernel_version=""
|
|
# Flag know if need to download the kernel source
|
|
download_kernel=false
|
|
# The repository where kernel configuration lives
|
|
runtime_repository="github.com/${project_name}/runtime"
|
|
# The repository where kernel configuration lives
|
|
readonly kernel_config_repo="github.com/${project_name}/packaging"
|
|
readonly patches_repo="github.com/${project_name}/packaging"
|
|
readonly patches_repo_dir="${GOPATH}/src/${patches_repo}"
|
|
# Default path to search patches to apply to kernel
|
|
readonly default_patches_dir="${patches_repo_dir}/kernel/patches/"
|
|
# Default path to search config for kata
|
|
readonly default_kernel_config_dir="${GOPATH}/src/${kernel_config_repo}/kernel/configs"
|
|
# Default path to search for kernel config fragments
|
|
readonly default_config_frags_dir="${GOPATH}/src/${kernel_config_repo}/kernel/configs/fragments"
|
|
#Path to kernel directory
|
|
kernel_path=""
|
|
#
|
|
patches_path=""
|
|
#
|
|
hypervisor_target=""
|
|
#
|
|
arch_target=""
|
|
#
|
|
kernel_config_path=""
|
|
# destdir
|
|
DESTDIR="${DESTDIR:-/}"
|
|
#PREFIX=
|
|
PREFIX="${PREFIX:-/usr}"
|
|
|
|
source "${script_dir}/../scripts/lib.sh"
|
|
|
|
usage() {
|
|
cat <<EOT
|
|
Overview:
|
|
|
|
Build a kernel for Kata Containers
|
|
${description}
|
|
|
|
Usage:
|
|
|
|
$script_name [options] <command> <argument>
|
|
|
|
Commands:
|
|
|
|
- setup
|
|
|
|
- build
|
|
|
|
- install
|
|
|
|
Options:
|
|
|
|
-c <path>: Path to config file to build a the kernel
|
|
-h : Display this help.
|
|
-k <path>: Path to kernel to build
|
|
-p <path>: Path to a directory with patches to apply to kernel.
|
|
-v : Kernel version to use if kernel path not provided.
|
|
EOT
|
|
}
|
|
|
|
# Convert architecture to the name used by the Linux kernel build system
|
|
arch_to_kernel() {
|
|
local -r arch="$1"
|
|
|
|
case "$arch" in
|
|
aarch64) echo "arm64" ;;
|
|
ppc64le) echo "powerpc" ;;
|
|
x86_64) echo "$arch" ;;
|
|
s390x) echo "s390" ;;
|
|
*) die "unsupported architecture: $arch" ;;
|
|
esac
|
|
}
|
|
|
|
get_kernel() {
|
|
local version="${1:-}"
|
|
#Remove extra 'v'
|
|
version=${version#v}
|
|
|
|
local kernel_path=${2:-}
|
|
[ -n "${kernel_path}" ] || die "kernel_path not provided"
|
|
[ ! -d "${kernel_path}" ] || die "kernel_path already exist"
|
|
|
|
major_version=$(echo "${version}" | cut -d. -f1)
|
|
kernel_tarball="linux-${version}.tar.xz"
|
|
|
|
curl --fail -OL "https://cdn.kernel.org/pub/linux/kernel/v${major_version}.x/sha256sums.asc"
|
|
grep "${kernel_tarball}" sha256sums.asc >"${kernel_tarball}.sha256"
|
|
|
|
if [ -f "${kernel_tarball}" ] && ! sha256sum -c "${kernel_tarball}.sha256"; then
|
|
info "invalid kernel tarball ${kernel_tarball} removing "
|
|
rm -f "${kernel_tarball}"
|
|
fi
|
|
if [ ! -f "${kernel_tarball}" ]; then
|
|
info "Download kernel version ${version}"
|
|
info "Download kernel"
|
|
curl --fail -OL "https://www.kernel.org/pub/linux/kernel/v${major_version}.x/${kernel_tarball}"
|
|
else
|
|
info "kernel tarball already downloaded"
|
|
fi
|
|
|
|
sha256sum -c "${kernel_tarball}.sha256"
|
|
|
|
tar xf "${kernel_tarball}"
|
|
|
|
mv "linux-${version}" "${kernel_path}"
|
|
}
|
|
|
|
get_major_kernel_version() {
|
|
local version="${1}"
|
|
[ -n "${version}" ] || die "kernel version not provided"
|
|
major_version=$(echo "${version}" | cut -d. -f1)
|
|
minor_version=$(echo "${version}" | cut -d. -f2)
|
|
echo "${major_version}.${minor_version}"
|
|
}
|
|
|
|
# Make a kernel config file from generic and arch specific
|
|
# fragments
|
|
# - arg1 - path to arch specific fragments
|
|
# - arg2 - path to kernel sources
|
|
#
|
|
get_kernel_frag_path() {
|
|
local arch_path="$1"
|
|
local common_path="${arch_path}/../common"
|
|
local kernel_path="$2"
|
|
local cmdpath="${kernel_path}/scripts/kconfig/merge_config.sh"
|
|
local config_path="${arch_path}/.config"
|
|
|
|
local arch_configs="$(ls ${arch_path}/*.conf)"
|
|
local common_configs="$(ls ${common_path}/*.conf)"
|
|
|
|
# These are the strings that the kernel merge_config.sh script kicks out
|
|
# when it reports an error or warning condition. We search for them in the
|
|
# output to try and fail when we think something has been misconfigured.
|
|
local not_in_string="not in final"
|
|
local redefined_string="not in final"
|
|
local redundant_string="not in final"
|
|
|
|
# Later, if we need to add kernel version specific subdirs in order to
|
|
# handle specific cases, then add the path definition and search/list/cat
|
|
# here.
|
|
local all_configs="${common_configs} ${arch_configs}"
|
|
|
|
info "Constructing config from fragments: ${config_path}"
|
|
local results=$(export KCONFIG_CONFIG=${config_path}; \
|
|
export ARCH=${arch_target}; \
|
|
cd ${kernel_path}; ${cmdpath} -r -n ${all_configs})
|
|
|
|
# Did we request any entries that did not make it?
|
|
local missing=$(echo $results | grep -v -q "${not_in_string}"; echo $?)
|
|
if [ ${missing} -ne 0 ]; then
|
|
info "Some CONFIG elements failed to make the final .config:"
|
|
info "${results}"
|
|
info "Generated config file can be found in ${config_path}"
|
|
die "Failed to construct requested .config file"
|
|
fi
|
|
|
|
# Did we define something as two different values?
|
|
local redefined=$(echo ${results} | grep -v -q "${redefined_string}"; echo $?)
|
|
if [ ${redefined} -ne 0 ]; then
|
|
info "Some CONFIG elements are redefined in fragments:"
|
|
info "${results}"
|
|
info "Generated config file can be found in ${config_path}"
|
|
die "Failed to construct requested .config file"
|
|
fi
|
|
|
|
# Did we define something twice? Nominally this may not be an error, and it
|
|
# might be convenient to allow it, but for now, let's pick up on them.
|
|
local redundant=$(echo ${results} | grep -v -q "${redundant_string}"; echo $?)
|
|
if [ ${redundant} -ne 0 ]; then
|
|
info "Some CONFIG elements failed to make the final .config"
|
|
info "${results}"
|
|
info "Generated config file can be found in ${config_path}"
|
|
die "Failed to construct requested .config file"
|
|
fi
|
|
|
|
echo "${config_path}"
|
|
}
|
|
|
|
# Locate and return the path to the relevant kernel config file
|
|
# - arg1: kernel version
|
|
# - arg2: hypervisor target
|
|
# - arg3: arch target
|
|
# - arg4: kernel source path
|
|
get_default_kernel_config() {
|
|
local version="${1}"
|
|
|
|
local hypervisor="$2"
|
|
local kernel_arch="$3"
|
|
local kernel_path="$4"
|
|
|
|
[ -n "${version}" ] || die "kernel version not provided"
|
|
[ -n "${hypervisor}" ] || die "hypervisor not provided"
|
|
[ -n "${kernel_arch}" ] || die "kernel arch not provided"
|
|
|
|
local kernel_ver
|
|
kernel_ver=$(get_major_kernel_version "${version}")
|
|
|
|
archfragdir="${default_config_frags_dir}/${kernel_arch}"
|
|
if [ -d "${archfragdir}" ]; then
|
|
config="$(get_kernel_frag_path ${archfragdir} ${kernel_path})"
|
|
else
|
|
config="${default_kernel_config_dir}/${kernel_arch}_kata_${hypervisor}_${major_kernel}.x"
|
|
fi
|
|
|
|
[ -f "${config}" ] || die "failed to find default config ${config}"
|
|
echo "${config}"
|
|
}
|
|
|
|
get_config_and_patches() {
|
|
if [ -z "${patches_path}" ]; then
|
|
info "Clone config and patches"
|
|
patches_path="${default_patches_dir}"
|
|
[ -d "${patches_path}" ] || git clone "https://${patches_repo}.git" "${patches_repo_dir}"
|
|
fi
|
|
}
|
|
|
|
get_config_version() {
|
|
get_config_and_patches
|
|
config_version_file="${default_patches_dir}/../kata_config_version"
|
|
if [ -f "${config_version_file}" ]; then
|
|
cat "${config_version_file}"
|
|
else
|
|
die "failed to find ${config_version_file}"
|
|
fi
|
|
}
|
|
|
|
setup_kernel() {
|
|
local kernel_path=${1:-}
|
|
[ -n "${kernel_path}" ] || die "kernel_path not provided"
|
|
if [ -d "$kernel_path" ]; then
|
|
info "${kernel_path} already exist"
|
|
return
|
|
fi
|
|
|
|
info "kernel path does not exist, will download kernel"
|
|
download_kernel="true"
|
|
[ -n "$kernel_version" ] || die "failed to get kernel version: Kernel version is emtpy"
|
|
|
|
if [[ ${download_kernel} == "true" ]]; then
|
|
get_kernel "${kernel_version}" "${kernel_path}"
|
|
fi
|
|
|
|
[ -n "$kernel_path" ] || die "failed to find kernel source path"
|
|
|
|
get_config_and_patches
|
|
|
|
[ -d "${patches_path}" ] || die " patches path '${patches_path}' does not exist"
|
|
|
|
local major_kernel
|
|
major_kernel=$(get_major_kernel_version "${kernel_version}")
|
|
local patches_dir_for_version="${patches_path}/${major_kernel}.x"
|
|
local kernel_patches=""
|
|
if [ -d "${patches_dir_for_version}" ]; then
|
|
kernel_patches=$(find "${patches_dir_for_version}" -name '*.patch' -type f)
|
|
else
|
|
info "kernel patches directory does not exit"
|
|
|
|
fi
|
|
|
|
[ -n "${arch_target}" ] || arch_target="$(uname -m)"
|
|
arch_target=$(arch_to_kernel "${arch_target}")
|
|
(
|
|
cd "${kernel_path}" || exit 1
|
|
for p in ${kernel_patches}; do
|
|
info "Applying patch $p"
|
|
patch -p1 --fuzz 0 <"$p"
|
|
done
|
|
|
|
[ -n "${hypervisor_target}" ] || hypervisor_target="kvm"
|
|
[ -n "${kernel_config_path}" ] || kernel_config_path=$(get_default_kernel_config "${kernel_version}" "${hypervisor_target}" "${arch_target}" "${kernel_path}")
|
|
|
|
info "Copying config file from: ${kernel_config_path}"
|
|
cp "${kernel_config_path}" ./.config
|
|
make oldconfig
|
|
)
|
|
}
|
|
|
|
build_kernel() {
|
|
local kernel_path=${1:-}
|
|
[ -n "${kernel_path}" ] || die "kernel_path not provided"
|
|
[ -d "${kernel_path}" ] || die "path to kernel does not exist, use ${script_name} setup"
|
|
[ -n "${arch_target}" ] || arch_target="$(uname -m)"
|
|
arch_target=$(arch_to_kernel "${arch_target}")
|
|
pushd "${kernel_path}" >>/dev/null
|
|
make -j $(nproc) ARCH="${arch_target}"
|
|
[ "$arch_target" != "powerpc" ] && ([ -e "arch/${arch_target}/boot/bzImage" ] || [ -e "arch/${arch_target}/boot/Image.gz" ])
|
|
[ -e "vmlinux" ]
|
|
popd >>/dev/null
|
|
}
|
|
|
|
install_kata() {
|
|
local kernel_path=${1:-}
|
|
[ -n "${kernel_path}" ] || die "kernel_path not provided"
|
|
[ -d "${kernel_path}" ] || die "path to kernel does not exist, use ${script_name} setup"
|
|
pushd "${kernel_path}" >>/dev/null
|
|
config_version=$(get_config_version)
|
|
[ -n "${config_version}" ] || die "failed to get config version"
|
|
install_path=$(readlink -m "${DESTDIR}/${PREFIX}/share/${project_name}")
|
|
vmlinuz="vmlinuz-${kernel_version}-${config_version}"
|
|
vmlinux="vmlinux-${kernel_version}-${config_version}"
|
|
|
|
if [ -e "arch/${arch_target}/boot/bzImage" ]; then
|
|
bzImage="arch/${arch_target}/boot/bzImage"
|
|
elif [ -e "arch/${arch_target}/boot/Image.gz" ]; then
|
|
bzImage="arch/${arch_target}/boot/Image.gz"
|
|
elif [ "${arch_target}" != "powerpc" ]; then
|
|
die "failed to find image"
|
|
fi
|
|
|
|
if [ "${arch_target}" = "powerpc" ]; then
|
|
install --mode 0644 -D "vmlinux" "${install_path}/${vmlinuz}"
|
|
else
|
|
install --mode 0644 -D "${bzImage}" "${install_path}/${vmlinuz}"
|
|
fi
|
|
|
|
install --mode 0644 -D "vmlinux" "${install_path}/${vmlinux}"
|
|
install --mode 0644 -D ./.config "${install_path}/config-${kernel_version}"
|
|
ln -sf "${vmlinuz}" "${install_path}/vmlinuz.container"
|
|
ln -sf "${vmlinux}" "${install_path}/vmlinux.container"
|
|
ls -la "${install_path}/vmlinux.container"
|
|
ls -la "${install_path}/vmlinuz.container"
|
|
popd >>/dev/null
|
|
}
|
|
|
|
main() {
|
|
while getopts "a:c:hk:p:t:v:" opt; do
|
|
case "$opt" in
|
|
a)
|
|
arch_target="${OPTARG}"
|
|
;;
|
|
c)
|
|
kernel_config_path="${OPTARG}"
|
|
;;
|
|
|
|
h)
|
|
usage
|
|
exit 0
|
|
;;
|
|
|
|
k)
|
|
kernel_path="${OPTARG}"
|
|
;;
|
|
|
|
t)
|
|
hypervisor_target="${OPTARG}"
|
|
;;
|
|
p)
|
|
patches_path="${OPTARG}"
|
|
;;
|
|
v)
|
|
kernel_version="${OPTARG}"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
shift $((OPTIND - 1))
|
|
|
|
subcmd="${1:-}"
|
|
|
|
[ -z "${subcmd}" ] && usage 1
|
|
|
|
# If not kernel version take it from versions.yaml
|
|
if [ -z "$kernel_version" ]; then
|
|
kernel_version=$(get_from_kata_deps "assets.kernel.version")
|
|
#Remove extra 'v'
|
|
kernel_version="${kernel_version#v}"
|
|
fi
|
|
|
|
if [ -z "${kernel_path}" ]; then
|
|
config_version=$(get_config_version)
|
|
kernel_path="${PWD}/kata-linux-${kernel_version}-${config_version}"
|
|
info "Config version: ${config_version}"
|
|
fi
|
|
|
|
info "Kernel version: ${kernel_version}"
|
|
|
|
case "${subcmd}" in
|
|
build)
|
|
build_kernel "${kernel_path}"
|
|
;;
|
|
install)
|
|
build_kernel "${kernel_path}"
|
|
install_kata "${kernel_path}"
|
|
;;
|
|
setup)
|
|
setup_kernel "${kernel_path}"
|
|
[ -d "${kernel_path}" ] || die "${kernel_path} does not exist"
|
|
echo "Kernel source ready: ${kernel_path} "
|
|
;;
|
|
*)
|
|
usage 1
|
|
;;
|
|
|
|
esac
|
|
}
|
|
|
|
main $@
|