Mellanox-rshim-user-space-0339e66/ 0000775 0001750 0001750 00000000000 15121734733 015063 5 ustar tai tai Mellanox-rshim-user-space-0339e66/third_party/ 0000775 0001750 0001750 00000000000 15101274612 017405 5 ustar tai tai Mellanox-rshim-user-space-0339e66/third_party/PLDM-unpack/ 0000775 0001750 0001750 00000000000 15101274612 021420 5 ustar tai tai Mellanox-rshim-user-space-0339e66/third_party/PLDM-unpack/fwpkg_unpack.py 0000775 0001750 0001750 00000132477 15101274612 024472 0 ustar tai tai #!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
"""Modules imported for unpack tool"""
import argparse
from datetime import datetime
import hashlib
import json
import math
import os
import re
import stat
import sys
import time
import uuid
UNPACK_TOOL_VERSION = "4.1.3"
class Util:
"""
Class with static helper functions
"""
LOG_FILE = "./fwpkg_unpack_log.txt"
LOGFILE_PATH = ""
@staticmethod
def cli_log(log_msg, log_file_only=False):
"""
Append log message to cli log file
"""
log_file = Util.LOG_FILE
file_handle = None
try:
with open(log_file, "a+", encoding="utf-8") as file_handle:
localtime = time.asctime(time.localtime(time.time()))
file_handle.write(f"{localtime} : {log_msg}\n")
Util.LOGFILE_PATH = os.path.abspath(file_handle.name)
if log_file_only is False:
print(log_msg)
except PermissionError as _:
print(log_msg)
print(f"Error: Failed to open or create {log_file}")
@staticmethod
def get_descriptor_type_name(desc_type):
"""
Return the descriptive name for given integer descriptor type.
"""
desc_type_dict = {
0x0000: "PCI Vendor ID",
0x0001: "IANA Enterprise ID",
0x0002: "UUID",
0x0003: "PnP Vendor ID",
0x0004: "ACPI Vendor ID",
0x0005: "IEEE Assigned Company ID",
0x0006: "SCSI Vendor ID",
0x0100: "PCI Device ID",
0x0101: "PCI Subsystem Vendor ID",
0x0102: "PCI Subsystem ID",
0x0103: "PCI Revision ID",
0x0104: "PnP Product Identifier",
0x0105: "ACPI Product Identifier",
0x0106: "ASCII Model Number",
0x0107: "ASCII Model Number",
0x0108: "SCSI Product ID",
0x0109: "UBM Controller Device Code",
0xffff: "Vendor Defined",
}
name = desc_type_dict.get(desc_type, f'{desc_type:#x}')
return name
@staticmethod
def get_alt_time_format(time_stamp):
""" Convert Y-m-d H:M:S:f z format to d/m/y H:M:S """
parts = time_stamp.split(' ')
time_stamp_no_zone = ' '.join(parts[:-1])
original_format = "%Y-%m-%d %H:%M:%S:%f"
date_object = datetime.strptime(time_stamp_no_zone, original_format)
new_format = "%d/%m/%Y %H:%M:%S"
new_time_stamp = date_object.strftime(new_format)
return new_time_stamp
@staticmethod
def get_set_bit_indices(int_val):
""" Get list of set bit indices in a number """
set_bit_indices = []
index = 0
while int_val > 0:
if int_val & 1:
set_bit_indices.append(index)
int_val >>= 1
index += 1
return set_bit_indices
@staticmethod
def get_timestamp_str(timestamp):
"""
Return timestamp string from 13 byte binary data
according to PLDM Base specification
"""
year = timestamp[11]
year = year << 8
year = year | timestamp[10]
time_str = str(year) + "-"
time_str = time_str + str(timestamp[9])
time_str = time_str + "-" + str(timestamp[8])
time_str = time_str + " " + str(timestamp[7])
time_str = time_str + ":" + str(timestamp[6])
time_str = time_str + ":" + str(timestamp[5])
micro_sec = timestamp[4]
micro_sec = micro_sec << 8
micro_sec = micro_sec | timestamp[3]
micro_sec = micro_sec << 8
micro_sec = micro_sec | timestamp[2]
time_str = time_str + ":" + str(micro_sec)
utc_offset = timestamp[1]
utc_offset = utc_offset << 8
utc_offset = utc_offset | timestamp[0]
sign = "+"
if utc_offset < 0:
utc_offset = utc_offset * -1
sign = "-"
time_str = time_str + " " + sign + str(utc_offset)
return time_str
@staticmethod
def get_checksum_for_component_image(fw_image):
"""
Compute SHA256 for the given component image.
"""
sha256 = ""
try:
with open(fw_image, 'rb') as file_name:
data = file_name.read()
sha256 = hashlib.sha256(data).hexdigest()
except (FileNotFoundError, IOError) as err:
log_msg = f'Error: {err}'
Util.cli_log(log_msg, False)
return sha256
@staticmethod
def get_padded_hex(byte_arr):
"""
Get hex formatted version of a byte array padded with 0
"""
total_len = len(byte_arr)
hex_str = hex(
int.from_bytes(byte_arr, byteorder='little', signed=False))[2:]
padded_str = '0x' + hex_str.zfill(total_len * 2)
return padded_str
class PLDMUnpack:
# pylint: disable=too-many-instance-attributes
"""
PLDMUnpack class implements a PLDM parser and the unpack tool
along with its required features.
...
Attributes
----------
package : str
Path/Name of the input firmware package
unpack : bool
True if tool should unpack firmware images
fwpkg_fd : io.TextIOWrapper
Instance used to read from package file
header_map : dict
Stores the PLDM Package Header Information parsed from given package
device_id_record_count : int
Number of PLDM FirmwareDeviceIDRecords found in given package
fd_id_record_list : list
List of FirmwareDeviceIDRecords parsed from given package
component_img_info_list : list
List of ComponentImageInformation parsed from given package
Methods
-------
parse_header() :
Parses PLDM Package Header Information
parse_device_id_records() :
Parses FirmwareDeviceIDRecords from package
parse_component_img_info() :
Parses ComponentImageInformation from package
get_image_name_from_records(comp_info_index) :
Identify records which which contain metadata for image naming
get_image_name(comp_info_index) :
Get image name string by appending various metadata
create_unpacked_files(output_dir) :
Extract each firmware image in a file
unpack_pldm_package(package_name, output_dir) :
Perform complete parsing and extraction of package
get_applicable_component_index(applicable_component):
Return applicable_component as list of indices
get_ec_info(filepath) :
Get all EC metadata from extraxted firmware
get_ap_metadata(filepath) :
Get all AP metadata from extraxted firmware
get_signature_type(fw_image, component_identifier):
Get Signature type for given firmware image and component identifier
is_glacier_device(product, device_name):
Is this device a glacer device
get_formatted_descriptors(record_desc, components):
Method to prepare descriptor section for json output
prepare_records_json():
Prepares the JSON output.
"""
def __init__(self):
"""
Contructor for PLDMUnpack class
"""
self.unpack = True
self.package = ""
self.fwpkg_fd = 0
self.header_map = {}
self.device_id_record_count = 0
self.fd_id_record_list = []
self.component_img_info_list = []
self.full_header = {
"PackageHeaderInformation": {},
"FirmwareDeviceIdentificationArea": {},
"ComponentImageInformationArea": {},
"Package Header Checksum": ''
}
self.pkg_builder_json = {
"PackageHeaderInformation":{},
"FirmwareDeviceIdentificationArea": [],
"ComponentImageInformationArea": []
}
self.verbose = False
self.little_endian_list = [
"IANA Enterprise ID", "PCI Vendor ID", "PCI Device ID",
"PCI Subsystem Vendor ID", "PCI Subsystem ID"
]
def parse_header(self):
"""
Parse PLDM header data into self.header_map
Returns :
True if parsing successful
"""
# check if UUID is valid
pldm_fw_header_id_v1_0 = b'\xf0\x18\x87\x8c\xcb\x7d\x49\x43\x98\x00\xa0\x2f\x05\x9a\xca\x02'
uuid_v1_0 = str(uuid.UUID(bytes=pldm_fw_header_id_v1_0))
try:
self.header_map["PackageHeaderIdentifier"] = str(
uuid.UUID(bytes=self.fwpkg_fd.read(16)))
except ValueError:
log_msg = "Error: incorrect package format."
Util.cli_log(log_msg, False)
return False
if uuid_v1_0 != self.header_map["PackageHeaderIdentifier"]:
log_msg = "Expected PLDM v1.0 but PackageHeaderIdentifier is "\
+ self.header_map["PackageHeaderIdentifier"]
Util.cli_log(log_msg, False)
return False
self.header_map["PackageHeaderFormatRevision"] = str(
int.from_bytes(self.fwpkg_fd.read(1),
byteorder='little',
signed=False))
self.header_map["PackageHeaderSize"] = int.from_bytes(
self.fwpkg_fd.read(2), byteorder='little', signed=False)
timestamp = self.fwpkg_fd.read(13)
self.header_map["PackageReleaseDateTime"] = Util.get_timestamp_str(
timestamp)
self.header_map["ComponentBitmapBitLength"] = int.from_bytes(
self.fwpkg_fd.read(2), byteorder='little', signed=False)
self.header_map["PackageVersionStringType"] = int.from_bytes(
self.fwpkg_fd.read(1), byteorder='little', signed=False)
version_str_len = int.from_bytes(self.fwpkg_fd.read(1),
byteorder='little',
signed=False)
self.header_map["PackageVersionStringLength"] = version_str_len
self.header_map["PackageVersionString"] = self.fwpkg_fd.read(
version_str_len).split(b'\x00')[0].decode('utf-8')
self.full_header["PackageHeaderInformation"] = self.header_map
return True
def parse_device_id_records(self):
"""
Parse PLDM FirmwareDeviceIDRecords data into self.fd_id_record_list
Returns:
True if parsing is successful
"""
# pylint: disable=line-too-long
self.device_id_record_count = int.from_bytes(self.fwpkg_fd.read(1),
byteorder='little',
signed=False)
for _ in range(self.device_id_record_count):
id_record_map = {}
id_record_map["RecordLength"] = int.from_bytes(
self.fwpkg_fd.read(2), byteorder='little', signed=False)
id_record_map["DescriptorCount"] = int.from_bytes(
self.fwpkg_fd.read(1), byteorder='little', signed=False)
id_record_map["DeviceUpdateOptionFlags"] = int.from_bytes(
self.fwpkg_fd.read(4), byteorder='little', signed=False)
id_record_map[
"ComponentImageSetVersionStringType"] = int.from_bytes(
self.fwpkg_fd.read(1), byteorder='little', signed=False)
id_record_map[
"ComponentImageSetVersionStringLength"] = int.from_bytes(
self.fwpkg_fd.read(1), byteorder='little', signed=False)
id_record_map["FirmwareDevicePackageDataLength"] = int.from_bytes(
self.fwpkg_fd.read(2), byteorder='little', signed=False)
applicable_component_size = math.ceil(
self.header_map["ComponentBitmapBitLength"] / 8)
id_record_map["ApplicableComponents"] = int.from_bytes(
self.fwpkg_fd.read(applicable_component_size),
byteorder='little',
signed=False)
id_record_map[
"ComponentImageSetVersionString"] = self.fwpkg_fd.read(
id_record_map["ComponentImageSetVersionStringLength"]
).split(b'\x00')[0].decode('utf-8')
descriptors = []
for j in range(id_record_map["DescriptorCount"]):
descriptor_map = {}
if j == 0:
descriptor_map["InitialDescriptorType"] = int.from_bytes(
self.fwpkg_fd.read(2),
byteorder='little',
signed=False)
descriptor_map["InitialDescriptorLength"] = int.from_bytes(
self.fwpkg_fd.read(2),
byteorder='little',
signed=False)
value = self.fwpkg_fd.read(
descriptor_map["InitialDescriptorLength"])
descriptor_map["InitialDescriptorData"] = value
else:
descriptor_map[
"AdditionalDescriptorType"] = int.from_bytes(
self.fwpkg_fd.read(2),
byteorder='little',
signed=False)
descriptor_map[
"AdditionalDescriptorLength"] = int.from_bytes(
self.fwpkg_fd.read(2),
byteorder='little',
signed=False)
if descriptor_map["AdditionalDescriptorType"] == 0xFFFF:
descriptor_map[
"VendorDefinedDescriptorTitleStringType"] = int.from_bytes(
self.fwpkg_fd.read(1),
byteorder='little',
signed=False)
descriptor_map[
"VendorDefinedDescriptorTitleStringLength"] = int.from_bytes(
self.fwpkg_fd.read(1),
byteorder='little',
signed=False)
descriptor_map[
"VendorDefinedDescriptorTitleString"] = self.fwpkg_fd.read(
descriptor_map[
"VendorDefinedDescriptorTitleStringLength"]
).split(b'\x00')[0].decode('utf-8')
vendor_def_data_len = (
descriptor_map["AdditionalDescriptorLength"] -
(2 + descriptor_map[
"VendorDefinedDescriptorTitleStringLength"]))
descriptor_map[
"VendorDefinedDescriptorData"] = self.fwpkg_fd.read(
vendor_def_data_len).hex()
else:
descriptor_map[
"AdditionalDescriptorIdentifierData"] = self.fwpkg_fd.read(
descriptor_map["AdditionalDescriptorLength"])
descriptors.append(descriptor_map)
id_record_map["RecordDescriptors"] = descriptors
id_record_map["FirmwareDevicePackageData"] = self.fwpkg_fd.read(
id_record_map["FirmwareDevicePackageDataLength"]).decode(
'utf-8')
self.fd_id_record_list.append(id_record_map)
self.full_header["FirmwareDeviceIdentificationArea"] = {
"DeviceIDRecordCount": self.device_id_record_count,
"FirmwareDeviceIDRecords": self.fd_id_record_list
}
return True
def parse_component_img_info(self):
"""
Parse PLDM Component Image info data into self.fd_id_record_list
Returns :
True if parsing successful
"""
component_image_count = int.from_bytes(self.fwpkg_fd.read(2),
byteorder='little',
signed=False)
for _ in range(component_image_count):
comp_info = {}
comp_info["ComponentClassification"] = int.from_bytes(
self.fwpkg_fd.read(2), byteorder='little', signed=False)
comp_info["ComponentIdentifier"] = hex(
int.from_bytes(self.fwpkg_fd.read(2),
byteorder='little',
signed=False))
comp_info["ComponentComparisonStamp"] = Util.get_padded_hex(self.fwpkg_fd.read(4))
comp_info["ComponentOptions"] = int.from_bytes(
self.fwpkg_fd.read(2), byteorder='little', signed=False)
comp_info["RequestedComponentActivationMethod"] = int.from_bytes(
self.fwpkg_fd.read(2), byteorder='little', signed=False)
# RequestedComponentActivationMethod can have any combination of bits 0:5 set
# Any value above 0x3F is invalid
activation_val = comp_info["RequestedComponentActivationMethod"]
if activation_val > 0x3F:
Util.cli_log(
f"Found invalid value for RequestedComponentActivationMethod={activation_val}",
True)
comp_info["ComponentLocationOffset"] = int.from_bytes(
self.fwpkg_fd.read(4), byteorder='little', signed=False)
comp_info["ComponentSize"] = int.from_bytes(self.fwpkg_fd.read(4),
byteorder='little',
signed=False)
comp_info["ComponentVersionStringType"] = int.from_bytes(
self.fwpkg_fd.read(1), byteorder='little', signed=False)
comp_info["ComponentVersionStringLength"] = int.from_bytes(
self.fwpkg_fd.read(1), byteorder='little', signed=False)
comp_info["ComponentVersionString"] = self.fwpkg_fd.read(
comp_info["ComponentVersionStringLength"]).split(b'\x00')[0].decode('utf-8')
self.component_img_info_list.append(comp_info)
self.full_header["ComponentImageInformationArea"] = {
"ComponentImageCount": component_image_count,
"ComponentImageInformation": self.component_img_info_list
}
return True
def get_image_name_from_records(self, comp_info_index):
"""
Identify records which which contain metadata for image at
index comp_info_index component image info list
Parameter:
comp_info_index index of image in component image
info section
Returns:
Name of the applicable record for given image
or "" if nothing found
"""
mask = 1 << comp_info_index
for rec in self.fd_id_record_list:
applicable_comp_indices = rec["ApplicableComponents"]
name = rec["ComponentImageSetVersionString"]
if mask & applicable_comp_indices == mask:
if name.find(",") == -1:
return name, rec['RecordDescriptors']
components = name.split(",")
applicable_comp = applicable_comp_indices
count = 0
for _ in range(comp_info_index + 1):
if applicable_comp & 1 == 1:
count = count + 1
applicable_comp = applicable_comp >> 1
return components[count - 1], rec['RecordDescriptors']
return "", None
def get_image_name(self, comp_info_index):
"""
Create the image name string by appending various metadata
separated by '_'
Parameter:
comp_info_index index of image in component image
for naming
Returns:
Name of the image for unpacking
or ""
"""
comp_info = self.component_img_info_list[comp_info_index]
name, _ = self.get_image_name_from_records(comp_info_index)
if name != "":
name = name.replace(":", "_")
name = name.replace("_N/A", "")
name = name + "_" + comp_info["ComponentVersionString"]
if name.startswith("FW-Package"):
name = name + ".fwpkg"
else:
name = name + "_image.bin"
name = re.sub("_+", "_", name)
return name
def create_unpacked_files(self, output_dir):
"""
Extract each firmware image from the
Firmware Package Payload section of the input file.
Parameter:
output_dir path of the directory to store the
extracted files
Returns:
True if unpacking was successful
"""
# pylint: disable=too-many-locals
package_size = os.path.getsize(self.package)
for index, info in enumerate(self.component_img_info_list):
offset = info["ComponentLocationOffset"]
size = info["ComponentSize"]
if offset + size > package_size:
log_msg = f"Error: ComponentLocationOffset {offset} + \
ComponentSize {size} exceeds given package size {package_size}"
Util.cli_log(log_msg, False)
return False
img_name = output_dir + self.get_image_name(index)
img_name = re.sub(r'\s+', '', img_name)
if img_name == "":
log_msg = "Error: The input firmware package does not conform to \
the format created by NVIDIA packaging tool."
Util.cli_log(log_msg, False)
return False
try:
if os.path.exists(img_name):
os.remove(img_name)
with open(img_name, "w+b") as component_img_fd:
self.fwpkg_fd.seek(offset, 0)
bytes_left = size
buffer_size = 2048
while bytes_left > 0:
if bytes_left < 2048:
buffer_size = bytes_left
buffer = self.fwpkg_fd.read(buffer_size)
component_img_fd.write(buffer)
bytes_left = bytes_left - buffer_size
info["FWImageName"] = img_name
if os.path.exists(img_name):
os.chmod(img_name,
stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
if img_name.endswith('_image.bin'):
sha256_hash = Util.get_checksum_for_component_image(
img_name)[:8]
base, _ = img_name.rsplit('_image.bin', 1)
new_img_name = base + "_" + sha256_hash + "_image.bin"
os.rename(img_name, new_img_name)
info["FWImageName"] = new_img_name
except OSError as err:
log_msg = f"Error: Could not create file {img_name} due to {err}"
Util.cli_log(log_msg, False)
return False
return True
def get_pldm_header_checksum(self):
""" Read PLDM header checksum """
self.full_header['Package Header Checksum'] = int.from_bytes(
self.fwpkg_fd.read(4), byteorder='little', signed=False)
def unpack_pldm_package(self, package_name, output_dir):
"""
Parse the PLDM package and get information about components included in the FW image.
Unpack the package if required.
Parameters:
package_name filepath of input package file
output_dir directory to store the resulting unpacked files
Returns:
True if parsing and unpacking was successful
"""
if package_name == "" or package_name is None:
log_msg = "ERROR: Firmware package file is mandatory."
Util.cli_log(log_msg, False)
return False
if os.path.exists(package_name) is False:
log_msg = print("ERROR: File does not exist at path ",
package_name)
Util.cli_log(log_msg, False)
return False
self.package = package_name
try:
with open(self.package, "rb") as self.fwpkg_fd:
parsing_valid = self.parse_header()
if parsing_valid:
parsing_valid = self.parse_device_id_records()
if parsing_valid:
parsing_valid = self.parse_component_img_info()
self.get_pldm_header_checksum()
if parsing_valid and self.unpack:
if output_dir == "" or output_dir is None:
# If outdir was not given in command
# assume current directory
output_dir = "."
output_dir = os.path.abspath(output_dir) + "/"
# If dir doesn't exist, create it
if os.path.isdir(output_dir) is False:
os.makedirs(output_dir)
parsing_valid = self.create_unpacked_files(output_dir)
if self.verbose:
log_message = f"PLDM Output directory: {output_dir}," \
f"Package name: {package_name}"
Util.cli_log(log_message, True)
if parsing_valid is False:
log_message = f"Package Header Contents: {str(self.header_map)}"
Util.cli_log(log_message, True)
log_message = f"FirmwareDeviceIDRecords Contents: \
{str(self.fd_id_record_list)}"
Util.cli_log(log_message, True)
log_message = f"ComponentImageInformation Contents:\
{str(self.component_img_info_list)}"
Util.cli_log(log_message, True)
return parsing_valid
except IOError as e_io_error:
log_message = f"Couldn't open or read given FW package ({e_io_error})"
Util.cli_log(log_message, False)
return False
def get_applicable_component_index(self, applicable_component):
"""
Return list of indices of applicable component images from
applicable_component index bitmap.
"""
# number of images in the image section
max_bits = len(self.component_img_info_list)
indices = []
for shift in range(max_bits):
# for each index check if the bit at that position is set in applicable_component
mask = 1 << shift
result = applicable_component & mask
if result == mask:
indices.append(shift)
return indices
# pylint: disable=unused-argument
def get_signature_type(self, fw_image, component_identifier):
""" Method to tell if unpacked bin is prod signed or debug signed """
return 'N/A'
@staticmethod
def is_glacier_device(record, device_name):
"""
Is this device a glacer device
"""
if device_name.startswith("ERoT"):
return True
if record["DescriptorCount"] == 0:
return False
record_desc = record["RecordDescriptors"]
for desc in record_desc:
descriptor_type = desc.get("AdditionalDescriptorType", "")
if descriptor_type == 65535:
title = desc.get("VendorDefinedDescriptorTitleString", "")
if title == "GLACIERDSD":
return True
return False
def get_applicable_components_names(self, record):
# pylint: disable=too-many-branches
"""
Method to create list of applicable component images and their metadata like
ComponentIdentifier and Version. FWImage is included if unpacking was done.
Also prepares ComponentImageSetVersionString in name:model:vendor,... format if
it is not already so.
"""
index = self.get_applicable_component_index(
record["ApplicableComponents"])
components = []
device_name = record["ComponentImageSetVersionString"]
for i in index:
component = {}
img = self.component_img_info_list[i]
if self.unpack is True:
component = {
"ComponentIdentifier": "",
"ComponentVersionString": "",
"FWImage": ""
}
component["FWImage"] = img["FWImageName"]
component[
"FWImageSHA256"] = Util.get_checksum_for_component_image(
component["FWImage"])
# For ERoT associated devices get signature type
if self.is_glacier_device(
record, component["FWImage"].rsplit('/', 1)[-1]):
signature_type = self.get_signature_type(
component["FWImage"], img["ComponentIdentifier"])
if signature_type:
component["SignatureType"] = signature_type
else:
component["SignatureType"] = "N/A"
component["FWImageSize"] = img["ComponentSize"]
else:
component = {
"ComponentIdentifier": "",
"ComponentVersionString": ""
}
component["ComponentIdentifier"] = img["ComponentIdentifier"]
component["ComponentVersionString"] = img["ComponentVersionString"]
components.append(component)
if not self.unpack:
ap_sku, ec_sku = 'N/A', 'N/A'
records = record["RecordDescriptors"]
for i in range(1, len(records)):
if records[i]["AdditionalDescriptorType"] == 65535:
if records[i][
"VendorDefinedDescriptorTitleString"] == "APSKU":
ap_sku = "0x" + records[i][
"VendorDefinedDescriptorData"]
elif records[i][
"VendorDefinedDescriptorTitleString"] == "ECSKU":
ec_sku = "0x" + records[i][
"VendorDefinedDescriptorData"]
for component in components:
if component.get("ComponentIdentifier") == "0xff00":
component["ECSKUID"] = ec_sku
else:
component["APSKUID"] = ap_sku
return components, device_name
def decode_descriptor_data(self, desc_type_name, desc_data):
""" Formatting for descriptor data based on endianess"""
desc_val = ""
if desc_type_name in self.little_endian_list:
desc_val = Util.get_padded_hex(desc_data)
else:
desc_val = "0x" + desc_data.hex()
return desc_val
def get_formatted_descriptors(self, record_desc, components):
"""
Method to prepare stripped and formatted descriptor section for json output.
"""
records = record_desc["RecordDescriptors"]
descriptors = []
desc = {}
if len(records) == 0:
return descriptors
desc["InitialDescriptorType"] = Util.get_descriptor_type_name(
records[0]["InitialDescriptorType"])
desc["InitialDescriptorData"] = self.decode_descriptor_data(
desc["InitialDescriptorType"], records[0]["InitialDescriptorData"])
descriptors.append(desc)
for i in range(1, len(records)):
desc = {}
desc["AdditionalDescriptorType"] = Util.get_descriptor_type_name(
records[i]["AdditionalDescriptorType"])
if records[i]["AdditionalDescriptorType"] == 65535:
desc["VendorDefinedDescriptorTitleString"] = records[i][
"VendorDefinedDescriptorTitleString"]
desc_data = records[i]["VendorDefinedDescriptorData"]
desc["VendorDefinedDescriptorData"] = '0x' + str(desc_data)
if desc["VendorDefinedDescriptorTitleString"] == "APSKU":
# AP SKU on Retimer is just vendor id, not a real AP SKU ID. So skip
if "FWImage" in components[-1] and \
not "PCIeRetimer" in components[-1]["FWImage"]:
bin_ary = bytearray.fromhex(
desc_data[:-2]) # First byte is strap id
bin_ary.reverse()
ap_sku_id = ''.join(format(x, '02x') for x in bin_ary)
components[-1]["AP_SKU_ID"] = "0x" + ap_sku_id
desc["VendorDefinedDescriptorData"] = components[-1][
"AP_SKU_ID"]
else:
desc["AdditionalDescriptorData"] = self.decode_descriptor_data(
desc["AdditionalDescriptorType"],
records[i]["AdditionalDescriptorIdentifierData"])
descriptors.append(desc)
return descriptors
def get_builder_json(self):
"""
Get PLDM metadata in JSON format ingestible by the open src pkg builder tool
OSS package builder script can be found here:
https://github.com/openbmc/pldm/blob/master/tools/fw-update/pldm_fwup_pkg_creator.py
"""
header_info = {
"PackageHeaderIdentifier": self.header_map["PackageHeaderIdentifier"].replace('-', ''),
"PackageHeaderFormatVersion": int(self.header_map["PackageHeaderFormatRevision"]),
"PackageReleaseDateTime": Util.get_alt_time_format(
self.header_map["PackageReleaseDateTime"]),
"PackageVersionString": self.header_map["PackageVersionString"]}
fw_id_area = []
for device_records in self.full_header[
'FirmwareDeviceIdentificationArea']['FirmwareDeviceIDRecords']:
fw_id_rec = {
"DeviceUpdateOptionFlags": Util.get_set_bit_indices(
device_records["DeviceUpdateOptionFlags"]),
"ComponentImageSetVersionString": device_records["ComponentImageSetVersionString"],
"ApplicableComponents": Util.get_set_bit_indices(
device_records["ApplicableComponents"]),
"Descriptors": []
}
desc_list = []
for descriptors in device_records["RecordDescriptors"]:
if descriptors.get("InitialDescriptorType"):
data = descriptors.get("InitialDescriptorData")
data_len = len(data)
desc_data = {
"DescriptorType": descriptors.get("InitialDescriptorType"),
"DescriptorData": int.from_bytes(
data,
byteorder='big',
signed=False).to_bytes(data_len, 'big').hex()
}
elif descriptors.get("AdditionalDescriptorType") == 65535:
desc_data = {
"DescriptorType": descriptors.get("AdditionalDescriptorType"),
"VendorDefinedDescriptorTitleString": descriptors.get(
"VendorDefinedDescriptorTitleString"),
"VendorDefinedDescriptorData": descriptors.get(
"VendorDefinedDescriptorData")
}
else:
data = descriptors.get("AdditionalDescriptorIdentifierData")
data_len = len(data)
desc_data = {
"DescriptorType": descriptors.get("AdditionalDescriptorType"),
"DescriptorData": int.from_bytes(
data,
byteorder='big',
signed=False).to_bytes(data_len, 'big').hex()
}
desc_list.append(desc_data)
fw_id_rec["Descriptors"] = desc_list
fw_id_area.append(fw_id_rec)
comp_img_area = []
for img_data in self.component_img_info_list:
img_info = {
"ComponentClassification": img_data["ComponentClassification"],
"ComponentIdentifier": int(img_data["ComponentIdentifier"][2:], 16),
"ComponentOptions": Util.get_set_bit_indices(img_data["ComponentOptions"]),
"RequestedComponentActivationMethod": Util.get_set_bit_indices(
img_data['RequestedComponentActivationMethod']),
"ComponentVersionString": img_data["ComponentVersionString"],
"ComponentComparisonStamp": img_data["ComponentComparisonStamp"]
}
comp_img_area.append(img_info)
self.pkg_builder_json = {
"PackageHeaderInformation": header_info,
"FirmwareDeviceIdentificationArea": fw_id_area,
"ComponentImageInformationArea": comp_img_area
}
def get_full_metadata_json(self):
""" Decode byte value descriptors for full package metadata command """
for device_records in self.full_header[
'FirmwareDeviceIdentificationArea']['FirmwareDeviceIDRecords']:
device_records[
'ApplicableComponents'] = self.get_applicable_component_index(
device_records['ApplicableComponents'])
records = device_records["RecordDescriptors"]
descriptors = []
if len(records) == 0:
continue
desc = records[0]
desc["InitialDescriptorType"] = Util.get_descriptor_type_name(
records[0]["InitialDescriptorType"])
desc["InitialDescriptorData"] = self.decode_descriptor_data(
desc["InitialDescriptorType"], desc["InitialDescriptorData"])
descriptors.append(desc)
for i in range(1, len(records)):
desc = records[i]
desc[
"AdditionalDescriptorType"] = Util.get_descriptor_type_name(
records[i]["AdditionalDescriptorType"])
if desc["AdditionalDescriptorType"] == 'Vendor Defined':
desc["VendorDefinedDescriptorTitleString"] = records[i][
"VendorDefinedDescriptorTitleString"]
desc_data = records[i]["VendorDefinedDescriptorData"]
desc["VendorDefinedDescriptorData"] = '0x' + str(desc_data)
else:
desc[
"AdditionalDescriptorIdentifierData"] = self.decode_descriptor_data(
desc["AdditionalDescriptorType"],
desc["AdditionalDescriptorIdentifierData"])
descriptors.append(desc)
device_records["RecordDescriptors"] = descriptors
def prepare_records_json(self):
# pylint: disable=line-too-long
"""
Prepares the JSON output for the tool.
"""
package_json = {
"PackageHeaderInformation": {},
"FirmwareDeviceRecords": []
}
package_json["PackageHeaderInformation"]["PackageHeaderIdentifier"] = (
self.header_map["PackageHeaderIdentifier"])
package_json["PackageHeaderInformation"][
"PackageHeaderFormatRevision"] = (
self.header_map["PackageHeaderFormatRevision"])
if package_json["PackageHeaderInformation"][
"PackageHeaderFormatRevision"] != "1":
return False, "The input firmware package version does not conform \
to the format created by NVIDIA packaging tool."
package_json["PackageHeaderInformation"]["PackageReleaseDateTime"] = (
self.header_map["PackageReleaseDateTime"])
package_json["PackageHeaderInformation"]["PackageVersionString"] = (
self.header_map["PackageVersionString"])
package_json['PackageHeaderInformation']["PackageSHA256"] = (
Util.get_checksum_for_component_image(self.package))
recordlist = []
for record in self.fd_id_record_list:
rec = {
"ComponentImageSetVersionString": "",
"DeviceDescriptors": [],
"Components": []
}
components, name = self.get_applicable_components_names(record)
if not components or not name:
return False, "The input firmware package does not conform to \
the format created by NVIDIA packaging tool."
rec["DeviceDescriptors"] = self.get_formatted_descriptors(
record, components)
rec["Components"] = components
rec["ComponentImageSetVersionString"] = name
recordlist.append(rec)
package_json["FirmwareDeviceRecords"] = recordlist
json_string = json.dumps(package_json, indent=4)
return True, json_string
def main():
"""
Call upack parser and prepare output json
"""
arg_parser = argparse.ArgumentParser(prog='fwpkg-unpack',
description=\
f"NVIDIA fwpkg-unpack v{UNPACK_TOOL_VERSION} The firmware package unpack tool performs\
parsing of the firmware package and unpacking. The unpacker will extract all firmware\
images from the package and create bin files for each.",
allow_abbrev=False)
arg_parser.add_argument(
"file", help="Provide firmware package filename to unpack.", nargs='?')
arg_group = arg_parser.add_mutually_exclusive_group(required=True)
arg_group.add_argument(
"--unpack",
action='store_true',
help="Unpack the firmware package and extract all component images.")
arg_group.add_argument(
"--show_pkg_content",
action='store_true',
help=
"Provide package content description without extracting firmware images."
)
arg_group.add_argument(
"--show_all_metadata",
action='store_true',
help=
"Provide all PLDM metadata in package without extracting firmware images."
)
arg_group.add_argument(
"--dump_builder_json",
action='store_true',
help=
"Dump PLDM metadata to stdout in JSON format, " \
"which shall be input to OSS PLDM package builder tool."
)
arg_parser.add_argument(
"--outdir",
help=
"Provide path to the directory where unpacked FW files will be stored. \
This option is used along with --unpack. \
If this option not specified with --unpack, current directory is assumed as outdir. \
Creates the directory at a given path if it does not exist.")
arg_group.add_argument("--version",
action='store_true',
help="Show tool version.")
arg_parser.add_argument(
"--verbose",
action='store_true',
help=
"Verbose Mode, This option is used along with --unpack or --show_pkg_content. \
By using this command, debug prints from the code will be copied in a debug \
logfile created in the same directory with name fwpkg_unpack_log.txt from\
unpack tool.")
tool_args = arg_parser.parse_args()
pldm_parser = PLDMUnpack()
pldm_parser.unpack = tool_args.unpack
pldm_parser.verbose = tool_args.verbose
if tool_args.show_pkg_content is True:
pldm_parser.unpack = False
if tool_args.version is True:
print(f"NVIDIA fwpkg-unpack - version {UNPACK_TOOL_VERSION}")
sys.exit(0)
else:
parser_status = pldm_parser.unpack_pldm_package(
tool_args.file, tool_args.outdir)
if parser_status is True:
json_output = {}
if tool_args.show_all_metadata is False:
parser_status, json_output = pldm_parser.prepare_records_json()
if not parser_status:
print("Status : Failed to prepare JSON records")
print("Path for LogFile ", Util.LOGFILE_PATH)
sys.exit(1)
if tool_args.dump_builder_json:
pldm_parser.get_builder_json()
json_output = json.dumps(pldm_parser.pkg_builder_json,
sort_keys=False,
indent=4)
else:
pldm_parser.get_full_metadata_json()
json_output = json.dumps(pldm_parser.full_header,
sort_keys=False,
indent=4)
if tool_args.verbose is True:
print(json_output)
sys.exit(0)
else:
print("Status : Failed")
print("Path for LogFile ", Util.LOGFILE_PATH)
sys.exit(1)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("Aborted (Ctrl+C)")
sys.exit(1)
Mellanox-rshim-user-space-0339e66/third_party/PLDM-unpack/License-MIT-fwpkg-unpack.txt 0000664 0001750 0001750 00000002250 15101274612 026564 0 ustar tai tai # SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
Mellanox-rshim-user-space-0339e66/third_party/PLDM-unpack/README.md 0000664 0001750 0001750 00000171147 15101274612 022712 0 ustar tai tai # PLDM-unpack
> SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
>
> SPDX-License-Identifier: MIT
# Firmware Package Unpack Tool
The firmware unpack tool is a command line tool that parses and unpacks a firmware package built according to the PLDM firmware update specification v1.0.1.
The tool also shows metadata of the package, including device name, model, vendor, other uniquely identifying device descriptors, and version of the included firmware images. It provides the full path of each firmware image extracted from the package, and shows which image belongs to which component.
## Source Code
The source code is written in the file fwpkg-unpack.py which is a Python script. The tool requires Python 3.8
## Usage
The tool supports the following options:
usage: python3 fwpkg_unpack.py --help
usage: fwpkg-unpack [-h] [--unpack] [--show_pkg_content] [--show_all_metadata] [--dump_builder_json] [--outdir OUTDIR] [--version] [--verbose] [file]
NVIDIA fwpkg-unpack v4.1.3 The firmware package unpack tool performs parsing of the firmware package and unpacking. The unpacker will extract all firmware images
from the package and create bin files for each.
positional arguments:
file Provide firmware package filename to unpack.
optional arguments:
-h, --help show this help message and exit
--unpack Unpack the firmware package and extract all component images.
--show_pkg_content Provide package content description without extracting firmware images.
--show_all_metadata Provide all PLDM metadata in package without extracting firmware images.
--dump_builder_json Dump PLDM metadata to stdout in JSON format, which shall be input to OSS PLDM package builder tool.
--outdir OUTDIR Provide path to the directory where unpacked FW files will be stored. This option is used along with --unpack. If this option not
specified with --unpack, current directory is assumed as outdir. Creates the directory at a given path if it does not exist.
--version Show tool version.
--verbose Verbose Mode, This option is used along with --unpack or --show_pkg_content. By using this command, debug prints from the code will be
copied in a debug logfile created in the same directory with name fwpkg_unpack_log.txt from unpack tool.
## Unpack Example
### --unpack command option
```
$ python3 fwpkg_unpack.py --unpack --outdir results/ nvfw_HGX-H100x8_0002_230517.3.0_prod-signed.fwpkg
```
```json
{
"PackageHeaderInformation": {
"PackageHeaderIdentifier": "f018878c-cb7d-4943-9800-a02f059aca02",
"PackageHeaderFormatRevision": "1",
"PackageReleaseDateTime": "2023-5-17 5:9:22:0 +0",
"PackageVersionString": "HGX-H100x8_0002_230517.3.0",
"PackageSHA256": "8a1fd39afea9d6c722ea311678f153d0808512c1f094a8f52c78fd35cc6872b6"
},
"FirmwareDeviceRecords": [
{
"ComponentImageSetVersionString": "ERoT,HMC::",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x10"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x1a03"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x2600"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x0d2452"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"FWImage": "/home/results/ERoT_00.02.0134.0000_n00_image.bin",
"FWImageSHA256": "9eb61dadc27c859a9dd018d4044afc20dafbb17fdb17fb6fe216664a7feac329",
"SignatureType": "N/A",
"FWImageSize": 188928
},
{
"ComponentIdentifier": "0x10",
"ComponentVersionString": "HGX-22.10-1-rc36",
"FWImage": "/home/results/HMC_HGX-22.10-1-rc36_image.bin",
"FWImageSHA256": "e306a43ee097ed8f4ef302af8433fc96bad59b1e784c1a50625422dbc5bc2c3f",
"SignatureType": "N/A",
"FWImageSize": 67105792,
"AP_SKU_ID": "0x0d2452"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,FPGA::",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x50"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x1172"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x0021"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x543210"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"FWImage": "/home/results/ERoT_00.02.0134.0000_n00_image.bin",
"FWImageSHA256": "9eb61dadc27c859a9dd018d4044afc20dafbb17fdb17fb6fe216664a7feac329",
"SignatureType": "N/A",
"FWImageSize": 188928
},
{
"ComponentIdentifier": "0x50",
"ComponentVersionString": "2.11",
"FWImage": "/home/results/FPGA_2.11_image.bin",
"FWImageSHA256": "f68274d43a656b357ccece8e9ab7d5878ee98a815ebab72fe0098ed47836b072",
"SignatureType": "N/A",
"FWImageSize": 32117760,
"AP_SKU_ID": "0x543210"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,GPU:GH100_HBM3-80GB-885_0200:",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x20"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x2330"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x16c1"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x000437"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"FWImage": "/home/results/ERoT_00.02.0134.0000_n00_image.bin",
"FWImageSHA256": "9eb61dadc27c859a9dd018d4044afc20dafbb17fdb17fb6fe216664a7feac329",
"SignatureType": "N/A",
"FWImageSize": 188928
},
{
"ComponentIdentifier": "0x20",
"ComponentVersionString": "96.00.68.00.01",
"FWImage": "/home/results/GPU_GH100_HBM3-80GB-885_0200_96.00.68.00.01_image.bin",
"FWImageSHA256": "eef57ef849e0c46c4d196d106b109f7d9a8557ebfd49bd08277b9f5a7d546f6d",
"SignatureType": "N/A",
"FWImageSize": 975872,
"AP_SKU_ID": "0x000437"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,NVSwitch:LS10_0002_890_B00:",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x70"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x22a3"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1796"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x0003b7"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"FWImage": "/home/results/ERoT_00.02.0134.0000_n00_image.bin",
"FWImageSHA256": "9eb61dadc27c859a9dd018d4044afc20dafbb17fdb17fb6fe216664a7feac329",
"SignatureType": "N/A",
"FWImageSize": 188928
},
{
"ComponentIdentifier": "0x70",
"ComponentVersionString": "96.10.38.00.01",
"FWImage": "/home/results/NVSwitch_LS10_0002_890_B00_96.10.38.00.01_image.bin",
"FWImageSHA256": "d854b8d89098ddc4943a551c31305f8b1d6b870ab4c71f6d83841c0df34cdb0c",
"SignatureType": "N/A",
"FWImageSize": 975872,
"AP_SKU_ID": "0x0003b7"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,PCIeSwitch::",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x40"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x11f8"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x4028"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x000001"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"FWImage": "/home/results/ERoT_00.02.0134.0000_n00_image.bin",
"FWImageSHA256": "9eb61dadc27c859a9dd018d4044afc20dafbb17fdb17fb6fe216664a7feac329",
"SignatureType": "N/A",
"FWImageSize": 188928
},
{
"ComponentIdentifier": "0x40",
"ComponentVersionString": "1.7.5F",
"FWImage": "/home/results/PCIeSwitch_1.7.5F_image.bin",
"FWImageSHA256": "e8382a794afd0e84eb6146bfcb944aec5d50b35eae1aa4f176fab2a8d56330a5",
"SignatureType": "N/A",
"FWImageSize": 4461824,
"AP_SKU_ID": "0x000001"
}
]
},
{
"ComponentImageSetVersionString": "PCIeRetimer:P8:",
"DeviceDescriptors": [
{
"InitialDescriptorType": "UUID",
"InitialDescriptorData": "0xef5eb98016d211ec8f40d45d64be4256"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x0001fa1d"
}
],
"Components": [
{
"ComponentIdentifier": "0x8000",
"ComponentVersionString": "1.31.8",
"FWImage": "/home/results/PCIeRetimer_P8_1.31.8_image.bin",
"FWImageSHA256": "13b214576fea1c1b9f02645bb949dca420a18cec904c39b48c27e43ccfd88a52",
"SignatureType": "N/A",
"FWImageSize": 262144
}
]
}
]
}
```
### --show_pkg_content command option
```
$ python3 fwpkg_unpack.py --show_pkg_content nvfw_HGX-H100x8_0002_230517.3.0_prod-signed.fwpkg
```
```json
{
"PackageHeaderInformation": {
"PackageHeaderIdentifier": "f018878c-cb7d-4943-9800-a02f059aca02",
"PackageHeaderFormatRevision": "1",
"PackageReleaseDateTime": "2023-5-17 5:9:22:0 +0",
"PackageVersionString": "HGX-H100x8_0002_230517.3.0",
"PackageSHA256": "8a1fd39afea9d6c722ea311678f153d0808512c1f094a8f52c78fd35cc6872b6"
},
"FirmwareDeviceRecords": [
{
"ComponentImageSetVersionString": "ERoT,HMC::",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x10"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x1a03"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x2600"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x52240d10"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"ECSKUID": "0x49353681"
},
{
"ComponentIdentifier": "0x10",
"ComponentVersionString": "HGX-22.10-1-rc36",
"APSKUID": "0x52240d10"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,FPGA::",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x50"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x1172"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x0021"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x10325450"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"ECSKUID": "0x49353681"
},
{
"ComponentIdentifier": "0x50",
"ComponentVersionString": "2.11",
"APSKUID": "0x10325450"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,GPU:GH100_HBM3-80GB-885_0200:",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x20"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x2330"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x16c1"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x37040020"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"ECSKUID": "0x49353681"
},
{
"ComponentIdentifier": "0x20",
"ComponentVersionString": "96.00.68.00.01",
"APSKUID": "0x37040020"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,NVSwitch:LS10_0002_890_B00:",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x70"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x22a3"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1796"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0xb7030070"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"ECSKUID": "0x49353681"
},
{
"ComponentIdentifier": "0x70",
"ComponentVersionString": "96.10.38.00.01",
"APSKUID": "0xb7030070"
}
]
},
{
"ComponentImageSetVersionString": "ERoT,PCIeSwitch::",
"DeviceDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x40"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorData": "0x11f8"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorData": "0x4028"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x01000040"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"Components": [
{
"ComponentIdentifier": "0xff00",
"ComponentVersionString": "00.02.0134.0000_n00",
"ECSKUID": "0x49353681"
},
{
"ComponentIdentifier": "0x40",
"ComponentVersionString": "1.7.5F",
"APSKUID": "0x01000040"
}
]
},
{
"ComponentImageSetVersionString": "PCIeRetimer:P8:",
"DeviceDescriptors": [
{
"InitialDescriptorType": "UUID",
"InitialDescriptorData": "0xef5eb98016d211ec8f40d45d64be4256"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x0001fa1d"
}
],
"Components": [
{
"ComponentIdentifier": "0x8000",
"ComponentVersionString": "1.31.8",
"APSKUID": "0x0001fa1d"
}
]
}
]
}
```
### --show_all_metadata command option
```
$ python3 fwpkg_unpack.py --show_all_metadata nvfw_HGX-H100x8_0002_230517.3.0_prod-signed.fwpkg
```
```json
{
"PackageHeaderInformation": {
"PackageHeaderIdentifier": "f018878c-cb7d-4943-9800-a02f059aca02",
"PackageHeaderFormatRevision": "1",
"PackageHeaderSize": 1023,
"PackageReleaseDateTime": "2023-5-17 5:9:22:0 +0",
"ComponentBitmapBitLength": 8,
"PackageVersionStringType": 1,
"PackageVersionStringLength": 26,
"PackageVersionString": "HGX-H100x8_0002_230517.3.0"
},
"FirmwareDeviceIdentificationArea": {
"DeviceIDRecordCount": 6,
"FirmwareDeviceIDRecords": [
{
"RecordLength": 121,
"DescriptorCount": 9,
"DeviceUpdateOptionFlags": 0,
"ComponentImageSetVersionStringType": 1,
"ComponentImageSetVersionStringLength": 10,
"FirmwareDevicePackageDataLength": 0,
"ApplicableComponents": [
0,
1
],
"ComponentImageSetVersionString": "ERoT,HMC::",
"RecordDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorLength": 4,
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorLength": 16,
"AdditionalDescriptorIdentifierData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 13,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 10,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x10"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x1a03"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x2600"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x52240d10"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"FirmwareDevicePackageData": ""
},
{
"RecordLength": 122,
"DescriptorCount": 9,
"DeviceUpdateOptionFlags": 0,
"ComponentImageSetVersionStringType": 1,
"ComponentImageSetVersionStringLength": 11,
"FirmwareDevicePackageDataLength": 0,
"ApplicableComponents": [
0,
2
],
"ComponentImageSetVersionString": "ERoT,FPGA::",
"RecordDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorLength": 4,
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorLength": 16,
"AdditionalDescriptorIdentifierData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 13,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 10,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x50"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x1172"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x0021"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x10325450"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"FirmwareDevicePackageData": ""
},
{
"RecordLength": 145,
"DescriptorCount": 9,
"DeviceUpdateOptionFlags": 0,
"ComponentImageSetVersionStringType": 1,
"ComponentImageSetVersionStringLength": 34,
"FirmwareDevicePackageDataLength": 0,
"ApplicableComponents": [
0,
3
],
"ComponentImageSetVersionString": "ERoT,GPU:GH100_HBM3-80GB-885_0200:",
"RecordDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorLength": 4,
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorLength": 16,
"AdditionalDescriptorIdentifierData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 13,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 10,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x20"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x2330"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x16c1"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x37040020"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"FirmwareDevicePackageData": ""
},
{
"RecordLength": 143,
"DescriptorCount": 9,
"DeviceUpdateOptionFlags": 0,
"ComponentImageSetVersionStringType": 1,
"ComponentImageSetVersionStringLength": 32,
"FirmwareDevicePackageDataLength": 0,
"ApplicableComponents": [
0,
4
],
"ComponentImageSetVersionString": "ERoT,NVSwitch:LS10_0002_890_B00:",
"RecordDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorLength": 4,
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorLength": 16,
"AdditionalDescriptorIdentifierData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 13,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 10,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x70"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x22a3"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x1796"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0xb7030070"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"FirmwareDevicePackageData": ""
},
{
"RecordLength": 128,
"DescriptorCount": 9,
"DeviceUpdateOptionFlags": 0,
"ComponentImageSetVersionStringType": 1,
"ComponentImageSetVersionStringLength": 17,
"FirmwareDevicePackageDataLength": 0,
"ApplicableComponents": [
0,
5
],
"ComponentImageSetVersionString": "ERoT,PCIeSwitch::",
"RecordDescriptors": [
{
"InitialDescriptorType": "IANA Enterprise ID",
"InitialDescriptorLength": 4,
"InitialDescriptorData": "0x00001647"
},
{
"AdditionalDescriptorType": "UUID",
"AdditionalDescriptorLength": 16,
"AdditionalDescriptorIdentifierData": "0x162023c93ec5411595f448701d49d675"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 13,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 10,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "0x40"
},
{
"AdditionalDescriptorType": "PCI Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x11f8"
},
{
"AdditionalDescriptorType": "PCI Device ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x4028"
},
{
"AdditionalDescriptorType": "PCI Subsystem Vendor ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x10de"
},
{
"AdditionalDescriptorType": "PCI Subsystem ID",
"AdditionalDescriptorLength": 2,
"AdditionalDescriptorIdentifierData": "0x1643"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x01000040"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "0x49353681"
}
],
"FirmwareDevicePackageData": ""
},
{
"RecordLength": 62,
"DescriptorCount": 2,
"DeviceUpdateOptionFlags": 1,
"ComponentImageSetVersionStringType": 1,
"ComponentImageSetVersionStringLength": 15,
"FirmwareDevicePackageDataLength": 0,
"ApplicableComponents": [
6
],
"ComponentImageSetVersionString": "PCIeRetimer:P8:",
"RecordDescriptors": [
{
"InitialDescriptorType": "UUID",
"InitialDescriptorLength": 16,
"InitialDescriptorData": "0xef5eb98016d211ec8f40d45d64be4256"
},
{
"AdditionalDescriptorType": "Vendor Defined",
"AdditionalDescriptorLength": 11,
"VendorDefinedDescriptorTitleStringType": 1,
"VendorDefinedDescriptorTitleStringLength": 5,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "0x0001fa1d"
}
],
"FirmwareDevicePackageData": ""
}
]
},
"ComponentImageInformationArea": {
"ComponentImageCount": 7,
"ComponentImageInformation": [
{
"ComponentClassification": 10,
"ComponentIdentifier": "0xff00",
"ComponentComparisonStamp": 4294967295,
"ComponentOptions": 1,
"RequestedComponentActivationMethod": 0,
"ComponentLocationOffset": 1023,
"ComponentSize": 188928,
"ComponentVersionStringType": 1,
"ComponentVersionStringLength": 19,
"ComponentVersionString": "00.02.0134.0000_n00"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": "0x10",
"ComponentComparisonStamp": 4294967295,
"ComponentOptions": 1,
"RequestedComponentActivationMethod": 0,
"ComponentLocationOffset": 189951,
"ComponentSize": 67105792,
"ComponentVersionStringType": 1,
"ComponentVersionStringLength": 16,
"ComponentVersionString": "HGX-22.10-1-rc36"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": "0x50",
"ComponentComparisonStamp": 4294967295,
"ComponentOptions": 1,
"RequestedComponentActivationMethod": 0,
"ComponentLocationOffset": 67295743,
"ComponentSize": 32117760,
"ComponentVersionStringType": 1,
"ComponentVersionStringLength": 4,
"ComponentVersionString": "2.11"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": "0x20",
"ComponentComparisonStamp": 4294967295,
"ComponentOptions": 1,
"RequestedComponentActivationMethod": 0,
"ComponentLocationOffset": 99413503,
"ComponentSize": 975872,
"ComponentVersionStringType": 1,
"ComponentVersionStringLength": 14,
"ComponentVersionString": "96.00.68.00.01"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": "0x70",
"ComponentComparisonStamp": 4294967295,
"ComponentOptions": 1,
"RequestedComponentActivationMethod": 0,
"ComponentLocationOffset": 100389375,
"ComponentSize": 975872,
"ComponentVersionStringType": 1,
"ComponentVersionStringLength": 14,
"ComponentVersionString": "96.10.38.00.01"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": "0x40",
"ComponentComparisonStamp": 4294967295,
"ComponentOptions": 1,
"RequestedComponentActivationMethod": 0,
"ComponentLocationOffset": 101365247,
"ComponentSize": 4461824,
"ComponentVersionStringType": 1,
"ComponentVersionStringLength": 6,
"ComponentVersionString": "1.7.5F"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": "0x8000",
"ComponentComparisonStamp": 4294967295,
"ComponentOptions": 1,
"RequestedComponentActivationMethod": 0,
"ComponentLocationOffset": 105827071,
"ComponentSize": 262144,
"ComponentVersionStringType": 1,
"ComponentVersionStringLength": 6,
"ComponentVersionString": "1.31.8"
}
]
},
"Package Header Checksum": 3701773251
}
```
### --dump_builder_json command option
#### This output can be used as metadata JSON input for the OSS PLDM package creator tool available here
https://github.com/openbmc/pldm/blob/master/tools/fw-update/pldm_fwup_pkg_creator.py
```
$ python3 fwpkg_unpack.py --dump_builder_json nvfw_GB200-P4975_0004_240819.1.0_custom_prod-signed.fwpkg
```
```json
{
"PackageHeaderInformation": {
"PackageHeaderIdentifier": "f018878ccb7d49439800a02f059aca02",
"PackageHeaderFormatVersion": 1,
"PackageReleaseDateTime": "19/08/2024 07:00:30",
"PackageVersionString": "GB200-P4975_0004_240819.1.0_custom"
},
"FirmwareDeviceIdentificationArea": [
{
"DeviceUpdateOptionFlags": [],
"ComponentImageSetVersionString": "ERoT,HMC:SKU_179:",
"ApplicableComponents": [
0,
1
],
"Descriptors": [
{
"DescriptorType": 1,
"DescriptorData": "47160000"
},
{
"DescriptorType": 2,
"DescriptorData": "162023c93ec5411595f448701d49d675"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "10"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "b3000010"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "4d35368b"
}
]
},
{
"DeviceUpdateOptionFlags": [
0
],
"ComponentImageSetVersionString": "CPLD:MAX10:",
"ApplicableComponents": [
2
],
"Descriptors": [
{
"DescriptorType": 2,
"DescriptorData": "f65ec98a70e84e3da6c18d9f2b51d3e0"
}
]
},
{
"DeviceUpdateOptionFlags": [],
"ComponentImageSetVersionString": "ERoT,SBIOS:C01_2P_894:",
"ApplicableComponents": [
0,
3
],
"Descriptors": [
{
"DescriptorType": 1,
"DescriptorData": "47160000"
},
{
"DescriptorType": 2,
"DescriptorData": "162023c93ec5411595f448701d49d675"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "38"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "23000038"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "4d35368b"
}
]
},
{
"DeviceUpdateOptionFlags": [],
"ComponentImageSetVersionString": "ERoT,SMR::",
"ApplicableComponents": [
0,
4
],
"Descriptors": [
{
"DescriptorType": 1,
"DescriptorData": "47160000"
},
{
"DescriptorType": 2,
"DescriptorData": "162023c93ec5411595f448701d49d675"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "GLACIERDSD",
"VendorDefinedDescriptorData": "50"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "03040250"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "ECSKU",
"VendorDefinedDescriptorData": "4d35368b"
}
]
},
{
"DeviceUpdateOptionFlags": [],
"ComponentImageSetVersionString": "GPU:GB100_SKU201_ES2:",
"ApplicableComponents": [
5
],
"Descriptors": [
{
"DescriptorType": 1,
"DescriptorData": "47160000"
},
{
"DescriptorType": 2,
"DescriptorData": "7865bed953204b6ab94d8fa70b6283d6"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "f6050000"
}
]
},
{
"DeviceUpdateOptionFlags": [],
"ComponentImageSetVersionString": "GPU:GB100_SKU201_ES2:",
"ApplicableComponents": [
6
],
"Descriptors": [
{
"DescriptorType": 1,
"DescriptorData": "47160000"
},
{
"DescriptorType": 2,
"DescriptorData": "7865bed953204b6ab94d8fa70b6283d6"
},
{
"DescriptorType": 65535,
"VendorDefinedDescriptorTitleString": "APSKU",
"VendorDefinedDescriptorData": "f7050000"
}
]
}
],
"ComponentImageInformationArea": [
{
"ComponentClassification": 10,
"ComponentIdentifier": 65280,
"ComponentOptions": [
1
],
"RequestedComponentActivationMethod": [],
"ComponentVersionString": "01.03.0183.0000_n04",
"ComponentComparisonStamp": "0x0103b700"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": 16,
"ComponentOptions": [
1
],
"RequestedComponentActivationMethod": [],
"ComponentVersionString": "GB200Nvl-24.08-6",
"ComponentComparisonStamp": "0x00240806"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": 0,
"ComponentOptions": [
0
],
"RequestedComponentActivationMethod": [],
"ComponentVersionString": "0.1C",
"ComponentComparisonStamp": "0xffffffff"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": 56,
"ComponentOptions": [
1
],
"RequestedComponentActivationMethod": [],
"ComponentVersionString": "02.02.03",
"ComponentComparisonStamp": "0x24080822"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": 80,
"ComponentOptions": [
1
],
"RequestedComponentActivationMethod": [],
"ComponentVersionString": "1.0A",
"ComponentComparisonStamp": "0x312e3041"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": 49152,
"ComponentOptions": [
1
],
"RequestedComponentActivationMethod": [],
"ComponentVersionString": "97.00.13.00.00",
"ComponentComparisonStamp": "0x01300000"
},
{
"ComponentClassification": 10,
"ComponentIdentifier": 49152,
"ComponentOptions": [
1
],
"RequestedComponentActivationMethod": [],
"ComponentVersionString": "97.00.13.00.00",
"ComponentComparisonStamp": "0x01300000"
}
]
}
``` Mellanox-rshim-user-space-0339e66/scripts/ 0000775 0001750 0001750 00000000000 15101274612 016543 5 ustar tai tai Mellanox-rshim-user-space-0339e66/scripts/build-rpm 0000775 0001750 0001750 00000002477 15101274612 020376 0 ustar tai tai #!/bin/sh -e
#
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
#
# Build rpm package for rshim driver for x86_64 and aarch64.
# The script generates source rpm, then builds x86_64 or aarch64 rpm depending
# on the CPU platform it's running on.
#
# Must run from the root of the rshim source tree.
#
# Usage:
# ./script/build-rpm
#
topdir=$(pwd)/rpmbuild
[ -d $topdir ] && rm -rf $topdir
mkdir -p $topdir/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
# Generate rshim.spec
./bootstrap.sh
./configure
make
cp rshim.spec $topdir/SPECS/
# Generate source tarball
rm -f *.tar.gz
ver_tag=$(grep "^Version:" rshim.spec | cut -d' ' -f2)
tarball="rshim-${ver_tag}.tar.gz"
git archive --prefix="rshim-${ver_tag}/" --format=tar.gz -o "$tarball" HEAD
mv $tarball $topdir/SOURCES/
#
# Generate source RPM
#
rpmbuild --define "_topdir ${topdir}" -bs $topdir/SPECS/rshim.spec
src_rpm=$(echo $topdir/SRPMS/rshim-*.src.rpm)
if [ ! -e "${src_rpm}" ]; then
echo "${src_rpm} not found"
exit 1
fi
#
# Build rshim RPM
#
rpmbuild --define "_topdir ${topdir}" --rebuild ${src_rpm}
version="$(./scripts/get-ver)"
arch=$(uname -m)
arch_rpm=$(echo ${topdir}/RPMS/${arch}/rshim*.rpm)
if [ -f "$arch_rpm" ]; then
rpm_file=rshim-${version}_${arch}.rpm
mv $arch_rpm ${topdir}/RPMS/${arch}/$rpm_file
echo "${arch} RPM: $rpm_file"
fi Mellanox-rshim-user-space-0339e66/scripts/bf-reg 0000775 0001750 0001750 00000003252 15101274612 017635 0 ustar tai tai #! /usr/bin/env perl
#
# Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
use strict;
use warnings;
my $RSHIM_IOC_READ = 0xc00d5200;
my $RSHIM_IOC_WRITE = 0xc00d5201;
sub usage {
$0 =~ m|[^/]+$|;
print "Usage: ./$& rshim .<32|64> [value]\n";
print "\n";
exit 1;
}
sub str2int {
if (substr($_[0], 0, 2) eq "0x") {
return hex($_[0]);
} else {
return int($_[0]);
}
}
my $s1 = $ARGV[1] || usage;
my @s2 = split(/\./, $s1);
my $addr = str2int($s2[0]) | 0x10000000;
if (scalar(@s2) != 2) {
usage
}
my $size = str2int($s2[1]) / 8;
my $value_lo = 0;
my $value_hi = 0;
my $is_read = 1;
if (scalar(@ARGV) > 2) {
if (substr($ARGV[2], 0, 2) eq "0x") {
if (length($ARGV[2]) <= 10) {
$value_lo = str2int($ARGV[2]);
} else {
$value_lo = hex(substr($ARGV[2], -8, 8));
$value_hi = hex(substr($ARGV[2], 0, length($ARGV[2]) - 8));
}
} else {
$value_lo = str2int($ARGV[2]);
}
$is_read = 0;
}
open(FH, '>', "/dev/$ARGV[0]/rshim") or die $!;
my $data = pack('LLLC', $addr, $value_lo, $value_hi, $size);
if ($is_read) {
ioctl FH, $RSHIM_IOC_READ, $data || die "can't ioctl: $!";
} else {
ioctl FH, $RSHIM_IOC_WRITE, $data || die "can't ioctl: $!";
if ($size) {
printf "[0x%x] <- 0x%08x%08x\n", $addr, $value_hi, $value_lo;
} else {
printf "[0x%x] <- 0x%08x\n", $addr, $value_lo;
}
}
my @ret;
if ($is_read) {
@ret = unpack('L 0x%08x%08x\n", $addr, $ret[2], $ret[1];
} else {
printf "[0x%x] -> 0x%08x\n", $addr, $ret[1];
}
}
close(FH);
Mellanox-rshim-user-space-0339e66/scripts/get-ver 0000775 0001750 0001750 00000003112 15101274612 020037 0 ustar tai tai #!/bin/bash
#
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# This script generates a version string based on the latest Git tag and branch.
#
# Usage:
# ./get-ver Outputs a simplified version for a release when on a tag.
# ./get-ver -v Outputs the full version string with commit count and hash.
# Output formats:
# Simplified: "X.Y.Z" (when the commit matches a tag and no options are passed)
# Full: "X.Y.Z-N-g" (always, or with -v option)
# Function to generate the version string
generate_version() {
local current_branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
# Find the latest tag matching "rshim-X.Y.Z" merged into the current branch
local latest_tag
latest_tag=$(git tag --list "rshim-[0-9]*.[0-9]*.[0-9]*" --merged "$current_branch" | sort -V | tail -n 1)
# Generate the full version string
local version
version=$(git describe --always --tags --match "$latest_tag" --long)
version=${version#rshim-} # Remove the "rshim-" prefix
# Extract components of the version string
local base_version commit_count commit_hash
base_version=$(echo "$version" | cut -d- -f1) # "X.Y.Z"
commit_count=$(echo "$version" | cut -d- -f2) # "N"
commit_hash=$(echo "$version" | cut -d- -f3) # "g"
# Simplified version output when commit is at the tag
if [[ "$commit_count" == "0" ]] && [[ "$1" != "-v" ]]; then
echo "$base_version"
else
echo "$base_version-$commit_count-$commit_hash"
fi
}
if [[ "$1" == "-v" ]]; then
generate_version -v
else
generate_version
fi
Mellanox-rshim-user-space-0339e66/scripts/get-changelog 0000775 0001750 0001750 00000003301 15101274612 021172 0 ustar tai tai #!/usr/bin/env bash
#
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Parse the top entry of debian/changelog and build a release note.
#
# Usage:
# ./make_release_body.sh debian/changelog
#
# Output:
# Prints the release body to stdout.
CHANGELOG_FILE="$1"
[ -z "$CHANGELOG_FILE" ] && {
echo "Usage: $0 debian/changelog"
exit 1
}
awk '
BEGIN {
top_version = ""
second_version = ""
in_top_entry = 0
}
# Match lines like: rshim (2.2.1) ...
# Extract the version inside parentheses.
# The first occurrence is top_version, the second is second_version.
/^rshim \(/ {
# Extract version from: rshim (X.Y.Z) ...
match($0, /^rshim \(([^)]+)\)/, arr)
this_version = arr[1]
if (top_version == "") {
top_version = this_version
in_top_entry = 1
next
} else if (second_version == "") {
second_version = this_version
# As soon as we see the second version, we can stop collecting.
# Because that means the top entry ends right before this line.
exit
}
}
# While we are in the top entry, collect the bullet points until we see -- or the next version.
in_top_entry == 1 {
# If we see a line starting with --, it means the top entry ended.
if ($0 ~ /^ -- /) {
in_top_entry = 0
next
}
# Otherwise, collect the lines (these are the bullet points).
top_entry_text = top_entry_text $0 "\n"
}
END {
# If we never found a second_version, set it to something to avoid blank output.
if (second_version == "") {
second_version = "previous"
}
print "## Changelog (" top_version " compared to " second_version "):\n" top_entry_text
}
' "$CHANGELOG_FILE"
Mellanox-rshim-user-space-0339e66/scripts/bf-pldm-ver 0000775 0001750 0001750 00000011650 15101274612 020607 0 ustar tai tai #!/bin/bash
###############################################################################
#
# Copyright 2025 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################
usage() {
cat << EOF
Usage: $(basename $0)
EOF
}
#cleanup
cleanup() {
# Remove the temp directory.
rm -rf $TMP_DIR
}
if [ $# -lt 1 ]; then
echo "Error: $(basename $0) requires 1 argument."
exit 1
fi
pldm_image_file=$1
if [ ! -e "$pldm_image_file" ]; then
echo "Error: $pldm_image_file file not found."
exit 1
fi
TMP_DIR=$(mktemp -d)
if [ ! -d "${TMP_DIR}" ]; then
echo "Error: TMP_DIR not found."
exit 1
fi
trap cleanup EXIT INT TERM
# NIC FW & BSP
fwpkg_unpack.py --show_all_metadata --verbose $pldm_image_file | grep "ComponentVersionString\"" | awk 'BEGIN { product[1] = "BlueField NICFW version: "; product[2] = "BlueField BSP version: ";} {print product[NR] $2}' | tr -d '"'
if [ $? -ne 0 ]; then
echo "Error: failed to get NICFW version."
fi
# Unpack
fwpkg_unpack.py --unpack --outdir ${TMP_DIR} $pldm_image_file
if [ $? -ne 0 ]; then
echo "Error: failed to unpack $pldm_image_file."
exit 1
fi
# UEFI
print_capsule_file_vers () {
# Print versions stored in files.
# UEFI image header
pattern="4266021321003005"
uefi_image_file="$TMP_DIR/temp_uefi_image.bin"
atf_version=$(strings "$IMAGE_PATH" | grep -m 1 "(\(release\|debug\))")
if [ -n "$atf_version" ]; then
echo "BlueField ATF version: $atf_version"
fi
# Search for the UEFI header pattern
xxd -p "$IMAGE_PATH" | tr -d "\n" | grep -b -o "$pattern" | cut -d: -f1 | while read -r header_offset2; do
header_offset=$(($header_offset2/2))
image_offset=$((header_offset + 24))
header_string=$(xxd -p -s $header_offset -l 24 "$IMAGE_PATH")
if echo "$header_string" | grep -q "^$pattern"; then
# Extract the image length (next 4 bytes after the header)
image_len_hex=$(echo "$header_string" | cut -c 17-24)
image_len=$(echo "$image_len_hex" | sed 's/\(..\)\(..\)\(..\)\(..\)/\4\3\2\1/')
image_len_dec=$(printf "%d" "0x${image_len#0*}")
# Check the image offset and length against the input file length
input_file_length=$(stat -c%s "$IMAGE_PATH")
end_position=$((image_offset + image_len_dec))
if [ "$end_position" -gt "$input_file_length" ]; then
echo "Error: Image offset + length is greater than input file length"
exit 1
fi
# Extract the UEFI image
tail -c +$((image_offset + 1)) "$IMAGE_PATH" | head -c $image_len_dec > "$uefi_image_file"
# Fetch the version from the UEFI image
gzipped=$(file $uefi_image_file | grep gzip)
if [ -n "$gzipped" ]; then
mv $uefi_image_file $uefi_image_file.gz
gunzip $uefi_image_file.gz
uefi_version="$(strings -el $uefi_image_file | grep "BlueField" | cut -d':' -f 2)"
else
echo "Warning: UEFI image not compressed and no version info"
fi
echo "BlueField UEFI version: $uefi_version"
break
fi
done
}
# ATF & UEFI
pushd . > /dev/null
cd ${TMP_DIR} > /dev/null
for file in ${TMP_DIR}/*; do
IMAGE_PATH="$file"
print_capsule_file_vers
# dump images if it contains them
mlx-mkbfb -x $file &> /dev/null
done
# BMC & CEC
for file in ${TMP_DIR}/dump*; do
fwpkg_unpack.py --show_all_metadata --verbose $file | grep "ComponentVersionString\"" | awk -v substrBMC="ApFw" -v substrCEC="Ecfw" '{ if (index($2, substrBMC)) {print "BlueField BMC version: " $2} else if (index($2, substrCEC)) { print "BlueField CEC version: " $2}}' | tr -d '"'
if [ $? -ne 0 ]; then
echo "Error: failed to read $file."
exit 1
fi
done
popd > /dev/null
exit 0
Mellanox-rshim-user-space-0339e66/scripts/bfb-install 0000775 0001750 0001750 00000105066 15101274612 020676 0 ustar tai tai #!/bin/bash
# Copyright (c) 2020, NVIDIA Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are those
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the FreeBSD Project.
TMP_DIR=$(mktemp -d)
DEBUG=${DEBUG:-0} # Debug mode
BF_REG=bf-reg
RSHIM_PIPE="/tmp/rshim_pipe"
LOG_FILE="/tmp/bfb-install.log"
run_cmd_local_ready=0 # whether run_cmd* local functions are ready to use
run_cmd_remote_ready=0 # whether run_cmd* remote functions are ready to use
# Register definition (BF3 by default).
RSH_BOOT_FIFO_COUNT=0x13001000
RSH_BOOT_FIFO_DATA=0x13002000
RSH_SCRATCHPAD2=0x13000c48
RSH_SWINT=0x13000318
RSH_BREADCRUMB1=0x13000518
usage ()
{
echo "Usage: $0 [options]"
echo "Options:"
echo " -a, --apply-lfwp <0|1> Apply the upgrade. Default is 0: not to apply."
echo " -b, --bfb BFB image file to use."
echo " -c, --config Optional configuration file."
echo " -d, --deferred Deferred activation (local rshim only: formerly runtime)."
echo " -f, --rootfs Optional rootfs file."
echo " -h, --help Show help message."
echo " -k, --keep-log Do not clear the log after reading during bfb install."
echo " -m, --remote-mode Remote mode to use (scp, nc, ncpipe)."
echo " -p, --pldm PLDM image for deferred upgrade."
echo " -r, --rshim Rshim device, format [::]rshim."
echo " -R, --reverse-nc Reverse netcat mode."
echo " -u, --runtime Runtime upgrade (local rshim only: same as deferred)."
echo " -v, --verbose Enable verbose output."
}
# Function to print messages in verbose mode
# Usage: echo_v "Your message"
echo_v() {
if [ "$verbose" -eq 1 ]; then
echo "$@"
fi
}
# Function to print messages for debugging
# Usage: echo_dbg "Your message"
echo_dbg() {
if [ -n "$DEBUG" ] && [ "$DEBUG" -eq 1 ]; then
echo "$@"
fi
}
# Run a command locally or remotely via SSH
#
# $1: mode (local or remote)
# $2: command
#
# Global variables used:
# $ip, $sudo_prefix, $run_cmd_local_ready, $run_cmd_remote_ready
#
# Example:
# run_cmd local "ls -l"
# run_cmd remote "ls -l"
run_cmd()
{
if [ $# -lt 2 ]; then
echo "Error: run_cmd() needs at least 2 arguments."
exit 1
fi
local mode=$1
local command=$2
echo_dbg "Running command in $mode mode: $command"
if [ "$mode" == "local" ]; then
if [ $run_cmd_local_ready -eq 0 ]; then
echo "Error: 'run_cmd local' are not ready to use"
exit 1
fi
$sudo_prefix sh -c "$command"
elif [ "$mode" == "remote" ]; then
if [ $run_cmd_remote_ready -eq 0 ]; then
echo "Error: 'run_cmd remote' are not ready to use"
exit 1
fi
# Execute the command networkly via SSH
ssh root@$ip "$command"
else
echo "Error: invalid mode: $mode"
return 1
fi
}
# Run a command locally or remotely via SSH and exit on error with a custom
# message
#
# $1: mode (local or remote)
# $2: command
# $3: custom error message (optional)
#
# Global variables used: $ip
run_cmd_exit()
{
if [ $# -lt 2 ]; then
echo "Error: run_cmd_exit() requires at least 2 arguments."
exit 1
fi
local mode=$1
local command=$2
local error_msg="${3:-"Error: Command failed"}: [$command]"
run_cmd "$mode" "$command"
local RETVAL=$?
if [ $RETVAL -ne 0 ]; then
echo "$error_msg"
exit $RETVAL
fi
}
# Return the local IP address
#
# Global variables used: $ip
get_local_ip()
{
if [ -z "$ip" ]; then
echo "The global variable \$ip is not defined."
return 1
fi
# Capture both stdout and stderr of the ip route get command
readarray -t output <<< "$(ip route get $ip 2>&1)"
# Check for known error messages in the command output
if echo "${output[@]}" | grep -qi "error"; then
echo "Error: Invalid IP address or routing error."
return 1
fi
# Parse the output for the local IP address, which is right after "src"
local_ip=$(echo "${output[@]}" | awk '/src/ {for(i=1;i<=NF;i++) if($i=="src") {print $(i+1); exit}}')
# Check if a local IP was found
if [ -z "$local_ip" ]; then
echo "Failed to determine the local IP address."
return 1
fi
echo $local_ip
}
clear_boot_fifo()
{
local cnt
while true; do
# Read BOOT_FIFO_DATA if BOOT_FIFO_COUNT != 0
cnt=`${BF_REG} $(basename ${rshim_node}) ${RSH_BOOT_FIFO_COUNT}.64 | awk '{print $3}'`
cnt=$((cnt))
[ $cnt -eq 0 ] && break
${BF_REG} $(basename ${rshim_node}) ${RSH_BOOT_FIFO_DATA}.64 >/dev/null
done
}
clear_sp2_267()
{
sp2=`${BF_REG} $(basename ${rshim_node}) ${RSH_SCRATCHPAD2}.64 | awk '{print $3}'`
# reset SP2.BIT2|6|7 4 + 64 + 128 = 196
sp2=$((sp2 & ~196))
${BF_REG} $(basename ${rshim_node}) ${RSH_SCRATCHPAD2}.64 $sp2 >/dev/null
# set SWINT2 for DPU mode
${BF_REG} $(basename ${rshim_node}) ${RSH_SWINT}.64 0x4 >/dev/null
sleep 1
}
# Push the boot stream to rshim via local rshim
push_boot_stream_via_local_rshim()
{
local sp2
# Push the boot stream to local rshim
echo "Pushing bfb${cfg:+ + cfg}${rootfs:+ + rootfs}"
if [ $deferred -eq 1 ]; then
# Skip reset when pushing bfb
echo "BOOT_RESET_SKIP 1" > ${rshim_node}/misc
# Clear the current boot fifo
clear_boot_fifo
# Set SP2.BIT2=1
sp2=`${BF_REG} $(basename ${rshim_node}) ${RSH_SCRATCHPAD2}.64 | awk '{print $3}'`
sp2=$((sp2 | 4))
${BF_REG} $(basename ${rshim_node}) ${RSH_SCRATCHPAD2}.64 $sp2 >/dev/null
# Set SWINT2.BIT2 for DPU mode
if [ ${nic_mode} -eq 0 ]; then
${BF_REG} $(basename ${rshim_node}) ${RSH_SWINT}.64 0x4 >/dev/null
fi
fi
if ! $sudo_prefix sh -c "cat ${bfb} ${cfg:+$cfg} ${rootfs:+${rootfs}} ${pv:+| ${pv} | cat -} > ${rshim_node}/boot"; then
echo "Error: Failed to push boot stream via local rshim"
return
fi
if [ $deferred -eq 1 ]; then
echo "BOOT_RESET_SKIP 0" > ${rshim_node}/misc
fi
}
# Push the boot stream to rshim via remote rshim with scp
#
# Global variables used
# $bfb, $cfg, $rootfs, $pv, $ip, $rshim
push_boot_stream_via_remote_rshim_scp()
{
# Push the boot stream to remote rshim via ssh copy
echo "Pushing bfb${cfg:+ + cfg}${rootfs:+ + rootfs} to ${ip} via scp"
if ! sh -c "cat ${bfb} ${cfg:+$cfg} ${rootfs:+${rootfs}} ${pv:+| ${pv} | cat -} | ssh root@$ip \"cat > ${rshim_node}/boot\""; then
echo "Error: Failed to push boot stream via remote rshim with scp"
return
fi
}
# Push the boot stream to rshim via remote rshim with netcat
#
# Global variables used:
# $bfb, $cfg, $rootfs, $pv, $ip, $port, $rshim_node, $reverse_nc
push_boot_stream_via_remote_rshim_nc()
{
timeout=20 # in seconds
data="${bfb} ${cfg:+$cfg} ${rootfs:+${rootfs}}"
# Push the boot stream to remote rshim via netcat
echo "Pushing $data to ${ip} via netcat $( [ "$reverse_nc" -eq 0 ] || echo '(in reverse mode)' )"
if [ "$reverse_nc" -eq 1 ]; then
# Remote as the netcat server and local as the client
echo "Starting a netcat server on the remote host..."
# We use nohup to keep the server running after the SSH session is closed.
# We use dd instead of writing directly to the file to avoid the error of
# "write: Interrupted system call"; The bs size doesn't matter.
start_nc_server_cmd="nohup nc -l -p $port | dd bs=1M of=${rshim_node}/boot 2>/dev/null &"
run_cmd_exit remote "$start_nc_server_cmd"
sleep 3 # delay to make sure the server is ready
wait_for_remote_process nc $timeout \
"Error: Failed to start the remote netcat server"
echo "Sending bitstream to a remote host with RSHIM..."
nc_client_cmd="cat $data ${pv:+| ${pv} | cat -} | nc $ip $port"
run_cmd_exit local "$nc_client_cmd"
else
# Local as the netcat server and remote as the client
echo "Starting a netcat server on the local host..."
start_nc_server_cmd="cat $data ${pv:+| ${pv} | cat -} | nc --send-only -l -p $port &"
run_cmd_exit local "$start_nc_server_cmd"
sleep 3 # delay to make sure the server is ready
echo "Sending bitstream from remote to local host with RSHIM..."
local_ip=$(get_local_ip)
# must put remote nc in the background to avoid blocking the script
nc_client_cmd="nohup nc $local_ip $port 2>/dev/null | dd bs=1M of=${rshim_node}/boot &>/dev/null"
run_cmd_exit remote "$nc_client_cmd" &
wait_for_remote_process nc $timeout \
"Error: Failed to start the remote netcat server"
fi
}
# Run a script remotely via SSH to forward data from a network receiver (netcat
# server or client) to the rshim device node. This separate script is needed
# for improved performance
run_pipe_to_rshim_script()
{
# Execute script remotely via SSH
# shellcheck disable=SC2087
ssh root@$ip 'sh -s' << EOF
RSHIM_PIPE=${RSHIM_PIPE:-"/tmp/rshim_pipe"}
RSHIM_BOOT_NODE=${rshim_node:-"/dev/rshim0"}/boot
BLOCK_SIZE=2048000 # smaller block size performs worse
if [ -e "\$RSHIM_PIPE" ]; then
rm \$RSHIM_PIPE
fi
mkfifo \$RSHIM_PIPE
if ! dd if=\$RSHIM_PIPE of=\$RSHIM_BOOT_NODE bs=\$BLOCK_SIZE; then
echo "Error occurred in dd command"
exit 1
fi
EOF
}
# Use SSH execution to check whether a process is running on the remote host
#
# $1: process name
# $2: timeout in seconds
# $3: custom error message (optional)
wait_for_remote_process()
{
default_timeout=10
local process=$1
local timeout=${2:-$default_timeout}
local error_msg="${3:-Error: Time out waiting for launching process $process}"
local cmd="while true; do pgrep -x $process >/dev/null && break; sleep 1; done"
local timeout_cmd="timeout $timeout sh -c \"$cmd\""
run_cmd_exit remote "$timeout_cmd" "$error_msg"
}
# You can call execute_remote_script multiple times as needed in your script
# Push the boot stream to rshim via remote rshim with netcat and a persistent
# pipe
#
# Global variables used:
# $bfb, $cfg, $rootfs, $pv, $ip, $port, $rshim_node,
# $pid_wait_timeout, $RSHIM_PIPE, $PIPE_READER_LOG
push_boot_stream_via_remote_rshim_ncpipe()
{
timeout=20 # in seconds
data="${bfb} ${cfg:+$cfg} ${rootfs:+${rootfs}}"
echo "Starting the remote pipe-to-rshim process..."
run_pipe_to_rshim_script &
wait_for_remote_process dd $timeout \
"Error: Failed to start the remote pipe-to-rshim process"
if [ "$reverse_nc" -eq 1 ]; then
echo "Starting the remote netcat server"
nc_server_cmd="nohup nc -l -p $port | dd bs=1M of=$RSHIM_PIPE 2>/dev/null &"
run_cmd_exit remote "$nc_server_cmd"
# It could be very slow to start the netcat server on the remtoe.
wait_for_remote_process nc $timeout \
"Error: Failed to start the remote netcat server"
# Push the boot stream to remote rshim via netcat + persistent pipe
echo "Pushing $data with nc + pipe to Remote"
nc_client_cmd="cat $data ${pv:+| ${pv} | cat -} | nc $ip $port"
run_cmd_exit local "$nc_client_cmd"
else # reverse_nc
# In reverse mode, the local host is the netcat server and the remote host
# is the client.
echo "Starting the local netcat server"
nc_server_cmd="cat $data ${pv:+| ${pv} | cat -} | nc --send-only -l -p $port &"
echo_dbg "Running command in local mode: $cmd"
run_cmd_exit local "$nc_server_cmd"
local_ip=$(get_local_ip)
echo "Starting remote netcat client to get data"
nc_client_cmd="nohup nc $local_ip $port > $RSHIM_PIPE 2>/dev/null"
run_cmd_exit remote "$nc_client_cmd" &
wait_for_remote_process nc $timeout \
"Error: Failed to start the remote netcat server"
fi
}
# Push the BFB stream to rshim
#
# Global variables used:
# $mode, $remote_mode
push_boot_stream()
{
if [ "$mode" == "local" ]; then
push_boot_stream_via_local_rshim
else
if [ "$remote_mode" == "scp" ]; then
push_boot_stream_via_remote_rshim_scp
elif [ "$remote_mode" == "nc" ]; then
push_boot_stream_via_remote_rshim_nc
elif [ "$remote_mode" == "ncpipe" ]; then
push_boot_stream_via_remote_rshim_ncpipe
fi
fi
}
# pcie_bd is needed by check_nic_mode and other places. Shall be called eary
check_pcie_bdf()
{
local str
[ "$mode" != "local" ] && return
# Only needs to check for BF3.
str=`cat ${rshim_node}/misc | grep DEV_INFO | grep BlueField-3`
[ -z "$str" ] && return
# Get PCIE BDF
str=`cat ${rshim_node}/misc | grep DEV_NAME | awk '{print $2}'`
str=${str:5}
str=${str/.*/}
pcie_bd="$str"
}
# Checks BF3 NIC_MODE
check_nic_mode()
{
local str
[ "$mode" != "local" ] && return
# Only needs to check for BF3.
str=`cat ${rshim_node}/misc | grep DEV_INFO | grep BlueField-3`
[ -z "$str" ] && return
num_ports=$(lspci -nn -s $pcie_bd | grep -v '\[0801\]' | wc -l || { echo "Failed to query PCIe ports for $pcie_bd"; echo 0; })
if [ "$num_ports" -eq 2 ]; then
[ $verbose -eq 1 ] && echo "Detected dual-port device: ${pcie_bd}.0 and ${pcie_bd}.1"
fi
# Check NIC mode
str=`mlxconfig -d ${pcie_bd}.0 -e q INTERNAL_CPU_OFFLOAD_ENGINE 2>/dev/null | grep INTERNAL_CPU_OFFLOAD_ENGINE | awk '{print $(NF-1)}'`
if [ ."$str" = ."DISABLED(1)" ] || grep -q "NIC mode" ${rshim_node}/misc; then
echo "${rshim_node} (${pcie_bd}) is in NIC mode"
nic_mode=1
else
nic_mode=0
fi
}
# Wait for RSHIM to finish updating by monitoring keywords in the RSHIM log
#
# Global variables used:
# $mode, $rshim_node, $remote_mode
wait_for_update_to_finish()
{
# 'filter0' indicates bfb installation completion, thus CLEAR_ON_READ
# can be disabled for next boot. 'filter' is related to specific mode
# which might include extra configuration or booting, and is used as
# the exit condition of the bfb-install script.
local filter0 filter
filter0="Rebooting\.\.\.|finished|DPU is ready|Linux up|CRITICAL ERROR"
if [ $deferred -eq 0 ]; then
filter0="$filter0|In Enhanced NIC mode"
if [ $nic_mode -eq 1 ]; then
filter="In Enhanced NIC mode"
else
filter="$filter0"
fi
else
filter0="Runtime upgrade finished"
filter="$filter0"
fi
echo "Collecting BlueField booting status. Press Ctrl+C to stop…"
# Enable CLEAR_ON_READ, so rshim log will be cleared after read.
if [ $clear_on_read -eq 1 ]; then
run_cmd_exit $mode "echo 'CLEAR_ON_READ 1' > ${rshim_node}/misc"
fi
# Set display level to 2 to show more information
run_cmd_exit $mode "echo 'DISPLAY_LEVEL 2' > ${rshim_node}/misc"
# Create log file with date
echo "# $(date)" > ${LOG_FILE}
last=""
finished=0
while [ $finished -eq 0 ]; do
last_len=${#last}
cmd_get_log="cat ${rshim_node}/misc | sed -n '/^ INFO/,\$p'"
cur=$(run_cmd_exit $mode "$cmd_get_log")
cur_len=${#cur}
sleep 1
if echo ${cur} | grep -Ei "$filter" >/dev/null; then
finished=1
fi
if echo ${cur} | grep -Ei "$filter0" >/dev/null; then
# Disable CLEAR_ON_READ.
run_cmd_exit $mode "echo 'CLEAR_ON_READ 0' > ${rshim_node}/misc"
fi
# Overwrite if current length smaller than previous length.
if [ ${last_len} -eq 0 -o ${last_len} -gt ${cur_len} ]; then
echo "${cur}" | sed '/^[[:space:]]*$/d' | tee -a ${LOG_FILE}
last="${cur}"
continue
fi
# Overwrite if first portion does not match.
sub_cur=$(echo "${cur}" | dd bs=1 count=${last_len} 2>/dev/null)
if [ "${sub_cur}" != "${last}" ]; then
echo "${cur}" | sed '/^[[:space:]]*$/d' | tee -a ${LOG_FILE}
last="${cur}"
continue
fi
# Nothing if no update.
if [ ${last_len} -eq ${cur_len} ]; then
[ $finished -eq 0 ] && continue;
fi
# Print the diff.
echo "${cur}" | dd bs=1 skip=${last_len} 2>/dev/null | \
sed '/^[[:space:]]*$/d' | tee -a ${LOG_FILE}
last="${cur}"
done
# Disable CLEAR_ON_READ.
run_cmd_exit $mode "echo 'CLEAR_ON_READ 0' > ${rshim_node}/misc"
}
apply_chip_settings()
{
local chip
chip=$(run_cmd_exit $mode "cat ${rshim_node}/misc | grep DEV_INFO")
chip=$(echo "${chip}" | awk '{print $2}')
chip=${chip:0:11}
if [ ."${chip}" == ."BlueField-1" -o ."${chip}" == ."BlueField-2" ]; then
RSH_BOOT_FIFO_COUNT=0x00010488
RSH_BOOT_FIFO_DATA=0x00010408
RSH_SCRATCHPAD2=0x00010c28
RSH_SWINT=0x00010318
RSH_BREADCRUMB1=0x00010518
fi
}
# Clean up function whenever the script exits
# shellcheck disable=SC2317
cleanup() {
# Remove the temp directory.
rm -rf $TMP_DIR
# prevent cleanup from being called multiple times
if [ "$cleanup_started" -eq 1 ]; then
exit 1
fi
cleanup_started=1
if [ "$?" -ne 0 ]; then
echo "BlueField Update Failed"
fi
# Kill all netcat related processes on both ends
if [ $run_cmd_local_ready -eq 1 ]; then
run_cmd local "pgrep -x nc >/dev/null && pgrep -x nc | xargs kill -9"
fi
if [ $run_cmd_remote_ready -eq 1 ]; then
run_cmd remote "pgrep -x nc >/dev/null && pgrep -x nc | xargs kill -9"
if [ $remote_mode == "nc" ] || [ $remote_mode == "ncpipe" ]; then
run_cmd remote \
"pgrep pipe_to_rshim >/dev/null && pgrep pipe_to_rshim | xargs kill -9"
run_cmd remote "rm -f $RSHIM_PIPE"
fi
fi
if [ $deferred -eq 1 ]; then
# Reset to default state.
echo "BOOT_RESET_SKIP 0" > ${rshim_node}/misc
sleep 5
clear_sp2_267
fi
# Disable CLEAR_ON_READ.
if [ $rshim_device_exists -eq 1 ]; then
if [ $mode == "local" ] && [ $run_cmd_local_ready -eq 1 ]; then
run_cmd_exit local "echo 'CLEAR_ON_READ 0' > ${rshim_node}/misc"
fi
if [ $mode == "remote" ] && [ $run_cmd_remote_ready -eq 1 ]; then
run_cmd_exit remote "echo 'CLEAR_ON_READ 0' > ${rshim_node}/misc"
fi
fi
# Restore the original binding states for PF0 and PF1
if [ $nic_mode -eq 1 -a -n "${pcie_bd}" -a ${deferred} -eq 0 ]; then
for i in 0 1; do
if eval "[ \${pf${i}_bound} -eq 0 ]"; then
[ $verbose -eq 1 ] && echo "Re-binding: skipping originally unbound pf${i} (${pcie_bd}.${i})"
continue
fi
if [ ! -e /sys/bus/pci/drivers/mlx5_core/${pcie_bd}.${i} ]; then
echo "Binding pf${i} (${pcie_bd}.${i})"
run_cmd_exit local "echo ${pcie_bd}.${i} > /sys/bus/pci/drivers/mlx5_core/bind"
fi
done
fi
}
# Main
default_remote_mode=scp
default_nc_port=9527 # default nc server port for nc* methods
bfb=
pldm=
cfg=
rootfs=
mode=local # Values can be local or remote
remote_mode= # Values can be scp, nc, or ncpipe
rshim= # rshim device string, format [::]rshim
deferred=0 # Values can be 0 or 1.
verbose=0 # Values can be 0 or 1.
reverse_nc=0 # Values can be 0 or 1.
clear_on_read=1 # Values can be 0 or 1.
num_bfb=0
num_rshim=0
max_bfb=1
max_rshim=1
apply_lfwp=0 # Values can be 0 or 1.
rshim_node= # rshim device identifier, e.g. rshim0
ip= # IP address for remote host
port=
cleanup_started=0
trap cleanup EXIT INT TERM
nic_mode=0 # Flag to indicate whether DPU in NIC mod or not
pcie_bd="" # PCIE Bus-Device
pf0_bound=0 # PF0 is bound prior to the script run
pf1_bound=0 # PF1 is bound prior to the script run
rshim_device_exists=0
options=`getopt -n bfb-install -o a:b:c:f:dhkm:p:r:Ruv \
-l apply-lfwp:,bfb:,config:,rootfs:,deferred,help,keep-log,remote-mode:,reverse-nc,rshim:,pldm:,runtime,verbose \
-- "$@"`
if [ $? != 0 ]; then echo "Command line error" >&2; exit 1; fi
eval set -- $options
while [ "$1" != -- ]; do
case $1 in
--apply-lfwp|-a) shift; apply_lfwp=$1 ;;
--bfb|-b) shift; bfb=$(readlink -f $1) num_bfb=$((num_bfb + 1));;
--config|-c) shift; cfg=$1 ;;
--deferred|-d) deferred=1 ;;
--rootfs|-f) shift; rootfs=$1 ;;
--help|-h) usage; exit 0 ;;
--keep-log|-k) clear_on_read=0 ;;
--pldm|-p) shift; pldm=$(readlink -f $1) ;;
--remote-mode|-m) shift; remote_mode=$1 ;;
--rshim|-r) shift; rshim=$1 num_rshim=$((num_rshim + 1));;
--reverse-nc|-R) reverse_nc=1 ;;
--runtime|-u) deferred=1 ;;
--verbose|-v) verbose=1 ;;
--) shift; break;;
*) echo "Error: Invalid argument: $1" >&2; usage >&2; exit 1 ;;
esac
shift
done
# Parameter checks
if [ -z "${bfb}" -a -z "${pldm}" -a ${apply_lfwp} -eq 0 ]; then
echo "Error: Need to provide either bfb or pldm file."
usage >&2
exit 1
fi
if [ -n "${bfb}" -a -n "${pldm}" ]; then
echo "Error: Can't provide both bfb and pldm file."
usage >&2
exit 1
fi
# Check if bfb file exists.
if [ -n "${bfb}" -a ! -e "${bfb}" ]; then
echo "Error: ${bfb} not found."
exit 1
fi
# Check if bfb and rshim are set and non-empty
if [ -z "${rshim}" ]; then
echo "Error: Need to provide rshim device name."
usage >&2
exit 1
fi
# Check if bfb and rshim options are valid or not
if [ ${num_bfb} -gt ${max_bfb} ]; then
echo "Error: More than one bfb image provided"
usage >&2
exit 1
fi
if [ ${num_rshim} -gt ${max_rshim} ]; then
echo "Error: More than one rshim device provided"
usage >&2
exit 1
fi
# Parse rshim for IP, optional port, and device identifier
if echo "$rshim" | grep -q ':'; then
mode=remote
remote_mode=${remote_mode:-$default_remote_mode}
ip=$(echo "$rshim" | cut -d':' -f1 | tr -d '\n')
# Attempt to extract a potential port number
potential_port=$(echo "$rshim" | cut -s -d':' -f2)
# Attempt to extract a potential rshim device identifier
potential_rshim_node=$(echo "$rshim" | cut -s -d':' -f3)
if [ -n "$potential_rshim_node" ]; then
# If there's a third field, it's clearly the rshim device, and the second
# field is the port
port=$potential_port
rshim_node=$potential_rshim_node
else
# If there's no third field, the second field could be either the port or
# the rshim device
if echo "$potential_port" | grep -qE '^[[:digit:]]+$'; then
# If the second field is numeric, it's the port, and the rshim device is
# missing
port=$potential_port
# This scenario implies a malformed rshim argument as the rshim device
# identifier is missing
echo "Error: Missing rshim device identifier." >&2
usage >&2
exit 1
else
# The second field is not numeric, so it's the rshim device
rshim_node=$potential_port
fi
fi
else
# Local mode, rshim_node is directly the value of rshim
rshim_node=$rshim
# Adjust log file to be per rshim
LOG_FILE=${LOG_FILE%.*}-$(basename $rshim_node).log
fi
# We don't allow remote modes for local rshim
if [ $mode == "local" ] && [ -n "$remote_mode" ]; then
echo "Error: Remote mode is not supported for local rshim."
exit 1
fi
if [ $mode == "remote" ] ; then
if [ $deferred -eq 1 ]; then
echo "Error: deferred upgrade is only supported for local rshim."
exit 1
fi
# convert potential host name to IP address
ip=$(getent ahosts $ip | awk '{print $1}' | head -n 1)
# We don't allow localhost for remote modes
if [ $ip == "127.0.0.1" ]; then
echo "Error: localhost is not supported for remote mode."
exit 1
fi
# Check allowed remote modes
if [ $remote_mode == "scp" ]; then
# We don't support port selection for scp mode
if [ -n "$port" ]; then
echo "Error: Port selection is not supported for scp mode."
usage >&2
exit 1
fi
elif [ $remote_mode == "nc" ] || [ $remote_mode == "ncpipe" ]; then
port=${port:-$default_nc_port}
if ! echo "$port" | grep -qE '^[0-9]+$'; then
echo "Error: Invalid port number: $port" >&2
usage >&2
exit 1
fi
else
echo "Error: Invalid remote mode: $remote_mode"
usage >&2
exit 1
fi
fi
# Check if rshim_node starts with "/" and add "/dev/" if not
if [ ."$(echo "${rshim_node}" | cut -c1-1)" != ."/" ]; then
rshim_node="/dev/${rshim_node}"
fi
if [ $verbose -eq 1 ]; then
echo "Updating BlueField with $mode RSHIM"
echo " BFB file: $bfb"
[ -n "$cfg" ] && echo " Config File:: $cfg"
[ -n "$rootfs" ] && echo " Rootfs File: $rootfs"
if [ "$mode" = "remote" ]; then
echo " Remote Update Mode: $remote_mode"
echo " Remote Host IP: $ip"
if [ "$remote_mode" = "nc" ] || [ "$remote_mode" = "ncpipe" ]; then
[ -n "$port" ] && echo " Remote port: $port"
[ "$reverse_nc" -eq 1 ] && echo " Using reverse netcat mode"
fi
fi
echo " RSHIM Device Node: $rshim_node"
fi
# Root access check.
check_root_cmd="[ \$(id -u) -eq 0 ]"
echo "Checking if local host has root access..."
if ! eval "$check_root_cmd"; then
echo " Warning: No host root access. Trying sudo"
sudo_prefix="sudo"
fi
# rshim is ready to use 'run_cmd_exit local xxx'.
run_cmd_local_ready=1
# Setup checks
check_pcie_bdf
# Check PLDM and convert it into BFB.
if [ -n "${pldm}" ]; then
if [ $mode == "remote" ] ; then
echo "Error: pldm is only for local rshim."
exit 1
fi
if [ ! -e "${pldm}" ]; then
echo "Error: ${pldm} not found."
exit 1
fi
if [ ! -d "${TMP_DIR}" ]; then
echo "Error: TMP_DIR not found."
exit 1
fi
# PLDM automatically indicate deferred upgrade.
deferred=1
pldm_nicfw=""
pldm_bfb=""
mkdir ${TMP_DIR}/pldm
fwpkg_unpack.py --unpack --outdir ${TMP_DIR}/pldm ${pldm}
for i in ${TMP_DIR}/pldm/*.bin; do
if [ ! -e "${i}" ]; then
echo "Error: unable to unpack ${pldm}."
exit 1
fi
sig=$(head -c 4 < ${i})
if [ ."${sig:0:2}" = ."Bf" ]; then
pldm_bfb="${i}"
elif [ ."${sig}" = ."MTFW" ]; then
pldm_nicfw="${i}"
else
printf "\\x4d\\x54\\x46\\x57\\xab\\xcd\\xef\\x00\\xfa\\xde\\x12\\x34\\x56\\x78\\xde\\xad" \
> ${TMP_DIR}/pldm/nicfw_header
dd if="${i}" of=${TMP_DIR}/pldm/nicfw_body bs=16 skip=1
cat ${TMP_DIR}/pldm/nicfw_header ${TMP_DIR}/pldm/nicfw_body > ${TMP_DIR}/pldm/nicfw.bin
pldm_nicfw=${TMP_DIR}/pldm/nicfw.bin
fi
done
if [ -z "${pldm_nicfw}" -a -z "${pldm_bfb}" ]; then
echo "Error: unable to find bfb or nicfw in ${pldm}."
exit 1
fi
if ! mlx-mkbfb ${pldm_nicfw:+--nicfw ${pldm_nicfw}} ${cfg:+--boot-args ${cfg}} ${pldm_bfb} ${TMP_DIR}/pldm/pldm.bfb; then
echo "Error: unable to create bfb from pldm"
exit 1
fi
pldm=""
bfb="${TMP_DIR}/pldm/pldm.bfb"
elif [ ${deferred} -eq 1 -a -e "${bfb}" ]; then
# Convert bundle BFB to flat BFB if needed.
# This conversion is only supported on PCIe host.
is_bundle=$(mlx-mkbfb -d "${bfb}" | grep "In-memory filesystem")
if [ -n "${is_bundle}" -a -n "$pcie_bd" ]; then
echo "Convert $(basename "${bfb}") to flat format for deferred upgrade"
if ! which flint &> /dev/null; then
echo "Error: flint not found."
exit 1
fi
psid=$(flint -d "$pcie_bd".0 q | grep PSID | awk '{print $2}')
if [ -z "${psid}" ]; then
echo "Error: failed to get PSID."
exit 1
fi
mkdir ${TMP_DIR}/bfb
bfb-tool repack --bfb "${bfb}" --psid ${psid} \
--output-dir ${TMP_DIR}/bfb --output-format flat \
--output-bfb flat.bfb
if [ $? -ne 0 ]; then
echo "Error: Failed to create BFB in flat format"
exit 1
fi
bfb=$(basename "${bfb}")
bfb=${bfb%.*}
bfb_path=${TMP_DIR}/bfb/"${bfb}"/${psid}
bfb="${bfb_path}"/flat.bfb
if [ ! -e "${bfb}" ]; then
echo "Error: ${bfb} not found"
exit 1
fi
# Replace config file if provided.
if [ -n "${cfg}" -a -e "${cfg}" ]; then
mlx-mkbfb --boot-args ${cfg} ${bfb} "${bfb_path}"/flat-cfg.bfb
bfb="${bfb_path}"/flat-cfg.bfb
fi
else
mkdir ${TMP_DIR}/bfb
bfb_path=${TMP_DIR}/bfb
# Replace config file if provided.
if [ -n "${cfg}" -a -e "${cfg}" ]; then
mlx-mkbfb --boot-args ${cfg} ${bfb} "${bfb_path}"/flat-cfg.bfb
bfb="${bfb_path}"/flat-cfg.bfb
fi
fi
fi
# Check again if bfb file exists (if not activate-only).
if [ ! -e "${bfb}" -a ${apply_lfwp} -eq 0 ]; then
echo "Error: ${bfb} not found."
exit 1
fi
# Check if rootfs exists if set
if [ -n "${rootfs}" ] && [ ! -e "${rootfs}" ]; then
echo "Error: ${rootfs} not found."
exit 1
fi
# Check if cfg exists if set
if [ -n "${cfg}" ] && [ ! -e "${cfg}" ]; then
echo "Error: ${cfg} not found."
exit 1
fi
rshim_check_cmd="[ -e ${rshim_node}/boot ]"
if [ $mode == "local" ]; then
run_cmd_exit local "$check_root_cmd" \
"Error: current login does not have sudo"
echo "Checking if rshim driver is running locally..."
run_cmd_exit local "$rshim_check_cmd" \
"Error: rshim driver not found at $rshim"
rshim_device_exists=1
fi
if [ $mode == "remote" ]; then
echo "Checking if remote host is reachable..."
ping_cmd="ping -c 1 $ip >/dev/null 2>&1"
run_cmd_exit local "$ping_cmd"
echo "Checking if Remote has SSH server running..."
run_cmd_exit local "nc -z $ip 22" \
"Error: Remote does not have SSH server running"
echo "Checking if Remote has password-less root SSH access..."
if ! ssh -o BatchMode=yes -o ConnectTimeout=5 root@$ip "exit"; then
echo "Error: Remote does not have password-less (public key authentication) root SSH access"
exit 1
fi
run_cmd_remote_ready=1
echo "Checking if rshim driver is running remotely..."
run_cmd_exit remote "$rshim_check_cmd" \
"Error: remote rshim driver not found"
rshim_device_exists=1
echo "Lowering the priority of the remote rshim process..."
run_cmd_exit remote "renice -n 19 -p \$(pgrep rshim)" \
"Error: Failed to lower the priority of the remote rshim process"
if [ $remote_mode == "nc" ] || [ $remote_mode == "ncpipe" ]; then
echo "Checking if local netcat is installed..."
run_cmd_exit local "command -v nc > /dev/null" \
"Error in $mode mode: Netcat is not installed locally"
echo "Checking if remote netcat is installed..."
run_cmd_exit remote "command -v nc > /dev/null" \
"Error in $mode mode: Netcat is not installed remotely"
# Try to test-connect the netcat port to see if it's available
if [ $reverse_nc -eq 1 ]; then
echo "Checking if remote netcat port $port is available..."
run_cmd_exit remote "! nc -z $ip $port" \
"Error: remote netcat port $port is not available"
else
echo "Checking if local netcat port $port is available..."
run_cmd_exit local "! nc -z localhost $port" \
"Error: local netcat port $port is not available"
fi
fi
fi
# Check the pv tool.
pv=$(which pv 2>/dev/null)
if [ -z "${pv}" ]; then
echo "Warn: 'pv' command not found. Continue without showing BFB progress."
fi
# Check BF chip version and adjust register offsets.
apply_chip_settings
# Check NIC mode and unbind mlx5_core driver in NIC mode.
check_nic_mode
# clear SP2 BITs to handle the case when ACPI events have been triggered before.
clear_sp2_267
if [ ${nic_mode} -eq 1 -a -n "${pcie_bd}" -a ${deferred} -eq 0 ]; then
# Set BREADCRUMB.BIT32 to indicate NIC mode.
breadcrumb1=$(${BF_REG} $(basename ${rshim_node}) ${RSH_BREADCRUMB1}.64 | awk '{print $3}')
breadcrumb1=$((breadcrumb1 | (0x1 << 32)))
breadcrumb1=$(printf "0x%x\n" $breadcrumb1)
${BF_REG} $(basename ${rshim_node}) ${RSH_BREADCRUMB1}.64 ${breadcrumb1} >/dev/null
for i in 0 1; do
if [[ ! -e /sys/bus/pci/drivers/mlx5_core/${pcie_bd}.${i} ]]; then
[ ${verbose} -eq 1 ] && echo "Unbinding: Skipping originally unbound pf${i} (${pcie_bd}.${i})"
continue
fi
eval "pf${i}_bound=1"
echo "Unbinding pf${i} (${pcie_bd}.${i})"
run_cmd_exit local "echo ${pcie_bd}.${i} > /sys/bus/pci/drivers/mlx5_core/unbind"
done
fi
# Reactivate NIC_FW if deferred.
if [ -n "${pcie_bd}" -a ${deferred} -eq 1 ]; then
if which flint &> /dev/null; then
# Suppress errors if already applied.
flint -d ${pcie_bd}.0 ir >&/dev/null
else
echo "Flint not found. Skip NIC_FW reactivation."
fi
fi
# Push BFB and wait for result.
if [ -e "${bfb}" ]; then
push_boot_stream
wait_for_update_to_finish
fi
# Got here after wait_for_update_to_finish() returns from polling. The transfer and
# verify is done.
if [ ${deferred} -eq 1 ]; then
# Note: OS bf-upgrade script will wait and check SP2.BITS right after successful
# upgrade/staging.
sp2=`${BF_REG} $(basename ${rshim_node}) ${RSH_SCRATCHPAD2}.64 | awk '{print $3}'`
# Note: check SP2.BIT11|12 for success: 10b. Send Activation only it's a success.
if [ $((sp2 & 6144)) -eq 4096 ]; then
clear_sp2_267
# Set SP2.BIT6=1 to issue PLDM ActivateFirmware command that activate new images
# after reboot
echo "Sending ActivateFirmware"
sp2=$((sp2 | 64))
${BF_REG} $(basename ${rshim_node}) ${RSH_SCRATCHPAD2}.64 $sp2 >/dev/null
# set SWINT2 for DPU mode
if [ ${nic_mode} -eq 0 ]; then
${BF_REG} $(basename ${rshim_node}) ${RSH_SWINT}.64 0x4 >/dev/null
fi
else
echo "Transfer/Verify failed"
exit -1
fi
fi
# LFWP activation(reset) on PCIe host.
if [ ${apply_lfwp} -eq 1 ]; then
if [ -z "${pcie_bd}" ]; then
echo "ERROR: Failed to activate LFWP, PCIe device not found."
exit 1
fi
if ! which mlxfwreset &> /dev/null; then
echo "ERROR: Failed to activate LFWP, mlxfwreset not found."
exit 1
fi
# Best-effort to check and apply L0 reset.
if (mlxfwreset -d ${pcie_bd}.0 q | grep live-Patch | grep -qw "\-Supported"); then
echo "Live Patch NIC Firmware reset is supported."
msg=$(mlxfwreset -d ${pcie_bd}.0 -y -l 0 r 2>&1)
if [ $? -ne 0 ]; then
echo "ERROR: Live Patch NIC Firmware reset failed. $msg"
else
echo "Live Patch NIC Firmware reset done"
fi
else
echo "Live Patch NIC Firmware reset not supported."
fi
fi
if [ ${deferred} -eq 1 ]; then
end=$((SECONDS + 60))
while [ $SECONDS -lt $end ]; do
sp2=`${BF_REG} $(basename ${rshim_node}) ${RSH_SCRATCHPAD2}.64 | awk '{print $3}'`
if [ $((sp2 & 6144)) -eq 4096 ]; then
# 10b
echo "ActivateFirmware Succeeded"
break
elif [ $((sp2 & 6144)) -eq 6144 ]; then
# 11b
echo "ActivateFirmware Failed"
break
elif [ $((sp2 & 6144)) -eq 0 ]; then
# idle
break
fi
sleep 1
done
echo "Upgrade Finished"
fi
Mellanox-rshim-user-space-0339e66/scripts/bfb-tool 0000775 0001750 0001750 00000062625 15101274612 020210 0 ustar tai tai #!/bin/bash
###############################################################################
#
# Copyright 2025 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################
if [ "$(id -u)" -ne 0 ]; then
echo "This script must be run as root"
exit 1
fi
info() {
echo >&2 "INFO: $*"
}
note() {
echo >&2 "NOTE: $*"
}
warn() {
echo >&2 "WARNING: $*"
}
error() {
echo >&2 "ERROR: $*"
}
usage() {
cat << EOF
Usage: $(basename $0) --bfb --psid |--opn |--all [-p|--profile ] [-o|--output-dir ] [-f|--output-format ] [-B|--output-bfb] [-r|--replace-fw ] [-v|--verbose] [-j|--json]
action: extract, repack or info. The repack action includes extracting and building a new BFB for a specific OPN/PSID
Options:
--bfb bf-bundle/bf-fwbundle BFB
--psid PSID of the DPU to extract the paylod
--opn OPN of the DPU to extract the payload
--profile Configuration Profile
--output-dir Directory to keep the results
--output-format Output format (bundle, flat)
Bundle format is the format for DPU mode (default).
Flat format is the format for NIC mode.
--output-bfb Output BFB name
--replace-fw Path to extracted mlnx-fw-updater directory
-j|--json Print version info in JSON format
-v|--verbose Verbose mode
EOF
}
finish() {
[ -n "$WDIR" ] && rm -rf "$WDIR"
}
replace_mlnx_fw_updater() {
local target_dir=$1
local fw_updater_path=$2
info "Replacing mlnx-fw-updater with content from $fw_updater_path"
# Check if the provided path exists and is a directory
if [ ! -d "$fw_updater_path" ]; then
error "mlnx-fw-updater path not found or not a directory: $fw_updater_path"
exit 1
fi
# Verify the required files exist in the provided path
info "Verifying mlnx-fw-updater directory structure"
if [ ! -f "$fw_updater_path/mlnx_fw_updater.pl" ]; then
error "Required file mlnx_fw_updater.pl not found in $fw_updater_path"
exit 1
fi
if [ ! -f "$fw_updater_path/mlnx_fpga_updater.sh" ]; then
error "Required file mlnx_fpga_updater.sh not found in $fw_updater_path"
exit 1
fi
if [ ! -f "$fw_updater_path/mlnx-fw-updater.conf" ]; then
error "Required file mlnx-fw-updater.conf not found in $fw_updater_path"
exit 1
fi
if [ ! -d "$fw_updater_path/firmware" ]; then
error "Required directory firmware not found in $fw_updater_path"
exit 1
fi
# Check for mlxfwmanager files in firmware directory
if ! ls "$fw_updater_path/firmware"/mlxfwmanager_sriov_dis_aarch64* >/dev/null 2>&1; then
error "No mlxfwmanager_sriov_dis_aarch64 files found in $fw_updater_path/firmware"
exit 1
fi
info "All required files verified"
# Remove existing mlnx-fw-updater directory
if [ -d "$target_dir/opt/mellanox/mlnx-fw-updater" ]; then
info "Removing existing mlnx-fw-updater directory"
rm -rf "$target_dir/opt/mellanox/mlnx-fw-updater"
fi
# Copy new mlnx-fw-updater directory
info "Copying new mlnx-fw-updater content"
mkdir -p "$target_dir/opt/mellanox"
cp -r "$fw_updater_path" "$target_dir/opt/mellanox/mlnx-fw-updater"
info "Successfully replaced mlnx-fw-updater"
}
MLX_MKBFB=$(which mlx-mkbfb 2> /dev/null)
BASE_BFB="/usr/lib/firmware/mellanox/boot/default.bfb"
OUTPUT_FORMAT="bundle"
OUTPUT_BFB=""
verbose=0
JSON=0
if [ -z "$1" ]; then
usage
exit 1
fi
action=$1
shift
REPACK=0
GET_INFO=0
case "$action" in
"repack")
REPACK=1
;;
"extract")
;;
"info")
GET_INFO=1
;;
*)
error "Unsupported action: $action"
echo
usage
exit 1
;;
esac
options=$(getopt -l "output-dir:,psid:,opn:,bfb:,profile:,output-format:,output-bfb:,replace-fw:,all,help,json,verbose" -o "o:p:O:b:p:f:B:r:ahjv" -a -- "$@")
eval set -- "$options"
while true
do
case $1 in
-h|--help)
usage
exit 0
;;
-a|--all)
BUILD_ALL=1
;;
-b|--bfb)
shift
bfb=$1
;;
-p|--profile)
shift
profile=$1
;;
-o|--output-dir)
shift
OUTPUT_DIR=$1
;;
-p|--psid)
shift
ID_SET="PSID"
BOARD_ID=$1
;;
-O|--opn)
shift
ID_SET="OPN"
BOARD_ID=$1
;;
-j|--json)
JSON=1
;;
-v|--verbose)
verbose=1
set -xv
;;
-f|--output-format)
shift
OUTPUT_FORMAT=$1
;;
-B|--output-bfb)
shift
OUTPUT_BFB=$1
;;
-r|--replace-fw)
shift
REPLACE_FW_PATH=$1
;;
--)
shift
break;;
esac
shift
done
BUILD_ALL=${BUILD_ALL:-0}
unset BSP_CAPSULE
unset BMC_FW
unset CEC_FW
unset NIC_FW
unset DPU_GI
unset NIC_FW_GI
unset MLXFWMANAGER
unset TARGET_DIR
if [ ! -e "$bfb" ]; then
error "BFB: $bfb does not exist"
exit 1
fi
if [ $GET_INFO -ne 1 ]; then
if [ $BUILD_ALL -eq 0 ]; then
if [ -z "$BOARD_ID" ]; then
error "PSID and OPN are not set. Provide one of them."
usage
exit 1
fi
else
BOARD_ID="FW"
fi
fi
if [ -z "$MLX_MKBFB" ]; then
error "mlx-mkbfb is required"
exit 1
fi
if ! jq --version > /dev/null 2>&1; then
error "jq is required"
exit 1
fi
case "$OUTPUT_FORMAT" in
"bundle")
;;
"flat")
;;
*)
error "Unsupported output format: $OUTPUT_FORMAT"
usage
exit 1
;;
esac
if [ "`uname -m`" != "aarch64" ]; then
if [ $GET_INFO -ne 1 ]; then
if [ ! -x /usr/bin/qemu-aarch64-static ]; then
error "qemu-aarch64-static is required"
cat << EOF
To install qemu-aarch64-static, use the following command, or install it via your Linux distribution's package manager if available:
docker run --rm --entrypoint tar multiarch/qemu-user-static -C /usr/bin -cf- . | sudo tar -C /usr/bin -xf-
EOF
exit 1
fi
if [ ! -d /etc/binfmt.d ]; then
error "systemd package is required"
exit 1
fi
if ! (grep -q /usr/bin/qemu-aarch64-static /etc/binfmt.d/qemu-aarch64.conf > /dev/null 2>&1); then
cat > /etc/binfmt.d/qemu-aarch64.conf << EOF
:qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7:\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/bin/qemu-aarch64-static:
EOF
systemctl restart systemd-binfmt
fi
fi
fi
trap finish EXIT
bfb_name=$(basename $bfb | sed -e 's/.bfb//')
OUTPUT_DIR=${OUTPUT_DIR:-"/tmp"}
doca_version=$(echo $bfb_name | cut -d '_' -f 1,2 | cut -d '-' -f 3-)
bfb_sfx=${bfb_name##*_}
TMPDIR=${TMPDIR:-"/tmp"}
mkdir -p ${TMPDIR}/bfb
WDIR=${WDIR:-$(mktemp -d ${TMPDIR}/bfb/tmp.XXXXXX)}
mkdir -p "${WDIR}"
cd $WDIR
if [ $GET_INFO -eq 1 ]; then
$MLX_MKBFB -x -n info-v0 $bfb
if [ -e dump-info-v0 ]; then
if [ $JSON -eq 1 ]; then
cat dump-info-v0
else
cat dump-info-v0 | jq '.Members[] |"\(.Name): \(.Version)"' | tr -d '"'
fi
else
if [ $JSON -eq 1 ]; then
cat << EOF
{
"error": {
"message": "This BFB file does not contain version information."
}
}
EOF
else
error "This BFB file does not contain version information."
fi
exit 1
fi
cd - > /dev/null 2>&1
exit 0
fi
INITRAMFS_WDIR=$WDIR/initramfs
INITRAMFS_REPKG_DIR=$WDIR/initramfs.repackage
info "Extracting BFB"
$MLX_MKBFB -x -n initramfs-v0 $bfb
mkdir -p $INITRAMFS_WDIR
cd $INITRAMFS_WDIR
info "Extracting BFB's initramfs"
gzip -d < ../dump-initramfs-v0 | cpio -id
if ! (/bin/ls */install.env/common > /dev/null 2>&1); then
error "This BFB does not support BMC components update"
exit 1
fi
if [ ! -d ./opt/mellanox/mlnx-fw-updater ]; then
info "Extracting mlnx-fw-updater"
tar xJf */image.tar.xz ./opt/mellanox/mlnx-fw-updater/
fi
if [ -n "$REPLACE_FW_PATH" ]; then
replace_mlnx_fw_updater "${INITRAMFS_WDIR}" "${REPLACE_FW_PATH}"
fi
BSP_CAPSULE="./usr/lib/firmware/mellanox/boot/capsule/boot_update2.cap"
BSP_VERSION=""
if [ -e ./lib/firmware/mellanox/boot/atf_uefi.version ]; then
BSP_VERSION="$(cat ./lib/firmware/mellanox/boot/atf_uefi.version 2> /dev/null)"
else
BSP_VERSION="$(strings $BSP_CAPSULE | grep -m 1 "(\(release\|debug\))" | cut -d ':' -f 2 | cut -d '-' -f 1)"
fi
if [ ! -f "$BSP_CAPSULE" ]; then
echo "ERROR: ATF/UEFI capsule was not found"
exit 1
fi
if [ -z "$BSP_VERSION" ]; then
echo "ERROR: Cannot identify ATF/UEFI version"
exit 1
fi
if [ ! -d ./usr/lib/firmware/mellanox/bmc ]; then
echo "Extract BMC components"
tar Jxf */image.tar.xz --warning=no-timestamp ./usr/lib/firmware/mellanox/{bmc,cec}/
fi
cp /usr/bin/qemu-aarch64-static ./usr/bin
if [ ! -e ".${BASE_BFB}" ]; then
echo "ERROR: ${BASE_BFB} not found. Invalid BFB format"
exit 1
fi
bfver_out="$(chroot ${INITRAMFS_WDIR} /usr/bin/bfver --file ${BASE_BFB} 2> /dev/null)"
ATF_VERSION=$(echo "$bfver_out" | grep -m 1 "ATF" | cut -d':' -f 3 | \
sed -e 's/[[:space:]]//')
UEFI_VERSION=$(echo "$bfver_out" | grep -m 1 "UEFI" | cut -d':' -f 2 | \
sed -e 's/[[:space:]]//')
if [ -z "$UEFI_VERSION" ]; then
mkdir uefi
cd uefi
$MLX_MKBFB -x ../${BASE_BFB}
mv dump-bl33-v0 dump-bl33-v0.gz
gunzip dump-bl33-v0.gz
UEFI_VERSION="$(strings -el dump-bl33-v0 | grep "BlueField" | cut -d':' -f 2)"
cd - >/dev/null
rm -rf uefi
fi
if [ $REPACK -eq 1 ]; then
info "Extracting initramfs for repackaging"
mkdir -p $INITRAMFS_REPKG_DIR
cd $INITRAMFS_REPKG_DIR
gzip -d < ../dump-initramfs-v0 | cpio -id
if [ ! -d ./opt/mellanox/mlnx-fw-updater ]; then
info "Extracting mlnx-fw-updater"
tar xJf */image.tar.xz ./opt/mellanox/mlnx-fw-updater/
fi
if [ -n "$REPLACE_FW_PATH" ]; then
replace_mlnx_fw_updater "${INITRAMFS_REPKG_DIR}" "${REPLACE_FW_PATH}"
fi
if [ ! -d ./usr/lib/firmware/mellanox/bmc ]; then
echo "Extract BMC components"
tar Jxf */image.tar.xz --warning=no-timestamp ./usr/lib/firmware/mellanox/{bmc,cec}/
fi
cp /usr/bin/qemu-aarch64-static ./usr/bin
cd $INITRAMFS_WDIR
else
INITRAMFS_REPKG_DIR=$INITRAMFS_WDIR
fi
cleanup_base_initramfs()
{
cd $INITRAMFS_REPKG_DIR
# Cleanup
rm -f ./tmp/*bin
rm -f ./usr/lib/firmware/mellanox/boot/capsule/MmcBootCap
rm -rf ./usr/lib/modules/*/kernel/drivers/net/ethernet/chelsio \
./usr/lib/modules/*/kernel/drivers/net/ethernet/broadcom \
./usr/lib/modules/*/kernel/drivers/net/ethernet/litex \
./usr/lib/aarch64-linux-gnu/perl/*/CORE \
./usr/include
# Remove unused MFT files
rm -f $(ls -1 ./usr/share/mft/mstdump_dbs/* | grep -iv BlueField)
rm -f ./usr/bin/mlxtokengenerator \
./usr/bin/mlxtrace_ext \
./usr/bin/mlxcables_ext \
./usr/bin/mlxarchive \
./usr/bin/mlxdump_ext \
./usr/bin/mlxlink_ext \
./usr/bin/wqdump_ext \
./usr/bin/mlxreg_ext \
./usr/bin/mtserver \
./usr/bin/mic \
./usr/bin/mlxdpa \
./usr/bin/mlxfwstress_ext \
./usr/lib64/mft/libmtcr.a \
./usr/lib64/mft/libmtcr_ul.a
rm -rf \
./usr/share/mft/prm_dbs/gpu \
./usr/share/mft/prm_dbs/retimers \
./usr/share/mft/prm_dbs/switch \
./usr/lib64/mft/mtcr_plugins \
./usr/lib64/mft/sdk \
./usr/lib/aarch64-linux-gnu/perl/*/auto/Encode/JP \
./usr/lib/aarch64-linux-gnu/perl/*/auto/Encode/KR \
./usr/lib/aarch64-linux-gnu/perl/*/auto/Encode/TW \
./usr/lib/aarch64-linux-gnu/perl/*/auto/Encode/EBCDIC \
./usr/lib/aarch64-linux-gnu/perl/*/auto/Encode/CN
}
create_info()
{
# Create JSON using jq
odata_count=1
if [ "$OUTPUT_FORMAT" == "bundle" ]; then
bsp_source="${BSP_CAPSULE##*/}"
nic_fw_source="${NIC_FW##*/}"
bmc_fw_source="${BMC_FW##*/}"
cec_fw_source="${CEC_FW##*/}"
dpu_gi_source="${DPU_GI##*/}"
nic_fw_gi_source="${NIC_FW_GI##*/}"
profile_source="${PROFILE##*/}"
else
bsp_source="dump-capsule-v0"
nic_fw_source="dump-nicfw-v0"
bmc_fw_source="dump-image-v0"
cec_fw_source="dump-upgrade-image-v0"
dpu_gi_source="dump-dpu-gi-v0"
nic_fw_gi_source="dump-ramdisk-v0"
profile_source="dump-cfg-gi-v0"
fi
json_output=$(jq -n \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg bsp_name "${BFREV}_BSP" \
--arg bsp_version "${BSP_VERSION}" \
--arg bsp_source "${bsp_source}" \
'{
"//": "This JSON represents a Redfish Software Inventory collection containing multiple software components.",
"@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
"@odata.id": "/redfish/v1/UpdateService/SoftwareInventory",
"Name": "BFB File Content",
"Members": [
{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $bsp_name,
"Version": $bsp_version,
"SoftwareId": $bsp_source,
}
],
"Members@odata.count": 1
}')
if [ -n "$ATF_VERSION" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg atf_name "${BFREV}_ATF" \
--arg atf_version "${ATF_VERSION}" \
--arg atf_source "${bsp_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $atf_name,
"Version": $atf_version,
"SoftwareId": $atf_source,
}] | .["Members@odata.count"] += 1')
fi
if [ -n "$UEFI_VERSION" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg uefi_name "${BFREV}_UEFI" \
--arg uefi_version "${UEFI_VERSION}" \
--arg uefi_source "${bsp_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $uefi_name,
"Version": $uefi_version,
"SoftwareId": $uefi_source,
}] | .["Members@odata.count"] += 1')
fi
if [ -n "$NIC_FW_VERSION" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg nic_fw_name "${BFREV}_NIC_FW" \
--arg nic_fw_version "${NIC_FW_VERSION}" \
--arg nic_fw_source "${nic_fw_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $nic_fw_name,
"Version": $nic_fw_version,
"SoftwareId": $nic_fw_source,
}] | .["Members@odata.count"] += 1')
fi
if [ -n "$BMC_FW_VERSION" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg bmc_fw_name "${BFREV}_BMC_FW" \
--arg bmc_fw_version "${BMC_FW_VERSION}" \
--arg bmc_fw_source "${bmc_fw_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $bmc_fw_name,
"Version": $bmc_fw_version,
"SoftwareId": $bmc_fw_source,
}] | .["Members@odata.count"] += 1')
fi
if [ -n "$CEC_FW_VERSION" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg cec_fw_name "${BFREV}_CEC_FW" \
--arg cec_fw_version "${CEC_FW_VERSION}" \
--arg cec_fw_source "${cec_fw_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $cec_fw_name,
"Version": $cec_fw_version,
"SoftwareId": $cec_fw_source,
}] | .["Members@odata.count"] += 1')
fi
if [ -n "$DPU_GI_VERSION" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg dpu_gi_name "${BFREV}_DPU_GI" \
--arg dpu_gi_version "${DPU_GI_VERSION}" \
--arg dpu_gi_source "${dpu_gi_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $dpu_gi_name,
"Version": $dpu_gi_version,
"SoftwareId": $dpu_gi_source,
}] | .["Members@odata.count"] += 1')
fi
if [ -n "$NIC_FW_GI_VERSION" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg nic_fw_gi_name "${BFREV}_NIC_FW_GI" \
--arg nic_fw_gi_version "${NIC_FW_GI_VERSION}" \
--arg nic_fw_gi_source "${nic_fw_gi_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $nic_fw_gi_name,
"Version": $nic_fw_gi_version,
"SoftwareId": $nic_fw_gi_source,
}] | .["Members@odata.count"] += 1')
fi
if [ -n "$profile" ]; then
let odata_count++
json_output=$( echo $json_output | jq \
--arg odata_count "$odata_count" \
--arg odata_id "/redfish/v1/UpdateService/SoftwareInventory/$odata_count" \
--arg profile_name "$PROFILE_NAME" \
--arg profile_version "$PROFILE_VERSION" \
--arg profile_source "${profile_source}" \
'.Members += [{
"@odata.id": $odata_id,
"Id": $odata_count,
"Name": $profile_name,
"Version": $profile_version,
"SoftwareId": $profile_source,
}] | .["Members@odata.count"] += 1')
fi
echo "$json_output" > ${TARGET_DIR}/info.json
}
rebuild_bfb_bundle()
{
info "Rebuilding BFB in bundle format"
cd $INITRAMFS_REPKG_DIR
# Remove the extra payload
rm -f ./usr/bin/qemu-aarch64-static
rm -f ./usr/lib/firmware/mellanox/bmc/*
rm -f ./usr/lib/firmware/mellanox/cec/*
cp ${TARGET_DIR}/${BMC_FW##*/} ./usr/lib/firmware/mellanox/bmc/
echo $BMC_FW_VERSION > ./usr/lib/firmware/mellanox/bmc/bf3-bmc-fw.version
cp ${TARGET_DIR}/${CEC_FW##*/} ./usr/lib/firmware/mellanox/cec/
echo $CEC_FW_VERSION > ./usr/lib/firmware/mellanox/cec/bf3-cec-fw.version
if [ -n "${DPU_GI}" ]; then
cp ${TARGET_DIR}/${DPU_GI##*/} ./usr/lib/firmware/mellanox/bmc/
echo $DPU_GI_VERSION > ./usr/lib/firmware/mellanox/bmc/bf3-bmc-preboot-install.version
fi
if [ -n "${NIC_FW_GI}" ]; then
cp ${TARGET_DIR}/${NIC_FW_GI##*/} ./usr/lib/firmware/mellanox/bmc/
fi
if [ -n "$profile" ]; then
cp ${TARGET_DIR}/${PROFILE##*/} ./usr/lib/firmware/mellanox/bmc/
echo $PROFILE_VERSION > ./usr/lib/firmware/mellanox/bmc/config-image.version
fi
find . | cpio -H newc -o | gzip -9 > ../dump-initramfs-v0
$MLX_MKBFB --initramfs ../dump-initramfs-v0 --info ${TARGET_DIR}/info.json ${bfb} ${TARGET_DIR}/${target_bfb}
cp /usr/bin/qemu-aarch64-static ./usr/bin
}
rebuild_bfb_flat()
{
info "Rebuilding BFB in flat format"
cd $INITRAMFS_REPKG_DIR
MKBFB_PARAMS="--info ${TARGET_DIR}/info.json \
--capsule ${TARGET_DIR}/${BSP_CAPSULE##*/} \
--image ${TARGET_DIR}/${BMC_FW##*/} \
--upgrade-image ${TARGET_DIR}/${CEC_FW##*/} \
--nicfw ${TARGET_DIR}/${NIC_FW##*/}"
if [ -f "${TARGET_DIR}/${DPU_GI##*/}" ]; then
MKBFB_PARAMS="${MKBFB_PARAMS} \
--dpu-gi ${TARGET_DIR}/${DPU_GI##*/}"
fi
if [ -f "${TARGET_DIR}/${NIC_FW_GI##*/}" ]; then
MKBFB_PARAMS="${MKBFB_PARAMS} \
--ramdisk ${TARGET_DIR}/${NIC_FW_GI##*/}"
fi
if [ -f "${TARGET_DIR}/${PROFILE##*/}" ]; then
MKBFB_PARAMS="${MKBFB_PARAMS} \
--cfg-gi ${TARGET_DIR}/${PROFILE##*/}"
fi
$MLX_MKBFB \
${MKBFB_PARAMS} \
./${BASE_BFB} \
${TARGET_DIR}/${target_bfb}
}
handle_opn()
{
OPN=$1
PSID=$2
NIC_FW_VERSION=$3
mlxfwmanager=$4
case $mlxfwmanager in
*41692*)
device=BlueField-3
;;
*41686*)
device=BlueField-2
;;
esac
cd $INITRAMFS_WDIR
echo "Extracting NIC Firmware Binary for PSID ${PSID} OPN ${OPN}..."
if ! (chroot $INITRAMFS_WDIR /$fwmanager --psid ${PSID} --extract --extract-file /tmp/fw-${device}-rel-${NIC_FW_VERSION//\./_}-${OPN}.bin > /dev/null 2>&1); then
echo "ERROR: Failed to extract NIC Firmware binary"
exit 1
fi
BMC_FW=
BMC_FW_VERSION=
CEC_FW=
CEC_FW_VERSION=
DPU_GI=
NIC_FW_GI=
PROFILE=
PROFILE_VERSION=
if [ "$device" == "BlueField-2" ]; then
BFREV="BF2"
BMC_FW="./usr/lib/firmware/mellanox/bmc/bf2-bmc-fw.tar"
BMC_FW_VERSION=$(cat ./usr/lib/firmware/mellanox/bmc/bf2-bmc-fw.version 2> /dev/null)
CEC_FW="./usr/lib/firmware/mellanox/cec/bf2-cec-fw.bin"
CEC_FW_VERSION=$(cat ./usr/lib/firmware/mellanox/cec/bf2-cec-fw.version 2> /dev/null)
elif [ "$device" == "BlueField-3" ]; then
BFREV="BF3"
BMC_FW="./usr/lib/firmware/mellanox/bmc/bf3-bmc-fw.fwpkg"
BMC_FW_VERSION=$(cat ./usr/lib/firmware/mellanox/bmc/bf3-bmc-fw.version 2> /dev/null)
CEC_FW="./usr/lib/firmware/mellanox/cec/bf3-cec-fw.fwpkg"
CEC_FW_VERSION=$(cat ./usr/lib/firmware/mellanox/cec/bf3-cec-fw.version 2> /dev/null)
if [ -e ./usr/lib/firmware/mellanox/bmc/bf3-bmc-preboot-install.pldm ]; then
DPU_GI="./usr/lib/firmware/mellanox/bmc/bf3-bmc-preboot-install.pldm"
elif [ -e ./usr/lib/firmware/mellanox/bmc/bf3-bmc-preboot-install.bfb ]; then
DPU_GI="./usr/lib/firmware/mellanox/bmc/bf3-bmc-preboot-install.bfb"
fi
DPU_GI_VERSION=$(cat ./usr/lib/firmware/mellanox/bmc/bf3-bmc-preboot-install.version 2> /dev/null)
if [ -e "$(/bin/ls -1 ./usr/lib/firmware/mellanox/bmc/fw-BlueField-3-rel-*-${OPN}-*.pldm 2> /dev/null)" ]; then
NIC_FW_GI="$(/bin/ls -1 ./usr/lib/firmware/mellanox/bmc/fw-BlueField-3-rel-*-${OPN}-*.pldm 2> /dev/null)"
elif [ -e "$(/bin/ls -1 ./usr/lib/firmware/mellanox/bmc/fw-BlueField-3-rel-*-${OPN}-*.bfb 2> /dev/null)" ]; then
NIC_FW_GI="$(/bin/ls -1 ./usr/lib/firmware/mellanox/bmc/fw-BlueField-3-rel-*-${OPN}-*.bfb 2> /dev/null)"
fi
NIC_FW_GI_VERSION=$(echo $NIC_FW_GI | grep -oP '(?<=BlueField-3-rel-)\d+_\d+_\d+')
fi
if [ -n "$profile" ]; then
if [ ! -e "$profile" ]; then
echo "ERROR: Profile not found: $profile"
exit 1
fi
if [[ "$profile" =~ "pldm" ]]; then
PROFILE_VERSION=$(echo $profile | grep -oP '(?<=config-image-)[0-9.-]+(?=\.pldm)')
PROFILE="./usr/lib/firmware/mellanox/bmc/config-image.pldm"
elif [[ "$profile" =~ "bfb" ]]; then
PROFILE_VERSION=$(echo $profile | grep -oP '(?<=config-image-)[0-9.-]+(?=\.bfb)')
PROFILE="./usr/lib/firmware/mellanox/bmc/config-image.bfb"
fi
cp $profile $PROFILE
else
if [ -e ./usr/lib/firmware/mellanox/bmc/config-image.pldm ]; then
PROFILE="./usr/lib/firmware/mellanox/bmc/config-image.pldm"
elif [ -e ./usr/lib/firmware/mellanox/bmc/config-image.bfb ]; then
PROFILE="./usr/lib/firmware/mellanox/bmc/config-image.bfb"
fi
if [ -n "$PROFILE" ]; then
PROFILE_VERSION=$(cat ./usr/lib/firmware/mellanox/bmc/config-image.version 2> /dev/null)
profile="${TARGET_DIR}/${PROFILE##*/}"
fi
fi
PROFILE_NAME="${BFREV}_PROFILE"
NIC_FW="${INITRAMFS_WDIR}/tmp/fw-${device}-rel-${NIC_FW_VERSION//\./_}-${OPN}.bin"
if [ ! -e "${NIC_FW}" ]; then
echo "ERROR: Failed to extract NIC FW for OPN ${OPN}"
exit 1
fi
rm -f ${INITRAMFS_REPKG_DIR}/opt/mellanox/mlnx-fw-updater/firmware/mlxfwmanager*
# Create mlxfwmanager with single FW binary
cp $NIC_FW ${INITRAMFS_REPKG_DIR}/opt/mellanox/mlnx-fw-updater/firmware/
sed -i -e "s@ 2> /dev/null@@" ${INITRAMFS_REPKG_DIR}/usr/bin/mlx_fwsfx_gen
chroot ${INITRAMFS_REPKG_DIR} /usr/bin/mlx_fwsfx_gen --source-dir /opt/mellanox/mlnx-fw-updater/firmware/ --out-dir /opt/mellanox/mlnx-fw-updater/firmware/ --sfx-name ${mlxfwmanager##*/} > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "ERROR: Failed to build mlxfwmanager for ${BOARD_ID}"
exit 1
else
rm -f ${INITRAMFS_REPKG_DIR}/opt/mellanox/mlnx-fw-updater/firmware/*bin
rm -f ${INITRAMFS_REPKG_DIR}/opt/mellanox/mlnx-fw-updater/firmware/*log
fi
MLXFWMANAGER=$(ls -1 ${INITRAMFS_REPKG_DIR}/opt/mellanox/mlnx-fw-updater/firmware/mlxfwmanager*)
TARGET_DIR="$OUTPUT_DIR/${bfb_name}/${OPN}"
if [ $BUILD_ALL -eq 0 ]; then
TARGET_DIR="$OUTPUT_DIR/${bfb_name}/${BOARD_ID}"
fi
mkdir -p "$TARGET_DIR"
cp \
$BSP_CAPSULE \
$BMC_FW \
$CEC_FW \
$NIC_FW \
$DPU_GI \
$NIC_FW_GI \
$MLXFWMANAGER \
$PROFILE \
${TARGET_DIR}
if [ $? -ne 0 ]; then
echo "ERROR: Failed to copy FW binaries to the target dir"
exit 1
fi
if [ $REPACK -eq 1 ]; then
if [ -n "$OUTPUT_BFB" ]; then
target_bfb=${OUTPUT_BFB}
else
target_bfb=${bfb##*/}
if [ "$OUTPUT_FORMAT" == "bundle" ]; then
target_bfb=${target_bfb/.bfb/-${OPN}.bfb}
else
target_bfb=${target_bfb/.bfb/-${OPN}.flat.bfb}
fi
fi
create_info
if [ "$OUTPUT_FORMAT" == "bundle" ]; then
rebuild_bfb_bundle
else
rebuild_bfb_flat
fi
fi
}
if [ $REPACK -eq 1 ]; then
if [ "$OUTPUT_FORMAT" == "bundle" ]; then
cleanup_base_initramfs
fi
fi
total_ids=0
mlxfwmanager_num=0
cd $INITRAMFS_WDIR
for fwmanager in $(ls -1r ./opt/mellanox/mlnx-fw-updater/firmware/mlxfwmanager*)
do
let mlxfwmanager_num++
while read line
do
set -- $(echo $line)
OPN=$1
PSID=$2
NIC_FW_VERSION=$3
if [ -z "$OPN" ]; then
if [ $verbose -eq 1 ]; then
echo "No data found for ${ID_SET}: ${BOARD_ID} in $fwmanager"
fi
continue
fi
echo "Found PSID $PSID OPN $OPN FW version $NIC_FW_VERSION in $fwmanager"
handle_opn ${OPN} ${PSID} ${NIC_FW_VERSION} $fwmanager
let total_ids++
done <<< $(chroot $INITRAMFS_WDIR /$fwmanager --list 2>&1 | grep -w $BOARD_ID | awk '{print $1, $2, $4}')
if [[ $total_ids -gt 0 && $BUILD_ALL -eq 0 ]]; then
break
fi
done
if [ $mlxfwmanager_num -eq 0 ]; then
echo "ERROR: No mlxfwmanager files found"
exit 1
fi
if [ $total_ids -eq 0 ]; then
echo "ERROR: NIC FW was not found for ${ID_SET}: ${BOARD_ID}"
exit 1
fi
if [ $REPACK -eq 1 ]; then
echo "BFB: ${TARGET_DIR}/$target_bfb"
else
if [ $BUILD_ALL -eq 0 ]; then
echo "See the result under ${TARGET_DIR}"
else
echo "See the result under $(readlink -f ${TARGET_DIR}/..)"
fi
du -ach $(find ${TARGET_DIR})
fi
exit 0
Mellanox-rshim-user-space-0339e66/scripts/mlx-mkbfb 0000775 0001750 0001750 00000076354 15101274612 020367 0 ustar tai tai #!/usr/bin/env python3
#
# Copyright 2017-2019 Mellanox Technologies. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of Mellanox nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
"""
Create or dump a BlueField boot stream.
"""
import binascii
import functools
import operator
import os
from io import StringIO
import struct
import sys
from optparse import OptionParser, OptionGroup
# Table of all possible image types. Order is significant, since we
# will emit images in this order unless overridden by the --expert
# switch. ATF image IDs match those used internally by ATF; see
# atf/include/common/tbbr/tbbr_img_def.h. UEFI image IDs are defined by
# us; see edk2/MlxPlatformPkg/Filesystem/BfbFs/BfbFs.c.
#
# Contents: (command-line option, description, image ID for header)
image_list = (
# Images for ATF
("psc-bl", "PSC bootloader image", 36),
("psc-fw", "PSC framework image", 37),
("bl2r-cert", "RIoT Core (BL2R) content certificate", 31),
("bl2r", "RIoT Core (BL2R) bin", 30),
("bl2r-auth-cert", "BL2R AUTHCERT DER-encoded certificate", 42),
("bl2-cert", "Trusted Boot Firmware BL2 certificate", 6),
("bl2", "Trusted Boot Firmware BL2 bin", 1),
("sys", "Running system's part number or PSID", 29),
("bl2-auth-cert", "BL2 AUTHCERT DER-encoded certificate", 43),
("ddr-cert", "DDR Images Content Certificate", 38),
("ddr_ini", "File From Which Will Load DDR (pseudo spd) Parameters", 32),
("snps_images", "Combined SNPS Images for all DIMM types", 33),
("ddr5_snps_images", "DDR5 Combined SNPS Images for all DIMM types", 40),
("ddr_ate_imem", "Analog Test Engine INSTRUCTIONS", 34),
("ddr_ate_dmem", "Analog Test Engine DATA", 35),
("bl30-key-cert", "SCP Firmware BL3-0 key certificate", 8),
("bl30-cert", "SCP Firmware BL3-0 certificate", 12),
("bl30", "SCP Firmware BL3-0", 2),
("psc-app", "PSC application image", 39),
("psc-certs", "PSC attestation certificates", 53),
("trusted-key-cert", "Trusted key certificate", 7),
("bl31-key-cert", "EL3 Runtime Firmware BL3-1 key certificate", 9),
("bl31-cert", "EL3 Runtime Firmware BL3-1 content certificate", 13),
("bl31", "EL3 Runtime Firmware BL3-1 bin", 3),
("bl32-key-cert", "Secure Payload BL3-2 (Trusted OS) key certificate", 10),
("bl32-cert", "Secure Payload BL3-2 (Trusted OS) content certificate", 14),
("bl32", "Secure Payload BL3-2 (Trusted OS) bin", 4),
("bl33-key-cert", "Non-Trusted Firmware BL3-3 key certificate", 11),
("bl33-cert", "Non-Trusted Firmware BL3-3 content certificate", 15),
("bl33", "Non-Trusted Firmware BL3-3 bin", 5),
# Images for UEFI
("capsule", "UEFI capsule image", 52),
("boot-acpi", "Name of the ACPI table", 55),
("boot-dtb", "Name of the dtb file", 56),
("boot-desc", "Default boot menu item description", 57),
("boot-path", "Boot image path", 58),
("boot-args", "Arguments for boot image", 59),
("boot-timeout", "Boot menu timeout", 60),
("uefi-tests", "Specify what UEFI tests to run", 61),
("nicfw", "NIC Firmware image", 41),
("ramdisk", "RAM Disk image", 54),
("dpu-gi", "DPU golden image", 49),
("cfg-gi", "Config golden image", 48),
("info", "BFB versioning information", 50),
("image", "Boot image", 62),
("initramfs", "In-memory filesystem", 63),
("upgrade-image", "Runtime upgrade image", 51),
)
# Map command-line option to (description, image ID)
image_table = dict([(x, (y, z)) for (x, y, z) in image_list])
# Map image ID to (command-line option, description)
rev_image_table = dict([(z, (x, y)) for (x, y, z) in image_list])
# Did we see the -v option?
verbose = False
# Maximum allowed image version number (inclusive)
MAX_VER = 2
MAJOR_VER = 1
MINOR_VER = 2
#
# We pad images out to an even multiple of 8 bytes.
#
def num_padding_bytes(length):
"""Return the number of padding bytes needed for the given length."""
return ((length + 7) & ~7) - length
class NoHdr(Exception):
"""
Exception raised when we try to create an ImageHdr from a stream at
end-of-file.
"""
pass
class BadHdr(Exception):
"""
Exception raised when we try to create an ImageHdr from a stream
which contains a bad image header.
"""
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class FormatError(Exception):
"""
Exception raised when we encounter a format error in the boot stream.
"""
pass
class CRCMismatch(Exception):
"""
Exception raised when the CRC of an image does not match the CRC
stored in the image header.
"""
pass
#
# Currently we produce/consume a little-endian boot stream. If we
# ever need to change that, you'll need to modify the code below that
# packs/unpacks the header, and possibly the code that handles padding
# bytes at the end of images.
#
class ImageHdr:
"""Represent a BlueField boot stream image header."""
magic = 0x13026642 # Magic number, "Bf^B^S"
default_major = MAJOR_VER # Major version number
default_minor = MINOR_VER # Minor version number
length = 24 # Header length; must be multiple of 8
def __init__(self, infile=None, major=default_major, minor=default_minor,
image_id=0, image_len=0, image_crc=0, following_images=0,
next_img_ver=0, cur_img_ver=0):
if infile:
self.__set_from_file(infile)
else:
self.major = major
self.minor = minor
self.image_id = image_id
self.next_img_ver = next_img_ver
self.cur_img_ver = cur_img_ver
self.image_len = image_len
self.image_crc = image_crc
self.following_images = following_images
def get_header_length(self):
"""Return length of header in bytes."""
#
# Right now this is constant; if later versions increase the header
# size, or include optional fields, this might vary based on the
# specific contents of this header.
#
return length
def get_image_id(self):
"""Return the image's ID."""
return self.image_id
def get_image_length(self):
"""
Return the image's length in bytes. Note that the image following
this header in the boot stream will be padded with the minimum
necessary number of trailing zeroes to make it an even multiple
of 8 bytes long; this padding is not included in the length value.
"""
return self.image_len
def get_image_ver(self):
"""Return the image version of the current image."""
return self.cur_img_ver
def set_next_image_ver(self, version):
"""Set the image version of the next image following this image"""
self.next_img_ver = version
def get_image_crc(self):
"""
Return the image's CRC. Note that this covers both the bytes of
the image, and any added padding bytes.
"""
return self.image_crc
def get_following_images(self):
"""Return bitmap of IDs of subsequent images."""
return self.following_images
def set_following_images(self, follow_map):
"""Set bitmap of IDs of subsequent images."""
self.following_images = follow_map
def get_bits(self):
"""Return a string containing the header."""
w0 = (((self.magic & 0xFFFFFFFF) << 0) |
((self.major & 0xF) << 32) |
((self.minor & 0xF) << 36) |
((self.next_img_ver & 0xF) << 44) |
((self.cur_img_ver & 0xF) << 48) |
(((self.length // 8) & 0xF) << 52) |
((self.image_id & 0xFF) << 56))
w1 = (((self.image_len & 0xFFFFFFFF) << 0) |
((self.image_crc & 0xFFFFFFFF) << 32))
w2 = self.following_images
return struct.pack("> 32) & 0xF
self.minor = (w0 >> 36) & 0xF
length = (w0 >> 52) & 0xF
self.image_id = (w0 >> 56) & 0xFF
self.image_len = w1 & 0xFFFFFFFF
self.image_crc = (w1 >> 32) & 0xFFFFFFFF
self.following_images = w2
# The next/cur image version fields were only added in minor 2
if self.minor <= 2:
self.next_img_ver = (w0 >> 44) & 0xF
self.cur_img_ver = (w0 >> 48) & 0xF
else:
self.next_img_ver = 0
self.cur_img_ver = 0
if magic != self.magic:
raise BadHdr("Bad ImageHdr magic number 0x%x" % magic)
#
# Obviously the stuff below will change once we support more than
# one version.
#
if self.major != self.default_major:
raise BadHdr("Bad ImageHdr major version %d" % self.major)
if self.minor > self.default_minor:
raise BadHdr("Bad ImageHdr minor version %d" % self.major)
if length != self.length / 8:
raise BadHdr("Bad ImageHdr header length %d" % length)
def dump(self, outfile=sys.stdout):
"""Dump out all internal state."""
outtext = "Ver: %d.%d Len: %d ID: %d " \
"ImLen: %d ImCRC: 0x%x FolIm: 0x%lx" % (
self.major, self.minor, self.length,
self.image_id, self.image_len,
self.image_crc, self.following_images)
if self.minor >= 2:
outtext += " NxImVr: %d ImVr: %d" % (
self.next_img_ver, self.cur_img_ver)
print(outtext, file=outfile)
class Image:
"""Represent a BlueField boot stream image."""
def __init__(self, instream=None, infile=None, idstr=None):
"""
Create an Image object.
instream: File object from which to read the next header and image
data. There may be additional headers, images, or other random
data following that, which will not be consumed.
infile: Name of file from which to read image data. Unlike when
instream is specified, the file does not contain a header, and
the entire file is consumed; a header will be constructed which
describes the data we read. Mutually exclusive with instream.
idstr: String ID (first column of image_list) for image. Required,
and only useful, with infile. Can be suffixed with '-vN' to also
indicate image version number.
"""
if instream:
self.__set_from_stream(instream)
elif infile:
self.__set_from_file(infile, idstr)
else:
self.header = ImageHdr()
self.bits = None
def get_bits(self):
"""Return image data."""
return self.bits
def get_padding(self):
"""Return pad bytes."""
length = self.header.get_image_length()
return b'\0' * num_padding_bytes(length)
def get_image_id(self):
"""Return the numeric image ID for this image."""
return self.header.get_image_id()
def get_image_ver(self):
"""Return the current image ID for this image."""
return self.header.get_image_ver()
def set_next_image_ver(self, next_img_ver):
"""Set the image version of the next image following this image"""
self.header.set_next_image_ver(next_img_ver)
def get_image_length(self):
"""Return the image's length in bytes."""
return self.header.get_image_length()
def set_following_images(self, follow_map):
"""Set the bitmap of images following this one."""
self.header.set_following_images(follow_map)
def write(self, outfile):
"""Write image contents to an output stream."""
outfile.write(self.header.get_bits())
outfile.write(self.bits)
outfile.write(self.get_padding())
def dump(self, outfile=sys.stdout):
self.header.dump(outfile)
def __set_from_stream(self, instream):
"""
Initialize ourselves from the given stream, which contains a header
and then image data; only the data described by the header will be
consumed, so you can call this repeatedly on a stream to pick off
all of the images it contains.
instream: stream to read.
"""
self.header = ImageHdr(infile=instream)
length = self.header.get_image_length()
self.bits = instream.read(length)
if len(self.bits) != length:
raise FormatError("Image ID %d: stream corrupted, image too short" %
self.header.get_image_id())
crc = binascii.crc32(self.bits, 0)
padding = instream.read(num_padding_bytes(length))
crc = binascii.crc32(padding, crc)
crc &= 0xFFFFFFFF
if crc != self.header.get_image_crc():
raise CRCMismatch("Image ID %d: header CRC of 0x%08x does "
"not match calculated CRC of 0x%08x" %
(self.header.get_image_id(),
self.header.get_image_crc(), crc))
def __set_from_file(self, infile, idstr):
"""
Initialize ourselves from the given filename/string. The entire
file or string makes up the image, and we then construct a header
which describes that image data.
stream: file name, or string preceded by "=".
idstr: string ID of image. Can be suffixed with '-vN' to also indicate
image version number.
"""
if infile.startswith("="):
self.bits = bytes(infile[1:], 'utf-8')
else:
with open(infile, "rb") as f:
self.bits = f.read()
length = len(self.bits)
crc = binascii.crc32(self.bits, 0)
crc = binascii.crc32(b'\0' * num_padding_bytes(length), crc)
crc &= 0xFFFFFFFF
# Check if idstr is suffixed with '-vN', while NOT assuming that
# image names can't contain '-v' in its name.
img_ver = 0
if '-' in idstr:
(img, ver) = idstr.rsplit('-', 1)
if len(ver) > 1 and ver[0] == 'v' and ver[1:].isdigit():
if img in image_table:
idstr = img
img_ver = int(ver[1:])
self.header = ImageHdr(image_id=image_table[idstr][1],
image_len=length, image_crc=crc,
cur_img_ver=img_ver)
def make_stream(infnt, outfn, image_tuples, expert):
"""
Write a boot stream to an output file.
infnt: tuple of input file names, files with bigger index takes priority
outfn: output file name.
image_tuples: an iterable containing tuples, each of which contains the
string image identifier (the first column of image_list) and the filename
(or literal string) from the command line.
"""
#
# We'll construct the following_images bitmap while reading in the
# images, and then will reduce it with every output image.
#
fim_map = 0
#
# If there's an input file, open it, and read in its contents.
#
infile_images = {}
for infn in infnt:
infile = open(infn, "rb")
while True:
try:
img = Image(instream=infile)
except NoHdr:
break
id = rev_image_table[img.get_image_id()][0]
if id not in infile_images:
infile_images[id] = {}
infile_images[id][img.get_image_ver()] = img
fim_map |= 1 << img.get_image_id()
infile.close()
#
# If there are files from the command line, open them and read in
# their contents.
#
cmdline_images = {}
# The idver from the command line might have the -vN suffix, so we need
# to generate one without the suffix to be used for expert mode
cmdline_image_order = []
for (idver, fn) in image_tuples:
img = Image(infile=fn, idstr=idver)
id = rev_image_table[img.get_image_id()][0]
if id not in cmdline_images:
cmdline_images[id] = {}
cmdline_images[id][img.get_image_ver()] = img
if id not in cmdline_image_order:
cmdline_image_order.append(id)
fim_map |= 1 << img.get_image_id()
#
# In expert mode, we emit images in the order we found them on the command
# line, but otherwise, we use the order they're found in image_list.
#
if expert:
image_order = cmdline_image_order
else:
image_order = [x[0] for x in image_list]
outfile = open(outfn, "wb")
#
# Emit each image in order, preferring the version from the command line.
#
for i in image_order:
images = {}
# Note the order here will let the images from the cmdline override
# images of the same version read from the file.
if i in infile_images:
images.update(infile_images[i])
if i in cmdline_images:
images.update(cmdline_images[i])
if len(images) == 0:
continue
# Version order is strictly enforced here, even in expert mode.
images = [images[x] for x in sorted(images.keys())]
while len(images) > 0:
img = images.pop(0)
if len(images) == 0:
fim_map &= ~(1 << img.get_image_id())
img.set_next_image_ver(0)
else:
img.set_next_image_ver(images[0].get_image_ver())
img.set_following_images(fim_map)
# The image might be loaded from a previous bfb of a lower version
# so make sure the generated bfb file have the current version.
img.header.minor = MAJOR_VER
img.header.minor = MINOR_VER
img.write(outfile)
outfile.close()
def dump_stream(infn, do_dump, do_extract, prefix, images):
"""
Dump a description of a boot stream.
infn: input filename.
do_dump: if true, print table of contents.
do_extract: if true, extract images to files.
prefix: prefix to use with extracted image filenames.
"""
inf = open(infn, "rb")
inf.seek(0, os.SEEK_END)
file_len = inf.tell()
if file_len < ImageHdr.length:
raise FormatError("BFB too short")
inf.seek(0, os.SEEK_SET)
count=0
while True:
try:
img = Image(instream=inf)
except NoHdr:
break
id = img.get_image_id()
if id in rev_image_table:
fn = rev_image_table[id][0]
desc = rev_image_table[id][1]
else:
fn = "image_id_%d" % id
desc = "Unknown image type, ID %d" % id
if img.header.minor >= 2:
fn += "-v%d" % img.get_image_ver()
desc += " (version %d)" % img.get_image_ver()
if do_dump:
if verbose:
img.dump()
else:
print("%10d %s" % (img.get_image_length(), desc))
if do_extract:
if not images or fn in images.split():
xfile = open(prefix + fn, "wb")
xfile.write(img.get_bits())
xfile.close()
if fn in images.split():
count = count + 1
if len(images.split()) == count:
break
inf.close()
# Fix the headers in a list of images so their
# following image bitmap and next version fields are
# correct. Does not enforce any image order.
def fix_image_headers(imgs):
# Figure out the last image of a particular ID
# that appears in the stream. This is repesented by
# the version number, allowing the image to be
# identified by a (ID, Version) pair.
last_images = {}
# In addition, we construct the initial image bitmap here.
fi_map = 0
for img in imgs:
last_images[img.get_image_id()] = img.get_image_ver()
fi_map |= 1 << img.get_image_id()
# Convert to set so we can lookup pairs
last_images = set(last_images.items())
for i, img in enumerate(imgs):
if (img.get_image_id(), img.get_image_ver()) in last_images:
fi_map &= ~(1 << img.get_image_id())
img.set_following_images(fi_map)
# Only following images and next image ver fields
# need to be changed
if i == len(imgs) - 1:
img.set_next_image_ver(0)
else:
img.set_next_image_ver(imgs[i+1].get_image_ver())
img.header.major = MAJOR_VER
img.header.minor = MINOR_VER
FILTER_KEEP = 0
FILTER_STRIP = 1
# Filter a bootstream based on a hardware version.
# On FILTER_KEEP, this function will remove:
# - Images that have a higher version than the one specified.
# - Images that will not execute (such as BF1 images on BF2).
#
# On FILTER_STRIP, this function will remove:
# - Only images that match the strip_ver.
#
# By default this function is "careful". It will attempt to preserve
# at least one image for each given ID, as long as it's compatible with
# the version we're targetting.
def filter_bootstream(
infn,
outfn,
version, # target hw version
filter_type,
strip_ver=None,
careful=True
):
imgs = []
if filter_type == FILTER_STRIP and strip_ver is None:
raise Exception("internal: must specify strip_ver with FILTER_STRIP")
with open(infn, 'rb') as inf:
while True:
try:
inimg = Image(instream=inf)
imgs.append(inimg)
except NoHdr:
break
# Iterate through images and work out what to drop.
# This is a map, ID -> list of versions.
to_drop = {}
# Also keep track of the highest compatible version of image in
# the stream. This is used for careful mode later.
highest_compatible_ver = {}
for img in imgs:
id = img.get_image_id()
ver = img.get_image_ver()
if id not in to_drop:
to_drop[id] = []
# If this ver is "compatible", keep track.
if ver <= version:
highest_compatible_ver[id] = max(
highest_compatible_ver.get(id, 0),
ver
)
if filter_type == FILTER_KEEP:
# Drop everything but specified version
if ver != version:
to_drop[id].append(ver)
elif filter_type == FILTER_STRIP:
# Drop only the version specified
if ver == strip_ver:
to_drop[id].append(ver)
else:
raise Exception("internal: bad filter_type %d" % filter_type)
if careful:
# If we're being careful, don't drop the highest-versioned image
# that is less than or equal to the filter version. This will
# preserve common images, and ensure that there's a (likely)
# compatible image for every ID in the original stream.
for id, ver in highest_compatible_ver.items():
# Remove drop instruction for compat ver
to_drop[id] = [v for v in to_drop[id] if v != ver]
# Filter images.
imgs = [
img for img in imgs
if not img.get_image_ver() in to_drop[img.get_image_id()]
]
# Fix headers and write out.
fix_image_headers(imgs)
with open(outfn, 'wb') as outf:
for img in imgs:
img.write(outf)
def parse_image_opt(option, opt_str, value, parser):
"""Handle one of the -- options."""
parser.values.images.append((opt_str.lstrip("-"), value))
def main(argv):
#
# Set up our option parser.
#
parser = OptionParser(
usage="\n %prog [ options ] [ INFILE ] [ INFILE2 ] OUTFILE\n"
" %prog -[dxc] [ options ] INFILE\n"
" %prog [ -h | --help ]",
description="%prog creates or dumps a BlueField boot stream.")
parser.add_option(
"-d", "--dump", dest="d", action="store_true",
help="print listing of images within INFILE")
parser.add_option(
"-x", "--extract", dest="x", action="store_true",
help="extract images from INFILE and write to files")
parser.add_option(
"-c", "--check", dest="c", action="store_true",
help="check integrity for images within INFILE")
parser.add_option(
"-n", "--image-name", dest="n", action="store", type="string",
metavar="INM", default="",
help="a string with image names (separated by space) to extract, (used with -x option); ")
parser.add_option(
"-p", "--prefix", dest="p", action="store", type="string",
metavar="PFX", default="dump-",
help="prefix for files containing extracted images; "
"default is '%default'")
parser.add_option(
"-v", "--verbose", dest="v", action="store_true",
help="provide more verbose output")
parser.add_option(
"-e", "--expert", dest="e", action="store_true",
help="expert mode: emit images in order specified on command line")
parser.add_option(
"-f", "--filter", dest="f", action="store", type="int",
metavar="VERSION", default=None,
help="filter away unneeded image versions, targetting the given version")
parser.add_option(
"-s", "--strip", dest="s", action="store", type="int",
metavar="VERSION", default=None,
help="modifies -f, so it only removes a certain version rather than as much as possible")
parser.add_option(
"--no-careful", dest="no_careful", action="store_true",
help=("modifies -f, so it will not attempt to preserve "
"at least one compatible image, instead removing as much "
"as is allowed by the filter"))
parser.set_defaults(images=[])
iog = OptionGroup(parser, "Image Options",
'Images specified on the command line replace images '
'of the same type within the input file. Note: an '
'image specification may either be the name of a file '
'which contains the image data (e.g., --image=vmlinux), '
'or a literal string prefixed with an equals sign '
'(e.g., --boot-args="=debug isolcpus=10").'
'An optional "-vN" can be added to the image name to '
'specify which version the image is, default to 0.')
for fn in image_table:
iog.add_option(
"--" + fn, type="string",
action="callback", callback=parse_image_opt, metavar="IMAGE",
help="take data for " + image_table[fn][0] + " from IMAGE")
# Also add the options with the "-vN" prefix in the image option
for v in range(MAX_VER + 1):
iog.add_option(
"--" + fn + "-v%d" % v, type="string", action="callback",
callback=parse_image_opt, metavar="IMAGE")
parser.add_option_group(iog)
#
# Parse the command line and execute.
#
(opt, args) = parser.parse_args()
if opt.v:
global verbose
verbose = True
if (opt.d or opt.x or opt.c) and len(args) > 1:
parser.error("no output file allowed with -d/-x")
if len(args) > 3:
parser.error("only two input and one output file allowed")
if opt.d or opt.x or opt.f or opt.c:
if opt.e:
parser.error("-e not applicable with -d/-x/-s/-c")
if opt.images:
parser.error("cannot specify images with -d/-x/-s/-c")
if opt.d or opt.x or opt.c:
try:
dump_stream(args[0], opt.d, opt.x, opt.p, opt.n)
except (NoHdr, BadHdr, FormatError, CRCMismatch) as e:
if opt.c:
print("BFB check failed (%s): %s" %
(e.__class__.__name__, e), file=sys.stderr)
sys.exit(1)
else:
raise
elif opt.f is not None:
if len(args) != 2:
parser.error("--filter/-f: must specify exactly one input file and "
"one output file")
infn = args[0]
outfn = args[1]
careful = not opt.no_careful
if opt.s is not None:
filter_bootstream(
infn,
outfn,
opt.f,
FILTER_STRIP,
strip_ver=opt.s,
careful=careful
)
else:
filter_bootstream(
infn,
outfn,
opt.f,
FILTER_KEEP,
careful=careful
)
else:
if len(args) <= 0:
parser.error("must specify a file")
elif len(args) == 1:
infn = ()
outfn = args[0]
if not opt.images:
parser.error("must specify input .bfb or at least one image "
"option with output file")
elif len(args) == 2:
infn = (args[0],)
outfn = args[1]
if opt.e:
parser.error("input file not permitted with -e")
else:
infn = (args[0], args[1])
outfn = args[2]
if opt.e:
parser.error("input file not permitted with -e")
make_stream(infn, outfn, opt.images, opt.e)
if __name__ == "__main__":
try:
main(sys.argv)
except KeyboardInterrupt:
print("Aborted (Ctrl+C)")
sys.exit(1)
Mellanox-rshim-user-space-0339e66/scripts/rshim-fix.te 0000664 0001750 0001750 00000003003 15101274612 020777 0 ustar tai tai #
# This policy is a temporary fix for the default SELinux "rshim" policy that
# comes with RHEL 9.5. It's be overlaid on top of the default "rshim" policy
# as part of rshim rpm installtion on RHEL 9.5 only.
#
# For future RHEL versions (9.6 or later), it's intended to merge the policy
# here to the official Fedora SELinux rshim policy.
#
module rshim-fix 1.0;
require {
type kernel_t;
type rshim_t;
type sysfs_t;
type tty_device_t;
type tun_tap_device_t;
type userio_device_t;
type var_run_t;
class capability { ipc_lock sys_admin net_admin};
class chr_file { open read write ioctl map };
class dir { write remove_name add_name search };
class file { read write open lock ioctl unlink create map };
class system module_request;
class tun_socket create;
class udp_socket { create ioctl };
}
allow rshim_t kernel_t:system module_request;
allow rshim_t rshim_t:tun_socket create;
allow rshim_t self:capability ipc_lock;
allow rshim_t self:capability net_admin;
allow rshim_t self:capability sys_admin;
allow rshim_t self:udp_socket { create ioctl };
allow rshim_t sysfs_t:file map;
allow rshim_t sysfs_t:file { write open map };
allow rshim_t tty_device_t:chr_file { open read write ioctl map };
allow rshim_t tun_tap_device_t:chr_file { open read write ioctl map };
allow rshim_t userio_device_t:chr_file { open read write ioctl map };
allow rshim_t var_run_t:dir { write remove_name add_name search };
allow rshim_t var_run_t:file { read write open lock ioctl unlink create };
Mellanox-rshim-user-space-0339e66/bootstrap.sh 0000775 0001750 0001750 00000000246 15101274612 017432 0 ustar tai tai #!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (C) 2019 Mellanox Technologies. All Rights Reserved.
#
autoreconf -ivf || exit 1
rm -rf autom4te.cache
Mellanox-rshim-user-space-0339e66/rshim.service 0000664 0001750 0001750 00000000533 15101274612 017561 0 ustar tai tai # SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
# Copyright 2019 Mellanox Technologies. All Rights Reserved.
[Unit]
Description=rshim driver for BlueField SoC
Documentation=man:rshim(8)
After=network.target
[Service]
Restart=always
Type=forking
ExecStart=-/usr/sbin/rshim $OPTIONS
KillMode=control-group
[Install]
WantedBy=multi-user.target
Mellanox-rshim-user-space-0339e66/.github/ 0000775 0001750 0001750 00000000000 15101274612 016414 5 ustar tai tai Mellanox-rshim-user-space-0339e66/.github/workflows/ 0000775 0001750 0001750 00000000000 15101274612 020451 5 ustar tai tai Mellanox-rshim-user-space-0339e66/.github/workflows/ci.yml 0000664 0001750 0001750 00000022372 15101274612 021575 0 ustar tai tai ---
#
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
name: CI/CD pipeline for rshim - deb and rpm for amd64 and arm64
on:
push:
branches:
- '**'
tags:
- '*'
permissions:
contents: write
jobs:
build-and-test:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
fetch-tags: true
- name: Create apt-get update retry script
run: |
cat << 'EOF' > retry_apt_update.sh
#!/bin/bash
# Retry apt-get update with exponential backoff and built-in retries
retry_apt_get_update() {
local attempt=0
local max_attempts=5
local delay=10
while (( attempt < max_attempts )); do
echo "Running apt-get update (attempt $((attempt+1))/$max_attempts)..."
if sudo apt-get update -o Acquire::Retries=3; then
return 0
fi
echo "apt-get update failed. Retrying in ${delay}s..."
sleep $delay
delay=$(( delay * 2 ))
attempt=$(( attempt + 1 ))
done
echo "apt-get update failed after $max_attempts attempts."
return 1
}
EOF
chmod +x retry_apt_update.sh
- name: Install dependencies (for .deb)
run: |
. ./retry_apt_update.sh
sudo apt-get update || retry_apt_get_update && \
sudo apt-get install -y \
build-essential debhelper devscripts fakeroot git \
libpci-dev libusb-1.0-0-dev libfuse-dev pkg-config
- name: Prepare release body
id: changelog
run: |
body=$(./scripts/get-changelog debian/changelog)
echo "body<> $GITHUB_OUTPUT
echo "${body}" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create source tarball
run: |
[ -d dist ] || mkdir -p dist
version="$(./scripts/get-ver)"
tarball="rshim-src-${version}.tar.gz"
git archive --format=tar.gz -o "$tarball" HEAD
mv -v "$tarball" dist/
ls -lh dist
- name: Build & Test x86_64 .deb package
run: |
version="$(./scripts/get-ver)"
sed -i "1s/(\(.*\))/($version)/" debian/changelog
DEB_BUILD_OPTIONS="nocheck nostrip nolto" \
CFLAGS="-fno-lto" LDFLAGS="-fno-lto" \
dpkg-buildpackage -us -uc -a amd64
mkdir -p dist
mv -v ../*.deb dist/
ls -lh dist
sudo dpkg -i dist/*.deb || sudo apt-get -f install -y
echo "Running rshim --version:"
rshim --version
- name: Capture UID/GID for Docker
id: uidgid
run: |
echo "HOST_UID=$(id -u)" >> $GITHUB_ENV
echo "HOST_GID=$(id -g)" >> $GITHUB_ENV
- name: Build & Test ARM64 .deb package in Docker
run: |
set -euo pipefail
docker run --rm --privileged multiarch/qemu-user-static \
--reset -p yes
# Retry function for Docker build
retry_count=0
max_retries=3
delay=20
while true; do
echo "Docker build attempt $((retry_count + 1))/$max_retries"
if docker run --rm --platform linux/arm64 \
-e HOST_UID="${{ env.HOST_UID }}" \
-e HOST_GID="${{ env.HOST_GID }}" \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
arm64v8/ubuntu:22.04 \
/bin/bash -c "
set -euo pipefail
. /workspace/retry_apt_update.sh
apt-get update || retry_apt_get_update
apt-get install -y \
autoconf automake libtool build-essential debhelper \
devscripts fakeroot gcc git libpci-dev libusb-1.0-0-dev \
libfuse-dev libsystemd-dev libpci3 libusb-1.0-0 fuse \
pkg-config
git config --global --add safe.directory /workspace && \
version=\$(/workspace/scripts/get-ver)
sed -i \"1s/(\(.*\))/(\$version)/\" /workspace/debian/changelog
mkdir -p /workspace/build
DEB_BUILD_OPTIONS='nocheck nostrip nolto' \
CFLAGS="-fno-lto" LDFLAGS="-fno-lto" \
dpkg-buildpackage -us -uc -a arm64 || {
echo '--- pkg-config failure diagnostics ---'
pkg-config --modversion libpci || true
pkg-config --modversion libusb-1.0 || true
pkg-config --modversion fuse || true
pkg-config --variable=systemdsystemunitdir systemd || true
echo '--- config.log tails ---'
find . -name config.log -exec sh -c \
'echo ==== {}; tail -n 200 {}' \;
exit 1
}
mv -v ../*.deb /workspace/build/ && \
dpkg -i /workspace/build/*.deb || apt-get -f install -y
echo 'Running rshim --version:'
rshim --version
chown -R \$HOST_UID:\$HOST_GID /workspace
"; then
echo "Docker build succeeded on attempt $((retry_count + 1))"
break
else
retry_count=$((retry_count + 1))
if [ $retry_count -lt $max_retries ]; then
echo "Docker build failed, waiting ${delay}s before retry..."
sleep $delay
else
echo "Docker build failed after $max_retries attempts"
exit 1
fi
fi
done
mkdir -p dist
mv -v build/*.deb dist/
ls -lh dist
- name: Build & Test x86_64 RPM using Rocky Linux
run: |
docker run --rm \
-e HOST_UID="${{ env.HOST_UID }}" \
-e HOST_GID="${{ env.HOST_GID }}" \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
quay.io/rockylinux/rockylinux:8 \
/bin/bash -c "
set -euo pipefail
yum -y install gcc make rpm-build git autoconf automake \
libtool pkgconfig pciutils-devel libusb1-devel fuse-devel && \
git config --global --add safe.directory /workspace && \
ARCH=x86_64 CFLAGS="-fno-lto" LDFLAGS="-fno-lto" \
./scripts/build-rpm && \
yum localinstall -y /workspace/rpmbuild/RPMS/x86_64/*.rpm && \
echo 'Running rshim --version:' && \
rshim --version && \
chown -R \$HOST_UID:\$HOST_GID /workspace
"
mkdir -p dist
mv -v $(find rpmbuild/RPMS -name '*.rpm') dist/
ls -lh dist
- name: Build & Test arm64 RPM using Rocky Linux
run: |
set -euo pipefail
# Prepare QEMU for ARM64 emulation
docker run --rm --privileged multiarch/qemu-user-static \
--reset -p yes
# Retry function for Docker build
retry_count=0
max_retries=3
delay=20
while true; do
echo "Docker build attempt $((retry_count + 1))/$max_retries"
if docker run --rm --platform linux/arm64 \
-e HOST_UID="${{ env.HOST_UID }}" \
-e HOST_GID="${{ env.HOST_GID }}" \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
quay.io/rockylinux/rockylinux:8 \
/bin/bash -c "
set -euo pipefail
yum -y install gcc make rpm-build git autoconf automake \
libtool pkgconfig pciutils-devel libusb1-devel fuse-devel && \
git config --global --add safe.directory /workspace && \
ARCH=aarch64 CFLAGS=\"-fno-lto\" LDFLAGS=\"-fno-lto\" \
./scripts/build-rpm && \
yum localinstall -y /workspace/rpmbuild/RPMS/aarch64/*.rpm && \
echo 'Running rshim --version:' && \
rshim --version && \
chown -R \$HOST_UID:\$HOST_GID /workspace
"; then
echo "Docker build succeeded on attempt $((retry_count + 1))"
break
else
retry_count=$((retry_count + 1))
if [ $retry_count -lt $max_retries ]; then
echo "Docker build failed, waiting ${delay}s before retry..."
sleep $delay
else
echo "Docker build failed after $max_retries attempts"
exit 1
fi
fi
done
mkdir -p dist
mv -v $(find rpmbuild/RPMS -name '*.rpm') dist/
ls -lh dist
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: rshim-packages
path: dist/*
- name: Create GitHub Release
if: startsWith(github.ref_name, 'rshim-')
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
body: ${{ steps.changelog.outputs.body }}
draft: false
prerelease: false
files: dist/*
Mellanox-rshim-user-space-0339e66/LICENSE 0000664 0001750 0001750 00000004561 15101274612 016067 0 ustar tai tai Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
This software is available to you under a choice of one of two licenses.
You may choose to be licensed under the terms of the GNU General Public
License (GPL) Version 2, or the BSD 3-Clause license.
BSD 3-Clause License
--------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions, and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
GNU General Public License v2.0 (GPL-2.0)
----------------------------------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Mellanox-rshim-user-space-0339e66/rhel/ 0000775 0001750 0001750 00000000000 15101274612 016006 5 ustar tai tai Mellanox-rshim-user-space-0339e66/rhel/rshim.spec.in 0000664 0001750 0001750 00000042760 15101274612 020422 0 ustar tai tai # SPDX-License-Identifier: GPL-2.0-only
# Copyright (C) 2019 Mellanox Technologies. All Rights Reserved.
#
Name: rshim
Version: @VERSION@
Release: 0%{?dist}
Summary: User-space driver for Mellanox BlueField SoC
License: GPLv2
URL: https://github.com/mellanox/rshim-user-space
Source0: https://github.com/Mellanox/rshim-user-space/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
BuildRequires: gcc, autoconf, automake, make
BuildRequires: pkgconfig(libpci), pkgconfig(libusb-1.0), pkgconfig(fuse)
BuildRequires: systemd
BuildRequires: systemd-rpm-macros
Requires: kmod(cuse.ko)
Suggests: kernel-modules-extra
%description
This is the user-space driver to access the BlueField SoC via the rshim
interface. It provides ways to push boot stream, debug the target or login
via the virtual console or network interface.
%prep
%setup -q -n %{name}-%{version}
%build
./bootstrap.sh
%configure
%make_build
%install
%make_install
%post
%systemd_post rshim.service
%preun
%systemd_preun rshim.service
%postun
%systemd_postun_with_restart rshim.service
%files
%license LICENSE
%doc README.md
%config(noreplace) %{_sysconfdir}/rshim.conf
%{_sbindir}/rshim
%{_sbindir}/mlx-mkbfb
%{_sbindir}/fwpkg_unpack.py
%{_sbindir}/bfb-install
%{_sbindir}/bfb-tool
%{_sbindir}/bf-reg
%{_sbindir}/bf-pldm-ver
%{_mandir}/man1/mlx-mkbfb.1.gz
%{_unitdir}/rshim.service
%{_mandir}/man8/rshim.8.gz
%{_mandir}/man8/bfb-install.8.gz
%{_mandir}/man8/bfb-tool.8.gz
%{_mandir}/man8/bf-reg.8.gz
%{_mandir}/man8/bf-pldm-ver.8.gz
%changelog
* Fri Oct 31 2025 Penghe Geng - 2.5.7
- bfb-install: fix deferred upgrade & BMC credential issue
* Wed Oct 29 2025 Penghe Geng - 2.5.6
- bfb-install: fix deferred upgrade & BMC credential issue
* Wed Oct 22 2025 Liming Sun - 2.5.4
- Some enhancement for the command mode
- Update rshim.spec.in to include additional build requirements
- bfb-install: Fix no proper output for missing rshim device
* Wed Oct 08 2025 Penghe Geng - 2.5.3
- Fix SIGTERM segfault when rshim exits
- bfb-install: add check for bfb file presence
* Wed Sep 24 2025 Penghe Geng - 2.5.2
- No service interrupt for DPU-BMC flow
- Support Golden Images in PLDM format
- Deregister driver when not in use
* Wed Aug 20 2025 Penghe Geng - 2.5.1
- Improve GitHub CI robustness for ARM builds
- Fix rshim drop mode driver binding
- bfb-tool: Added qemu-aarch64-static installation guidance
- bfb-tool: Added workaround for mlx_fwsfx_gen
* Tue Jul 22 2025 Penghe Geng - 2.4.4
- Added support for bf-fwbundle per OPN
- Set is_uek64k flag at build time
- Fix bfdump doesn't return error code in case of success
* Wed Jul 09 2025 Liming Sun - 2.4.3
- bf-pldm-ver: initial version to retrieve image versions from PLDM
- Fix bfdump doesn't return error code
* Fri Jun 06 2025 Penghe Geng - 2.4.2
- Update bfb-tool - support NIC FW replacing
- Reduce CPU usage by polling optimization
* Fri May 30 2025 Liming Sun - 2.4.1
- bfb-tool: Add error for missing version information in BFB files
- bfb-tool: Add command to print versions of components in BFB
- bfb-install: add command syntax for lfwp
- bfb-install: BFB format conversion for runtime upgrade
- bfb-install: Convert to flat BFB for runtime upgrade
- scripts/bfb-tool: Add flat format support for BFB
- Updated mlx-mkbfb
- Disable LTO build option in github CI
- Fix transient pipeline error caused by apt update
- Skip SELinux fix on non-RHEL distros like SLES
* Tue Apr 22 2025 Penghe Geng - 2.3.8
- Fix a potentially unintialized variable
* Wed Apr 16 2025 Liming Sun - 2.3.7
- bfb-install: Reactivate NIC_FW for runtime upgrade
* Thu Apr 03 2025 Liming Sun - 2.3.6
- bfb-install: cleanup the TMP_DIR
* Sat Mar 29 2025 Liming Sun - 2.3.5
- bfb-install: add validation of bfb and rshim options
- Fix the rshim command line for register read/write
* Tue Mar 25 2025 Liming Sun - 2.3.4
- mlx-mkbfb: Improve the performance when extracting a single image
- Reduce CPU utilization by network optimization
* Sat Mar 22 2025 Liming Sun - 2.3.3
- bfb-install: register usage cleanup
- PM pkg: Apply selinux workaround to RHEL 9.5 or later
- mlx-mkbfb/fwpkg_unpack.py: Add graceful handling of ctrl+c
- bfb-install: pack the bf.cfg into the generated BFB
- Fix occasional github pipeline docker error
* Fri Mar 14 2025 Liming Sun - 2.3.2
- bfb-install: Support trimmed NIC_FW
- bfdump support
- Use BREADCRUMB.BIT32 to indicate NIC mode
- Added bfb-tool script
* Thu Mar 06 2025 Liming Sun - 2.3.1
- Enhance command line for register read/write
- Support PCIe device name runtime update
- bfb-install: Enhancement for runtime upgrade
- bfb-install: don't exit script when rshim install fails
- Added fwpkg_unpack.py
* Tue Feb 18 2025 Vladimir Sokolovsky - 2.2.4
- Added mlx-mkbfb
* Fri Jan 10 2025 Liming Sun - 2.2.3
- bfb-install: Handle PF1 bind/unbind in NIC mode
* Fri Jan 03 2025 Penghe Geng - 2.2.2
- Add GitHub pipeline to create deb/rpm packages
- Fix SELinux policy in enforcing mode
* Fri Dec 06 2024 Liming Sun - 2.2.1
- USB: removes the unnecessary POLLOUT polling
- Force to stop if stuck during systemd service stop
* Tue Nov 26 2024 Liming Sun - 2.1.8
- Allow multi rshim processes for dev attachment
- configure: fix fuse errors
* Mon Nov 18 2024 Liming Sun - 2.1.7
- Update default USB timeout
- Update license file to be dual-license
- Add BF_MODE misc output to show DPU or NIC mode
- Fix a compiling warning
- Allow 0 to restore USB_TIMEOUT default value
* Tue Nov 12 2024 Penghe Geng - 2.1.6
- Add USB_TIMEOUT to rshim misc and conf settings
- bfb-install: Add -k/--keep-log option
- bfb-install: exit when pushing bfb error
- Use BOOT_RESET_SKIP command to simulate eMMC boot
* Mon Oct 14 2024 Penghe Geng - 2.1.5
- Revert "Abort rshim rpm installation if no cuse.ko found"
* Thu Oct 10 2024 Penghe Geng - 2.1.4
- Make rshim run in single instance
- Abort rshim rpm installation if no cuse.ko found
- Increase default boot timeout to 300s
- bfb-install: Fix premature bfb-install exit when rebooting BMC
* Tue Sep 10 2024 Penghe Geng - 2.1.3
- Reduce the access_check() wait time
* Fri Aug 30 2024 Liming Sun - 2.1.2
- Improve access_check() to reduce likelihood of race condition
- Revert the 2-second delay
* Thu Aug 15 2024 Liming Sun - 2.1.1
- Add support for command mode
- Fix some coding style issues
- Cleanup rshim debug/syslog messages
* Thu Aug 08 2024 Liming Sun - 2.0.41
- Add a small delay to access the boot file
- Fix a valgrind warning
* Mon Aug 05 2024 Penghe Geng - 2.0.40
- Fix rshim deb package for DOCA build on Ubuntu
* Fri Aug 02 2024 Penghe Geng - 2.0.39
- Fix rshim masking issue on Ubuntu
- bfb-install: Fix NIC_MODE installation for BlueField-2
- pcie: Add VFIO support for BlueField-3
* Fri Jul 26 2024 Penghe Geng - 2.0.38
- Make sending the initial force command a one-time event
- bfb-install: adjust the log file to be per rshim
* Tue Jul 16 2024 Penghe Geng - 2.0.37
- add missing --force in help menu
* Mon Jul 15 2024 Penghe Geng - 2.0.36
- Allow /dev/rshim devfs creation only with --force option enabled
- bfb-install: fix for NIC mode
- bfb-install: Exit with error if running remote bfb-install without
password-less root SSH
- Fix compiling issue for FreeBSD
* Fri Jul 05 2024 Penghe Geng - 2.0.35
- Add ownership transfer feature (primarily via "FORCE_CMD")
- bfb-install: enhancement for NIC mode
* Tue Jun 11 2024 Liming Sun - 2.0.34
- bfb-install: Enable CLEAR_ON_READ
- bfb-install: add cleanup code for runtime update
* Thu Jun 06 2024 Liming Sun - 2.0.33
- misc: add 'CLEAR_ON_READ' command
- bfb-install: add runtime image support
* Tue Jun 04 2024 Liming Sun - 2.0.32
- bf3/pcie_lf: Fix the 4B access via MSN GW
* Fri May 17 2024 Liming Sun - 2.0.31
- bf3/pcie_lf: support register read/write via /dev/rshim0/rshim
- Only poll/check locked mode for PCIe backend
- Remove workaround support for BF2 A0 chip
* Mon May 13 2024 Liming Sun - 2.0.30
- pcie: Adjust default reset delay to 3 seconds
- Avoid polling blocked status during reset
- Disable installation of rshim on host by default
* Tue Apr 30 2024 Liming Sun - 2.0.29
- Some robust fixes for rshim over USB
- Lower log level for register read errors as it's normal during reset
* Thu Apr 25 2024 Penghe Geng - 2.0.28
- Secure NIC Mode: Prevent running simultaneously on both bmc and host
* Fri Apr 12 2024 Penghe Geng - 2.0.27
- bfb-install: Fix incorrect IP address resolution for multi-hop routing
* Fri Apr 12 2024 Liming Sun - 2.0.26
- rshim_pcie: set PCIE bit in scratchpad6
- Revert semantics of --reverse-nc
* Fri Apr 05 2024 Liming Sun - 2.0.25
- Avoid a race of rshim ownership during bfb push
* Thu Apr 04 2024 Liming Sun - 2.0.24
- DROP_MODE: sync-up the Rx FIFO when clearing DROP_MODE
* Tue Apr 02 2024 Liming Sun - 2.0.23
- Add some robust fixes for the DROP_MODE
* Fri Mar 22 2024 Penghe Geng - 2.0.22
- bfb-install: add support for remote rshim update; add speed optimizations
* Tue Mar 19 2024 Penghe Geng - 2.0.21
- rshim_pci: output Secure NIC mode status in misc file
* Fri Feb 16 2024 Liming Sun - 2.0.20
- rshim_pci: adjust delay time for nic_fw reset
- bfb-install: Exit on "Linux up"
* Wed Jan 10 2024 Liming Sun - 2.0.19
- Fix incorrect console message drop
- Allow runtime debug code for DK cards
* Thu Dec 14 2023 Liming Sun - 2.0.18
- Clear scratchpad1 register when setting drop_mode
* Wed Nov 22 2023 Liming Sun - 2.0.17
- bfb-install: Fix duplicate output
* Thu Nov 16 2023 Liming Sun - 2.0.16
- Remove fuse build dependency
* Tue Nov 14 2023 Liming Sun - 2.0.15
- Add BFB completion condition for enhanced NIC mode
* Fri Nov 10 2023 Liming Sun - 2.0.14
- Fix 9f19cfb4a75687ae
* Wed Nov 08 2023 Liming Sun - 2.0.13
- Several robust fixes
- Add fuse3 support
* Mon Oct 23 2023 Liming Sun - 2.0.12
- BF3: Add UPTIME display in seconds
* Tue Sep 26 2023 Liming Sun - 2.0.11
- Remove version 0 support for NIC FW_RESET
- bfb-install: Return failure code
* Mon Sep 18 2023 Liming Sun - 2.0.10
- Fix interrupt handling for NIC FW_RESET
* Sat Jun 17 2023 Liming Sun - 2.0.9
- rshim/usb/bf3: fix timeout logic
* Tue May 16 2023 Liming Sun - 2.0.8
- Fix the fall-back logic of direct-mapping
* Thu Mar 30 2023 Liming Sun - 2.0.7
- Avoid opening /dev/uio multiple times
- Update common files to dual-license
- Adjust rshim reset delay
* Sun Nov 20 2022 Liming Sun - 2.0.6-19
- BF3: Support 4B access for PCIe
* Tue Oct 25 2022 Liming Sun - 2.0.6-18
- pcie: fix initialization issue when setting DROP_MODE in rshim.conf
* Thu Oct 20 2022 Liming Sun - 2.0.6-17
- pcie: Avoid using cached pci_dev
- rshim_fuse: display misc file even when rshim is not accessible
* Thu Oct 06 2022 Liming Sun - 2.0.6-16
- pcie: Support mixed vfio and direct mapping mode
* Thu Sep 29 2022 Liming Sun - 2.0.6-15
- Add dependency of libfuse2 for .deb
- rshim-pcie: add a new bad-access code
- Fix a potential NULL pointer access during USB disconnect
- Adjust default boot timeout to 150s
* Tue Aug 16 2022 Liming Sun - 2.0.6-14
- Avoid potential race when stopping the rshim process
- Add configuration option to enable/disable PCIe VFIO/UIO
- Fix warnings for compiling on 32-bit BMC
- Mustang rshim usb supports for 4B and 8B transactions
* Sun Jul 17 2022 Liming Sun - 2.0.6-13
- BF3: Support 32-bit CR-space access via USB
- Avoid kernel-modules-extra dependency on ctyunos
* Thu Jun 16 2022 Liming Sun - 2.0.6-12
- Optimize the rshim_work_fd
- Detect new USB/rshim hot plugin
* Mon May 16 2022 Liming Sun - 2.0.6-11
- Avoid kernel crash when unbind rshim from uio
* Mon May 02 2022 Liming Sun - 2.0.6-10
- Fix several compiling issues for FreeBSD
* Thu Apr 28 2022 Liming Sun - 2.0.6-9
- Use per-device memory-map mode
* Mon Apr 18 2022 Liming Sun - 2.0.6-8
- Add interrupt polling for direct mmap() mode
- Fix several coverity warnings
* Thu Apr 07 2022 Liming Sun - 2.0.6-7
- Keep intr_fd during rshim_pcie disable/enable
- Mustang: Add support for rshim over pcie and pcie_lf
* Wed Mar 30 2022 Liming Sun - 2.0.6-6
- Clear scratchpad1 to 0 before PCI resources are unmapped
- Fallback to UIO if VFIO failed
* Fri Mar 18 2022 Liming Sun - 2.0.6-5
- PCIe: Add UIO and IRQ support
- PCIe: Remove 32-bit support
* Mon Feb 28 2022 Liming Sun - 2.0.6-4
- VFIO support
- Fix potential race in rshim_work_signal
* Mon Nov 29 2021 Liming Sun - 2.0.6-3
- Adjust the defaul value of usb_reset_delay to 5
- Add a delay after USB probe
- Make the reset delay configurable
* Wed Nov 03 2021 Liming Sun - 2.0.6-2
- bfb-install: Handle new indications for installation completion
- Clean up some un-needed register definition
- Fix MTU of the tmfifo_net0 interface on FreeBSD
- Several fixes to prevent hypervisor crash
- Refine some BF-2 Rev0 workaround condition
* Wed May 12 2021 Liming Sun - 2.0.6-1
- Disable the background timer if no rshim devices
- Setting default path for rshim config file
* Wed Mar 10 2021 Liming Sun - 2.0.5-10
- PCIe hotplug support
- Reduce CPU utilization when there is no rshim device
* Wed Jan 27 2021 Liming Sun - 2.0.5-9
- Fix potential tmfifo data loss
- Add workaround checking for Bluefield-2 REV-0
- Fix network traffic stop issue when Tx buffer full
* Fri Dec 11 2020 Liming Sun - 2.0.5-8
- Don't allow any register access when DROP_MODE is set
- Avoid potential race in rshim_fifo_read
* Wed Dec 09 2020 Liming Sun - 2.0.5-7
- Fix potential dead-lock when calling rshim_access_check
- Ignore rshim access checking when global drop mode is enabled
- Fix some secure boot related issue
* Wed Dec 02 2020 Liming Sun - 2.0.5-6
- Add some default configuration in rshim.conf
- Change the debug level of Rshim byte access widget timeout
- Add bfb-install script
* Thu Oct 29 2020 Liming Sun - 2.0.5-5
- Check rshim accessibility when re-enabling it
- Enable console output during boot stream pushing
- Add some delay for the pcie_lf probe
- Auto-start rshim service after installation
* Fri Sep 25 2020 Liming Sun - 2.0.5-4
- Some robust fixes for USB rshim
- Fix a typo in pcie mmap
* Mon Aug 17 2020 Liming Sun - 2.0.5-3
- Fix several coverity warnings
- Add workaround to boot Viper rev A0 in LiveFish mode
- Display/configure OPN string for BlueField-2
* Fri Jul 24 2020 Liming Sun - 2.0.5-2
- Add configuration file support
- misc: Display device version / revision ID
- Add service file for FreeBSD
* Tue Jun 16 2020 Liming Sun - 2.0.5-1
- Improve response time to ctrl+c for boot stream
- Fix a rpmbuild issue when make_build is not defined
- Add DROP_MODE configuration in misc file
- Avoid reading the fifo if still booting
- Fix configure issue for FreeBSD 12.1-RELEASE
- Add domain id to the DEV_NAME in the misc file
- Fix the debian copyright format
- Enhance rshim_pcie_enable function
* Tue Apr 21 2020 Liming Sun - 2.0.4-1
- Update .spec file according to review comments
- Fix the 'KillMode' in rshim.service
- Support process termination by SIGTERM
- Fix some compiling warnings and configure issue for FreeBSD
- Fix a read()/write() issue in rshim_pcie.c caused by optimization
* Tue Apr 14 2020 Liming Sun - 2.0.3-1
- Enable pci device during probing
- Map the pci resource0 file instead of /dev/mem
- Add copyright header in bootstrap.sh
- Add 'Requires' tag check in the rpm .spec for kernel-modules-extra
- Fix the 'rshim --version' output
* Thu Apr 09 2020 Liming Sun - 2.0.2-1
- Remove unnecessary dependency in .spec and use make_build
- Add package build for debian/ubuntu
- Fix some format in the man page
- Add check for syslog headers
* Mon Mar 23 2020 Liming Sun - 2.0.1-1
- Rename bfrshim to rshim
- Remove rshim.spec since it's auto-generated from rshim.spec.in
- Fix warnings reported by coverity
- Add rhel/rshim.spec.in for fedora
- Move rshim to sbin and move man page to man8
* Fri Mar 13 2020 Liming Sun - 2.0-1
- Update the spec file according to fedora packaging-guidelines
* Mon Dec 16 2019 Liming Sun
- Initial packaging
Mellanox-rshim-user-space-0339e66/Makefile.am 0000664 0001750 0001750 00000001305 15101274612 017107 0 ustar tai tai # SPDX-License-Identifier: GPL-2.0-only
# Copyright (C) 2019 Mellanox Technologies. All Rights Reserved.
#
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src man
dist_doc_DATA = README.md
confdir = $(sysconfdir)
dist_conf_DATA = etc/rshim.conf
dist_sbin_SCRIPTS = scripts/bfb-install \
scripts/bf-reg \
scripts/bfb-tool \
scripts/mlx-mkbfb \
third_party/PLDM-unpack/fwpkg_unpack.py
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
if HAVE_SYSTEMD
systemdsystemunit_DATA = rshim.service
else
if OS_FREEBSD
init_ddir = $(sysconfdir)/rc.d/
init_d_SCRIPTS = freebsd/rshim
endif
endif
Mellanox-rshim-user-space-0339e66/README.md 0000664 0001750 0001750 00000006667 15101274612 016352 0 ustar tai tai BlueField Rshim Host Driver
The rshim driver provides a way to access the rshim resources on the BlueField
target from external host machine. The current version implements device files
for boot image push and virtual console access. It also creates virtual network
interface to connect to the BlueField target and provides a way to access the
internal rshim registers.
*) Build
Linux:
Make sure autoconf/automake/pkg-config tools are available. Run bootstrap.sh
for the first time to generate the configure file. Then run the ./configure
script followed by make & make install to build and install it.
FreeBSD:
Require FreeBSD 12.0+ with packages autoconf, automake, gmake, libepoll-shim,
libpciaccess, libpci, pkgconf.
Follow the same steps above to build it. Use 'gmake install' to install it.
*) Usage
rshim -h
syntax: rshim [--help|-h] [--backend|-b usb|pcie|pcie_lf]
[--device|-d device-name] [--foreground|-f]
[--debug-level|-l <0~4>]
*) Device Files
Each rshim target will create a directory /dev/rshim\/ with the
following device files. \ is the device id, which could be 0, 1, etc.
- /dev/rshim\/boot
Boot device file used to push boot stream to the ARM side, for example,
cat install.bfb > /dev/rshim/boot
- /dev/rshim\/console
Console device, which can be used by console apps to connect to the ARM side,
such as
screen /dev/rshim/console
- /dev/rshim\/rshim
Device file used to access the rshim registers. The read/write offset is
encoded as "((rshim_channel << 16) | register_offset)".
- /dev/rshim\/misc
Key/Value pairs used to read/write misc information. For example,
Display the content:
cat /dev/rshim/misc
DISPLAY_LEVEL 0 (0:basic, 1:advanced, 2:log)
BOOT_MODE 1 (0:rshim, 1:emmc, 2:emmc-boot-swap)
BOOT_TIMEOUT 100 (seconds)
DROP_MODE 0 (0:normal, 1:drop)
SW_RESET 0 (1: reset)
DEV_NAME usb-3.3
DEV_INFO BlueField-3(Rev 1)
OPN_STR 9009D3B400ENEA
UP_TIME 179752(s)
SECURE_NIC_MODE 1 (0:no, 1:yes)
Display more infomation:
echo "DISPLAY_LEVEL 1" > cat /dev/rshim/misc
cat /dev/rshim/misc
...
PEER_MAC 00:1a:ca:ff:ff:01 # Target-side MAC address
PXE_ID 0x01020304 # PXE DHCP-client-identifier
The 'PEER_MAC' attribute can be used to display and set the target-side MAC
address of the rshim network interface. It works when the target-side is in
UEFI BootManager or in Linux where the tmfifo has been loaded. The new MAC
address will take effect in next boot.
Initiate a SW reset:
echo "SW_RESET 1" > /dev/rshim/misc
When 'SECURE_NIC_MODE' is shown as 1, the NIC firmware is in Secure NIC mode
and most rshim functionalities are disabled. This mode applies to PCIe rshim
backend only. PCIe LF and USB rshim backends are not affected.
*) Multiple Boards Support
Multiple boards could connect to the same host machine. Each of them has its
own device directory /dev/rshim/. Network subnet needs to be set properly
just like any other standard NIC.
*) How to change the MAC address of the ARM side interface
Update the 'PEER_MAC' attribute in the misc file like below. Display the value
to confirm it's set. Reboot the device to take effect.
echo "PEER_MAC 00:1a:ca:ff:ff:10" > /dev/rshim\/misc
Mellanox-rshim-user-space-0339e66/rshim.spec.in 0000664 0001750 0001750 00000052744 15101274612 017473 0 ustar tai tai # SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
# Copyright (C) 2019 Mellanox Technologies. All Rights Reserved.
#
Name: rshim
Version: @VERSION@
Release: 0%{?dist}
Summary: User-space driver for Mellanox BlueField SoC
License: GPLv2
URL: https://github.com/mellanox/rshim-user-space
Source0: https://github.com/mellanox/rshim-user-space/archive/%{name}-%{version}.tar.gz
BuildRequires: gcc, autoconf, automake, pkgconfig, make
BuildRequires: pkgconfig(libpci), pkgconfig(libusb-1.0)
BuildRequires: fuse-devel
BuildRequires: pciutils-devel
%if 0%{?suse_version}
# SLES-specific package names
BuildRequires: libusb-1_0-devel
%else
BuildRequires: libusbx-devel
%endif
%if (0%{?oraclelinux} >= 9)
%define is_uek64k 0
%{lua:
local handle = io.popen("uname -r")
local kernelver = handle:read("*l")
handle:close()
if kernelver and kernelver:match("64k") then
rpm.define("is_uek64k 1")
end
}
%if (0%{?is_uek64k} == 1)
Requires: kernel-uek64k-core
%else
Requires: kernel-uek-core
%endif
%else
%if (0%{?rhel} >= 8 || 0%{?fedora} > 0) && "0%{?ctyunos}" == "0"
Requires: kernel-modules-extra
%endif
%endif
%global with_systemd %(if (test -d "%{_unitdir}" > /dev/null); then echo -n '1'; else echo -n '0'; fi)
%global debug_package %{nil}
%description
This is the user-space driver to access the BlueField SoC via the rshim
interface. It provides ways to push boot stream, debug the target or login
via the virtual console or network interface.
%prep
rm -fr %{name}-%{version}
mkdir %{name}-%{version}
tar -axf %{SOURCE0} -C %{name}-%{version} --strip-components 1
%setup -q -D -T
%build
./bootstrap.sh
%configure
%if %{?make_build:1}%{!?make_build:0}
%make_build
%else
make
%endif
%install
%undefine _missing_build_ids_terminate_build
%makeinstall -C src INSTALL_DIR="%{buildroot}%{_sbindir}"
%if "%{with_systemd}" == "1"
%{__install} -d %{buildroot}%{_unitdir}
%{__install} -m 0644 rshim.service %{buildroot}%{_unitdir}
%endif
%{__install} -d %{buildroot}%{_mandir}/man1
%{__install} -m 0644 man/mlx-mkbfb.1 %{buildroot}%{_mandir}/man1
%{__install} -d %{buildroot}%{_mandir}/man8
%{__install} -m 0644 man/rshim.8 %{buildroot}%{_mandir}/man8
%{__install} -m 0644 man/bfb-install.8 %{buildroot}%{_mandir}/man8
%{__install} -m 0644 man/bfb-tool.8 %{buildroot}%{_mandir}/man8
%{__install} -m 0644 man/bf-reg.8 %{buildroot}%{_mandir}/man8
%{__install} -m 0644 man/bf-pldm-ver.8 %{buildroot}%{_mandir}/man8
%{__install} -d %{buildroot}%{_sysconfdir}
%{__install} -m 0644 etc/rshim.conf %{buildroot}%{_sysconfdir}
%{__install} -m 0755 scripts/bfb-install %{buildroot}%{_sbindir}
%{__install} -m 0755 scripts/bfb-tool %{buildroot}%{_sbindir}
%{__install} -m 0755 scripts/mlx-mkbfb %{buildroot}%{_sbindir}
%{__install} -m 0755 third_party/PLDM-unpack/fwpkg_unpack.py %{buildroot}%{_sbindir}
%{__install} -m 0755 scripts/bf-reg %{buildroot}%{_sbindir}
%{__install} -d %{buildroot}%{_datadir}/selinux/packages
%{__install} -m 0644 scripts/rshim-fix.te %{buildroot}%{_datadir}/selinux/packages/rshim-fix.te
%{__install} -m 0755 scripts/bf-pldm-ver %{buildroot}%{_sbindir}
%pre
%if "%{with_systemd}" == "1"
if systemctl is-active --quiet rshim ; then
systemctl stop rshim
fi
%endif
%post
if [ -f /etc/redhat-release ] && [ -f /etc/os-release ]; then
. /etc/os-release
RHEL_MAJOR=$(echo $VERSION_ID | cut -d '.' -f 1)
RHEL_MINOR=$(echo $VERSION_ID | cut -d '.' -f 2)
if [ "$RHEL_MAJOR" -gt 9 ] || \
{ [ "$RHEL_MAJOR" -eq 9 ] && [ "$RHEL_MINOR" -ge 5 ]; }; then
polver=$(grep "^module" %{_datadir}/selinux/packages/rshim-fix.te | sed 's/;//' | awk '{print $3}')
echo "Applying SELinux rshim policy fix $polver for RHEL 9.5..."
if [ -x /usr/bin/checkmodule ] && [ -x /usr/bin/semodule_package ]; then
mkdir -p /tmp/rshim-selinux
checkmodule -M -m -o /tmp/rshim-selinux/rshim-fix.mod %{_datadir}/selinux/packages/rshim-fix.te
semodule_package -o /tmp/rshim-selinux/rshim-fix.pp -m /tmp/rshim-selinux/rshim-fix.mod
semodule -i /tmp/rshim-selinux/rshim-fix.pp || :
rm -rf /tmp/rshim-selinux
else
echo "SELinux policy tools are not available. rshim policy update failed."
fi
fi
else
echo "Skipping SELinux rshim policy fix on non-supported distribution."
fi
%if "%{with_systemd}" == "1"
echo "Installation complete. To enable and start the rshim service, run:"
echo " systemctl daemon-reload"
echo " systemctl enable rshim"
echo " systemctl start rshim"
%endif
%preun
if [ "$1" = "0" ]; then
%if "%{with_systemd}" == "1"
if systemctl is-active --quiet rshim ; then
systemctl stop rshim
fi
%else
killall -9 rshim
%endif
fi
%postun
if [ $1 -eq 0 ] && [ -x /usr/sbin/semodule ] && semodule -l | grep -q '^rshim-fix\b'; then
semodule -r rshim-fix >/dev/null 2>&1 || true
fi
%files
%{!?_licensedir:%global license %%doc}
%license LICENSE
%defattr(-,root,root,-)
%doc README.md
%config(noreplace) %{_sysconfdir}/rshim.conf
%if "%{with_systemd}" == "1"
%{_unitdir}/rshim.service
%endif
%{_sbindir}/rshim
%{_sbindir}/bfb-install
%{_sbindir}/bfb-tool
%{_sbindir}/mlx-mkbfb
%{_sbindir}/bf-reg
%{_sbindir}/bf-pldm-ver
%{_sbindir}/fwpkg_unpack.py
%{_sbindir}/bf-pldm-ver
%{_mandir}/man1/mlx-mkbfb.1.gz
%{_mandir}/man8/rshim.8.gz
%{_mandir}/man8/bfb-install.8.gz
%{_mandir}/man8/bfb-tool.8.gz
%{_mandir}/man8/bf-reg.8.gz
%{_mandir}/man8/bf-pldm-ver.8.gz
%{_datadir}/selinux/packages/rshim-fix.te
%changelog
* Fri Oct 31 2025 Penghe Geng - 2.5.7
- bfb-install: fix deferred upgrade & BMC credential issue
* Wed Oct 29 2025 Penghe Geng - 2.5.6
- bfb-install: fix deferred upgrade & BMC credential issue
* Wed Oct 22 2025 Liming Sun - 2.5.4
- Some enhancement for the command mode
- Update rshim.spec.in to include additional build requirements
- bfb-install: Fix no proper output for missing rshim device
* Wed Oct 08 2025 Penghe Geng - 2.5.3
- Fix SIGTERM segfault when rshim exits
- bfb-install: add check for bfb file presence
* Wed Sep 24 2025 Penghe Geng - 2.5.2
- No service interrupt for DPU-BMC flow
- Support Golden Images in PLDM format
- Deregister driver when not in use
* Wed Aug 20 2025 Penghe Geng - 2.5.1
- Improve GitHub CI robustness for ARM builds
- Fix rshim drop mode driver binding
- bfb-tool: Added qemu-aarch64-static installation guidance
- bfb-tool: Added workaround for mlx_fwsfx_gen
* Tue Jul 22 2025 Penghe Geng - 2.4.4
- Added support for bf-fwbundle per OPN
- Set is_uek64k flag at build time
- Fix bfdump doesn't return error code in case of success
* Wed Jul 09 2025 Liming Sun - 2.4.3
- bf-pldm-ver: initial version to retrieve image versions from PLDM
- Fix bfdump doesn't return error code
* Fri Jun 06 2025 Penghe Geng - 2.4.2
- Update bfb-tool - support NIC FW replacing
- Reduce CPU usage by polling optimization
* Fri May 30 2025 Liming Sun - 2.4.1
- bfb-tool: Add error for missing version information in BFB files
- bfb-tool: Add command to print versions of components in BFB
- bfb-install: add command syntax for lfwp
- bfb-install: BFB format conversion for runtime upgrade
- bfb-install: Convert to flat BFB for runtime upgrade
- scripts/bfb-tool: Add flat format support for BFB
- Updated mlx-mkbfb
- Disable LTO build option in github CI
- Fix transient pipeline error caused by apt update
- Skip SELinux fix on non-RHEL distros like SLES
* Tue Apr 22 2025 Penghe Geng - 2.3.8
- Fix a potentially unintialized variable
* Wed Apr 16 2025 Liming Sun - 2.3.7
- bfb-install: Reactivate NIC_FW for runtime upgrade
* Thu Apr 03 2025 Liming Sun - 2.3.6
- bfb-install: cleanup the TMP_DIR
* Sat Mar 29 2025 Liming Sun - 2.3.5
- bfb-install: add validation of bfb and rshim options
- Fix the rshim command line for register read/write
* Tue Mar 25 2025 Liming Sun - 2.3.4
- mlx-mkbfb: Improve the performance when extracting a single image
- Reduce CPU utilization by network optimization
* Sat Mar 22 2025 Liming Sun - 2.3.3
- bfb-install: register usage cleanup
- RPM pkg: Apply selinux workaround to RHEL 9.5 or later
- mlx-mkbfb/fwpkg_unpack.py: Add graceful handling of ctrl+c
- bfb-install: pack the bf.cfg into the generated BFB
- Fix occasional github pipeline docker error
* Fri Mar 14 2025 Liming Sun - 2.3.2
- bfb-install: Support trimmed NIC_FW
- bfdump support
- Use BREADCRUMB.BIT32 to indicate NIC mode
- Added bfb-tool script
* Thu Mar 06 2025 Liming Sun - 2.3.1
- Enhance command line for register read/write
- Support PCIe device name runtime update
- bfb-install: Enhancement for runtime upgrade
- bfb-install: don't exit script when rshim install fails
- Added fwpkg_unpack.py
* Tue Feb 18 2025 Vladimir Sokolovsky - 2.2.4
- Added mlx-mkbfb
* Tue Jan 14 2025 Liming Sun - 2.2.4
- Fix RPM dependency on Oracle Linux 8.6
* Fri Jan 10 2025 Liming Sun - 2.2.3
- bfb-install: Handle PF1 bind/unbind in NIC mode
- Fix RPM installation dependency on Oracle Linux
* Fri Jan 03 2025 Penghe Geng - 2.2.2
- Add GitHub pipeline to create deb/rpm packages
- Fix SELinux policy in enforcing mode
* Fri Dec 06 2024 Liming Sun - 2.2.1
- USB: removes the unnecessary POLLOUT polling
- Force to stop if stuck during systemd service stop
* Tue Nov 26 2024 Liming Sun - 2.1.8
- Allow multi rshim processes for dev attachment
- configure: fix fuse errors
* Mon Nov 18 2024 Liming Sun - 2.1.7
- Update default USB timeout
- Update license file to be dual-license
- Add BF_MODE misc output to show DPU or NIC mode
- Fix a compiling warning
- Allow 0 to restore USB_TIMEOUT default value
* Tue Nov 12 2024 Penghe Geng - 2.1.6
- Add USB_TIMEOUT to rshim misc and conf settings
- bfb-install: Add -k/--keep-log option
- bfb-install: exit when pushing bfb error
- Use BOOT_RESET_SKIP command to simulate eMMC boot
* Mon Oct 14 2024 Penghe Geng - 2.1.5
- Revert "Abort rshim rpm installation if no cuse.ko found"
* Thu Oct 10 2024 Penghe Geng - 2.1.4
- Make rshim run in single instance
- Abort rshim rpm installation if no cuse.ko found
- Increase default boot timeout to 300s
- bfb-install: Fix premature bfb-install exit when rebooting BMC
* Tue Sep 10 2024 Penghe Geng - 2.1.3
- Reduce the access_check() wait time
* Fri Aug 30 2024 Liming Sun - 2.1.2
- Improve access_check() to reduce likelihood of race condition
- Revert the 2-second delay
* Thu Aug 15 2024 Liming Sun - 2.1.1
- Add support for command mode
- Fix some coding style issues
- Cleanup rshim debug/syslog messages
* Thu Aug 08 2024 Liming Sun - 2.0.41
- Add a small delay to access the boot file
- Fix a valgrind warning
* Mon Aug 05 2024 Penghe Geng - 2.0.40
- Fix rshim deb package for DOCA build on Ubuntu
* Fri Aug 02 2024 Penghe Geng - 2.0.39
- Fix rshim masking issue on Ubuntu
- bfb-install: Fix NIC_MODE installation for BlueField-2
- pcie: Add VFIO support for BlueField-3
* Fri Jul 26 2024 Penghe Geng - 2.0.38
- Make sending the initial force command a one-time event
- bfb-install: adjust the log file to be per rshim
* Tue Jul 16 2024 Penghe Geng - 2.0.37
- add missing --force in help menu
* Mon Jul 15 2024 Penghe Geng - 2.0.36
- Allow /dev/rshim devfs creation only with --force option enabled
- bfb-install: fix for NIC mode
- bfb-install: Exit with error if running remote bfb-install without
password-less root SSH
- Fix compiling issue for FreeBSD
* Fri Jul 05 2024 Penghe Geng - 2.0.35
- Add ownership transfer feature (primarily via "FORCE_CMD")
- bfb-install: enhancement for NIC mode
* Tue Jun 11 2024 Liming Sun - 2.0.34
- bfb-install: Enable CLEAR_ON_READ
- bfb-install: add cleanup code for runtime update
* Thu Jun 06 2024 Liming Sun - 2.0.33
- misc: add 'CLEAR_ON_READ' command
- bfb-install: add runtime image support
* Tue Jun 04 2024 Liming Sun - 2.0.32
- bf3/pcie_lf: Fix the 4B access via MSN GW
* Fri May 17 2024 Liming Sun - 2.0.31
- bf3/pcie_lf: support register read/write via /dev/rshim0/rshim
- Only poll/check locked mode for PCIe backend
- Remove workaround support for BF2 A0 chip
* Mon May 13 2024 Liming Sun - 2.0.30
- pcie: Adjust default reset delay to 3 seconds
- Avoid polling blocked status during reset
- Disable installation of rshim on host by default
* Tue Apr 30 2024 Liming Sun - 2.0.29
- Some robust fixes for rshim over USB
- Lower log level for register read errors as it's normal during reset
* Thu Apr 25 2024 Penghe Geng - 2.0.28
- Secure NIC Mode: Prevent running simultaneously on both bmc and host
* Fri Apr 12 2024 Penghe Geng - 2.0.27
- bfb-install: Fix incorrect IP address resolution for multi-hop routing
* Fri Apr 12 2024 Liming Sun - 2.0.26
- rshim_pcie: set PCIE bit in scratchpad6
- Revert semantics of --reverse-nc
* Fri Apr 05 2024 Liming Sun - 2.0.25
- Avoid a race of rshim ownership during bfb push
* Thu Apr 04 2024 Liming Sun - 2.0.24
- DROP_MODE: sync-up the Rx FIFO when clearing DROP_MODE
* Tue Apr 02 2024 Liming Sun - 2.0.23
- Add some robust fixes for the DROP_MODE
* Fri Mar 22 2024 Penghe Geng - 2.0.22
- bfb-install: add support for remote rshim update; add speed optimizations
* Tue Mar 19 2024 Penghe Geng - 2.0.21
- rshim_pci: output Secure NIC mode status in misc file
* Fri Feb 16 2024 Liming Sun - 2.0.20
- rshim_pci: adjust delay time for nic_fw reset
- bfb-install: Exit on "Linux up"
* Wed Jan 10 2024 Liming Sun - 2.0.19
- Fix incorrect console message drop
- Allow runtime debug code for DK cards
* Thu Dec 14 2023 Liming Sun - 2.0.18
- Clear scratchpad1 register when setting drop_mode
* Wed Nov 22 2023 Liming Sun - 2.0.17
- bfb-install: Fix duplicate output
* Thu Nov 16 2023 Liming Sun - 2.0.16
- Remove fuse build dependency
* Tue Nov 14 2023 Liming Sun - 2.0.15
- Add BFB completion condition for enhanced NIC mode
* Fri Nov 10 2023 Liming Sun - 2.0.14
- Fix 9f19cfb4a75687ae
* Wed Nov 08 2023 Liming Sun - 2.0.13
- Several robust fixes
- Add fuse3 support
* Mon Oct 23 2023 Liming Sun - 2.0.12
- BF3: Add UPTIME display in seconds
* Tue Sep 26 2023 Liming Sun - 2.0.11
- Remove version 0 support for NIC FW_RESET
- bfb-install: Return failure code
* Mon Sep 18 2023 Liming Sun - 2.0.10
- Fix interrupt handling for NIC FW_RESET
* Sat Jun 17 2023 Liming Sun - 2.0.9
- rshim/usb/bf3: fix timeout logic
* Tue May 16 2023 Liming Sun - 2.0.8
- Fix the fall-back logic of direct-mapping
* Thu Mar 30 2023 Liming Sun - 2.0.7
- Avoid opening /dev/uio multiple times
- Update common files to dual-license
- Adjust rshim reset delay
* Sun Nov 20 2022 Liming Sun - 2.0.6-19
- BF3: Support 4B access for PCIe
* Tue Oct 25 2022 Liming Sun - 2.0.6-18
- pcie: fix initialization issue when setting DROP_MODE in rshim.conf
* Thu Oct 20 2022 Liming Sun - 2.0.6-17
- pcie: Avoid using cached pci_dev
- rshim_fuse: display misc file even when rshim is not accessible
* Thu Oct 06 2022 Liming Sun - 2.0.6-16
- pcie: Support mixed vfio and direct mapping mode
* Thu Sep 29 2022 Liming Sun - 2.0.6-15
- Add dependency of libfuse2 for .deb
- rshim-pcie: add a new bad-access code
- Fix a potential NULL pointer access during USB disconnect
- Adjust default boot timeout to 150s
* Tue Aug 16 2022 Liming Sun - 2.0.6-14
- Avoid potential race when stopping the rshim process
- Add configuration option to enable/disable PCIe VFIO/UIO
- Fix warnings for compiling on 32-bit BMC
- Mustang rshim usb supports for 4B and 8B transactions
* Sun Jul 17 2022 Liming Sun - 2.0.6-13
- BF3: Support 32-bit CR-space access via USB
- Avoid kernel-modules-extra dependency on ctyunos
* Thu Jun 16 2022 Liming Sun - 2.0.6-12
- Optimize the rshim_work_fd
- Detect new USB/rshim hot plugin
* Mon May 16 2022 Liming Sun - 2.0.6-11
- Avoid kernel crash when unbind rshim from uio
* Mon May 02 2022 Liming Sun - 2.0.6-10
- Fix several compiling issues for FreeBSD
* Thu Apr 28 2022 Liming Sun - 2.0.6-9
- Use per-device memory-map mode
* Mon Apr 18 2022 Liming Sun - 2.0.6-8
- Add interrupt polling for direct mmap() mode
- Fix several coverity warnings
* Thu Apr 07 2022 Liming Sun - 2.0.6-7
- Keep intr_fd during rshim_pcie disable/enable
- Mustang: Add support for rshim over pcie and pcie_lf
* Wed Mar 30 2022 Liming Sun - 2.0.6-6
- Clear scratchpad1 to 0 before PCI resources are unmapped
- Fallback to UIO if VFIO failed
* Fri Mar 18 2022 Liming Sun - 2.0.6-5
- PCIe: Add UIO and IRQ support
- PCIe: Remove 32-bit support
* Mon Feb 28 2022 Liming Sun - 2.0.6-4
- VFIO support
- Fix potential race in rshim_work_signal
* Mon Nov 29 2021 Liming Sun - 2.0.6-3
- Adjust the defaul value of usb_reset_delay to 5
- Add a delay after USB probe
- Make the reset delay configurable
* Wed Nov 03 2021 Liming Sun - 2.0.6-2
- bfb-install: Handle new indications for installation completion
- Clean up some un-needed register definition
- Fix MTU of the tmfifo_net0 interface on FreeBSD
- Several fixes to prevent hypervisor crash
- Refine some BF-2 Rev0 workaround condition
* Wed May 12 2021 Liming Sun - 2.0.6-1
- Disable the background timer if no rshim devices
- Setting default path for rshim config file
* Wed Mar 10 2021 Liming Sun - 2.0.5-10
- PCIe hotplug support
- Reduce CPU utilization when there is no rshim device
* Wed Jan 27 2021 Liming Sun - 2.0.5-9
- Fix potential tmfifo data loss
- Add workaround checking for Bluefield-2 REV-0
- Fix network traffic stop issue when Tx buffer full
* Fri Dec 11 2020 Liming Sun - 2.0.5-8
- Don't allow any register access when DROP_MODE is set
- Avoid potential race in rshim_fifo_read
* Wed Dec 09 2020 Liming Sun - 2.0.5-7
- Fix potential dead-lock when calling rshim_access_check
- Ignore rshim access checking when global drop mode is enabled
- Fix some secure boot related issue
* Wed Dec 02 2020 Liming Sun - 2.0.5-6
- Add some default configuration in rshim.conf
- Change the debug level of Rshim byte access widget timeout
- Add bfb-install script
* Thu Oct 29 2020 Liming Sun - 2.0.5-5
- Check rshim accessibility when re-enabling it
- Enable console output during boot stream pushing
- Add some delay for the pcie_lf probe
- Auto-start rshim service after installation
* Fri Sep 25 2020 Liming Sun - 2.0.5-4
- Some robust fixes for USB rshim
- Fix a typo in pcie mmap
* Mon Aug 17 2020 Liming Sun - 2.0.5-3
- Fix several coverity warnings
- Add workaround to boot Viper rev A0 in LiveFish mode
- Display/configure OPN string for BlueField-2
* Fri Jul 24 2020 Liming Sun - 2.0.5-2
- Add configuration file support
- misc: Display device version / revision ID
- Add service file for FreeBSD
* Tue Jun 16 2020 Liming Sun - 2.0.5-1
- Improve response time to ctrl+c for boot stream
- Fix a rpmbuild issue when make_build is not defined
- Add DROP_MODE configuration in misc file
- Avoid reading the fifo if still booting
- Fix configure issue for FreeBSD 12.1-RELEASE
- Add domain id to the DEV_NAME in the misc file
- Fix the debian copyright format
- Enhance rshim_pcie_enable function
* Tue Apr 21 2020 Liming Sun - 2.0.4-1
- Update .spec file according to review comments
- Fix the 'KillMode' in rshim.service
- Support process termination by SIGTERM
- Fix some compiling warnings and configure issue for FreeBSD
- Fix a read()/write() issue in rshim_pcie.c caused by optimization
* Tue Apr 14 2020 Liming Sun - 2.0.3-1
- Enable pci device during probing
- Map the pci resource0 file instead of /dev/mem
- Add copyright header in bootstrap.sh
- Add 'Requires' tag check in the rpm .spec for kernel-modules-extra
- Fix the 'rshim --version' output
* Thu Apr 09 2020 Liming Sun - 2.0.2-1
- Remove unnecessary dependency in .spec and use make_build
- Add package build for debian/ubuntu
- Fix some format in the man page
- Add check for syslog headers
* Mon Mar 23 2020 Liming Sun - 2.0.1-1
- Rename bfrshim to rshim
- Remove rshim.spec since it's auto-generated from rshim.spec.in
- Fix some warnings reported by coverity
- Add file rhel/rshim.spec.in for fedora
- Move rshim to sbin and move man page to man8
* Fri Mar 13 2020 Liming Sun - 2.0-1
- Update the spec file according to fedora packaging-guidelines
* Mon Dec 16 2019 Liming Sun