/*
 * Copyright (C) Jan 2013 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.
 */

#ifndef FW_OPS_H
#define FW_OPS_H

#include "flint_base.h"
#include "flint_io.h"
#include "aux_tlv_ops.h"
#include "mlxfwops_com.h"
#include "signature_manager_factory.h"
#include "fw_version.h"
#include "tools_layouts/cx4fw_layouts.h"
#include <mlxsign_lib/mlxsign_lib.h>
#ifdef CABLES_SUPP
#include <cable_access/cable_access.h>
#endif
#include <fw_comps_mgr/fw_comps_mgr.h>
#if !defined(NO_OPEN_SSL)
#include <mlxsign_lib/mlxsign_lib.h>
#if !defined(NO_DYNAMIC_ENGINE)
#include <mlxsign_lib/mlxsign_openssl_engine.h>
#endif
#endif

// declaration only to enable compilation when NO_OPEN_SSL
// of signForFwUpdateUsingHSM(...), signForSecureBootUsingHSM(...) which decelare OpensslEngineSigner in argument.
#ifdef NO_OPEN_SSL
namespace MlxSign
{
class OpensslEngineSigner;
}
#endif

typedef f_prog_func_str VerifyCallBack;
typedef f_prog_func ProgressCallBack;
typedef f_prog_func_ex ProgressCallBackEx;
typedef f_prog_func_adv_st ProgressCallBackAdvSt;
typedef f_prog_func_str PrintCallBack;
typedef fw_ver_info_t FwVerInfo;

typedef int (*PrintCallBackAdv)(int completion, char* str);
MLXFWOP_API extern bool nextBootFwVer;
#define GLOBAL_ALIGNMENT 0x80
#define UUID_LEN 16
class MLXFWOP_API FwOperations : public FlintErrMsg
{
public:
#define EXP_ROM_GEN_DEVID 0
#define MISS_MATCH_DEV_ID 0xffff
    class ExtBurnParams;
    class ExtVerifyParams;
    struct fwOpsParams;
    struct sgParams;
    typedef fwOpsParams fw_ops_params_t;
    typedef sgParams sg_params_t;
    // typedef std::tr1::function<void (void)> VerifyCallback;
    enum
    {
        IMG_SIG_TYPE_UNKNOWN = 0,
        IMG_SIG_TYPE_BIN = 1,
        IMG_SIG_TYPE_MFA = 2,
        IMG_SIG_TYPE_CF = 3,
        IMG_SIG_TYPE_CC = 4,
        IMG_SIG_OPEN_FILE_FAILED = 5
    };
    FwOperations(FBase* ioAccess) :
        _ioAccess(ioAccess),
        _isCached(false),
        _wasVerified(false),
        _quickQuery(false),
        _printFunc((PrintCallBack)NULL),
        _fname((const char*)NULL),
        _devName((const char*)NULL),
        _advErrors(true),
        _minBinMinorVer(0),
        _minBinMajorVer(0),
        _maxBinMajorVer(0),
        _signatureMngr((ISignatureManager*)NULL),
        _internalQueryPerformed(false)
    {
        memset(_sectionsToRead, 0, sizeof(_sectionsToRead));
        memset(&_fwImgInfo, 0, sizeof(_fwImgInfo));
        memset(&_fwParams, 0, sizeof(_fwParams));
    };

    bool IsFifthGen() { return (_ioAccess != NULL && _ioAccess->is_flash() && _ioAccess->is_fifth_gen()); }

    bool CreateSignatureManager();

    virtual ~FwOperations()
    {
        if (_ioAccess)
        {
            delete _ioAccess;
        }
        if (_signatureMngr)
        {
            delete _signatureMngr;
        }
    };
    // virtual void print_type() {};
    virtual mfile* getMfileObj()
    {
        mfile* mf = _ioAccess->is_flash() ? ((Flash*)_ioAccess)->getMfileObj() : (mfile*)NULL;
        return mf;
    }
    FBase* GetIoAccess() { return _ioAccess; }
    virtual u_int8_t FwType() = 0;
    static bool IsFwSupportingRomModify(const FwVersion&);
    static bool CntxEthOnly(u_int32_t devid);
    static void SetDevFlags(chip_type_t chipType, u_int32_t devType, fw_img_type_t fwType, bool& ibDev, bool& ethDev);
    static bool checkMatchingExpRomDevId(const fw_info_t& info);
    static bool checkMatchingExpRomDevId(u_int16_t dev_type, const roms_info_t& roms_info);
    static const char* expRomType2Str(u_int16_t type);
    static chip_type GetChipType(string chip);
    static chip_type_t getChipType(u_int32_t devid);
    bool readBufAux(FBase& f, u_int32_t o, void* d, int l, const char* p);
    virtual bool FwQuery(fw_info_t* fwInfo,
                         bool readRom = true,
                         bool isStripedImage = false,
                         bool quickQuery = true,
                         bool ignoreDToc = false,
                         bool verbose = false) = 0;
    virtual bool FwVerify(VerifyCallBack verifyCallBackFunc,
                          bool isStripedImage = false,
                          bool showItoc = false,
                          bool ignoreDToc = false) = 0; // Add callback print
    virtual bool FwVerifyAdv(ExtVerifyParams& verifyParams);
    // on call of FwReadData with Null image we get image_size
    virtual bool FwReadData(void* image, u_int32_t* image_size, bool verbose = false) = 0;
    virtual bool FwReadBlock(u_int32_t addr, u_int32_t size, std::vector<u_int8_t>& dataVec);
    virtual u_int32_t GetPublicKeySecureBootPtr();
    virtual bool FwReactivateImage() { return errmsg("Operation not supported."); }
    virtual bool
      PreparePublicKeyData(const char* public_key_file, vector<u_int8_t>& publicKeyData, unsigned int& pem_offset);
    virtual bool storePublicKeyInSection(const char* public_key_file, const char* uuid);
    virtual bool FwInsertSHA256(PrintCallBack printFunc = (PrintCallBack)NULL);
    virtual bool InsertSecureFWSignature(vector<u_int8_t> signature, const char* uuid, PrintCallBack printFunc);
    virtual bool
      storeSecureBootSignaturesInSection(vector<u_int8_t> boot_signature,
                                         vector<u_int8_t> critical_sections_signature = vector<u_int8_t>(),
                                         vector<u_int8_t> non_critical_sections_signature = vector<u_int8_t>());
    virtual bool
      signForFwUpdate(const char* privPemFile, const char* uuid, PrintCallBack printFunc = (PrintCallBack)NULL);
    virtual bool
      signForFwUpdateUsingHSM(const char* uuid, MlxSign::OpensslEngineSigner& engineSigner, PrintCallBack printFunc);
    virtual bool FwSignWithTwoRSAKeys(const char* privPemFile1,
                                      const char* uuid1,
                                      const char* privPemFile2,
                                      const char* uuid2,
                                      PrintCallBack printFunc = (PrintCallBack)NULL);
    virtual bool FwSignWithHmac(const char* key_file);
    virtual bool signForSecureBoot(const char* private_key_file, const char* public_key_file, const char* guid_key_file);
    virtual bool signForSecureBootUsingHSM(const char* public_key_file,
                                           const char* uuid,
                                           MlxSign::OpensslEngineSigner& engineSigner);
    virtual bool PrepItocSectionsForHmac(vector<u_int8_t>& critical, vector<u_int8_t>& non_critical);
    virtual bool IsCriticalSection(u_int8_t sect_type);

    virtual bool FwExtract4MBImage(vector<u_int8_t>& img,
                                   bool maskMagicPatternAndDevToc,
                                   bool verbose = false,
                                   bool ignoreImageStart = false);
    virtual bool RestoreDevToc(vector<u_int8_t>& img,
                               char* psid,
                               dm_dev_id_t devid_t,
                               const cx4fw_uid_entry& base_guid,
                               const cx4fw_uid_entry& base_mac);
    virtual bool initHwPtrs(bool isVerify = false);
    virtual bool isHashesTableHwPtrValid();
    virtual bool openEncryptedImageAccess(const char* encrypted_image_path);
    virtual bool isEncrypted(bool& is_encrypted);
    virtual bool FwExtractEncryptedImage(vector<u_int8_t>& img,
                                         bool maskMagicPatternAndDevToc,
                                         bool verbose = false,
                                         bool ignoreImageStart = false);
    virtual bool burnEncryptedImage(FwOperations* imageOps, ExtBurnParams& burnParams);
    virtual bool FwSetPublicKeys(char* fname, PrintCallBack callBackFunc = (PrintCallBack)NULL);
    virtual bool FwSetForbiddenVersions(char* fname, PrintCallBack callBackFunc = (PrintCallBack)NULL);
    virtual bool CalcHMAC(const vector<u_int8_t>& key, const vector<u_int8_t>& data, vector<u_int8_t>& digest);
    virtual bool FwReadRom(std::vector<u_int8_t>& romSect) = 0;
    virtual bool FwBurnRom(FImage* romImg,
                           bool ignoreProdIdCheck = false,
                           bool ignoreDevidCheck = false,
                           ProgressCallBack progressFunc = (ProgressCallBack)NULL) = 0; // can also read the rom from
                                                                                        // flint and give a vector of
                                                                                        // u_int8_t
    virtual bool FwDeleteRom(bool ignoreProdIdCheck, ProgressCallBack progressFunc = (ProgressCallBack)NULL) = 0;

    virtual bool
      FwBurn(FwOperations* imageOps, u_int8_t forceVersion, ProgressCallBack progressFunc = (ProgressCallBack)NULL) = 0;
    virtual bool FwBurnAdvanced(FwOperations* imageOps, ExtBurnParams& burnParams) = 0;
    virtual bool
      getExtendedHWAravaPtrs(VerifyCallBack verifyCallBackFunc, FBase* ioAccess, bool IsBurningProcess, bool isVerify);
    virtual bool FwBurnAdvanced(std::vector<u_int8_t> imageOps4MData,
                                ExtBurnParams& burnParams,
                                FwComponent::comps_ids_t ComponentId = FwComponent::COMPID_BOOT_IMG);
    virtual bool FwBurnBlock(FwOperations* imageOps,
                             ProgressCallBack progressFunc) = 0; // Add: callback progress, question arr, callback
                                                                 // question, configurations
    virtual bool FwWriteBlock(u_int32_t addr,
                              std::vector<u_int8_t> dataVec,
                              ProgressCallBack progressFunc = (ProgressCallBack)NULL);

    virtual bool FwSetGuids(sg_params_t& sgParam,
                            PrintCallBack callBackFunc = (PrintCallBack)NULL,
                            ProgressCallBack progressFunc = (ProgressCallBack)NULL) = 0;

    virtual bool FwSetMFG(fs3_uid_t baseGuid, PrintCallBack callBackFunc = (PrintCallBack)NULL) = 0;
    virtual bool FwSetMFG(guid_t baseGuid, PrintCallBack callBackFunc = (PrintCallBack)NULL) = 0;
    // use progressFunc when dealing with FS2 image and printFunc when dealing with FS3 image.
    virtual bool FwSetVSD(char* vsdStr,
                          ProgressCallBack progressFunc = (ProgressCallBack)NULL,
                          PrintCallBack printFunc = (PrintCallBack)NULL) = 0;
    virtual bool FwSetVPD(char* vpdFileStr, PrintCallBack callBackFunc = (PrintCallBack)NULL) = 0;
    virtual bool
      FwSetCertChain(char* certFileStr, u_int32_t certIndex, PrintCallBack callBackFunc = (PrintCallBack)NULL);
    virtual bool FwSetAccessKey(hw_key_t userKey, ProgressCallBack progressFunc = (ProgressCallBack)NULL) = 0;
    virtual bool FwGetSection(u_int32_t sectType, std::vector<u_int8_t>& sectInfo, bool stripedImage = false) = 0;
    virtual bool FwResetNvData() = 0;
    virtual bool FwShiftDevData(PrintCallBack progressFunc = (PrintCallBack)NULL) = 0;
    virtual const char* FwGetResetRecommandationStr() = 0;
    virtual const char* FwGetReSignMsgStr();

    virtual bool FwSetTimeStamp(struct tools_open_ts_entry& timestamp, struct tools_open_fw_version& fwVer);
    virtual bool FwQueryTimeStamp(struct tools_open_ts_entry& timestamp,
                                  struct tools_open_fw_version& fwVer,
                                  bool queryRunning = false);
    virtual bool FwResetTimeStamp();

    virtual bool FwCheckIfWeCanBurnWithFwControl(FwOperations*) { return true; }
    virtual bool FwCheckIf8MBShiftingNeeded(FwOperations*, const ExtBurnParams&) { return false; }

    bool CreateBasicImageFromData(u_int32_t* data, u_int32_t dataSize, FwOperations** newImgOps);

    virtual bool CheckIfAlignmentIsNeeded(FwOperations*) { return false; }
    virtual bool AlignDeviceSections(FwOperations* /*imageOps*/)
    {
        return errmsg("Align device sections is not supported");
    }
    virtual bool RemoveWriteProtection()
    {
        return true;
        // Though Remove write protection is not supported, return true.
    }
    virtual void FwCleanUp();
    virtual bool FwInit() = 0;
    virtual bool FsIntQuery() { return true; }
    bool FwSetPrint(PrintCallBack PrintFunc);

    virtual bool UpdateSection(void* new_info,
                               fs3_section_t sect_type = FS3_DEV_INFO,
                               bool is_sect_failsafe = true,
                               CommandType cmd_type = CMD_UNKNOWN,
                               PrintCallBack callBackFunc = (PrintCallBack)NULL);
    // needed for flint low level operations
    bool FwSwReset();
    virtual bool CheckCX4Device() { return true; /* deprecated always return true*/ }
    virtual bool FwCalcMD5(u_int8_t md5sum[16]) = 0;
    virtual u_int32_t GetHwDevId()
    {
        mfile* mf = _ioAccess->getMfileObj();
        dm_dev_id_t deviceId = DeviceUnknown;
        u_int32_t hwDevId = 0x0, hwRevId = 0x0;
        if (dm_get_device_id(mf, &deviceId, &hwDevId, &hwRevId))
        {
            return 0xffff;
        }
        return hwDevId;
    }
    // virtual bool FwBurnBlock(FwOperations &FwImageAccess); // Add call back
    static FwOperations* FwOperationsCreate(void* fwHndl,
                                            void* info,
                                            char* psid,
                                            fw_hndl_type_t hndlType,
                                            char* errBuff = (char*)NULL,
                                            int buffSize = 0,
                                            bool ignore_crc_check = false);
    static FwOperations* FwOperationsCreate(fw_ops_params_t& fwParams);

    static bool imageDevOperationsCreate(fw_ops_params_t& devParams,
                                         fw_ops_params_t& imgParams,
                                         FwOperations** devFwOps,
                                         FwOperations** imgFwOps,
                                         bool ignoreSecurityAttributes = false,
                                         bool ignoreDToc = false);

    virtual bool IsFsCtrlOperations();
    virtual bool PrepItocSectionsForCompare(vector<u_int8_t>& critical, vector<u_int8_t>& non_critical);
    virtual bool IsSecureBootSupported();
    virtual bool IsCableQuerySupported();
    virtual bool IsLifeCycleSupported();
    virtual bool IsEncryptionSupported();
    void GetFwParams(fw_ops_params_t&);
    virtual void CleanInterruptedCommand() {} // by default do nothing
    virtual bool FwCalcSHA(MlxSign::SHAType, vector<u_int8_t>&, vector<u_int8_t>&);
    // bool GetExpRomVersionWrapper();
    void getSupporteHwId(u_int32_t** supportedHwId, u_int32_t& supportedHwIdNum);

    static FwVersion createFwVersion(const fw_info_com_t*);
    static FwVersion createFwVersion(u_int16_t fw_ver0, u_int16_t fw_ver1, u_int16_t fw_ver2);
    static FwVersion createRunningFwVersion(const fw_info_com_t*);
    static int getFileSignature(const char* fname);
    virtual bool IsLifeCycleAccessible(chip_type_t chip_type);
    virtual bool IsSecurityVersionViolated(u_int32_t image_security_version);
    virtual bool GetImageSize(u_int32_t* image_size);

#ifndef UEFI_BUILD
    static bool CheckPemKeySize(const string privPemFileStr, u_int32_t& keySize);
#endif
    class MLXFWOP_API RomInfo : FlintErrMsg
    {
    public:
        RomInfo(const std::vector<u_int8_t>& romSector, bool resEndi = true);
        ~RomInfo(){};
        bool initRomsInfo(roms_info_t* info);
        bool ParseInfo();
        static u_int8_t getNumVerFromProdId(u_int16_t prodId);

    private:
        // Rom Information
        bool expRomFound;
        u_int8_t numOfExpRom;
        u_int8_t noRomChecksum;
        u_int16_t expRomComDevid;
        u_int8_t expRomWarning;
        char expRomWarningMsg[MAX_ROM_ERR_MSG_LEN];
        u_int8_t expRomErrMsgValid;
        char expRomErrMsg[MAX_ROM_ERR_MSG_LEN];
        rom_info_t romsInfo[MAX_ROMS_NUM];
        std::vector<u_int8_t> romSect;

        bool GetExpRomVerForOneRom(u_int32_t verOffset);
        bool GetExpRomVersion();
    };

    class ExtBurnStatus
    {
    public:
        bool imageCachedSuccessfully;
        ExtBurnStatus() : imageCachedSuccessfully(false) {}
    };
    class ExtBurnParams
    {
    public:
        typedef enum BurnRomOption
        {
            BRO_DEFAULT,
            BRO_ONLY_FROM_IMG,
            BRO_FROM_DEV_IF_EXIST,
        } BurnRomOption;
        // burn params
        bool userGuidsSpecified;
        bool userMacsSpecified;
        bool userUidSpecified;
        bool vsdSpecified;
        bool blankGuids;
        bool burnFailsafe;
        bool allowPsidChange;
        bool useImagePs;
        bool useImageGuids;
        bool singleImageBurn;
        bool noDevidCheck;
        bool skipCiReq; // FS2 image only - skip sending cache image request to driver at the end of the burn
        bool ignoreVersionCheck;
        bool useImgDevData; // FS3 image only - take device data sections from image (valid only if burnFailsafe==
                            // false)
        bool useDevImgInfo; // FS3 image only - preserve select fields of image_info section on the device when burning.
        BurnRomOption burnRomOptions;
        bool shift8MBIfNeeded;

        // callback fun
        ProgressCallBack progressFunc;
        ProgressCallBackAdvSt ProgressFuncAdv;
        ProgressCallBackEx progressFuncEx;
        void* progressUserData;
        // data
        char* userVsd;
        bool use_cpu_utilization;
        int cpu_utilization;
        std::vector<guid_t> userUids; // contains either guids or uids
        ExtBurnStatus burnStatus;
        chip_type_t chip_type;
        bool use_chip_type;
        ExtBurnParams() :
            userGuidsSpecified(false),
            userMacsSpecified(false),
            userUidSpecified(false),
            vsdSpecified(false),
            blankGuids(false),
            burnFailsafe(true),
            allowPsidChange(false),
            useImagePs(false),
            useImageGuids(false),
            singleImageBurn(true),
            noDevidCheck(false),
            skipCiReq(false),
            ignoreVersionCheck(false),
            useImgDevData(false),
            useDevImgInfo(false),
            burnRomOptions(BRO_DEFAULT),
            shift8MBIfNeeded(false),
            progressFunc((ProgressCallBack)NULL),
            progressFuncEx((ProgressCallBackEx)NULL),
            progressUserData(NULL),
            userVsd((char*)NULL),
            use_cpu_utilization(false),
            cpu_utilization(-1),
            chip_type(CT_UNKNOWN),
            use_chip_type(false)
        {
            ProgressFuncAdv.func = (f_prog_func_adv)NULL;
            ProgressFuncAdv.opaque = NULL;
        }

        void updateParamsForBasicImage(ProgressCallBack progressFunc)
        {
            ignoreVersionCheck = true;
            this->progressFunc = progressFunc;
            useImagePs = true;
            useImageGuids = true;
            burnRomOptions = ExtBurnParams::BRO_ONLY_FROM_IMG;
        }
    };

    class ExtVerifyParams
    {
    public:
        VerifyCallBack verifyCallBackFunc; // Print function call back for print the different sections in the verify
        bool isStripedImage;               // If the image is striped
        bool showItoc;                     // Show the ITOC header only
        bool ignoreDToc;                   // Ignore verifying DTOC sections
        ProgressCallBackAdvSt* progressFuncAdv; // Advance progress function that used in FW controlled operations (e.g.
                                                // under secure fw)

        ExtVerifyParams(VerifyCallBack vFunc) :
            verifyCallBackFunc(vFunc),
            isStripedImage(false),
            showItoc(false),
            ignoreDToc(false),
            progressFuncAdv((ProgressCallBackAdvSt*)NULL){};
    };

    struct fwOpsParams
    {
        // COMMON
        char* psid; // can be NULL
        fw_hndl_type_t hndlType;
        char* errBuff;   // can be NULL
        int errBuffSize; // can be zero if above NULL
        // FHT_FW_FILE
        char* fileHndl;
        // FHT_FW_BUFF
        u_int32_t* buffHndl;
        u_int32_t buffSize;
        // FHT_UEFI_DEV
        uefi_Dev_t* uefiHndl;
        uefi_dev_extra_t uefiExtra;
        // FHT_MST_DEV
        char* mstHndl;
        bool forceLock;
        bool readOnly;
        int numOfBanks;              // should be set to -1 for "auto-detect"
        flash_params_t* flashParams; // can be NULL
        int ignoreCacheRep;
        bool noFlashVerify;
        bool shortErrors; // show short/long error msgs (default shuold be false)
        int cx3FwAccess;
        int isCableFw;
        bool noFwCtrl;
        bool mccUnsupported;
        bool canSkipFwCtrl;
        bool ignoreCrcCheck;
    };

    struct sgParams
    {
        bool updateCrc;    // default should be set to true
        bool stripedImage; // default shuold be set to false unless working on striped image file
        bool macsSpecified;
        bool guidsSpecified;
        bool uidSpecified; // valid for ConnectIB only
        std::vector<guid_t> userGuids;
        u_int8_t numOfGUIDs;      // number of GUIDs to allocate for each port. keep zero for default. (FS3 image Only)
        u_int8_t stepSize;        // step size between GUIDs. keep zero for default. (FS3 Image Only)
        bool usePPAttr;           // if set, use the per prot attributes below (FS3 Image Only)
        u_int8_t numOfGUIDsPP[2]; // number of GUIDs to allocate for each port. keep 0xff for default. (FS3 image Only)
        u_int8_t stepSizePP[2];   // step size between GUIDs. keep 0xff for default. (FS3 Image Only)
    };

protected:
#define FS3_IND_ADDR 0x24
#define FS4_IND_ADDR 0x10
#define ARR_SIZE(arr) sizeof(arr) / sizeof(arr[0])

    struct FwImgInfo
    {
        fw_info_com_t ext_info;
        u_int32_t imgStart;
        bool actuallyFailsafe;
        u_int32_t cntxLog2ChunkSize;
        u_int32_t bootSize;
        bool isGa;
        u_int32_t supportedHwId[MAX_NUM_SUPP_HW_IDS];
        int supportedHwIdNum;
        bool magicPatternFound;
        bool imageOk;
        bool wasQueried;
        u_int32_t lastImageAddr;
        fw_img_type_t fwType;
    };
    enum
    {
        OLD_CNTX_START_POS_SIZE = 6,
        CNTX_START_POS_SIZE = 10
    };
    enum
    {
        MAX_SW_DEVICES_PER_HW = 32
    };

    enum
    {
        IMG_VER_FS2 = 0,
        IMG_VER_FS3 = 3,
        IMG_VER_FS4 = 4
    };
    enum
    {
        FS_OLD_GEN = 0,
        FS_FS2_GEN,
        FS_FS3_GEN,
        FS_FS4_GEN,
        FS_FC1_GEN,
        FS_FSCTRL_GEN,
        FS_UNKNOWN_IMG
    };

    struct BinId2SwId
    {
        BinIdT binId;
        // Zero terminated list of SW device ids
        u_int32_t swId[MAX_SW_DEVICES_PER_HW];
    };

    struct HwDevData
    {
        const char* name;
        u_int32_t hwDevId;
        chip_type_t chipType;
        chip_family_type chipFamilyType;
        int portNum;
        // Zero terminated list of SW device ids
        const u_int32_t swDevIds[MAX_SW_DEVICES_PER_HW];
        // -1 terminated list of the bins of the device that match every SW ID
        const BinId2SwId binningId[MAX_SW_DEVICES_PER_HW];
    };

    struct HwDev2Str
    {
        const char* name;
        u_int32_t hwDevId;
        u_int8_t revId;
    };

    struct SectionInfo
    {
        u_int8_t type;
        const char* name;
    };

    struct QueryOptions
    {
        bool quickQuery;
        bool readRom;
    };

    class burnDataParamsT
    {
    public:
        u_int32_t* data;
        u_int32_t dataSize;
        ProgressCallBack progressFunc;
        bool calcSha;

        burnDataParamsT() : data((u_int32_t*)NULL), dataSize(0), progressFunc((ProgressCallBack)NULL), calcSha(false){};
    };

    typedef int (*print2log_func)(const char* format, ...);

    // Protected Methods
    static int GetFwVerFormat(u_int16_t fwVer[3]);
    virtual bool UpdateImgCache(u_int8_t* buff, u_int32_t addr, u_int32_t size);
    bool CheckAndPrintCrcRes(char* pr,
                             bool blank_crc,
                             u_int32_t off,
                             u_int32_t crc_act,
                             u_int32_t crc_exp,
                             bool ignore_crc = false,
                             VerifyCallBack verifyCallBackFunc = (VerifyCallBack)NULL);
    bool checkBoot2(u_int32_t beg,
                    u_int32_t offs,
                    u_int32_t& next,
                    bool fullRead,
                    const char* pref,
                    VerifyCallBack verifyCallBackFunc = (VerifyCallBack)NULL);
    u_int32_t CalcImageCRC(u_int32_t* buff, u_int32_t size);
    bool writeImage(ProgressCallBack progressFunc,
                    u_int32_t addr,
                    void* data,
                    int cnt,
                    bool isPhysAddr = false,
                    bool readModifyWrite = false,
                    int totalSz = -1,
                    int alreadyWrittenSz = 0);
    bool writeImageEx(ProgressCallBackEx progressFuncEx,
                      void* progressUserData,
                      ProgressCallBack progressFunc,
                      u_int32_t addr,
                      void* data,
                      int cnt,
                      bool isPhysAddr = false,
                      bool readModifyWrite = false,
                      int totalSz = -1,
                      int alreadyWrittenSz = 0,
                      bool cpuUtilization = false,
                      int cpuPercent = -1);
    //////////////////////////////////////////////////////////////////
    bool GetSectData(std::vector<u_int8_t>& file_sect, const u_int32_t* buff, const u_int32_t size);
    ////////////////////////////////////////////////////////////////////
    bool CheckMatchingDevId(u_int32_t hwDevId, u_int32_t imageDevId);
    bool CheckMatchingHwDevId(u_int32_t hwDevId, u_int32_t rev_id, u_int32_t* supportedHwId, u_int32_t supportedHwIdNum);
    bool CheckMatchingBinning(u_int32_t hwDevId, BinIdT binningVal, u_int32_t imageDevId);
    bool HWIdRevToName(u_int32_t hw_id, u_int8_t rev_id, char* hw_name);
    bool CheckMac(u_int64_t mac);
    bool CheckMac(guid_t mac);
    void recalcSectionCrc(u_int8_t* buf, u_int32_t data_size);
    void FwInitCom();
    void FwDebugPrint(char* str);

    static bool FindAllImageStart(FBase* ioAccess,
                                  u_int32_t start_locations[CNTX_START_POS_SIZE],
                                  u_int32_t* found_images,
                                  u_int32_t const cntx_magic_pattern[]);
    static bool getRomsInfo(FBase* io, roms_info_t& romsInfo);

    bool GetQuickQuery() { return _quickQuery; }
    bool CheckFwVersion(FwOperations& imgFwOps, u_int8_t forceVersion);
    bool CheckPSID(FwOperations& imageOps, u_int8_t allow_psid_change = false);
    chip_type_t getChipType();
    bool getInfoFromHwDevid(u_int32_t hwDevId, chip_type_t& chipT, const u_int32_t** swIds);
    HwDevData getInfoFromChipType(chip_type_t chipT) const;

    bool ReadBinFile(const char* fimage, u_int8_t*& file_data, int& file_size);
    bool FwBurnData(u_int32_t* data, u_int32_t dataSize, ProgressCallBack progressFunc);
    bool FwBurnData(burnDataParamsT& burnDataParams);
    static bool FwAccessCreate(fw_ops_params_t& fwParams, FBase** ioAccessP);
    bool CheckBinVersion(u_int8_t binVerMajor, u_int8_t binVerMinor);

    static u_int8_t GetFwFormatFromHwDevID(u_int32_t hwDevId);

    virtual Tlv_Status_t GetTsObj(TimeStampIFC** tsObj);
    bool TestAndSetTimeStamp(FwOperations* imageOps);
    virtual bool VerifyBranchFormat(const char* vsdString);

    // Protected Members
    FBase* _ioAccess;
    bool _isCached;
    FwImgInfo _fwImgInfo;
    fw_ops_params_t _fwParams;
    std::vector<u_int8_t> _romSect;
    std::vector<u_int8_t> _fwConfSect;
    std::vector<u_int8_t> _hashFileSect;
    std::vector<u_int8_t> _readSectList;
    bool _sectionsToRead[H_LAST];
    bool _wasVerified;
    bool _quickQuery;

    PrintCallBack _printFunc;
    const char* _fname;
    const char* _devName;
    // show advanced error msgs
    bool _advErrors;

    u_int8_t _minBinMinorVer;
    u_int8_t _minBinMajorVer;
    u_int8_t _maxBinMajorVer;
    ISignatureManager* _signatureMngr;
    bool _internalQueryPerformed;

private:
    // Static Methods
#ifndef NO_MFA_SUPPORT
    static int getMfaImgInner(char* fileName,
                              u_int8_t* mfa_buf,
                              int size,
                              char* psid,
                              u_int8_t** imgbuf,
                              char* errBuf,
                              int errBufSize);
    static int getMfaImg(char* fileName, char* psid, u_int8_t** imgbuf, char* errBuf, int errBufSize);
    static int getMfaImg(u_int8_t* mfa_buf, int size, char* psid, u_int8_t** imgbuf, char* errMsg, int errBufSize);
#endif

    static int getBufferSignature(u_int8_t* buf, u_int32_t size);
    static u_int8_t CheckFwFormat(FBase& f, bool getFwFormatFromImg = false);
    static u_int8_t IsFS4Image(FBase& f, u_int32_t* found_images);
    static u_int8_t IsFS3OrFS2Image(FBase& f, u_int32_t* found_images);
    static u_int8_t IsCableImage(FBase& f);
    static bool FindMagicPattern(FBase* ioAccess, u_int32_t addr, u_int32_t const cntx_magic_pattern[]);

    /* Name:        WriteToErrBuff
     * Description: Write a string into buffer.
     *              if buffer is null or smaller than string size,
     *              write "..." as at the end of the string.
     * @param[in] errBuff - pointer to dist error buffer
     * @param[in] errStr - pointer to source string
     * @param[in] bufSize - size of error buffer */
    static void WriteToErrBuff(char* errBuff, char* errStr, int bufSize);

    void BackUpFwParams(fw_ops_params_t& fwParams);
    // Methods

    // Static Members
    static const u_int32_t _cntx_image_start_pos[CNTX_START_POS_SIZE];

    // Members
    static const HwDevData hwDevData[];
    static const HwDev2Str hwDev2Str[];
    // fw_hndl_type_t _hndlType;  //not used atm

protected:
    static const u_int32_t _cntx_magic_pattern[4];
    static const u_int32_t _fs4_magic_pattern[4];
};

class CRSpaceRegisters
{
public:
    CRSpaceRegisters(mfile* mf, chip_type_t chip_type);

    int getGlobalImageStatus();
    life_cycle_t getLifeCycle();
    u_int32_t getSecurityVersion();

private:
    mfile* _mf;
    chip_type_t _chip_type;
    u_int32_t countSetBits(u_int32_t num);
    u_int32_t getConsecutiveBits(u_int32_t dword, u_int8_t firstBit, u_int8_t numOfBits);
    u_int32_t getRegister(u_int32_t address);
};

#endif // FW_ACCESS_H
