| #!/bin/bash |
| |
| # Copyright (C) 2021 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # TODO (b/231473697): rel_path and rel_path2 should use realpath --relative-to |
| # rel_path <to> <from> |
| # Generate relative directory path to reach directory <to> from <from> |
| function rel_path() { |
| local to=$1 |
| local from=$2 |
| local path= |
| local stem= |
| local prevstem= |
| [ -n "$to" ] || return 1 |
| [ -n "$from" ] || return 1 |
| to=$(readlink -e "$to") |
| from=$(readlink -e "$from") |
| [ -n "$to" ] || return 1 |
| [ -n "$from" ] || return 1 |
| stem=${from}/ |
| while [ "${to#$stem}" == "${to}" -a "${stem}" != "${prevstem}" ]; do |
| prevstem=$stem |
| stem=$(readlink -e "${stem}/..") |
| [ "${stem%/}" == "${stem}" ] && stem=${stem}/ |
| path=${path}../ |
| done |
| echo ${path}${to#$stem} |
| } |
| |
| # TODO (b/231473697): rel_path and rel_path2 should use realpath --relative-to |
| # rel_path2 <to> <from> |
| # Generate relative directory path to reach directory <to> from <from> |
| # This is slower than rel_path, but returns a simpler path when <from> |
| # is directly under <to>. |
| function rel_path2() { |
| local to=$1 |
| local from=$2 |
| python3 -c 'import os,sys;print(os.path.relpath(*(sys.argv[1:])))' "$to" "$from" |
| } |
| |
| # $1 directory of kernel modules ($1/lib/modules/x.y) |
| # $2 flags to pass to depmod |
| # $3 kernel version |
| function run_depmod() { |
| ( |
| local ramdisk_dir=$1 |
| local depmod_stdout |
| local depmod_stderr=$(mktemp) |
| |
| cd ${ramdisk_dir} |
| if ! depmod_stdout="$(depmod $2 -F ${DIST_DIR}/System.map -b . $3 \ |
| 2>${depmod_stderr})"; then |
| echo "$depmod_stdout" |
| cat ${depmod_stderr} >&2 |
| rm -f ${depmod_stderr} |
| exit 1 |
| fi |
| [ -n "$depmod_stdout" ] && echo "$depmod_stdout" |
| cat ${depmod_stderr} >&2 |
| if { grep -q "needs unknown symbol" ${depmod_stderr}; }; then |
| echo "ERROR: kernel module(s) need unknown symbol(s)" >&2 |
| rm -f ${depmod_stderr} |
| exit 1 |
| fi |
| rm -f ${depmod_stderr} |
| ) |
| } |
| |
| # $1 MODULES_LIST, <File contains the list of modules that should go in the ramdisk> |
| # $2 MODULES_STAGING_DIR <The directory to look for all the compiled modules> |
| # $3 IMAGE_STAGING_DIR <The destination directory in which MODULES_LIST is |
| # expected, and it's corresponding modules.* files> |
| # $4 MODULES_BLOCKLIST, <File contains the list of modules to prevent from loading> |
| # $5 flags to pass to depmod |
| function create_modules_staging() { |
| local modules_list_file=$1 |
| local src_dir=$(echo $2/lib/modules/*) |
| local version=$(basename "${src_dir}") |
| local dest_dir=$3/lib/modules/${version} |
| local dest_stage=$3 |
| local modules_blocklist_file=$4 |
| local depmod_flags=$5 |
| |
| rm -rf ${dest_dir} |
| mkdir -p ${dest_dir}/kernel |
| find ${src_dir}/kernel/ -maxdepth 1 -mindepth 1 \ |
| -exec cp -r {} ${dest_dir}/kernel/ \; |
| # The other modules.* files will be generated by depmod |
| cp ${src_dir}/modules.order ${dest_dir}/modules.order |
| cp ${src_dir}/modules.builtin ${dest_dir}/modules.builtin |
| cp ${src_dir}/modules.builtin.modinfo ${dest_dir}/modules.builtin.modinfo |
| |
| if [[ -n "${EXT_MODULES}" ]] || [[ -n "${EXT_MODULES_MAKEFILE}" ]]; then |
| mkdir -p ${dest_dir}/extra/ |
| cp -r ${src_dir}/extra/* ${dest_dir}/extra/ |
| |
| # Check if we have modules.order files for external modules. This is |
| # supported in android-mainline since 5.16 and androidX-5.15 |
| FIND_OUT=$(find ${dest_dir}/extra -name modules.order.* -print -quit) |
| if [[ -n "${EXT_MODULES}" ]] && [[ "${FIND_OUT}" =~ modules.order ]]; then |
| # If EXT_MODULES is defined and we have modules.order.* files for |
| # external modules, then we should follow this module load order: |
| # 1) Load modules in order defined by EXT_MODULES. |
| # 2) Within a given external module, load in order defined by |
| # modules.order. |
| for EXT_MOD in ${EXT_MODULES}; do |
| # Since we set INSTALL_MOD_DIR=extra/${EXTMOD}, we can directly use the |
| # modules.order.* file at that path instead of tring to figure out the |
| # full name of the modules.order file. This is complicated because we |
| # set M=... to a relative path which can't easily be calculated here |
| # when using kleaf due to sandboxing. |
| modules_order_file=$(ls ${dest_dir}/extra/${EXT_MOD}/modules.order.*) |
| if [[ -f "${modules_order_file}" ]]; then |
| cat ${modules_order_file} >> ${dest_dir}/modules.order |
| else |
| # We need to fail here; otherwise, you risk the module(s) not getting |
| # included in modules.load. |
| echo "Failed to find ${modules_order_file}" >&2 |
| exit 1 |
| fi |
| done |
| else |
| # TODO: can we retain modules.order when using EXT_MODULES_MAKEFILE? For |
| # now leave this alone since EXT_MODULES_MAKEFILE isn't support in v5.13+. |
| (cd ${dest_dir}/ && \ |
| find extra -type f -name "*.ko" | sort >> modules.order) |
| fi |
| fi |
| |
| if [ "${DO_NOT_STRIP_MODULES}" = "1" ]; then |
| # strip debug symbols off initramfs modules |
| find ${dest_dir} -type f -name "*.ko" \ |
| -exec ${OBJCOPY:-${CROSS_COMPILE}objcopy} --strip-debug {} \; |
| fi |
| |
| if [ -n "${modules_list_file}" ]; then |
| # Need to make sure we can find modules_list_file from the staging dir |
| if [[ -f "${ROOT_DIR}/${modules_list_file}" ]]; then |
| modules_list_file="${ROOT_DIR}/${modules_list_file}" |
| elif [[ "${modules_list_file}" != /* ]]; then |
| echo "modules list must be an absolute path or relative to ${ROOT_DIR}: ${modules_list_file}" |
| exit 1 |
| elif [[ ! -f "${modules_list_file}" ]]; then |
| echo "Failed to find modules list: ${modules_list_file}" |
| exit 1 |
| fi |
| |
| local modules_list_filter=$(mktemp) |
| local old_modules_list=$(mktemp) |
| |
| # Remove all lines starting with "#" (comments) |
| # Exclamation point makes interpreter ignore the exit code under set -e |
| ! grep -v "^\#" ${modules_list_file} > ${modules_list_filter} |
| |
| # Append a new line at the end of file |
| # If file doesn't end in newline the last module is skipped from filter |
| echo >> ${modules_list_filter} |
| |
| # grep the modules.order for any KOs in the modules list |
| cp ${dest_dir}/modules.order ${old_modules_list} |
| ! grep -w -f ${modules_list_filter} ${old_modules_list} > ${dest_dir}/modules.order |
| rm -f ${modules_list_filter} ${old_modules_list} |
| fi |
| |
| if [ -n "${modules_blocklist_file}" ]; then |
| # Need to make sure we can find modules_blocklist_file from the staging dir |
| if [[ -f "${ROOT_DIR}/${modules_blocklist_file}" ]]; then |
| modules_blocklist_file="${ROOT_DIR}/${modules_blocklist_file}" |
| elif [[ "${modules_blocklist_file}" != /* ]]; then |
| echo "modules blocklist must be an absolute path or relative to ${ROOT_DIR}: ${modules_blocklist_file}" |
| exit 1 |
| elif [[ ! -f "${modules_blocklist_file}" ]]; then |
| echo "Failed to find modules blocklist: ${modules_blocklist_file}" |
| exit 1 |
| fi |
| |
| cp ${modules_blocklist_file} ${dest_dir}/modules.blocklist |
| fi |
| |
| if [ -n "${TRIM_UNUSED_MODULES}" ]; then |
| echo "========================================================" |
| echo " Trimming unused modules" |
| local used_blocklist_modules=$(mktemp) |
| if [ -f ${dest_dir}/modules.blocklist ]; then |
| # TODO: the modules blocklist could contain module aliases instead of the filename |
| sed -n -E -e 's/blocklist (.+)/\1/p' ${dest_dir}/modules.blocklist > $used_blocklist_modules |
| fi |
| |
| # Trim modules from tree that aren't mentioned in modules.order |
| ( |
| cd ${dest_dir} |
| find * -type f -name "*.ko" | (grep -v -w -f modules.order -f $used_blocklist_modules - || true) | xargs -r rm |
| ) |
| rm $used_blocklist_modules |
| fi |
| |
| # Re-run depmod to detect any dependencies between in-kernel and external |
| # modules. Then, create modules.order based on all the modules compiled. |
| run_depmod ${dest_stage} "${depmod_flags}" "${version}" |
| cp ${dest_dir}/modules.order ${dest_dir}/modules.load |
| } |
| |
| function build_system_dlkm() { |
| echo "========================================================" |
| echo " Creating system_dlkm image" |
| |
| rm -rf ${SYSTEM_DLKM_STAGING_DIR} |
| create_modules_staging "${SYSTEM_DLKM_MODULES_LIST:-${MODULES_LIST}}" "${MODULES_STAGING_DIR}" \ |
| ${SYSTEM_DLKM_STAGING_DIR} "${SYSTEM_DLKM_MODULES_BLOCKLIST:-${MODULES_BLOCKLIST}}" "-e" |
| |
| local system_dlkm_root_dir=$(echo ${SYSTEM_DLKM_STAGING_DIR}/lib/modules/*) |
| cp ${system_dlkm_root_dir}/modules.load ${DIST_DIR}/system_dlkm.modules.load |
| local system_dlkm_props_file |
| |
| local system_dlkm_default_fs_type="ext4" |
| if [[ "${SYSTEM_DLKM_FS_TYPE}" != "ext4" && "${SYSTEM_DLKM_FS_TYPE}" != "erofs" ]]; then |
| echo "WARNING: Invalid SYSTEM_DLKM_FS_TYPE = ${SYSTEM_DLKM_FS_TYPE}" |
| SYSTEM_DLKM_FS_TYPE="${system_dlkm_default_fs_type}" |
| echo "INFO: Defaulting SYSTEM_DLKM_FS_TYPE to ${SYSTEM_DLKM_FS_TYPE}" |
| fi |
| |
| if [ -z "${SYSTEM_DLKM_PROPS}" ]; then |
| system_dlkm_props_file="$(mktemp)" |
| echo -e "system_dlkm_fs_type=${SYSTEM_DLKM_FS_TYPE}\n" >> ${system_dlkm_props_file} |
| echo -e "use_dynamic_partition_size=true\n" >> ${system_dlkm_props_file} |
| if [[ "${SYSTEM_DLKM_FS_TYPE}" == "ext4" ]]; then |
| echo -e "ext_mkuserimg=mkuserimg_mke2fs\n" >> ${system_dlkm_props_file} |
| echo -e "ext4_share_dup_blocks=true\n" >> ${system_dlkm_props_file} |
| fi |
| else |
| system_dlkm_props_file="${SYSTEM_DLKM_PROPS}" |
| if [[ -f "${ROOT_DIR}/${system_dlkm_props_file}" ]]; then |
| system_dlkm_props_file="${ROOT_DIR}/${system_dlkm_props_file}" |
| elif [[ "${system_dlkm_props_file}" != /* ]]; then |
| echo "SYSTEM_DLKM_PROPS must be an absolute path or relative to ${ROOT_DIR}: ${system_dlkm_props_file}" |
| exit 1 |
| elif [[ ! -f "${system_dlkm_props_file}" ]]; then |
| echo "Failed to find SYSTEM_DLKM_PROPS: ${system_dlkm_props_file}" |
| exit 1 |
| fi |
| fi |
| |
| # Re-sign the stripped modules using kernel build time key |
| # If SYSTEM_DLKM_RE_SIGN=0, this is a trick in Kleaf for building |
| # device-specific system_dlkm image, where keys are not available but the |
| # signed and stripped modules are in MODULES_STAGING_DIR. |
| if [[ ${SYSTEM_DLKM_RE_SIGN:-1} == "1" ]]; then |
| for module in $(find ${SYSTEM_DLKM_STAGING_DIR} -type f -name "*.ko"); do |
| ${OUT_DIR}/scripts/sign-file sha1 \ |
| ${OUT_DIR}/certs/signing_key.pem \ |
| ${OUT_DIR}/certs/signing_key.x509 "${module}" |
| done |
| fi |
| |
| build_image "${SYSTEM_DLKM_STAGING_DIR}" "${system_dlkm_props_file}" \ |
| "${DIST_DIR}/system_dlkm.img" /dev/null |
| |
| # No need to sign the image as modules are signed |
| avbtool add_hashtree_footer \ |
| --partition_name system_dlkm \ |
| --image "${DIST_DIR}/system_dlkm.img" |
| |
| # Archive system_dlkm_staging_dir |
| tar -czf "${DIST_DIR}/system_dlkm_staging_archive.tar.gz" -C "${SYSTEM_DLKM_STAGING_DIR}" . |
| } |
| |
| function build_vendor_dlkm() { |
| echo "========================================================" |
| echo " Creating vendor_dlkm image" |
| |
| create_modules_staging "${VENDOR_DLKM_MODULES_LIST}" "${MODULES_STAGING_DIR}" \ |
| "${VENDOR_DLKM_STAGING_DIR}" "${VENDOR_DLKM_MODULES_BLOCKLIST}" |
| |
| local vendor_dlkm_modules_root_dir=$(echo ${VENDOR_DLKM_STAGING_DIR}/lib/modules/*) |
| local vendor_dlkm_modules_load=${vendor_dlkm_modules_root_dir}/modules.load |
| if [ -f ${vendor_dlkm_modules_root_dir}/modules.blocklist ]; then |
| cp ${vendor_dlkm_modules_root_dir}/modules.blocklist ${DIST_DIR}/vendor_dlkm.modules.blocklist |
| fi |
| |
| # Modules loaded in vendor_boot should not be loaded in vendor_dlkm. |
| if [ -f ${DIST_DIR}/modules.load ]; then |
| local stripped_modules_load="$(mktemp)" |
| ! grep -x -v -F -f ${DIST_DIR}/modules.load \ |
| ${vendor_dlkm_modules_load} > ${stripped_modules_load} |
| mv -f ${stripped_modules_load} ${vendor_dlkm_modules_load} |
| fi |
| |
| cp ${vendor_dlkm_modules_load} ${DIST_DIR}/vendor_dlkm.modules.load |
| local vendor_dlkm_props_file |
| |
| local vendor_dlkm_default_fs_type="ext4" |
| if [[ "${VENDOR_DLKM_FS_TYPE}" != "ext4" && "${VENDOR_DLKM_FS_TYPE}" != "erofs" ]]; then |
| echo "WARNING: Invalid VENDOR_DLKM_FS_TYPE = ${VENDOR_DLKM_FS_TYPE}" |
| VENDOR_DLKM_FS_TYPE="${vendor_dlkm_default_fs_type}" |
| echo "INFO: Defaulting VENDOR_DLKM_FS_TYPE to ${VENDOR_DLKM_FS_TYPE}" |
| fi |
| |
| if [ -z "${VENDOR_DLKM_PROPS}" ]; then |
| vendor_dlkm_props_file="$(mktemp)" |
| echo -e "vendor_dlkm_fs_type=${VENDOR_DLKM_FS_TYPE}\n" >> ${vendor_dlkm_props_file} |
| echo -e "use_dynamic_partition_size=true\n" >> ${vendor_dlkm_props_file} |
| if [[ "${VENDOR_DLKM_FS_TYPE}" == "ext4" ]]; then |
| echo -e "ext_mkuserimg=mkuserimg_mke2fs\n" >> ${vendor_dlkm_props_file} |
| echo -e "ext4_share_dup_blocks=true\n" >> ${vendor_dlkm_props_file} |
| fi |
| else |
| vendor_dlkm_props_file="${VENDOR_DLKM_PROPS}" |
| if [[ -f "${ROOT_DIR}/${vendor_dlkm_props_file}" ]]; then |
| vendor_dlkm_props_file="${ROOT_DIR}/${vendor_dlkm_props_file}" |
| elif [[ "${vendor_dlkm_props_file}" != /* ]]; then |
| echo "VENDOR_DLKM_PROPS must be an absolute path or relative to ${ROOT_DIR}: ${vendor_dlkm_props_file}" |
| exit 1 |
| elif [[ ! -f "${vendor_dlkm_props_file}" ]]; then |
| echo "Failed to find VENDOR_DLKM_PROPS: ${vendor_dlkm_props_file}" |
| exit 1 |
| fi |
| fi |
| build_image "${VENDOR_DLKM_STAGING_DIR}" "${vendor_dlkm_props_file}" \ |
| "${DIST_DIR}/vendor_dlkm.img" /dev/null |
| } |
| |
| function check_mkbootimg_path() { |
| if [ -z "${MKBOOTIMG_PATH}" ]; then |
| MKBOOTIMG_PATH="tools/mkbootimg/mkbootimg.py" |
| fi |
| if [ ! -f "${MKBOOTIMG_PATH}" ]; then |
| echo "mkbootimg.py script not found. MKBOOTIMG_PATH = ${MKBOOTIMG_PATH}" |
| exit 1 |
| fi |
| } |
| |
| function build_boot_images() { |
| check_mkbootimg_path |
| |
| BOOT_IMAGE_HEADER_VERSION=${BOOT_IMAGE_HEADER_VERSION:-3} |
| MKBOOTIMG_ARGS=("--header_version" "${BOOT_IMAGE_HEADER_VERSION}") |
| if [ -n "${BASE_ADDRESS}" ]; then |
| MKBOOTIMG_ARGS+=("--base" "${BASE_ADDRESS}") |
| fi |
| if [ -n "${PAGE_SIZE}" ]; then |
| MKBOOTIMG_ARGS+=("--pagesize" "${PAGE_SIZE}") |
| fi |
| if [ -n "${KERNEL_VENDOR_CMDLINE}" -a "${BOOT_IMAGE_HEADER_VERSION}" -lt "3" ]; then |
| KERNEL_CMDLINE+=" ${KERNEL_VENDOR_CMDLINE}" |
| fi |
| if [ -n "${KERNEL_CMDLINE}" ]; then |
| MKBOOTIMG_ARGS+=("--cmdline" "${KERNEL_CMDLINE}") |
| fi |
| if [ -n "${TAGS_OFFSET}" ]; then |
| MKBOOTIMG_ARGS+=("--tags_offset" "${TAGS_OFFSET}") |
| fi |
| if [ -n "${RAMDISK_OFFSET}" ]; then |
| MKBOOTIMG_ARGS+=("--ramdisk_offset" "${RAMDISK_OFFSET}") |
| fi |
| |
| DTB_FILE_LIST=$(find ${DIST_DIR} -name "*.dtb" | sort) |
| if [ -z "${DTB_FILE_LIST}" ]; then |
| if [ -z "${SKIP_VENDOR_BOOT}" ]; then |
| echo "No *.dtb files found in ${DIST_DIR}" |
| exit 1 |
| fi |
| else |
| cat $DTB_FILE_LIST > ${DIST_DIR}/dtb.img |
| MKBOOTIMG_ARGS+=("--dtb" "${DIST_DIR}/dtb.img") |
| fi |
| |
| rm -rf "${MKBOOTIMG_STAGING_DIR}" |
| MKBOOTIMG_RAMDISK_STAGING_DIR="${MKBOOTIMG_STAGING_DIR}/ramdisk_root" |
| mkdir -p "${MKBOOTIMG_RAMDISK_STAGING_DIR}" |
| |
| if [ -z "${SKIP_UNPACKING_RAMDISK}" ]; then |
| if [ -n "${VENDOR_RAMDISK_BINARY}" ]; then |
| VENDOR_RAMDISK_CPIO="${MKBOOTIMG_STAGING_DIR}/vendor_ramdisk_binary.cpio" |
| rm -f "${VENDOR_RAMDISK_CPIO}" |
| for vendor_ramdisk_binary in ${VENDOR_RAMDISK_BINARY}; do |
| if ! [ -f "${vendor_ramdisk_binary}" ]; then |
| echo "Unable to locate vendor ramdisk ${vendor_ramdisk_binary}." |
| exit 1 |
| fi |
| if ${DECOMPRESS_GZIP} "${vendor_ramdisk_binary}" 2>/dev/null >> "${VENDOR_RAMDISK_CPIO}"; then |
| echo "${vendor_ramdisk_binary} is GZIP compressed" |
| elif ${DECOMPRESS_LZ4} "${vendor_ramdisk_binary}" 2>/dev/null >> "${VENDOR_RAMDISK_CPIO}"; then |
| echo "${vendor_ramdisk_binary} is LZ4 compressed" |
| elif cpio -t < "${vendor_ramdisk_binary}" &>/dev/null; then |
| echo "${vendor_ramdisk_binary} is plain CPIO archive" |
| cat "${vendor_ramdisk_binary}" >> "${VENDOR_RAMDISK_CPIO}" |
| else |
| echo "Unable to identify type of vendor ramdisk ${vendor_ramdisk_binary}" |
| rm -f "${VENDOR_RAMDISK_CPIO}" |
| exit 1 |
| fi |
| done |
| |
| # Remove lib/modules from the vendor ramdisk binary |
| # Also execute ${VENDOR_RAMDISK_CMDS} for further modifications |
| ( cd "${MKBOOTIMG_RAMDISK_STAGING_DIR}" |
| cpio -idu --quiet <"${VENDOR_RAMDISK_CPIO}" |
| rm -rf lib/modules |
| eval ${VENDOR_RAMDISK_CMDS} |
| ) |
| fi |
| |
| fi |
| |
| if [ -f "${VENDOR_FSTAB}" ]; then |
| mkdir -p "${MKBOOTIMG_RAMDISK_STAGING_DIR}/first_stage_ramdisk" |
| cp "${VENDOR_FSTAB}" "${MKBOOTIMG_RAMDISK_STAGING_DIR}/first_stage_ramdisk/" |
| fi |
| |
| HAS_RAMDISK= |
| MKBOOTIMG_RAMDISK_DIRS=() |
| if [ -n "${VENDOR_RAMDISK_BINARY}" ] || [ -f "${VENDOR_FSTAB}" ]; then |
| HAS_RAMDISK="1" |
| MKBOOTIMG_RAMDISK_DIRS+=("${MKBOOTIMG_RAMDISK_STAGING_DIR}") |
| fi |
| |
| if [ "${BUILD_INITRAMFS}" = "1" ]; then |
| HAS_RAMDISK="1" |
| if [ -z "${INITRAMFS_VENDOR_RAMDISK_FRAGMENT_NAME}" ]; then |
| MKBOOTIMG_RAMDISK_DIRS+=("${INITRAMFS_STAGING_DIR}") |
| fi |
| fi |
| |
| if [ -z "${HAS_RAMDISK}" ] && [ -z "${SKIP_VENDOR_BOOT}" ]; then |
| echo "No ramdisk found. Please provide a GKI and/or a vendor ramdisk." |
| exit 1 |
| fi |
| |
| if [ -n "${SKIP_UNPACKING_RAMDISK}" ] && [ -e "${VENDOR_RAMDISK_BINARY}" ]; then |
| cp "${VENDOR_RAMDISK_BINARY}" "${DIST_DIR}/ramdisk.${RAMDISK_EXT}" |
| elif [ "${#MKBOOTIMG_RAMDISK_DIRS[@]}" -gt 0 ]; then |
| MKBOOTIMG_RAMDISK_CPIO="${MKBOOTIMG_STAGING_DIR}/ramdisk.cpio" |
| mkbootfs "${MKBOOTIMG_RAMDISK_DIRS[@]}" >"${MKBOOTIMG_RAMDISK_CPIO}" |
| ${RAMDISK_COMPRESS} "${MKBOOTIMG_RAMDISK_CPIO}" >"${DIST_DIR}/ramdisk.${RAMDISK_EXT}" |
| fi |
| |
| if [ -n "${BUILD_BOOT_IMG}" ]; then |
| if [ ! -f "${DIST_DIR}/$KERNEL_BINARY" ]; then |
| echo "kernel binary(KERNEL_BINARY = $KERNEL_BINARY) not present in ${DIST_DIR}" |
| exit 1 |
| fi |
| MKBOOTIMG_ARGS+=("--kernel" "${DIST_DIR}/${KERNEL_BINARY}") |
| fi |
| |
| if [ "${BOOT_IMAGE_HEADER_VERSION}" -ge "4" ]; then |
| if [ -n "${VENDOR_BOOTCONFIG}" ]; then |
| for PARAM in ${VENDOR_BOOTCONFIG}; do |
| echo "${PARAM}" |
| done >"${DIST_DIR}/vendor-bootconfig.img" |
| MKBOOTIMG_ARGS+=("--vendor_bootconfig" "${DIST_DIR}/vendor-bootconfig.img") |
| KERNEL_VENDOR_CMDLINE+=" bootconfig" |
| fi |
| fi |
| |
| if [ "${BOOT_IMAGE_HEADER_VERSION}" -ge "3" ]; then |
| if [ -f "${GKI_RAMDISK_PREBUILT_BINARY}" ]; then |
| MKBOOTIMG_ARGS+=("--ramdisk" "${GKI_RAMDISK_PREBUILT_BINARY}") |
| fi |
| |
| if [ "${BUILD_VENDOR_KERNEL_BOOT}" = "1" ]; then |
| VENDOR_BOOT_NAME="vendor_kernel_boot.img" |
| elif [ -z "${SKIP_VENDOR_BOOT}" ]; then |
| VENDOR_BOOT_NAME="vendor_boot.img" |
| fi |
| if [ -n "${VENDOR_BOOT_NAME}" ]; then |
| MKBOOTIMG_ARGS+=("--vendor_boot" "${DIST_DIR}/${VENDOR_BOOT_NAME}") |
| if [ -n "${KERNEL_VENDOR_CMDLINE}" ]; then |
| MKBOOTIMG_ARGS+=("--vendor_cmdline" "${KERNEL_VENDOR_CMDLINE}") |
| fi |
| if [ -f "${DIST_DIR}/ramdisk.${RAMDISK_EXT}" ]; then |
| MKBOOTIMG_ARGS+=("--vendor_ramdisk" "${DIST_DIR}/ramdisk.${RAMDISK_EXT}") |
| fi |
| if [ "${BUILD_INITRAMFS}" = "1" ] \ |
| && [ -n "${INITRAMFS_VENDOR_RAMDISK_FRAGMENT_NAME}" ]; then |
| MKBOOTIMG_ARGS+=("--ramdisk_type" "DLKM") |
| for MKBOOTIMG_ARG in ${INITRAMFS_VENDOR_RAMDISK_FRAGMENT_MKBOOTIMG_ARGS}; do |
| MKBOOTIMG_ARGS+=("${MKBOOTIMG_ARG}") |
| done |
| MKBOOTIMG_ARGS+=("--ramdisk_name" "${INITRAMFS_VENDOR_RAMDISK_FRAGMENT_NAME}") |
| MKBOOTIMG_ARGS+=("--vendor_ramdisk_fragment" "${DIST_DIR}/initramfs.img") |
| fi |
| fi |
| else |
| if [ -f "${DIST_DIR}/ramdisk.${RAMDISK_EXT}" ]; then |
| MKBOOTIMG_ARGS+=("--ramdisk" "${DIST_DIR}/ramdisk.${RAMDISK_EXT}") |
| fi |
| fi |
| |
| if [ -z "${BOOT_IMAGE_FILENAME}" ]; then |
| BOOT_IMAGE_FILENAME="boot.img" |
| fi |
| if [ -n "${BUILD_BOOT_IMG}" ]; then |
| MKBOOTIMG_ARGS+=("--output" "${DIST_DIR}/${BOOT_IMAGE_FILENAME}") |
| fi |
| |
| for MKBOOTIMG_ARG in ${MKBOOTIMG_EXTRA_ARGS}; do |
| MKBOOTIMG_ARGS+=("${MKBOOTIMG_ARG}") |
| done |
| |
| "${MKBOOTIMG_PATH}" "${MKBOOTIMG_ARGS[@]}" |
| |
| if [ -n "${BUILD_BOOT_IMG}" -a -f "${DIST_DIR}/${BOOT_IMAGE_FILENAME}" ]; then |
| echo "boot image created at ${DIST_DIR}/${BOOT_IMAGE_FILENAME}" |
| |
| if [ -n "${AVB_SIGN_BOOT_IMG}" ]; then |
| if [ -n "${AVB_BOOT_PARTITION_SIZE}" ] \ |
| && [ -n "${AVB_BOOT_KEY}" ] \ |
| && [ -n "${AVB_BOOT_ALGORITHM}" ]; then |
| echo "Signing ${BOOT_IMAGE_FILENAME}..." |
| |
| if [ -z "${AVB_BOOT_PARTITION_NAME}" ]; then |
| AVB_BOOT_PARTITION_NAME=${BOOT_IMAGE_FILENAME%%.*} |
| fi |
| |
| avbtool add_hash_footer \ |
| --partition_name ${AVB_BOOT_PARTITION_NAME} \ |
| --partition_size ${AVB_BOOT_PARTITION_SIZE} \ |
| --image "${DIST_DIR}/${BOOT_IMAGE_FILENAME}" \ |
| --algorithm ${AVB_BOOT_ALGORITHM} \ |
| --key ${AVB_BOOT_KEY} |
| else |
| echo "Missing the AVB_* flags. Failed to sign the boot image" 1>&2 |
| exit 1 |
| fi |
| fi |
| fi |
| |
| if [ -z "${SKIP_VENDOR_BOOT}" ] \ |
| && [ "${BOOT_IMAGE_HEADER_VERSION}" -ge "3" ] \ |
| && [ -f "${DIST_DIR}/${VENDOR_BOOT_NAME}" ]; then |
| echo "Created ${VENDOR_BOOT_NAME} at ${DIST_DIR}/${VENDOR_BOOT_NAME}" |
| fi |
| } |
| |
| function make_dtbo() { |
| echo "========================================================" |
| echo " Creating dtbo image at ${DIST_DIR}/dtbo.img" |
| ( |
| cd ${OUT_DIR} |
| mkdtimg create "${DIST_DIR}"/dtbo.img ${MKDTIMG_FLAGS} ${MKDTIMG_DTBOS} |
| ) |
| } |
| |
| # gki_get_boot_img_size <compression method>. |
| # The function echoes the value of the preconfigured size variable |
| # based on the input compression method. |
| # - (empty): echo ${BUILD_GKI_BOOT_IMG_SIZE} |
| # - gz: echo ${BUILD_GKI_BOOT_IMG_GZ_SIZE} |
| # - lz4: echo ${BUILD_GKI_BOOT_IMG_LZ4_SIZE} |
| function gki_get_boot_img_size() { |
| local compression |
| |
| if [ -z "$1" ]; then |
| boot_size_var="BUILD_GKI_BOOT_IMG_SIZE" |
| else |
| compression=$(echo "$1" | tr '[:lower:]' '[:upper:]') |
| boot_size_var="BUILD_GKI_BOOT_IMG_${compression}_SIZE" |
| fi |
| |
| if [ -z "${!boot_size_var}" ]; then |
| echo "ERROR: ${boot_size_var} is not set." >&2 |
| exit 1 |
| fi |
| |
| echo "${!boot_size_var}" |
| } |
| |
| # gki_add_avb_footer <image> <partition_size> |
| function gki_add_avb_footer() { |
| avbtool add_hash_footer --image "$1" \ |
| --partition_name boot --partition_size "$2" |
| } |
| |
| # gki_dry_run_certify_bootimg <boot_image> <gki_artifacts_info_file> |
| # The certify_bootimg script will be executed on a server over a GKI |
| # boot.img during the official certification process, which embeds |
| # a GKI certificate into the boot.img. The certificate is for Android |
| # VTS to verify that a GKI boot.img is authentic. |
| # Dry running the process here so we can catch related issues early. |
| function gki_dry_run_certify_bootimg() { |
| certify_bootimg --boot_img "$1" \ |
| --algorithm SHA256_RSA4096 \ |
| --key tools/mkbootimg/gki/testdata/testkey_rsa4096.pem \ |
| --gki_info "$2" \ |
| --output "$1" |
| } |
| |
| # build_gki_artifacts_info <output_gki_artifacts_info_file> |
| function build_gki_artifacts_info() { |
| local artifacts_info="certify_bootimg_extra_args=--prop ARCH:${ARCH} \ |
| --prop BRANCH:${BRANCH}" |
| |
| if [ -n "${BUILD_NUMBER}" ]; then |
| artifacts_info="${artifacts_info} --prop BUILD_NUMBER:${BUILD_NUMBER}" |
| fi |
| |
| KERNEL_RELEASE="$(cat "${OUT_DIR}"/include/config/kernel.release)" |
| artifacts_info="${artifacts_info} --prop KERNEL_RELEASE:${KERNEL_RELEASE}" |
| |
| echo "${artifacts_info}" > "$1" |
| } |
| |
| # build_gki_boot_images <uncompressed kernel path>. |
| # The function builds boot-*.img for kernel images |
| # with the prefix of <uncompressed kernel path>. |
| # It also generates a boot-img.tar.gz containing those |
| # boot-*.img files. The uncompressed kernel image should |
| # exist, e.g., ${DIST_DIR}/Image, while other compressed |
| # kernel images are optional, e.g., ${DIST_DIR}/Image.gz. |
| function build_gki_boot_images() { |
| local uncompressed_kernel_path=$1 |
| |
| if ! [ -f "${uncompressed_kernel_path}" ]; then |
| echo "ERROR: '${uncompressed_kernel_path}' doesn't exist" >&2 |
| exit 1 |
| fi |
| |
| uncompressed_kernel_image="$(basename "${uncompressed_kernel_path}")" |
| |
| DEFAULT_MKBOOTIMG_ARGS=("--header_version" "4") |
| if [ -n "${GKI_KERNEL_CMDLINE}" ]; then |
| DEFAULT_MKBOOTIMG_ARGS+=("--cmdline" "${GKI_KERNEL_CMDLINE}") |
| fi |
| |
| GKI_ARTIFACTS_INFO_FILE="${DIST_DIR}/gki-info.txt" |
| build_gki_artifacts_info "${GKI_ARTIFACTS_INFO_FILE}" |
| local images_to_pack=("$(basename "${GKI_ARTIFACTS_INFO_FILE}")") |
| |
| # Compressed kernel images, e.g., Image.gz, Image.lz4 have the same |
| # prefix as the uncompressed kernel image, e.g., Image. |
| for kernel_path in "${uncompressed_kernel_path}"*; do |
| GKI_MKBOOTIMG_ARGS=("${DEFAULT_MKBOOTIMG_ARGS[@]}") |
| GKI_MKBOOTIMG_ARGS+=("--kernel" "${kernel_path}") |
| |
| if [ "${kernel_path}" = "${uncompressed_kernel_path}" ]; then |
| boot_image="boot.img" |
| else |
| kernel_image="$(basename "${kernel_path}")" |
| compression="${kernel_image#"${uncompressed_kernel_image}".}" |
| boot_image="boot-${compression}.img" |
| fi |
| |
| boot_image_path="${DIST_DIR}/${boot_image}" |
| GKI_MKBOOTIMG_ARGS+=("--output" "${boot_image_path}") |
| "${MKBOOTIMG_PATH}" "${GKI_MKBOOTIMG_ARGS[@]}" |
| |
| gki_add_avb_footer "${boot_image_path}" \ |
| "$(gki_get_boot_img_size "${compression}")" |
| gki_dry_run_certify_bootimg "${boot_image_path}" \ |
| "${GKI_ARTIFACTS_INFO_FILE}" |
| images_to_pack+=("${boot_image}") |
| done |
| |
| GKI_BOOT_IMG_ARCHIVE="boot-img.tar.gz" |
| echo "Creating ${GKI_BOOT_IMG_ARCHIVE} for" "${images_to_pack[@]}" |
| tar -czf "${DIST_DIR}/${GKI_BOOT_IMG_ARCHIVE}" -C "${DIST_DIR}" \ |
| "${images_to_pack[@]}" |
| } |
| |
| function build_gki_artifacts() { |
| check_mkbootimg_path |
| |
| if [ "${ARCH}" = "arm64" -o "${ARCH}" = "riscv64" ]; then |
| build_gki_boot_images "${DIST_DIR}/Image" |
| elif [ "${ARCH}" = "x86_64" ]; then |
| build_gki_boot_images "${DIST_DIR}/bzImage" |
| else |
| echo "ERROR: unknown ARCH to BUILD_GKI_ARTIFACTS: '${ARCH}'" >&2 |
| exit 1 |
| fi |
| } |
| |
| function sort_config() { |
| # Normal sort won't work because all the "# CONFIG_.. is not set" would come |
| # before all the "CONFIG_..=m". Use sed to extract the CONFIG_ option and prefix |
| # the line in front of the line to create a key (e.g. CONFIG_.. # CONFIG_.. is not set), |
| # sort, then remove the key |
| sed -E -e 's/.*(CONFIG_[^ =]+).*/\1 \0/' $1 | sort -k1 | cut -F2- |
| } |
| |
| function menuconfig() { |
| set +x |
| local orig_config=$(mktemp) |
| local new_config="${OUT_DIR}/.config" |
| local changed_config=$(mktemp) |
| local new_fragment=$(mktemp) |
| |
| trap "rm -f ${orig_config} ${changed_config} ${new_fragment}" EXIT |
| |
| if [ -n "${FRAGMENT_CONFIG}" ]; then |
| if [[ -f "${ROOT_DIR}/${FRAGMENT_CONFIG}" ]]; then |
| FRAGMENT_CONFIG="${ROOT_DIR}/${FRAGMENT_CONFIG}" |
| elif [[ "${FRAGMENT_CONFIG}" != /* ]]; then |
| echo "FRAGMENT_CONFIG must be an absolute path or relative to ${ROOT_DIR}: ${FRAGMENT_CONFIG}" |
| exit 1 |
| elif [[ ! -f "${FRAGMENT_CONFIG}" ]]; then |
| echo "Failed to find FRAGMENT_CONFIG: ${FRAGMENT_CONFIG}" |
| exit 1 |
| fi |
| fi |
| |
| cp ${OUT_DIR}/.config ${orig_config} |
| (cd ${KERNEL_DIR} && make ${TOOL_ARGS} O=${OUT_DIR} ${MAKE_ARGS} ${1:-menuconfig}) |
| |
| if [ -z "${FRAGMENT_CONFIG}" ]; then |
| (cd ${KERNEL_DIR} && make ${TOOL_ARGS} O=${OUT_DIR} ${MAKE_ARGS} savedefconfig) |
| [ "$ARCH" = "x86_64" -o "$ARCH" = "i386" ] && local ARCH=x86 |
| echo "Updating ${ROOT_DIR}/${KERNEL_DIR}/arch/${ARCH}/configs/${DEFCONFIG}" |
| mv ${OUT_DIR}/defconfig ${ROOT_DIR}/${KERNEL_DIR}/arch/${ARCH}/configs/${DEFCONFIG} |
| return |
| fi |
| |
| ${KERNEL_DIR}/scripts/diffconfig -m ${orig_config} ${new_config} > ${changed_config} |
| KCONFIG_CONFIG=${new_fragment} ${ROOT_DIR}/${KERNEL_DIR}/scripts/kconfig/merge_config.sh -m ${FRAGMENT_CONFIG} ${changed_config} |
| sort_config ${new_fragment} > ${FRAGMENT_CONFIG} |
| set +x |
| |
| |
| echo |
| echo "Updated ${FRAGMENT_CONFIG}" |
| echo |
| } |