grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026# Copyright (c) 2004-2010 Mellanox Technologies LTD. All rights reserved. # Copyright (c) 2021 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, available from the file # COPYING in the main directory of this source tree, or the # OpenIB.org BSD license below: # # 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. # # 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. # Author: Ahmed Awwad ahmadaw@mellanox.com Created: 2019-Jan import binascii class BinaryFile(object): """ Binary File class is dealing with r/w of binary files """ def __init__(self, file_path): self._file_path = file_path def read_byte(self, offset): """ Read 1B from the pci configuration """ return self.read(1, offset)[0] def read_word(self, offset): """ Read 2B for the pci configuration """ bytes_list = self.read(2, offset) if bytes_list != []: byte0 = "{0:x}".format(bytes_list[0]).zfill(2) byte1 = "{0:x}".format(bytes_list[1]).zfill(2) return int("{0}{1}".format(byte1, byte0), 16) else: return None def read_long(self, offset): """ Reads 4B from the pci configuration """ bytes_list = self.read(4, offset) if bytes_list != []: byte0 = "{0:x}".format(bytes_list[0]).zfill(2) byte1 = "{0:x}".format(bytes_list[1]).zfill(2) byte2 = "{0:x}".format(bytes_list[2]).zfill(2) byte3 = "{0:x}".format(bytes_list[3]).zfill(2) return int("{0}{1}{2}{3}".format(byte3, byte2, byte1, byte0), 16) else: return None def read(self, size, offset=0, skip_offset_list=None): """ Read a given binary file and return the output as a string in hex representation Skip-list is a list of addresses the function need to skip. The function will insert '00' on every address that is skipped Example read(size=10, offset=0, skip_offset_list=[0x5]) will read from address 0x0 to address 0x9 and replace address 0x5 with '00' """ try: with open(self._file_path, "rb") as f: if skip_offset_list: data = binascii.unhexlify("") # Initialization zero_binary = binascii.unhexlify("00") # Initialization offset_interval = self._get_read_intervals(skip_offset_list, offset, size) for interval_start, interval_size in offset_interval: if interval_size: # read interval f.seek(interval_start) data += f.read(interval_size) else: # add '00' to data data += zero_binary else: f.seek(offset) data = f.read(size) except Exception as err: raise RuntimeError("Failed to parse file: {0} for reading. ERROR: {1}".format(self._file_path, err)) data = binascii.hexlify(data) bytes_as_string = self.chunkstring(data, 2) bytes_list = [] for byte in bytes_as_string: if byte != "": bytes_list.append(int(byte, 16)) else: bytes_list.append(None) return bytes_list @staticmethod def _get_read_intervals(skip_offset_list, offset, size): """ The method prepare the skip list in order to read a range and skipping on some (dangerous) offsets The method return list of tuples Example , offset:0, size:10, skiplist=[4, 5] The function return [(0, 4),(4, 0), (5, 0) (6, 10)] when each item is (start, size) when size is 0 it means we need to skip this offset """ # remove out of range skip addresses for skip_offset in skip_offset_list: if skip_offset not in range(offset, size + 1): skip_offset_list.remove(skip_offset) read_interval_set = set(skip_offset_list) # Add offset, offset+size to skip_list read_interval_set.add(offset - 1) read_interval_set.add(offset + size) read_interval_list = sorted(list(read_interval_set)) result = [] for start, end in zip(read_interval_list[:-1], read_interval_list[1:]): interval_start = start + 1 interval_end = end result.append((interval_start, interval_end - interval_start)) # interval result.append((interval_end, 0)) # skip interval result = result[:-1] # remove the last tuple (offset+size, 0) return sorted(set(result)) def write(self, bytes_list, size, offset=0): """ A method to write data to a binary file data is a list of values """ data_to_write = "" for byte in bytes_list: data_to_write += "{0:x}".format(byte).zfill(2) if len(data_to_write) > size * 2: raise RuntimeError("Failed to write data {0} invalid size".format(data_to_write)) bin_data = binascii.unhexlify(data_to_write) # Return the binary data represented by the hexadecimal string try: with open(self._file_path, "wb") as f: f.seek(offset) f.write(bin_data) except Exception as e: raise RuntimeError("Failed writing to a file: {0}. ERROR: {1}".format(self._file_path, e)) def chunkstring(self, string, length): """ Chunks the string to list of strings in the given length """ return (string[0 + i:length + i] for i in range(0, len(string), length))