#!/bin/bash ## (c) Copyright 2020 Xilinx, Inc. All rights reserved. ## ## This file contains confidential and proprietary information ## of Xilinx, Inc. and is protected under U.S. and ## international copyright and other intellectual property ## laws. ## ## DISCLAIMER ## This disclaimer is not a license and does not grant any ## rights to the materials distributed herewith. Except as ## otherwise provided in a valid license issued to you by ## Xilinx, and to the maximum extent permitted by applicable ## law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND ## WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES ## AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING ## BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- ## INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and ## (2) Xilinx shall not be liable (whether in contract or tort, ## including negligence, or under any other theory of ## liability) for any loss or damage of any kind or nature ## related to, arising under or in connection with these ## materials, including for any direct, or any indirect, ## special, incidental, or consequential loss or damage ## (including loss of data, profits, goodwill, or any type of ## loss or damage suffered as a result of any action brought ## by a third party) even if such damage or loss was ## reasonably foreseeable or Xilinx had been advised of the ## possibility of the same. ## ## CRITICAL APPLICATIONS ## Xilinx products are not designed or intended to be fail- ## safe, or for use in any application requiring fail-safe ## performance, such as life-support or safety devices or ## systems, Class III medical devices, nuclear facilities, ## applications related to the deployment of airbags, or any ## other applications that could lead to death, personal ## injury, or severe property or environmental damage ## (individually and collectively, "Critical ## Applications"). Customer assumes the sole risk and ## liability of any use of Xilinx products in Critical ## Applications, subject only to applicable laws and ## regulations governing limitations on product liability. ## ## THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS ## PART OF THIS FILE AT ALL TIMES. # This script must be run with root permissions # if [[ "$EUID" -ne 0 ]]; then # echo "This script must be run as root." # exit # fi # Get absolute path to this script with any symlinks resolved realme=$(realpath $0) scriptpath="${realme%/*}" echo "This is create_xsabin.sh running from $scriptpath on $(date)" # The directory above that is the human-readable installation path - probably /opt/xilinx/firmware//// humanpath=${scriptpath%/*} pushd $humanpath > /dev/null # This script may be called during firmware upgrade, in which case the firmware product, branch, version and release # are provided as script arguments, to help this script to select the new firmware file if [[ "$#" -ge 4 ]]; then firmware_upgrade_product=$1 firmware_upgrade_branch=$2 firmware_upgrade_version=$3 firmware_upgrade_release=$4 echo "Run for install of firmware $firmware_upgrade_product-$firmware_upgrade_branch version $firmware_upgrade_version release $firmware_upgrade_release" elif [[ "$#" -eq 3 ]]; then # If 3 script arguments, these are the partition name, version and release, so that this script can report them for debug echo "Run for install of partition $1 version $2 release $3" fi # Find the partition_metadata.json link in the install directory jsonlink="partition_metadata.json" if [[ ! -e "$jsonlink" ]]; then echo "Cannot find $jsonlink file in $humanpath - install failed" exit 1 fi # Find the machine-readable directory for this partition: # this is the target of the partition_metadata.json link if [[ ! -h "$jsonlink" ]]; then echo "$jsonlink in $humanpath should be a symlink, but it is not - install failed" exit 1 fi jsonpath=$(readlink $jsonlink) if [[ $? -ne 0 ]]; then echo "Failed to read target of symlink $jsonlink in $humanpath - install failed" exit 1 fi if [[ ! -e "$jsonpath" ]]; then echo "Target of symlink $jsonlink in $humanpath is $jsonpath, which does not exist - install failed" exit 1 fi echo "Metadata file is $jsonpath" machinepath=${jsonpath%/*} json=${jsonpath##*/} echo "User install path is $humanpath" echo "Machine-readable path is $machinepath" pushd $machinepath > /dev/null # Parse the partition_metadata.json file to find the required firmware declare -A firmware firmware_products=() product="" branch="mainline" major="*" minor="*" revision="*" while IFS= read -r line; do key=${line#*\"} key=${key%%\"*} value=${line%\"*} value=${value##*\"} numvalue=$value if [[ "$numvalue" =~ ^0x ]]; then numvalue=$(($numvalue)) fi case "$key" in "firmware") # Starts a new section: record current one (except if before the first section) if [[ -n "$product" ]]; then firmware_products+=($product) firmware["$product.branch"]=$branch firmware["$product.version"]="$major.$minor.$revision" product="" branch="mainline" major="*" minor="*" revision="*" fi ;; "firmware_product_name") product=${value,,} ;; "firmware_branch_name") branch=${value,,} ;; "firmware_version_major") major=$numvalue ;; "firmware_version_minor") minor=$numvalue ;; "firmware_version_revision") revision=$numvalue ;; esac done <<< "$(grep '\"firmware' $json)" # Record last section firmware_products+=($product) firmware["$product.branch"]=$branch firmware["$product.version"]="$major.$minor.$revision" # Locate the required firmware in existing installed directories, and build xclbinutil options to add firmware # For each firmware, there is already a symlink in the human-readable directory's firmware directory # which points to the existing firmware install directory firmware_opts="" for product in "${firmware_products[@]}"; do uc_product=${product^^} branch=${firmware[$product.branch]} version=${firmware[$product.version]} link="$humanpath/firmware/$product-$branch" if [[ ! -L "$link" ]]; then echo "Expected symlink $link for required $product firmware, but this either does not exist or is not a symlink - install failed" exit 1 fi firmware_path=$(readlink -f $humanpath/firmware/$product-$branch) if [[ ! -e "$firmware_path" ]]; then echo "Required $product firmware install directory not found at $firmware_path. Unable to build xsabin files" exit 1 fi # Locate the required firmware binary file case "$product" in "ert") # ERT firmware is deployed within XRT and has its own file naming rule if [[ "$branch" == "mainline" ]] || [[ "$branch" == "legacy" ]] || [[ "$branch" == "" ]]; then ert_name="sched.bin" else ert_name="sched_$branch.bin" fi firmware_file="$firmware_path/$ert_name" if [[ ! -e "$firmware_file" ]]; then echo "Cannot locate required $product firmware: not found at $firmware_file. Unable to build xsabin files" exit 1 fi firmware_opts+=" --add-section SCHED_FIRMWARE:RAW:${firmware_file}" ;; *) # All other firmware is deployed in its own package # Accommodate possible variations in firmware file name, as long as the file name contains the product name # During firmware upgrade, it is possible that both the old and the new firmware files are both present # (the old one may not be removed until after this script has run). # In this situation, the new firmware product, branch and version are provided as script arguments: # select the appropriate file here (if multiple files are found). firmware_files=() for globfile in $firmware_path/*; do if [[ -e "$globfile" ]] && [[ ! -d "$globfile" ]]; then globfilename=${globfile##*/} if [[ "$globfilename" == *"$product"* ]] || [[ "$globfilename" == *"$uc_product"* ]]; then firmware_files+=($globfile) fi fi done if [[ "${#firmware_files[@]}" -eq 0 ]]; then echo "Cannot locate required $product firmware: not found at $firmware_path. Unable to build xsabin files" exit 1 fi firmware_file="" if [[ "${#firmware_files[@]}" -gt 1 ]]; then IFS=$'\n' firmware_files=( $(sort -V <<<"${firmware_files[*]}") ) unset IFS if [[ "$firmware_upgrade_product" == "$product" ]]; then firmware_file="" for fw_file in "${firmware_files[@]}"; do fw_filename=${fw_file##*/} if [[ "$fw_filename" == *"$firmware_upgrade_version"* ]]; then firmware_file=$fw_file fi done fi fi if [[ -z "$firmware_file" ]]; then firmware_file="${firmware_files[-1]}" fi # Select the correct xsabin section name, depending on the firmware product section="" case "$product" in "cmc") section="FIRMWARE" ;; "sc-fw" | "sc") section="BMC-FW" ;; *) echo "Unrecognised firmware product name '$product', unable to select the correct xsabin section name" exit 1 ;; esac firmware_opts+=" --add-section ${section}:RAW:${firmware_file}" # The SC firmware (BMC-FW section) may have a metadata JSON file also to be added if [[ "$section" == "BMC-FW" && -e "$firmware_path/metadata.json" ]]; then firmware_opts+=" --add-section BMC-METADATA:JSON:${firmware_path}/metadata.json" fi ;; esac done # Extract vendor, board, name and version from partition_metadata.json, to build PlatformVBNV declare -A vbnv for element in {partition_vendor,partition_card,partition_family,partition_name,installed_package_version}; do line="$(grep $element $json)" if [[ -n "$line" ]]; then value=${line%\"*} value=${value##*\"} if [[ "$element" != "partition_vendor" ]] && [[ "$element" != "partition_card" ]]; then value=${value//-/_} fi else value="UNKNOWN" fi vbnv[$element]=$value done platform_vbnv="${vbnv[partition_vendor]}:${vbnv[partition_card]}:${vbnv[partition_family]}_${vbnv[partition_name]}:${vbnv[installed_package_version]}" # Check for VBNV override in partition_metadata.json line="$(grep vbnv_override $json)" if [[ -n "$line" ]]; then value=${line%\"*} value=${value##*\"} # Check VBNV override value is correctly formatted (4 fields separated by colons) fields="$(echo "$value" | tr ':' ' ' | wc -w)" if [[ "$fields" == "4" ]]; then platform_vbnv=$value fi fi # Use the XRT standard install path to find xclbinutil xclbinutil="${xclbinutil:-/opt/xilinx/xrt/bin/xclbinutil}" if [[ ! -e "$xclbinutil" ]]; then echo "xclbinutil tool not found at $xclbinutil, unable to build xsabin files" exit 1 fi ## Must source XRT's setup.sh to set up environment correctly #if [[ ! -e /opt/xilinx/xrt/setup.sh ]]; then # echo "XRT setup.sh not found at /opt/xilinx/xrt/setup.sh, XRT installation is bad. Cannot build xsabin files" # exit 1 #fi #source /opt/xilinx/xrt/setup.sh # Build xclbinutil options for creating xsabin files xclbinopts=" --force" if [[ -e "partition.mcs" ]]; then xclbinopts+=" --add-section MCS-PRIMARY:RAW:partition.mcs" fi if [[ -e "partition_secondary.mcs" ]]; then xclbinopts+=" --add-section MCS-SECONDARY:RAW:partition_secondary.mcs" fi if [[ -e "partition.bin" ]]; then xclbinopts+=" --add-section FLASH[BIN]-DATA:RAW:partition.bin" fi if [[ -e "bin_metadata.json" ]]; then xclbinopts+=" --add-section FLASH[BIN]-METADATA:JSON:bin_metadata.json" fi if [[ -e "partition.bit" ]]; then xclbinopts+=" --add-section BITSTREAM:RAW:partition.bit" fi if [[ -e "partition.pdi" ]]; then xclbinopts+=" --add-section PDI:RAW:partition.pdi" fi xclbinopts+=" --add-section PARTITION_METADATA:JSON:${json}" xclbinopts+=$firmware_opts xclbinopts+=" --key-value SYS:PlatformVBNV:${platform_vbnv}" # Create partition.xsabin xsabin="partition.xsabin" xclbincmd="${xclbinutil} ${xclbinopts} --output $xsabin" echo $xclbincmd $xclbincmd if [[ $? -ne 0 ]]; then echo "An error occurred while running xclbinutil" exit 1 fi if [[ ! -e "$xsabin" ]]; then echo "xclbinutil did not create output file $xsabin" exit 1 fi # And we're done echo "create_xsabin.sh completed successfully"