/*
*
* subcommands.cpp - FLash INTerface
*
* Copyright (c) 2013 Mellanox Technologies Ltd. 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#include <iostream>
#include <sstream>
#include <string>
#include <common/compatibility.h>
#include <fw_comps_mgr/fw_comps_mgr.h>
#include <mlxfwops/lib/fw_version.h>
#ifndef NO_ZLIB
#include <zlib.h>
#endif
#define MAX_IMG_TYPE_LEN 20
#if !defined(__WIN__) && !defined(__DJGPP__) && !defined(UEFI_BUILD) && defined(HAVE_TERMIOS_H)
// used in mygetchar
#include <termios.h>
#endif
#ifdef __WIN__
#include <ctype.h>
#include <win_driver_cif.h>
#endif // WIN
#include "subcommands.h"
#include "tools_layouts/cx4fw_layouts.h"
using namespace std;
#ifndef NO_MSTARCHIVE
using namespace mfa2;
#endif
/***********************************
* Log file writing implementation
************************************/
//global log file header
FILE *flint_log_fh = NULL;
#define BURN_INTERRUPTED 0x1234
void close_log()
{
if (flint_log_fh != NULL) {
fclose(flint_log_fh);
flint_log_fh = NULL;
}
return;
}
static const char* life_cycle_strings[NUM_OF_LIFE_CYCLES] = {
"PRODUCTION",
"GA SECURED",
"GA NON SECURED",
"RMA"
};
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
const char* month_2monstr(int month)
{
static const char *month_2monstr_arr[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
};
int arr_size = (int)ARRAY_SIZE(month_2monstr_arr);
return month < arr_size ? month_2monstr_arr[month] : "???";
}
void print_time_to_log()
{
time_t rawtime;
struct tm *timeinfo;
if (flint_log_fh == NULL) {
return;
}
time(&rawtime);
timeinfo = localtime(&rawtime);
if (!timeinfo) {
printf("localtime returned NULL. Can't print time.\n");
return;
}
fprintf(flint_log_fh, "%-3s %2d %02d:%02d:%02d ", month_2monstr(timeinfo->tm_mon), timeinfo->tm_mday,
timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
return;
}
int print_line_to_log(const char *format, ...)
{
va_list args;
if (flint_log_fh == NULL) {
return 0;
}
print_time_to_log();
va_start(args, format);
vfprintf(flint_log_fh, format, args);
va_end(args);
return 0;
}
int write_cmd_to_log(string fullCmd, sub_cmd_t cmd, bool write)
{
if (!write) {
return 0;
}
char pre_str[50];
if (flint_log_fh == NULL) {
return 0;
}
if (cmd == SC_Brom) {
snprintf(pre_str, 50, "ROM");
} else {
snprintf(pre_str, 50, "FW");
}
print_time_to_log();
fprintf(flint_log_fh, "Start %s burning: ", pre_str);
fprintf(flint_log_fh, "%s ", fullCmd.c_str());
fprintf(flint_log_fh, "\n");
return 0;
}
int write_result_to_log(int is_failed, const char *err_msg, bool write)
{
if (!write) {
return 0;
}
char msg[MAX_ERR_STR_LEN + 1] = {0};
strncpy(msg, err_msg, MAX_ERR_STR_LEN);
if (is_failed == 0) {
print_line_to_log("Burn completed successfully\n");
} else if (is_failed == BURN_INTERRUPTED) {
print_line_to_log("Burn interrupted by user\n");
} else {
int msg_len = strlen(msg);
// cleanup the msg
for (int i = 0; i < msg_len; i++) {
if (msg[i] == '\n') {
if (i == msg_len - 1) {
msg[i] = '\0';
} else {
msg[i] = ' ';
}
}
}
print_line_to_log("Burn failed: %s\n", msg);
}
return 0;
}
/*******************
* Static functions
******************/
static bool str2Num(const char *str, u_int32_t& num)
{
char *endp;
u_int32_t tempNum;
if (!str) {
return false;
}
tempNum = strtoul(str, &endp, 0);
if (*endp) {
return false;
}
num = tempNum;
return true;
}
/*******************
* Class: Subcommand
******************/
#define MAX_ERR_STR_LEN 1024
#define PRE_ERR_MSG "-E-"
bool SubCommand::isCmdSupportLog()
{
// a subcommand supports Logging if: A & B where:
// A. it is either Burn, Burn Block or Burn ROM.
// B. log flag was given in the cmd line.
switch (_cmdType) {
case SC_Burn:
case SC_Bb:
case SC_Brom:
return _flintParams.log_specified;
default:
return false;
}
return false;
}
void SubCommand::reportErr(bool shouldPrint, const char *format, ...)
{
va_list args;
va_start(args, format);
if (vsnprintf(_errBuff, FLINT_ERR_LEN, format, args) >= FLINT_ERR_LEN) {
strcpy(&_errBuff[FLINT_ERR_LEN - 5], "...\n");
}
//print to the user and to the log if needed
if (shouldPrint) {
fprintf(stdout, PRE_ERR_MSG " %s", _errBuff);
}
write_result_to_log(FLINT_FAILED, _errBuff, isCmdSupportLog());
va_end(args);
return;
}
bool SubCommand::writeToFile(string filePath, const std::vector<u_int8_t>& buff)
{
FILE *fh = fopen(filePath.c_str(), "wb");
if (fh == NULL) {
reportErr(true, FLINT_OPEN_FILE_ERROR, filePath.c_str(), strerror(errno));
return false;
}
// Write
if (fwrite(&buff[0], 1, buff.size(), fh) != buff.size()) {
fclose(fh);
reportErr(true, FLINT_WRITE_FILE_ERROR, filePath.c_str(), strerror(errno));
return false;
}
fclose(fh);
return true;
}
FlintStatus SubCommand::writeImageToFile(const char *file_name, u_int8_t *data, u_int32_t length)
{
FILE *fh = fopen(file_name, "wb");
if (fh == NULL) {
reportErr(true, "Can not open %s: %s\n", file_name, strerror(errno));
return FLINT_FAILED;
}
// Write output
if (fwrite(data, 1, length, fh) != length) {
fclose(fh);
reportErr(true, "Failed to write to %s: %s\n", file_name, strerror(errno));
return FLINT_FAILED;
}
fclose(fh);
return FLINT_SUCCESS;
}
void SubCommand::openLog()
{
if (isCmdSupportLog()) {
flint_log_fh = fopen(_flintParams.log.c_str(), "a+");
if (flint_log_fh == NULL) {
printf("-W- Failed to open log file \"%s\": %s. No logs will be saved\n", _flintParams.log.c_str()
, strerror(errno));
}
write_cmd_to_log(_flintParams.fullCmd, _flintParams.cmd, _flintParams.log_specified);
}
}
int SubCommand::verifyCbFunc(char *str)
{
printf("%s", str);
return 0;
}
int SubCommand::CbCommon(int completion, char *preStr, char *endStr)
{
if (completion < 100) {
printf("\r%s%3d%%", preStr, completion);
} else if (completion == 100) {
printf("\r%sOK \n", preStr);
} else { // printing endStr
if (endStr) {
printf("\r%s\n", endStr);
}
}
fflush(stdout);
return 0;
}
// HACK: the endStr is printed when we reach 101% this is for backward compat with the original flint
// output. thus in subcommands that use these callbacks you will see we manually call them at the end with the 101 arg
int SubCommand::burnCbFs3Func(int completion)
{
char *message = (char*)"Burning FW image without signatures - ";
char *endStr = (char*)"Restoring signature - OK";
return CbCommon(completion, message, endStr);
}
int SubCommand::advProgressFunc(int completion, const char *stage, prog_t type, int *unknownProgress)
{
switch (type) {
case PROG_WITH_PRECENTAGE:
printf("\r%s - %3d%%", stage, completion);
break;
case PROG_OK:
printf("\r%s - OK\n", stage);
break;
case PROG_STRING_ONLY:
printf("%s\n", stage);
break;
case PROG_WITHOUT_PRECENTAGE:
if (unknownProgress) {
static const char *progStr[] = { "[. ]", "[.. ]", "[... ]", "[.... ]", "[.....]", "[ ....]", "[ ...]", "[ ..]", "[ .]", "[ ]" };
int size = sizeof(progStr) / sizeof(progStr[0]);
printf("\r%s - %s", stage, progStr[(*unknownProgress) % size]);
(*unknownProgress)++;
}
break;
}
fflush(stdout);
return 0;
}
int SubCommand::burnCbFs2Func(int completion)
{
char *message = (char*)"Burning FS2 FW image without signatures - ";
char *endStr = (char*)"Restoring signature - OK";
if (completion == 102) {
endStr = (char*)"Image was successfully cached by driver.";
}
return CbCommon(completion, message, endStr);
}
int SubCommand::bromCbFunc(int completion)
{
char *message = (char*)"Burning ROM image - ";
char *endStr = (char*)"Restoring signature - OK";
return CbCommon(completion, message, endStr);
}
int SubCommand::dromCbFunc(int completion)
{
char *message = (char*)"Removing ROM image - ";
char *endStr = (char*)"Restoring signature - OK";
return CbCommon(completion, message, endStr);
}
int SubCommand::resetCfgCbFunc(int completion)
{
char *message = (char*)"Resetting NV configuration - ";
char *endStr = (char*)"Restoring signature - OK";
return CbCommon(completion, message, endStr);
}
int SubCommand::burnBCbFunc(int completion)
{
return CbCommon(completion, (char*)"");
}
int SubCommand::vsdCbFunc(int completion)
{
char *message = (char*)"Setting the VSD - ";
char *endStr = (char*)"Restoring signature - OK";
return CbCommon(completion, message, endStr);
}
int SubCommand::setKeyCbFunc(int completion)
{
char *message = (char*)"Setting the HW Key - ";
char *endStr = (char*)"Restoring signature - OK";
return CbCommon(completion, message, endStr);
}
int SubCommand::wbCbFunc(int completion)
{
char *message = (char*)"Writing Block: - ";
return CbCommon(completion, message, NULL);
}
#define ERR_BUFF_SIZE 1024
void SubCommand::initDeviceFwParams(char *errBuff, FwOperations::fw_ops_params_t& fwParams)
{
memset(&fwParams, 0, sizeof(FwOperations::fw_ops_params_t));
fwParams.errBuff = errBuff;
fwParams.errBuffSize = ERR_BUFF_SIZE;
fwParams.flashParams = _flintParams.flash_params_specified ? &_flintParams.flash_params : NULL;
fwParams.forceLock = _flintParams.clear_semaphore;
fwParams.hndlType = FHT_MST_DEV;
fwParams.ignoreCacheRep = _flintParams.override_cache_replacement ? 1 : 0;
fwParams.mstHndl = strcpy(new char[_flintParams.device.length() + 1], _flintParams.device.c_str());
fwParams.numOfBanks = _flintParams.banks;
fwParams.readOnly = false;
fwParams.noFlashVerify = _flintParams.no_flash_verify;
fwParams.cx3FwAccess = _flintParams.use_fw;
fwParams.noFwCtrl = _flintParams.no_fw_ctrl;
fwParams.mccUnsupported = !_mccSupported;
}
FlintStatus SubCommand::openOps(bool ignoreSecurityAttributes, bool ignoreDToc)
{
char errBuff[ERR_BUFF_SIZE] = {0};
if (_flintParams.device_specified) {
// fillup the fw_ops_params_t struct
FwOperations::fw_ops_params_t fwParams;
initDeviceFwParams(errBuff, fwParams);
if (_flintParams.image_specified) {
FwOperations::fw_ops_params_t imgFwParams;
memset(&imgFwParams, 0, sizeof(imgFwParams));
imgFwParams.psid = NULL;
imgFwParams.hndlType = FHT_FW_FILE;
imgFwParams.errBuff = errBuff;
imgFwParams.errBuffSize = 1024;
imgFwParams.shortErrors = true;
imgFwParams.fileHndl = (char*)_flintParams.image.c_str();
if (!FwOperations::imageDevOperationsCreate(fwParams, imgFwParams, &_fwOps, &_imgOps, ignoreSecurityAttributes, ignoreDToc)) {
/*
* Error are being handled after
*/
}
} else {
_fwOps = FwOperations::FwOperationsCreate(fwParams);
}
delete[] fwParams.mstHndl;
}
if (_flintParams.image_specified && !_flintParams.device_specified) {
_imgOps = FwOperations::FwOperationsCreate((void*)_flintParams.image.c_str(), NULL, NULL, \
FHT_FW_FILE, errBuff, 1024);
}
if (_flintParams.image_specified && _imgOps == NULL) {
reportErr(true, FLINT_OPEN_FWOPS_IMAGE_ERROR, _flintParams.image.c_str(), strlen(errBuff) != 0 ? errBuff : "");
return FLINT_FAILED;
}
if (_flintParams.device_specified && _fwOps == NULL) {
if (_flintParams.silent == false) {
reportErr(true, FLINT_OPEN_FWOPS_DEVICE_ERROR, _flintParams.device.c_str(), strlen(errBuff) != 0 ? errBuff : "");
}
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
FlintStatus SubCommand::openIo()
{
//TODO: consider adding a parameter for when image/device will be opened as "readOnly" in the open routine.
if (_flintParams.device_specified && _flintParams.image_specified) {
//should not arrive here as we verify params at each subcommand.
reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR);
return FLINT_FAILED;
}
if (_flintParams.device_specified) {
_io = new Flash;
if (!((Flash*)_io)->open(_flintParams.device.c_str(), _flintParams.clear_semaphore, false, _flintParams.banks, \
_flintParams.flash_params_specified ? &_flintParams.flash_params : NULL, _flintParams.override_cache_replacement, true, _flintParams.use_fw)) {
// if we have Hw_Access command we dont fail straght away
u_int8_t lockedCrSpace = ((Flash*)_io)->get_cr_space_locked();
if (lockedCrSpace && (_flintParams.cmd == SC_Hw_Access ||
(_flintParams.cmd == SC_Set_Key && ((Flash*)_io)->is_fifth_gen()))) {
return FLINT_SUCCESS;
}
reportErr(true, FLINT_IO_OPEN_ERROR, "Device", (_io)->err());
delete _io;
_io = NULL;
return FLINT_FAILED;
}
// we have successfully opened a Flash Obj
//set no flash verify if needed (default =false)
((Flash*)_io)->set_no_flash_verify(_flintParams.no_flash_verify);
} else if (_flintParams.image_specified) {
_io = new FImage;
if (!((FImage*)_io)->open(_flintParams.image.c_str())) {
reportErr(true, FLINT_IO_OPEN_ERROR, "Image", (_io)->err());
delete _io;
_io = NULL;
return FLINT_FAILED;
}
}
return FLINT_SUCCESS;
}
bool SubCommand::basicVerifyParams()
{
if (!_flintParams.log_specified) {
char *logFile;
logFile = getenv(FLINT_LOG_ENV);
if (logFile) {
_flintParams.log = logFile;
_flintParams.log_specified = true;
}
}
//open log if needed
openLog();
if (_maxCmdParamNum == _minCmdParamNum && _maxCmdParamNum != -1 && (int)_flintParams.cmd_params.size() != _maxCmdParamNum) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), _maxCmdParamNum, _flintParams.cmd_params.size());
return false;
} else if (_maxCmdParamNum != -1 && (int)_flintParams.cmd_params.size() > _maxCmdParamNum) {
// _maxCmdParamNum == -1 means ignore this check
if (_maxCmdParamNum) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), _maxCmdParamNum, _flintParams.cmd_params.size());
} else {
reportErr(true, FLINT_CMD_ARGS_ERROR5, _name.c_str());
}
return false;
} else if (_minCmdParamNum != -1 && (int)_flintParams.cmd_params.size() < _minCmdParamNum) {
// _minCmdParamNum == -1 means ignore this check
reportErr(true, FLINT_CMD_ARGS_ERROR3, _name.c_str(), _minCmdParamNum, _flintParams.cmd_params.size());
return false;
}
switch (_v) {
case Wtv_Img:
if (_flintParams.device_specified == true) {
_flintParams.image_specified ? reportErr(true, FLINT_COMMAND_IMAGE_ERROR2, _name.c_str()) :
reportErr(true, FLINT_COMMAND_IMAGE_ERROR, _name.c_str());
return false;
}
if (_flintParams.image_specified == false) {
reportErr(true, FLINT_NO_IMAGE_ERROR);
return false;
}
break;
case Wtv_Dev:
if (_flintParams.image_specified == true) {
_flintParams.device_specified ? reportErr(true, FLINT_COMMAND_DEVICE_ERROR2, _name.c_str()) :
reportErr(true, FLINT_COMMAND_DEVICE_ERROR, _name.c_str());
return false;
}
if (_flintParams.device_specified == false) {
reportErr(true, FLINT_NO_DEVICE_ERROR);
return false;
}
break;
case Wtv_Dev_And_Img:
if ((_flintParams.image_specified == false) || (_flintParams.device_specified == false)) {
reportErr(true, FLINT_COMMAND_DEVICE_IMAGE_ERROR, _name.c_str());
return false;
}
break;
case Wtv_Dev_Or_Img:
if (_flintParams.image_specified == true && _flintParams.device_specified == true) {
reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR);
return false;
}
if (_flintParams.device_specified == false && _flintParams.image_specified == false) {
reportErr(true, FLINT_DEVICE_AND_IMAGE_ERROR);
return false;
}
break;
default:
reportErr(true, "Failed to verify parms(internal error).");
return false;
}
if (_flintParams.device_specified && _flintParams.striped_image) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-device", "-striped_image");
return false;
}
if (_flintParams.override_cache_replacement) {
printf(FLINT_OCR_WARRNING);
}
return true;
}
FlintStatus SubCommand::preFwOps(bool ignoreSecurityAttributes, bool ignoreDToc)
{
if (!basicVerifyParams()) {
return FLINT_FAILED;
}
if (!verifyParams()) {
return FLINT_FAILED;
}
if (_flintParams.mfa2_specified) {
bool saved_value = _flintParams.image_specified;
_flintParams.image_specified = false;
FlintStatus result = openOps(true);
_flintParams.image_specified = saved_value;
return result;
}
else {
return openOps(ignoreSecurityAttributes, ignoreDToc);
}
}
FlintStatus SubCommand::preFwAccess()
{
if (!basicVerifyParams()) {
return FLINT_FAILED;
}
if (!verifyParams()) {
return FLINT_FAILED;
}
return openIo();
}
SubCommand::~SubCommand()
{
if (_fwOps != NULL) {
_fwOps->FwCleanUp();
delete _fwOps;
}
if (_imgOps != NULL) {
_imgOps->FwCleanUp();
delete _imgOps;
}
if (_io != NULL) {
_io->close();
delete _io;
}
}
bool SubCommand::getRomsInfo(FBase *io, roms_info_t& romsInfo)
{
std::vector<u_int8_t> romSector;
romSector.clear();
romSector.resize(io->get_size());
if (!io->read(0, &romSector[0], io->get_size())) {
reportErr(true, FLINT_READ_ERROR, _flintParams.image.c_str(), io->err());
return false;
}
FwOperations::RomInfo info(romSector, false);
info.ParseInfo();
info.initRomsInfo(&romsInfo);
return true;
}
bool SubCommand::getGUIDFromStr(string str, guid_t& guid, string prefixErr)
{
char *endp;
u_int64_t g;
g = strtoull(str.c_str(), &endp, 16);
if (*endp || (g == 0xffffffffffffffffULL && errno == ERANGE)) {
if (prefixErr.size() == 0) {
reportErr(true, "Invalid GUID syntax (%s) %s\n", str.c_str(), errno ? strerror(errno) : "");
} else {
reportErr(true, "%s\n", prefixErr.c_str());
}
return false;
}
guid.h = (u_int32_t)(g >> 32);
guid.l = (u_int32_t)(g & 0xffffffff);
return true;
}
#if !defined(__WIN__) && !defined(__DJGPP__) && !defined(UEFI_BUILD) && defined(HAVE_TERMIOS_H)
static int mygetch(void)
{
struct termios oldt,
newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
bool SubCommand::getPasswordFromUser(const char *preStr, char buffer[MAX_PASSWORD_LEN + 1])
{
char c;
int pos = 0;
printf("%s: ", preStr);
do {
c = mygetch();
if (((pos < MAX_PASSWORD_LEN)) && isprint(c)) {
buffer[pos++] = c;
printf("%c", '*');
} else if ((c == 8 || c == 127) && pos) {
buffer[pos--] = '\0';
printf("%s", "\b \b");
}
} while (c != '\n');
printf("\n");
buffer[pos] = '\0';
return true;
}
#else
bool SubCommand::getPasswordFromUser(const char *preStr, char buffer[MAX_PASSWORD_LEN + 1])
{
static HANDLE stdinHndl = NULL;
DWORD numOfBytesRead = 0;
DWORD oldConsoleMode, consoleMode;
BOOL status = FALSE;
char ch;
int i;
if (!stdinHndl) {
// adrianc: this might be problematic if called and stdout was alreading overridden use CIN$ instead
stdinHndl = GetStdHandle(STD_INPUT_HANDLE);
}
printf("%s:", preStr);
// disable console echoing
if (!GetConsoleMode(stdinHndl, &oldConsoleMode)) {
reportErr(true, "Failed to get console mode.\n");
return false;
}
consoleMode = oldConsoleMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
if (!SetConsoleMode(stdinHndl, consoleMode)) {
reportErr(true, "Failed to set console mode.\n");
return 1;
}
// read chars from stdin and print * to stdout using putchar
for (i = 0;;) {
status = ReadFile(stdinHndl, &ch, sizeof(char), &numOfBytesRead, NULL);
if (!status || numOfBytesRead != sizeof(char) || ch == '\n' || ch == '\r' || i == (MAX_PASSWORD_LEN - 1)) {
// user finished giving the pw
if (!SetConsoleMode(stdinHndl, oldConsoleMode)) {
reportErr(true, "Failed to restore console mode.\n");
return false;
}
if (!status || numOfBytesRead != sizeof(char)) {
reportErr(true, "Failed to get input from console.\n");
return false;
}
break;
}
if (isalpha(ch) || isdigit(ch)) {
putchar('*');
buffer[i++] = ch;
} else if (ch == '\b' && i) {
//delete last astrix and set correct position
printf("\b \b");
i--;
}
}
buffer[i] = '\0';
putchar('\n');
return true;
}
#endif
//
// Asks user a yes/no question.
// Returns true if user chose Y, false if user chose N.
//
bool SubCommand::askUser(const char *question, bool printAbrtMsg)
{
if (question == NULL) {
printf("\n Do you want to continue ? (y/n) [n] : ");
} else {
printf("\n %s ? (y/n) [n] : ", question);
}
if (_flintParams.yes) {
printf("y\n");
} else {
if (_flintParams.no) {
printf("n\n");
reportErr(false, "-no flag is set\n");
return false;
}
fflush(stdout);
std::string answer;
std::getline(std::cin, answer);
//fgets(ansbuff, 30, stdin);
//if (!fscanf(stdin, "%[^\n]30s", ansbuff)) {
// return false;
//}
if (strcasecmp(answer.c_str(), "y") &&
strcasecmp(answer.c_str(), "yes")) {
if (printAbrtMsg) {
reportErr(true, "Aborted by user\n");
}
return false;
}
}
return true;
}
string SubCommand::getRomProtocolStr(u_int8_t proto)
{
string result;
switch (proto) {
case ER_IB:
result = "IB";
break;
case ER_ETH:
result = "ETH";
break;
case ER_VPI:
result = "VPI";
break;
default:
result = "N/A";
}
return result;
}
string SubCommand::getRomSuppCpuStr(u_int8_t suppCpu)
{
string result;
switch (suppCpu) {
case ERC_AMD64:
result = "AMD64";
break;
case ERC_AARCH64:
result = "AARCH64";
break;
case ERC_AMD64_AARCH64:
result = "AMD64,AARCH64";
break;
case ERC_IA32:
result = "IA32";
break;
default:
result = "N/A";
}
return result;
}
string SubCommand::getExpRomVerStr(const rom_info_t& info)
{
stringstream verStream;
if (info.exp_rom_num_ver_fields) {
for (int i = 0; i < info.exp_rom_num_ver_fields; i++) {
verStream << info.exp_rom_ver[i];
if (i + 1 < info.exp_rom_num_ver_fields) {
verStream << ".";
}
}
}
return verStream.str();
}
void SubCommand::displayOneExpRomInfo(const rom_info_t& info)
{
const char *typeStr = FwOperations::expRomType2Str(info.exp_rom_product_id);
if (info.exp_rom_product_id == 0xf) {
// version id in this case is the freeStr that was moved to exp_rom_ver[0] in mlxfwops
printf("version_id=%s type=%s ", getExpRomVerStr(info).c_str(), typeStr);
} else {
if (typeStr) {
printf("type=%s ", typeStr);
} else {
printf("0x%x - Unknown ROM product ID\n", info.exp_rom_product_id);
return;
}
printf("version=%s", getExpRomVerStr(info).c_str());
if (info.exp_rom_product_id >= 0x10) {
if (info.exp_rom_port) {
// Do not display if 0 - port independent
printf(" port=%d", info.exp_rom_port);
}
if (info.exp_rom_product_id != 0x12 && info.exp_rom_proto != 0xff) {
// on CLP(0x12) there is no meaning to protocol
printf(" proto=%s", getRomProtocolStr(info.exp_rom_proto).c_str());
}
if (info.exp_rom_supp_cpu_arch) {
printf(" cpu=%s", getRomSuppCpuStr(info.exp_rom_supp_cpu_arch).c_str());
}
}
}
return;
}
void SubCommand::displayExpRomInfo(const roms_info_t& romsInfo, const char *preStr)
{
int i;
int strLen = strlen(preStr);
if (romsInfo.num_of_exp_rom > 0) {
for (i = 0; i < romsInfo.num_of_exp_rom; i++) {
// Print the pre string or spaces
if (i == 0) {
printf("%s", preStr);
} else {
int j;
for (j = 0; j < strLen; j++) {
printf("%s", " ");
}
}
// Display a ROM info
displayOneExpRomInfo(romsInfo.rom_info[i]);
if (i != romsInfo.num_of_exp_rom - 1) {
// Don't print new line after the info of the last ROM
printf("\n");
}
}
if (romsInfo.exp_rom_warning) {
printf(" (-W- %s)", romsInfo.exp_rom_warning_msg);
}
printf("\n");
} else {
printf("%s", preStr);
printf("N/A");
if (romsInfo.exp_rom_err_msg_valid) {
printf(" (-E- %s)", romsInfo.exp_rom_err_msg);
}
printf("\n");
}
return;
}
bool SubCommand::printGuidLine(guid_t *new_guids, guid_t *old_guids, int guid_index)
{
printf(GUID_FORMAT GUID_SPACES, new_guids[guid_index].h, new_guids[guid_index].l);
if (old_guids != NULL) {
printf(GUID_FORMAT, old_guids[guid_index].h, old_guids[guid_index].l);
} else {
printf(" N/A");
}
printf("\n");
return true;
}
bool SubCommand::printMacLine(guid_t *new_guids, guid_t *old_guids, int mac_index)
{
printf(" " MAC_FORMAT MAC_SPACES, new_guids[mac_index].h, new_guids[mac_index].l);
if (old_guids != NULL) {
printf(MAC_FORMAT, old_guids[mac_index].h, old_guids[mac_index].l);
} else {
printf(" N/A");
}
printf("\n");
return true;
}
bool SubCommand::printGUIDsFunc(guid_t guids[GUIDS], guid_t macs[MACS], guid_t old_guids[GUIDS], \
guid_t old_macs[MACS], bool print_guids, bool print_macs, int portNum, bool old_guid_fmt)
{
if (print_guids) {
printf(" Node GUID: ");
printGuidLine(guids, old_guids, 0);
if (portNum > 0) {
printf(" Port1 GUID: ");
printGuidLine(guids, old_guids, 1);
}
if (portNum > 1) {
printf(" Port2 GUID: ");
printGuidLine(guids, old_guids, 2);
}
if (!old_guid_fmt) {
printf(" Sys.Image GUID: ");
printGuidLine(guids, old_guids, 3);
}
}
if (print_macs) {
printf(" Port1 MAC: ");
printMacLine(macs, old_macs, 0);
printf(" Port2 MAC: ");
printMacLine(macs, old_macs, 1);
}
return true;
}
bool SubCommand::reportGuidChanges(guid_t *new_guids, guid_t *new_macs, \
guid_t *old_guids, guid_t *old_macs, bool printGuids, \
bool printMacs, int guidNum)
{
//should be used ONLY on FS2 in current implementation
printf(" You are about to change the Guids/Macs/Uids on the %s:\n\n", _flintParams.device_specified ? "device" : "image");
printf(" New Values " GUID_SPACES "Current Values\n");
printGUIDsFunc(new_guids, new_macs,
old_guids, old_macs,
printGuids,
printMacs,
guidNum,
guidNum < GUIDS);
if (!askUser()) {
return false;
}
return true;
}
//used for dc and dh subcommands
bool SubCommand::unzipDataFile(std::vector<u_int8_t> data, std::vector<u_int8_t> &newData, const char *sectionName)
{
#ifndef NO_ZLIB
int rc;
if (data.empty()) {
reportErr(true, "%s section not found in the given image.", sectionName);
return false;
}
// restore endianess.
TOCPUn(&(data[0]), data.size() / 4);
// uncompress:
uLongf destLen = data.size();
destLen *= 40; // Assuming this is the best compression ratio
vector<u_int8_t> dest(destLen);
for (int i = 0; i < 32; i++) {
rc = uncompress((Bytef*)&(dest[0]), &destLen,
(const Bytef*)&(data[0]), data.size());
if (rc != Z_BUF_ERROR) {
break;
}
destLen *= 2;
dest.resize(destLen);
}
if (rc != Z_OK) {
reportErr(true, "Failed uncompressing FW configuration section. uncompress returns %d", rc);
return false;
}
// printf("%s", (char*)&(dest[0]));
newData = dest;
newData[destLen] = 0; // Terminating NULL
newData.resize(destLen + 1);
return true;
#else
// avoid warnings
(void) data;
(void) newData;
(void) sectionName;
reportErr(true, FLINT_NO_ZLIB_ERROR);
return false;
#endif
}
bool SubCommand::dumpFile(const char *confFile, std::vector<u_int8_t>& data, const char *sectionName)
{
FILE *out;
vector<u_int8_t> dest;
if (confFile == NULL) {
out = stdout;
} else {
out = fopen(confFile, "w");
if (out == NULL) {
reportErr(true, "Can not open file %s for write: %s.", confFile, strerror(errno));
return false;
}
}
if (unzipDataFile(data, dest, sectionName) == false) {
if (confFile != NULL) {
fclose(out);
}
return false;
}
fprintf(out, "%s", (char*)&(dest[0]));
if (confFile != NULL) {
fclose(out);
}
return true;
}
bool SubCommand::checkGuidsFlags(u_int16_t devType, u_int8_t fwType,
bool guidsSpecified, bool macsSpecified, bool uidSpecified, bool ibDev, bool ethDev)
{
(void)ibDev;
if (guidsSpecified || macsSpecified || uidSpecified) {
if (uidSpecified && fwType != FIT_FS3 && fwType != FIT_FS4 && fwType != FIT_FSCTRL) {
reportErr(true, "-uid flag is applicable only for FS3/FS4 FW Only.\n");
return false;
} else if (fwType != FIT_FS2 && !ethDev && macsSpecified) {
reportErr(true, "-mac(s) flag is not applicable for IB MT%d device.\n", devType);
return false;
}
}
return true;
}
void SubCommand::printMissingGuidErr(bool ibDev, bool ethDev)
{
const char *missingInfo;
const char *missingFlags;
if (ibDev && ethDev) {
missingInfo = "GUIDs / MACs";
missingFlags = "-guid(s) / -mac(s)";
} else if (ibDev) {
missingInfo = "GUIDs";
missingFlags = "-guid(s)";
} else {
missingInfo = "MACs";
missingFlags = "-mac(s)";
}
printf("Please specify %s (using command line flags %s ).\n", missingInfo, missingFlags);
return;
}
bool SubCommand::extractValuesFromString(string valStr, u_int8_t values[2], string origArg)
{
// check if we need to extract 2 values or 1
u_int32_t tempNum0 = 0, tempNum1 = 0;
string tempNumStr;
if (valStr.find(',') != string::npos) {
std::stringstream ss((valStr.c_str()));
// get first value
if (!std::getline(ss, tempNumStr, ',')) {
reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str());
return false;
}
if (!str2Num(tempNumStr.c_str(), tempNum0)) {
reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str());
return false;
}
// get second value
if (!std::getline(ss, tempNumStr, ',')) {
reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str());
return false;
}
if (!str2Num(tempNumStr.c_str(), tempNum1)) {
reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str());
return false;
}
// make sure no other tokens are present
if (!(!std::getline(ss, tempNumStr, ','))) {
reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str());
return false;
}
} else {
if (!str2Num(valStr.c_str(), tempNum0)) {
reportErr(true, FLINT_INVALID_ARG_ERROR, origArg.c_str());
return false;
}
tempNum1 = tempNum0;
}
// perform checks
if (tempNum0 >= 255 || tempNum1 >= 255) {
reportErr(true, "Invalid argument values, values should be taken from the range [0..254]\n");
return false;
}
values[0] = tempNum0;
values[1] = tempNum1;
return true;
}
bool SubCommand::extractUIDArgs(std::vector<string>& cmdArgs, u_int8_t numOfGuids[2], u_int8_t stepSize[2])
{
//extract num_of_guids and step_size from numGuidsStr, stepStr
string tag, valStr;
for (std::vector<string>::iterator it = cmdArgs.begin(); it != cmdArgs.end(); it++) {
std::stringstream ss((it->c_str()));
// get the tag
if (!std::getline(ss, tag, '=')) {
reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str());
return false;
}
// get the val
if (!std::getline(ss, valStr, '=')) {
reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str());
return false;
}
// make sure no other tokens are present
if (!(!std::getline(ss, valStr, '='))) {
reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str());
return false;
}
if (tag == "guids_num") {
if (!extractValuesFromString(valStr, numOfGuids, *it)) {
return false;
}
} else if (tag == "step_size") {
if (!extractValuesFromString(valStr, stepSize, *it)) {
return false;
}
} else {
reportErr(true, FLINT_INVALID_ARG_ERROR, it->c_str());
return false;
}
}
return true;
}
const char* SubCommand::fwImgTypeToStr(u_int8_t fwImgType)
{
switch (fwImgType) {
case FIT_FS2:
return "FS2";
break;
case FIT_FS3:
return "FS3";
break;
case FIT_FS4:
return "FS4";
break;
case FIT_FSCTRL:
return "FSCTRL";
break;
default:
return "Unknown";
break;
}
}
/***************************
* Extract4MBImageSubCommand
***********************/
Extract4MBImageSubCommand::Extract4MBImageSubCommand()
{
_name = "extract_fw_data";
_desc = "Extract firmware data for firmware controlled updates";
_extendedDesc = "Extract 4MB firmware image file for firmware controlled updates. "
"The extracted data will have the image signature and the device ToCs "
"overwritten with 0xFF";
_flagLong = "extract_fw_data";
_param = "<out-file>";
_paramExp = "file - filename to write the extracted data";
_example = FLINT_NAME " -i fw_image.bin extract_fw_data outputfile.bin";
_v = Wtv_Img;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Extract_4MB_Image;
}
Extract4MBImageSubCommand::~Extract4MBImageSubCommand()
{
}
FlintStatus Extract4MBImageSubCommand::executeCommand()
{
vector<u_int8_t> img;
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_imgOps->FwType() == FIT_FS2) {
reportErr(true, "Extracting FW Data is applicable only for FS3/FS4 FW.\n");
return FLINT_FAILED;
}
if (!_imgOps->FwExtract4MBImage(img, true)) {
reportErr(true, "Extracting FW Data failed: %s.\n", _imgOps->err());
return FLINT_FAILED;
}
if (!writeToFile(_flintParams.cmd_params[0], img)) {
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* * Class: AddHmacSubCommand
* ***********************/
AddHmacSubCommand::AddHmacSubCommand()
{
_name = "sign_with_hmac";
_desc = "Sign image with HMAC";
_extendedDesc = "Sign image with HMAC";
_flagLong = "sign_with_hmac";
_flagShort = "";
_paramExp = "None";
_example = FLINT_NAME " -i fw_image.bin --hmac_key hmac_key_file sign_with_hmac";
_v = Wtv_Img;
_maxCmdParamNum = 0;
_cmdType = SC_Add_Hmac;
}
AddHmacSubCommand:: ~AddHmacSubCommand()
{
}
FlintStatus AddHmacSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_imgOps->FwType() != FIT_FS4) {
reportErr(true, "Signing with HMAC is applicable only for FS4 FW.\n");
return FLINT_FAILED;
}
if (!_imgOps->FwSignWithHmac(_flintParams.key.c_str())) {
reportErr(true, FLINT_HMAC_ERROR, _imgOps->err());
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
bool AddHmacSubCommand::verifyParams()
{
if (!_flintParams.key_specified) {
reportErr(true, "To sign with HMAC, you must provide a key \n");
return false;
}
if (_flintParams.cmd_params.size() > 0) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 1,
(int)_flintParams.cmd_params.size());
return false;
}
return true;
}
/***********************
* Class: SignSubCommand
***********************/
SignSubCommand::SignSubCommand()
{
_name = "sign";
_desc = "Sign firmware image file";
_extendedDesc = "Sign firmware image file";
_flagLong = "sign";
_flagShort = "";
_paramExp = "None";
_example = FLINT_NAME " -i fw_image.bin [--private_key file.pem --key_uuid uuid string] sign";
_v = Wtv_Img;
_maxCmdParamNum = 0;
_cmdType = SC_Sign;
}
SignSubCommand:: ~SignSubCommand()
{
}
FlintStatus SignSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_imgOps->FwType() != FIT_FS3 && _imgOps->FwType() != FIT_FS4) {
reportErr(true, "Image signing is applicable only for FS3/FS4 FW.\n");
return FLINT_FAILED;
}
if (_flintParams.privkey_specified && _flintParams.uuid_specified) {
if (_flintParams.privkey2_specified && _flintParams.uuid2_specified) {
if (!_imgOps->FwSignWithTwoRSAKeys(_flintParams.privkey_file.c_str(),
_flintParams.privkey_uuid.c_str(),
_flintParams.privkey2_file.c_str(),
_flintParams.privkey2_uuid.c_str(),
&verifyCbFunc)) {
reportErr(true, FLINT_SIGN_ERROR, _imgOps->err());
return FLINT_FAILED;
}
} else {
if (!_imgOps->FwSignWithOneRSAKey(_flintParams.privkey_file.c_str(),
_flintParams.privkey_uuid.c_str(),
&verifyCbFunc)) {
reportErr(true, FLINT_SIGN_ERROR, _imgOps->err());
return FLINT_FAILED;
}
}
} else {
if (!_imgOps->FwInsertSHA256(&verifyCbFunc)) {
reportErr(true, FLINT_SIGN_ERROR, _imgOps->err());
return FLINT_FAILED;
}
}
return FLINT_SUCCESS;
}
bool SignSubCommand::verifyParams()
{
if (_flintParams.privkey_specified ^ _flintParams.uuid_specified) {
reportErr(true, "To Sign the image with RSA you must provide "
"private key and uuid.\n");
return false;
}
if (!_flintParams.privkey_specified && _flintParams.privkey2_specified) {
reportErr(true, "Use --private_key if you want to sign with only one key.\n");
return false;
}
if (_flintParams.privkey2_specified ^ _flintParams.uuid2_specified) {
reportErr(true, "To Sign the image with two RSA keys you must provide "
"two private keys and two uuid.\n");
return false;
}
if (_flintParams.cmd_params.size() > 0) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 1,
(int)_flintParams.cmd_params.size());
return false;
}
return true;
}
BinaryCompareSubCommand::BinaryCompareSubCommand()
{
_name = "Binary compare";
_desc = "Binary compare between device firmware and given BIN file. If there is a silent mode, no progress is displayed.";
_extendedDesc = _desc;
_flagLong = "binary_compare";
_flagShort = "bc";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " -i image1.bin <-silent>/<-s> (optional) bc \n";
_v = Wtv_Dev_And_Img;
_maxCmdParamNum = 1;
_minCmdParamNum = 0;
_cmdType = SC_Binary_Compare;
_fwType = 0;
_devQueryRes = 0;
_mccSupported = false;
memset(&_devInfo, 0, sizeof(_devInfo));
memset(&_imgInfo, 0, sizeof(_imgInfo));
_unknownProgress = 0;
}
BinaryCompareSubCommand:: ~BinaryCompareSubCommand()
{
#ifndef NO_MSTARCHIVE
if (_mfa2Pkg != NULL) {
delete _mfa2Pkg;
}
#endif
}
bool BinaryCompareSubCommand::verifyParams()
{
if (_flintParams.num_of_args == 2) {
return true;
}
else if (_flintParams.num_of_args == 3 && _flintParams.silent == true) {
return true;
}
else {
fprintf(stdout, "The binary comparison command doesn't accept any flags, except device, image and silent mode.\n");
return false;
}
}
FlintStatus BinaryCompareSubCommand::compareMFA2()
{
#ifndef NO_MSTARCHIVE
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
mfile *mf = _fwOps->getMfileObj();
int is_livefish_mode = dm_is_livefish_mode(mf);
if (is_livefish_mode == 1) {
_flintParams.override_cache_replacement = true;
}
if (!_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "Device", _flintParams.device.c_str(), _fwOps->err());
return FLINT_FAILED;
}
vector<u_int8_t> componentBuffer;
map_string_to_component matchingComponentsMap = _mfa2Pkg->getMatchingComponents((char*)_devInfo.fw_info.psid, _devInfo.fw_info.fw_ver[0]);
u_int32_t matchingSize = matchingComponentsMap.size();
if (matchingSize == 0) {
printf("\33[2K\r");//clear the current line
reportErr(true, "CompareMFA2 : No matching component found for device.\n");
return FLINT_FAILED;
}
std::vector<u_int8_t> imgBuffInFile;
if (!_fwOps->FwExtract4MBImage(imgBuffInFile, true, (_flintParams.silent == false))) {
reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err());
return FLINT_FAILED;
}
for (u_int32_t choice = 0; choice < matchingSize; choice++) {
if (_mfa2Pkg->unzipComponent(matchingComponentsMap, choice, componentBuffer) == false) {
reportErr(true, "CompareMFA2 : Error occurred while extracting MFA2\n");
return FLINT_FAILED;
}
unsigned int i = 0;
for (; i < imgBuffInFile.size(); i++) {
if (componentBuffer[i] != imgBuffInFile[i]) {
break;
}
}
if (i == imgBuffInFile.size()) {
printf("\33[2K\r");//clear the current line
printf("Binary comparison success.\n");
return FLINT_SUCCESS;
}
}
printf("\33[2K\r");//clear the current line
reportErr(true, "Binary comparison failed.\n");
return FLINT_FAILED;
#else
reportErr(true, FLINT_NO_MFA2);
return FLINT_FAILED;
#endif
}
FlintStatus BinaryCompareSubCommand::executeCommand()
{
#ifndef NO_MSTARCHIVE
string mfa2file = _flintParams.image;
_mfa2Pkg = MFA2::LoadMFA2Package(mfa2file);
if (_mfa2Pkg != NULL) {
_flintParams.mfa2_specified = true;
return compareMFA2();
}
#endif
vector<u_int8_t> device_critical;
vector<u_int8_t> device_non_critical;
vector<u_int8_t> image_critical;
vector<u_int8_t> image_non_critical;
if (preFwOps() == FLINT_FAILED) {
if (_imgOps) {
const char* errMessage = _imgOps->err();
if (errMessage != NULL && strlen(errMessage) > 0) {
reportErr(true, "Error occurred while executing flint initialization : %s\n", errMessage);
}
}
return FLINT_FAILED;
}
mfile *mf = _fwOps->getMfileObj();
int is_livefish_mode = dm_is_livefish_mode(mf);
if (is_livefish_mode == 1) {
_flintParams.override_cache_replacement = true;
}
_fwType = _fwOps->FwType();
// query both image and device
if (!_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "Device", _flintParams.device.c_str(), _fwOps->err());
return FLINT_FAILED;
}
if (!_imgOps->FwQuery(&_imgInfo)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "Image", _flintParams.image.c_str(), _imgOps->err());
return FLINT_FAILED;
}
if (strcmp((char*)_imgInfo.fw_info.psid, (char*)_devInfo.fw_info.psid)) {
printf("\33[2K\r");//clear the current line
reportErr(true, "Binary comparison failed - PSID mismatch.\n");
return FLINT_FAILED;
}
FwVersion img_version = FwOperations::createFwVersion(&_imgInfo.fw_info);
FwVersion dev_version = FwOperations::createFwVersion(&_devInfo.fw_info);
if (img_version != dev_version) {
printf("\33[2K\r");//clear the current line
reportErr(true, "Binary comparison failed - versions mismatch.\n");
return FLINT_FAILED;
}
u_int32_t imgSize = 0;
//on first call we get the image size
if (!_fwOps->FwReadData(NULL, &imgSize)) {
reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err());
return FLINT_FAILED;
}
std::vector<u_int8_t> imgBuffOnDevice(imgSize);
//on second call we fill it
if (!_fwOps->FwReadData((void*)(&imgBuffOnDevice[0]), &imgSize, _flintParams.silent == false)) {
reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err());
return FLINT_FAILED;
}
std::vector<u_int8_t> imgBuffInFile;
if (!_imgOps->FwExtract4MBImage(imgBuffInFile, false, (_flintParams.silent == false))) {
reportErr(true, FLINT_IMAGE_READ_ERROR, _imgOps->err());
return FLINT_FAILED;
}
_imgOps->PrepItocSectionsForCompare(image_critical, image_non_critical);
_fwOps->PrepItocSectionsForCompare(device_critical, device_non_critical);
if (image_critical != device_critical) {
reportErr(true, "Binary comparison failed - binary mismatch.\n");
return FLINT_FAILED;
}
if (image_non_critical != device_non_critical) {
reportErr(true, "Binary comparison failed - binary mismatch.\n");
return FLINT_FAILED;
}
printf("\33[2K\r");//clear the current line
printf("Binary comparison success.\n");
return FLINT_SUCCESS;
}
/***********************
* Class: BurnSubCommand
**********************/
BurnSubCommand::BurnSubCommand()
{
_name = "burn";
_desc = "Burn flash. Use \"-ir burn\" flag to perform image reactivation prior burning.";
_extendedDesc = "Burn flash \n"
"Performs failsafe FW update from a raw binary image.";
_flagLong = "burn";
_flagShort = "b";
_param = "-ir";
_paramExp = "If supplied, perform image reactivation before burning.";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " -i image1.bin -ir burn\n"
FLINT_NAME " -d " MST_DEV_EXAMPLE2 " -guid 0x2c9000100d050 -i image1.bin b";
_v = Wtv_Dev_And_Img;
_maxCmdParamNum = 1;
_cmdType = SC_Burn;
_fwType = 0;
_devQueryRes = 0;
_mccSupported = true;
memset(&_devInfo, 0, sizeof(_devInfo));
memset(&_imgInfo, 0, sizeof(_imgInfo));
_unknownProgress = 0;
}
BurnSubCommand:: ~BurnSubCommand()
{
closeLog();
if (_burnParams.userVsd != NULL) {
delete[] _burnParams.userVsd;
}
#ifndef NO_MSTARCHIVE
if (_mfa2Pkg != NULL) {
delete _mfa2Pkg;
}
#endif
}
bool BurnSubCommand::verifyMFA2Params(bool IsLiveFish)
{
if (IsLiveFish) {
if (_flintParams.use_psid == false) {
reportErr(true, FLINT_COMMAND_INCORRECT_FLAGS_ERROR, "Burn MFA2", "PSID must be supplied in livefish mode");
return false;
}
if (_flintParams.use_latest_fw_version == true && _flintParams.num_of_args != 4) {
reportErr(true, FLINT_COMMAND_INCORRECT_FLAGS_ERROR, "Burn MFA2", "incorrect flag combination is supplied");
return false;
}
if (_flintParams.use_latest_fw_version == false && _flintParams.num_of_args != 3) {
reportErr(true, FLINT_COMMAND_INCORRECT_FLAGS_ERROR, "Burn MFA2", "incorrect flag combination is supplied");
return false;
}
return true;
}
else {
if (_flintParams.use_latest_fw_version == true && _flintParams.num_of_args != 3) {
reportErr(true, FLINT_COMMAND_INCORRECT_FLAGS_ERROR, "Burn MFA2", "incorrect flag combination is supplied");
return false;
}
if (_flintParams.use_latest_fw_version == false && _flintParams.num_of_args != 2) {
reportErr(true, FLINT_COMMAND_INCORRECT_FLAGS_ERROR, "Burn MFA2", "incorrect flag combination is supplied");
return false;
}
return true;
}
}
bool BurnSubCommand::verifyParams()
{
if (_flintParams.mfa2_specified) {
return true;
}
else {
if ((_flintParams.guid_specified || _flintParams.guids_specified) && (_flintParams.uid_specified)) {
reportErr(true, FLINT_COMMAND_FLAGS_ERROR, _name.c_str(), "either GUIDs / UID (using command line flags -guid(s) / -uid )");
return false;
}
if ((_flintParams.mac_specified || _flintParams.macs_specified) && (_flintParams.uid_specified)) {
reportErr(true, FLINT_COMMAND_FLAGS_ERROR, _name.c_str(), "either MACs / UID (using command line flags -mac(s) / -uid )");
return false;
}
bool GuidsFromUser = _flintParams.guid_specified || _flintParams.guids_specified || \
_flintParams.uid_specified || \
_flintParams.mac_specified || _flintParams.macs_specified;
if (GuidsFromUser && _flintParams.use_image_guids) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "GUIDs/UIDs/MACs", "-use_image_guids");
return false;
}
if ((GuidsFromUser || _flintParams.use_image_guids) && _flintParams.blank_guids) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, _flintParams.use_image_guids ? \
"-use_image_guids" : "GUIDs/UIDs/MACs", "-blank_guids");
return false;
}
if (_flintParams.guid_specified && _flintParams.guids_specified) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-guids", "-guid");
return false;
}
if (_flintParams.mac_specified && _flintParams.macs_specified) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-macs", "-mac");
return false;
}
if (_flintParams.use_image_ps && _flintParams.vsd_specified) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-use_image_ps", "-vsd");
return false;
}
if (_flintParams.ignore_dev_data && !_flintParams.nofs) {
reportErr(true, FLINT_INVALID_FLAG_WITHOUT_FLAG_ERROR, "-nofs", "-ignore_dev_data");
return false;
}
if (_flintParams.use_dev_rom && _flintParams.use_image_rom) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "--use_dev_rom", "--use_image_rom");
return false;
}
if (_flintParams.nofs || _flintParams.allow_psid_change || _flintParams.use_dev_rom) {
// attempt to fallback to legacy flow (direct flash access via FW)
_mccSupported = false;
}
if (_flintParams.image_reactivation && _flintParams.no_fw_ctrl) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-image_reactivation", "-no_fw_ctrl");
return false;
}
if (_flintParams.image_reactivation && _flintParams.override_cache_replacement) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-image_reactivation", "-ocr");
return false;
}
}
return true;
}
void BurnSubCommand::updateBurnParams()
{
_burnParams.progressFunc = _flintParams.silent == true ? (ProgressCallBack)NULL : \
_fwType == FIT_FS2 ? &burnCbFs2Func : &burnCbFs3Func;
_burnParams.ProgressFuncAdv.func = _flintParams.silent == true ? (f_prog_func_adv)NULL : (f_prog_func_adv) & advProgressFunc;
_burnParams.ProgressFuncAdv.opaque = &_unknownProgress;
_burnParams.userGuidsSpecified = _flintParams.guids_specified || _flintParams.guid_specified;
_burnParams.userMacsSpecified = _flintParams.macs_specified || _flintParams.mac_specified;
_burnParams.userUidSpecified = _flintParams.uid_specified;
_burnParams.vsdSpecified = _flintParams.vsd_specified;
_burnParams.blankGuids = _flintParams.blank_guids;
_burnParams.burnFailsafe = !_flintParams.nofs;
_burnParams.allowPsidChange = _flintParams.allow_psid_change;
_burnParams.useDevImgInfo = _flintParams.use_dev_img_info;
_burnParams.useImagePs = _flintParams.use_image_ps;
_burnParams.burnRomOptions = _flintParams.use_image_rom ? FwOperations::ExtBurnParams::BRO_ONLY_FROM_IMG \
: FwOperations::ExtBurnParams::BRO_DEFAULT;
_burnParams.useImageGuids = _flintParams.use_image_guids;
_burnParams.singleImageBurn = !_flintParams.dual_image;
_burnParams.noDevidCheck = _flintParams.no_devid_check;
_burnParams.skipCiReq = _flintParams.skip_ci_req;
_burnParams.useImgDevData = _flintParams.ignore_dev_data;
if (_burnParams.userGuidsSpecified) {
_burnParams.userUids = _flintParams.user_guids;
}
if (_burnParams.userUidSpecified) {
_burnParams.userUids.resize(0);
_burnParams.userUids.push_back(_flintParams.baseUid);
}
if (_burnParams.userMacsSpecified) {
if (!_burnParams.userGuidsSpecified) {
//we dont care about the first 4 values
_burnParams.userUids.resize(GUIDS);
}
_burnParams.userUids.push_back(_flintParams.user_macs[0]);
_burnParams.userUids.push_back(_flintParams.user_macs[1]);
}
if (_burnParams.vsdSpecified) {
_burnParams.userVsd = strcpy(new char[_flintParams.vsd.size() + 1], _flintParams.vsd.c_str());
}
//make sure its of max size and fill the rest with 0xffff
guid_t tmpGuid;
tmpGuid.h = 0xffffffff;
tmpGuid.l = 0xffffffff;
_burnParams.userUids.resize(MAX_GUIDS, tmpGuid);
}
#define VERSION_FORMAT(minor) minor < 100 ? "%d.%d.%04d" : "%d.%04d.%04d"
bool BurnSubCommand::checkFwVersion(bool CreateFromImgInfo, u_int16_t fw_ver0, u_int16_t fw_ver1, u_int16_t fw_ver2)
{
FwVersion current = FwOperations::createFwVersion(&_devInfo.fw_info);
FwVersion new_version;
if (CreateFromImgInfo) {
new_version = FwOperations::createFwVersion(&_imgInfo.fw_info);
}
else {
new_version = FwOperations::createFwVersion(fw_ver0, fw_ver1, fw_ver2);
}
char curr_ver[124], new_ver[124];
printf("\n");
printf(" Current FW version on flash: ");
snprintf(curr_ver, 124,
current.get_fw_version(VERSION_FORMAT(_devInfo.fw_info.fw_ver[1]),
false, "N/A").c_str());
printf("%s", curr_ver);
printf("\n");
printf(" New FW version: ");
if (CreateFromImgInfo) {
snprintf(new_ver, 124,
new_version.get_fw_version(
VERSION_FORMAT(_imgInfo.fw_info.fw_ver[1]), false,
"N/A").c_str());
}
else {
snprintf(new_ver, 124,
new_version.get_fw_version(VERSION_FORMAT(fw_ver1), false,
"N/A").c_str());
}
printf("%s", new_ver);
printf("\n");
if (_flintParams.log_specified) {
print_line_to_log(
"Current FW version on flash: %s, New FW version: %s\n",
curr_ver, new_ver);
}
if (current.is_set() && new_version.is_set()) {
if (!current.are_same_branch(new_version)) {
printf("\n Note: The new FW version is on a different branch"
" then the current FW version on flash.\n");
} else if (current >= new_version) {
printf("\n Note: The new FW version is %s the current FW"
" version on flash.\n",
current == new_version ? "the same as" : "older than");
if (!askUser()) {
return false;
}
}
}
printf("\n");
_burnParams.ignoreVersionCheck = true;
return true;
}
bool BurnSubCommand::checkPSID()
{
if (strlen(_imgInfo.fw_info.psid) != 0 && strlen(_devInfo.fw_info.psid) != 0 &&
strncmp(_imgInfo.fw_info.psid, _devInfo.fw_info.psid, PSID_LEN)) {
if (_flintParams.allow_psid_change) {
printf("\n You are about to replace current PSID on flash - \"%s\" with a different PSID - \"%s\".\n"
" Note: It is highly recommended not to change the PSID.\n",
_devInfo.fw_info.psid, _imgInfo.fw_info.psid);
if (!askUser()) {
return false;
}
} else {
printf("\n");
reportErr(true, FLINT_PSID_ERROR, _devInfo.fw_info.psid, _imgInfo.fw_info.psid);
return false;
}
}
return true;
}
FlintStatus BurnSubCommand::burnFs3()
{
bool printPreparing = false;
if (_devQueryRes) {
char errBuff[ERR_BUFF_SIZE] = {0};
FwOperations::fw_ops_params_t fwParams;
initDeviceFwParams(errBuff, fwParams);
FsChecks fsChecks(_devInfo, _fwOps, _imgOps, _burnParams, fwParams);
if (fsChecks.ExecuteChecks(&_fwOps, _burnParams, _devInfo)) {
vector<string> questions;
fsChecks.GetUserQuestions(questions, " ");
delete[] fwParams.mstHndl;
for (unsigned int i = 0; i < questions.size(); i++) {
printf("\n%s\n", questions[i].c_str());
if (!askUser()) {
return FLINT_FAILED;
}
}
} else {
delete[] fwParams.mstHndl;
reportErr(true, "Fixes is needed for Flash layout, an error occurred while preparing the operation");
return FLINT_FAILED;
}
printPreparing = fsChecks._isTimeConsumingFixesNeeded;
}
// Here we want to burn FS3 device so we check if the image is indeed FS3 image
if (_imgInfo.fw_type != FIT_FS3 && _imgInfo.fw_type != FIT_FS4) {
reportErr(true, FLINT_IMG_DEV_COMPAT_ERROR, "FS3", "FS3");
return FLINT_FAILED;
}
const char *imgTypeStr = fwImgTypeToStr(_imgInfo.fw_type);
// on FS3 burn we require query to pass
if (!_devQueryRes && _burnParams.burnFailsafe) {
reportErr(true, FLINT_FSX_BURN_ERROR, imgTypeStr, _fwOps->err());
return FLINT_FAILED;
}
//check FwVersion
if (!checkFwVersion()) {
return FLINT_BURN_ABORTED;
}
// check Psid
if (_devQueryRes && !checkPSID()) {
return FLINT_FAILED;
}
// deal with rom
if (!dealWithExpRom()) {
return FLINT_FAILED;
}
bool getRomFromDev = (_burnParams.burnRomOptions == FwOperations::ExtBurnParams::BRO_FROM_DEV_IF_EXIST);
if (!getRomFromDev && !checkMatchingExpRomDevId(_imgInfo)) {
printf("Image file ROM: FW is for device %d, but Exp-ROM is for device %d\n", _imgInfo.fw_info.dev_type, \
_imgInfo.fw_info.roms_info.exp_rom_com_devid);
if (!askUser()) {
return FLINT_FAILED;
}
}
if (!_burnParams.burnFailsafe) {
printf("Burn process will not be failsafe. No checks will be performed.\n");
if (_burnParams.useImgDevData) {
printf("ALL flash, including the device data sections will be overwritten.\n");
}
printf("If this process fails, computer may remain in an inoperable state.\n");
if (!askUser()) {
return FLINT_FAILED;
}
}
if (printPreparing) {
printf(" Preparing...\n");
}
if (!_fwOps->FwBurnAdvanced(_imgOps, _burnParams)) {
reportErr(true, FLINT_FSX_BURN_ERROR, imgTypeStr, _fwOps->err());
return FLINT_FAILED;
}
PRINT_PROGRESS(_burnParams.progressFunc, 101);
write_result_to_log(FLINT_SUCCESS, "", _flintParams.log_specified);
const char *resetRec = _fwOps->FwGetResetRecommandationStr();
if (resetRec) {
printf("-I- %s\n", resetRec);
}
return FLINT_SUCCESS;
}
FlintStatus BurnSubCommand::burnFs2()
{
if (_flintParams.striped_image) {
reportErr(true, FLINT_FS2_STRIPED_ERROR);
return FLINT_FAILED;
}
if (_imgInfo.fw_type != FIT_FS2) {
reportErr(true, FLINT_IMG_DEV_COMPAT_ERROR, "FS2", "FS2");
return FLINT_FAILED;
}
//CheckMatchingHwDevId is done in mlxfwops burn routine.
//CheckMatchingDevId is done in mlxfwops burn routine.
(void)dealWithExpRom();
bool getRomFromDev = _burnParams.burnRomOptions == FwOperations::ExtBurnParams::BRO_FROM_DEV_IF_EXIST;
if (!getRomFromDev && !checkMatchingExpRomDevId(_imgInfo)) {
printf("Image file ROM: FW is for device %d, but Exp-ROM is for device %d\n", _imgInfo.fw_info.dev_type, \
_imgInfo.fw_info.roms_info.exp_rom_com_devid);
if (!askUser()) {
return FLINT_FAILED;
}
}
//deal with guids
if (!dealWithGuids()) {
return FLINT_FAILED;
}
//deal with failsifity should be made in fwops as we dont know if image/device fw is failsafe
if (_burnParams.burnFailsafe & (!_imgInfo.fw_info.is_failsafe || !_devInfo.fw_info.is_failsafe)) {
if ((!_imgInfo.fw_info.is_failsafe && !_devInfo.fw_info.is_failsafe)) {
// When both image and flash are non-failsafe, flint will burn in a non-failsafe mode
_burnParams.burnFailsafe = false;
} else {
// when only one of image and flash is non-failsafe, flint will fail with appropriate message
reportErr(true, "Failsafe burn failed: FW image in the %s is non failsafe.\n"
" you cannot burn a%s failsafe image over a%s failsafe image in a failsafe mode.\n"
" If you want to burn in non failsafe mode, use the \"-nofs\" switch.\n",
_imgInfo.fw_info.is_failsafe ? "flash" : "given file", _imgInfo.fw_info.is_failsafe ? "" : " non", \
_devInfo.fw_info.is_failsafe ? "" : " non");
return FLINT_FAILED;
}
}
//deal with vsd
if (!dealWithVSD()) {
return FLINT_FAILED;
}
//check versions
if (!checkFwVersion()) {
return FLINT_BURN_ABORTED;
}
//check Psid
if (_devQueryRes && !checkPSID()) {
return FLINT_FAILED;
}
// Warn if a fw which does not support config is burnt over fw that does support config
// The other way (new fw with config, old fw w/o config) is a normal update flow.
// Update: all fw should now support config sectors, so we just check any mismatch in the config pads
// Verify config offset. Should never be different between image and flash (unless changing PSID).
if (_imgInfo.fs2_info.config_pad != _devInfo.fs2_info.config_pad) {
printf("\n");
printf("-W- Configuration section offset on flash (%u sectors) differs from the"
" Configuration section offset in the given image (%u sectors)."
" Current device configuration (if exists) will be deleted.\n",
_devInfo.fs2_info.config_pad,
_imgInfo.fs2_info.config_pad);
if (_burnParams.allowPsidChange) {
if (!askUser()) {
return FLINT_FAILED;
}
} else {
reportErr(true, "Use the '-allow_psid_change' flag to force this change.\n");
return FLINT_FAILED;
}
}
if (!_burnParams.burnFailsafe) {
printf("Burn process will not be failsafe. No checks will be performed.\n");
printf("ALL flash, including the Invariant Sector will be overwritten.\n");
printf("If this process fails, computer may remain in an inoperable state.\n");
if (!askUser()) {
return FLINT_FAILED;
}
}
//Finally we can burn
if (!_fwOps->FwBurnAdvanced(_imgOps, _burnParams)) {
reportErr(true, FLINT_FS2_BURN_ERROR, _fwOps->err());
return FLINT_FAILED;
}
PRINT_PROGRESS(_burnParams.progressFunc, 101);
write_result_to_log(FLINT_SUCCESS, "", _flintParams.log_specified);
if (_burnParams.burnStatus.imageCachedSuccessfully) {
PRINT_PROGRESS(_burnParams.progressFunc, 102);
}
return FLINT_SUCCESS;
}
bool BurnSubCommand::dealWithVSD()
{
if (!(_burnParams.vsdSpecified || _burnParams.useImagePs) && !((strlen(_devInfo.fw_info.psid) != 0 \
&& _devInfo.fw_info.vsd_sect_found))) {
printf("\n");
if (_burnParams.burnFailsafe) {
reportErr(true, "Can not extract VSD/PSID info from flash.\n"
" Can not burn in a failsafe mode. Please use \"-nofs\" flag to burn in a non failsafe mode.\n");
return false;
} else {
printf("-W- Can not extract VSD/PSID info from flash.\n\n"
" To use a specific VSD, abort and re-burn specifying the\n"
" needed info (using command line flags -vsd / -use_image_ps).\n"
" You can also continue burn using blank VSD.\n");
if (!askUser()) {
return false;
}
}
}
return true;
}
bool BurnSubCommand::dealWithGuids()
{
bool read_guids = true;
bool ib_dev;
bool eth_dev;
// Get the FW types
FwOperations::SetDevFlags(_imgInfo.fw_info.chip_type, _imgInfo.fw_info.dev_type, (fw_img_type)_imgInfo.fw_type, ib_dev, eth_dev);
//setDevFlags(_imgInfo, ib_dev, eth_dev);
// Check if there is a need to read guids
if (_burnParams.useImageGuids || _burnParams.blankGuids
|| (_burnParams.userGuidsSpecified && ib_dev)
|| (_burnParams.userMacsSpecified)) {
read_guids = false;
}
// Check if the burnt FW is ok and readable in order to get the GUIDs later
if (read_guids && !_devQueryRes) {
//printMissingGuidErr(ib_dev, eth_dev);
if (_burnParams.burnFailsafe) {
reportErr(true,
"Can not extract GUIDs/MACs info from flash, %s\n"
" Can not burn in a failsafe mode.\n"
" If you want to burn in non failsafe mode, use the \"-nofs\" switch.\n", _fwOps->err());
} else {
reportErr(true, "Can not extract GUIDs/MACs info from flash, %s", _fwOps->err());
printMissingGuidErr(ib_dev, eth_dev);
}
return false;
}
// Check guids flag to ensure correct patching of guids in mlxfwops
bool is_guids_specified = _burnParams.userGuidsSpecified
|| _burnParams.userMacsSpecified
|| _burnParams.userUidSpecified;
if (is_guids_specified) {
if (!checkGuidsFlags(_imgInfo.fw_info.dev_type, _fwType, \
_burnParams.userGuidsSpecified, _burnParams.userMacsSpecified, _burnParams.userUidSpecified, ib_dev, eth_dev)) {
return false;
}
}
//report guid changes if needed. and update the user_guids vector in _burnParams
if (is_guids_specified || _flintParams.use_image_guids) {
guid_t *new_guids = (_burnParams.userGuidsSpecified || _burnParams.userUidSpecified) ? \
&_burnParams.userUids[0] : _devInfo.fs2_info.guids;
guid_t *new_macs = _burnParams.userMacsSpecified != 0 ? &_burnParams.userUids[GUIDS] : &_devInfo.fs2_info.guids[GUIDS];
guid_t *old_guids = !_devQueryRes ? NULL : _devInfo.fs2_info.guids;
guid_t *old_macs = old_guids != NULL ? &old_guids[GUIDS] : NULL;
if (!is_guids_specified && _flintParams.use_image_guids) {
new_guids = _imgInfo.fs2_info.guids;
new_macs = &_imgInfo.fs2_info.guids[GUIDS];
}
//printf("-D- l=%d, h=%d\n", new_macs->l, new_macs->h);
if (!reportGuidChanges(new_guids, new_macs, old_guids, old_macs, ib_dev, \
eth_dev, _imgInfo.fs2_info.guid_num)) {
return false;
}
}
return true;
}
bool BurnSubCommand::dealWithExpRom()
{
bool getRomFromDev = false;
// Check exp rom:
bool fs2Cond;
if (_fwType != FIT_FS2) {
_burnParams.burnRomOptions =
FwOperations::ExtBurnParams::BRO_ONLY_FROM_IMG;
bool cond = _devQueryRes && IS_HCA(_devInfo.fw_info.chip_type);
if (cond && _flintParams.use_dev_rom) {
if (_devInfo.fw_info.roms_info.num_of_exp_rom > 0) {
if (!strcmp(_devInfo.fw_info.product_ver, "") && !strcmp(_imgInfo.fw_info.product_ver, "")) {
_burnParams.burnRomOptions =
FwOperations::ExtBurnParams::BRO_FROM_DEV_IF_EXIST;
} else if (_flintParams.allow_rom_change) {
_burnParams.burnRomOptions =
FwOperations::ExtBurnParams::BRO_FROM_DEV_IF_EXIST;
} else {
//error, please use allow_rom_change flag
reportErr(true, "The device FW contains common FW/ROM Product Version - "
"The ROM cannot be updated separately.\n");
return false;
}
} else {
if (_imgInfo.fw_info.roms_info.num_of_exp_rom > 0) {
if (!askUser("No Expansion ROM found in the device, "
"Do you want to use the ROM from the image file",
false)) {
return false;
}
} else {
if (!askUser("No Expansion ROM found in the device"
", Do you want to continue")) {
return false;
}
}
}
}
return true;
}
FwVersion dev_version = FwOperations::createFwVersion(&_devInfo.fw_info);
bool rom_condition = (FwOperations::IsFwSupportingRomModify(dev_version) || (_imgInfo.fw_info.roms_info.num_of_exp_rom > 0));
fs2Cond = (_devQueryRes && IS_HCA(_devInfo.fw_info.chip_type)
&& rom_condition
&& !_flintParams.use_image_rom
&& !strcmp(_devInfo.fw_info.product_ver, "")
&& !strcmp(_imgInfo.fw_info.product_ver, ""));
if (fs2Cond) {
// Enter here when:
// The fw on the flash is OK (passed query, and it should pass verify in mlxfwops) &&
// ( The device is connectx || connectib )&&
// The image fw supports modifying ROM OR it contains ROM &&.
// The user didn't ask to burn the image rom. &&
// The fw on the flash doesn't contain product version
if (_imgInfo.fw_info.roms_info.num_of_exp_rom > 0 && _devInfo.fw_info.roms_info.num_of_exp_rom > 0) {
printf("\n Note: Both the image file and the flash contain a ROM image.\n"
" Select \"yes\" to use the ROM from the given image file.\n"
" Select \"no\" to keep the existing ROM in the flash\n");
displayExpRomInfo(_devInfo.fw_info.roms_info, " Current ROM info on flash: ");
displayExpRomInfo(_imgInfo.fw_info.roms_info, " ROM info from image file : ");
if (!askUser("Use the ROM from the image file", false)) {
getRomFromDev = true;
} else {
getRomFromDev = false;
}
} else if (!(_imgInfo.fw_info.roms_info.num_of_exp_rom > 0) && _devInfo.fw_info.roms_info.num_of_exp_rom > 0) {
getRomFromDev = true;
}
}
if (getRomFromDev) {
_burnParams.burnRomOptions = FwOperations::ExtBurnParams::BRO_FROM_DEV_IF_EXIST;
}
return true;
}
bool BurnSubCommand::checkMatchingExpRomDevId(const fw_info_t& info)
{
if ((info.fw_info.roms_info.num_of_exp_rom > 0) && (info.fw_info.dev_type)
&& (info.fw_info.roms_info.exp_rom_com_devid != EXP_ROM_GEN_DEVID) \
&& (info.fw_info.roms_info.exp_rom_com_devid != MISS_MATCH_DEV_ID)
&& (info.fw_info.dev_type != info.fw_info.roms_info.exp_rom_com_devid)) {
return false;
}
return true;
}
FlintStatus BurnSubCommand::executeCommand()
{
#ifndef NO_MSTARCHIVE
string mfa2file = _flintParams.image;
_mfa2Pkg = MFA2::LoadMFA2Package(mfa2file);
if (_mfa2Pkg != NULL) {
_flintParams.mfa2_specified = true;
}
#endif
if (_flintParams.image_reactivation) {
if (preFwOps(true) == FLINT_FAILED) {
return FLINT_FAILED;
}
if (!_fwOps->FwReactivateImage()) {
reportErr(true, FLINT_FAILED_IMAGE_REACTIVATION_ERROR, _flintParams.device.c_str(), _fwOps->err());
return FLINT_FAILED;
}
printf("\n-I- FW Image Reactivation succeeded.\n\n");
_fwOps = _imgOps = NULL;
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
}
else if (_flintParams.mfa2_specified) {
bool saved_value = _flintParams.silent;
_flintParams.silent = true;
FlintStatus res = preFwOps();
_flintParams.silent = saved_value;
if (res == FLINT_FAILED) {
_flintParams.override_cache_replacement = true;
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
}
mfile *mf = _fwOps->getMfileObj();
int is_livefish_mode = dm_is_livefish_mode(mf);
if (verifyMFA2Params(is_livefish_mode == 1) == false) {
return FLINT_FAILED;
}
//check if the device is in FW control mode ("mcc flow"). Other flow is unsupported.
if (is_livefish_mode) {
dm_dev_id_t devid_t;
u_int32_t devid;
u_int32_t revid;
int rc = dm_get_device_id(mf, &devid_t, &devid, &revid);
if (rc != 0) {
reportErr(true, "Burning MFA2: can't get device Id");
return FLINT_FAILED;
}
return burnMFA2LiveFish(devid_t);
}
bool is_fw_ctrl = _fwOps->IsFsCtrlOperations();
if (!is_fw_ctrl) {
reportErr(true, "Burning MFA2 is not supported without FW control.\n");
return FLINT_FAILED;
}
else {
updateBurnParams();
if (_flintParams.use_psid == true) {
reportErr(true, FLINT_COMMAND_INCORRECT_FLAGS_ERROR, "Burn MFA2", "incorrect flag combination is supplied");
return FLINT_FAILED;
}
return burnMFA2();
}
}
else {
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
}
//set fw type
_fwType = _fwOps->FwType();
if (_fwOps->IsFsCtrlOperations() || _fwOps->IsFifthGen()) {
if (_flintParams.mac_specified || _flintParams.macs_specified) {
reportErr(true, FLINT_INVALID_FLAG_ERROR_5TH_GEN, _flintParams.macs_specified ? "-macs" : "-mac");
return FLINT_FAILED;
}
if (_flintParams.guid_specified || _flintParams.guids_specified) {
reportErr(true, FLINT_INVALID_FLAG_ERROR_5TH_GEN, _flintParams.guids_specified ? "-guids" : "-guid");
return FLINT_FAILED;
}
}
// query both image and device (deviceQuery can fail but we save rc)
_devQueryRes = _fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false));
if (_imgOps) {
if (!_imgOps->FwQuery(&_imgInfo)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "image", _flintParams.image.c_str(), _imgOps->err());
return FLINT_FAILED;
}
}
//updateBurnParams with input given by user
updateBurnParams();
if (_flintParams.use_image_guids && _fwType != FIT_FS2) {
reportErr(true, "The \"--use_image_guids\" flag is supported only for GEN4 devices (CX3/Pro).\n");
return FLINT_FAILED;
}
if (_fwType == FIT_FS3 || _fwType == FIT_FS4 || _fwType == FIT_FSCTRL) {
return burnFs3();
} else if (_fwType == FIT_FS2) {
return burnFs2();
}
// unknown fw type
reportErr(true, FLINT_UNKNOWN_FW_TYPE_ERROR);
return FLINT_FAILED;
}
u_int32_t SubCommand::getUserChoice(u_int32_t maximumValue)
{
u_int32_t choice = 0xffff;
while (true) {
int res = scanf("%d", &choice);
if (res != 1) {
while (getchar() != '\n');
printf("Invalid data entered, try again!\n");
continue;
}
if (choice > maximumValue) {
printf("Please choose the version or 0 to exit:\n");
continue;
}
break;
}
if (choice == 0) {
exit(0);
}
return choice;
}
FlintStatus BurnSubCommand::burnMFA2LiveFish(dm_dev_id_t devid_t)
{
#ifndef NO_MSTARCHIVE
int deviceMajorVer = 0;
if (DeviceConnectX4 == devid_t) {
deviceMajorVer = 12;
}
else if (DeviceConnectX4LX == devid_t) {
deviceMajorVer = 14;
}
else if (DeviceConnectX5 == devid_t) {
deviceMajorVer = 16;
}
else if (DeviceConnectX6 == devid_t) {
deviceMajorVer = 20;
}
else if (DeviceConnectX6DX == devid_t) {
deviceMajorVer = 22;
}
else {
reportErr(true, "The MFA2 burning is not supported in livefish for current device");
return FLINT_FAILED;
}
vector<u_int8_t> componentBuffer;
if (_flintParams.use_psid == false) {
reportErr(true, "Must supply \"--psid\" flag while burning device in the livefish mode with MFA2\n");
return FLINT_FAILED;
}
char* psid = (char*)_flintParams.psid.c_str();
map_string_to_component matchingComponentsMap = _mfa2Pkg->getMatchingComponents(psid, deviceMajorVer);
u_int32_t matchingSize = matchingComponentsMap.size();
if (matchingSize == 0) {
reportErr(true, "No matching binaries found for device %s\n", _flintParams.device.c_str());
return FLINT_FAILED;
}
else {
if (matchingSize == 1) {
_mfa2Pkg->unzipComponent(matchingComponentsMap, 0, componentBuffer);
}
else {
if (_flintParams.use_latest_fw_version == true) {
if (_mfa2Pkg->unzipLatestVersionComponent(matchingComponentsMap, componentBuffer) == false) {
return FLINT_FAILED;
}
}
else {
int i = 1;
printf("------FW Version Selection for %s------\n", _flintParams.device.c_str());
for (map_string_to_component::iterator it = matchingComponentsMap.begin(); it != matchingComponentsMap.end(); it++) {
printf("%d. %s\n", i++, it->first.c_str());
}
printf("-I- Please choose the version or 0 to exit:\n");
u_int32_t choice = getUserChoice(matchingSize) - 1;
if (_mfa2Pkg->unzipComponent(matchingComponentsMap, choice, componentBuffer) == false) {
return FLINT_FAILED;
}
while (getchar() != '\n');//clean the stdin buffer
}
}
}
_flintParams.override_cache_replacement = true;
_flintParams.image_specified = false;
if (openOps(true, true) == FLINT_FAILED) {
return FLINT_FAILED;
}
struct cx4fw_uid_entry base_guid = {0, 0, 0};
struct cx4fw_uid_entry base_mac = {0, 0, 0};
bool NeedToSetMacManually = true;
if (_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) {
if (_devInfo.fs3_info.fs3_uids_info.valid_field == 1) {
base_guid.num_allocated = _devInfo.fs3_info.fs3_uids_info.cx4_uids.base_guid.num_allocated;
base_guid.step = _devInfo.fs3_info.fs3_uids_info.cx4_uids.base_guid.step;
base_guid.uid = _devInfo.fs3_info.fs3_uids_info.cx4_uids.base_guid.uid;
base_mac.num_allocated = _devInfo.fs3_info.fs3_uids_info.cx4_uids.base_mac.num_allocated;
base_mac.step = _devInfo.fs3_info.fs3_uids_info.cx4_uids.base_mac.step;
base_mac.uid = _devInfo.fs3_info.fs3_uids_info.cx4_uids.base_mac.uid;
NeedToSetMacManually = false;
}
}
u_int8_t fs4_image_signature[] = { 0x4D, 0x54, 0x46, 0x57, 0xAB, 0xCD, 0xEF, 0x00, 0xFA, 0xDE, 0x12, 0x34, 0x56, 0x78, 0xDE, 0xAD };
u_int8_t fs3_image_signature[] = { 0x4D, 0x54, 0x46, 0x57, 0x8C, 0xDF, 0xD0, 0x00, 0xDE, 0xAD, 0x92, 0x70, 0x41, 0x54, 0xBE, 0xEF };
_fwType = _fwOps->FwType();
if (_fwType == FIT_FS4 || _fwType == FIT_FSCTRL) {
for (u_int8_t i = 0; i < sizeof(fs4_image_signature); i++) {
componentBuffer[i] = fs4_image_signature[i];
}
}
else if (_fwType == FIT_FS3) {
for (u_int8_t i = 0; i < sizeof(fs3_image_signature); i++) {
componentBuffer[i] = fs3_image_signature[i];
}
}
string fileName = "/tmp/temp.bin"; // Get temp name
writeImageToFile(fileName.c_str(), componentBuffer.data(), componentBuffer.size());
_flintParams.image_specified = true;
_flintParams.image = fileName;
if (openOps(true, true) == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_fwOps->RemoveWriteProtection() == false) {
reportErr(true, "Failed to disable flash write protection: %s", _fwOps->err());
return FLINT_FAILED;
}
if (_imgOps->RestoreDevToc(componentBuffer, psid, devid_t, base_guid, base_mac) == false) {
reportErr(true, "Failed to restore DTOCs for device %s: %s.\n", _flintParams.device.c_str(), _imgOps->err());
return FLINT_FAILED;
}
writeImageToFile(fileName.c_str(), componentBuffer.data(), componentBuffer.size());
if (openOps(true, false) == FLINT_FAILED) {
return FLINT_FAILED;
}
if (!_imgOps->FwQuery(&_imgInfo)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "Image", _flintParams.image.c_str(), _imgOps->err());
return FLINT_FAILED;
}
_flintParams.nofs = true;
_flintParams.ignore_dev_data = true;
_flintParams.override_cache_replacement = true;
_flintParams.guid_specified = true;
if (NeedToSetMacManually) {
printf("Warning: No valid GUID/MAC found on the device flash. You will need to set it manually.\n");
}
updateBurnParams();
_burnParams.allowPsidChange = true;
return burnFs3();
#else
(void)devid_t;
reportErr(true, FLINT_NO_MFA2);
return FLINT_FAILED;
#endif
}
FlintStatus BurnSubCommand::burnMFA2()
{
#ifndef NO_MSTARCHIVE
vector<u_int8_t> componentBuffer;
map_string_to_component matchingComponentsMap;
if (!_fwOps->FwQuery(&_devInfo, true, false, true, false, (_flintParams.silent == false))) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "Device", _flintParams.device.c_str(), _fwOps->err());
return FLINT_FAILED;
}
printf("-I- Fetching FW versions from MFA2 image, this operation may take a minute, please wait..\n");
matchingComponentsMap = _mfa2Pkg->getMatchingComponents((char*)_devInfo.fw_info.psid, _devInfo.fw_info.fw_ver[0]);
u_int32_t matchingSize = matchingComponentsMap.size();
if (matchingSize == 0) {
reportErr(true, "No matching binaries found for device %s\n", _flintParams.device.c_str());
return FLINT_FAILED;
}
else {
//If there is only one matching FW binary, unzip it
if (matchingSize == 1) {
_mfa2Pkg->unzipComponent(matchingComponentsMap, 0, componentBuffer);
}
else {
//user wants the latest version automatically
if (_flintParams.use_latest_fw_version == true) {
if (_mfa2Pkg->unzipLatestVersionComponent(matchingComponentsMap, componentBuffer) == false) {
return FLINT_FAILED;
}
}
//otherwise, user must supply required version
else {
int i = 1;
printf("------FW Version Selection for %s------\n", _flintParams.device.c_str());
for (map_string_to_component::iterator it = matchingComponentsMap.begin(); it != matchingComponentsMap.end(); it++) {
printf("%d. %s\n", i++, it->first.c_str());
}
printf("-I- Please choose the version or 0 to exit:\n");
u_int32_t choice = getUserChoice(matchingSize) - 1;
if (_mfa2Pkg->unzipComponent(matchingComponentsMap, choice, componentBuffer) == false) {
return FLINT_FAILED;
}
while (getchar() != '\n');//clean the stdin buffer
map_string_to_component::iterator itAtOffset = matchingComponentsMap.begin();
std::advance(itAtOffset, choice);
Component* requiredComponent = &itAtOffset->second;
VersionExtension version = requiredComponent->getComponentDescriptor().getVersionExtension();
u_int32_t fw_ver0 = version.getMajor();
u_int32_t fw_ver1 = version.getMinor();
u_int32_t fw_ver2 = version.getSubMinor();
if (!checkFwVersion(false, fw_ver0, fw_ver1, fw_ver2)) {
return FLINT_BURN_ABORTED;
}
}
}
}
const char *imgTypeStr = fwImgTypeToStr(_devInfo.fw_type);
bool res = _fwOps->FwBurnAdvanced(componentBuffer, _burnParams);
if (!res) {
reportErr(true, FLINT_FSX_BURN_ERROR, imgTypeStr, _fwOps->err());
return FLINT_FAILED;
}
else {
PRINT_PROGRESS(_burnParams.progressFunc, 101);
write_result_to_log(FLINT_SUCCESS, "", _flintParams.log_specified);
const char *resetRec = _fwOps->FwGetResetRecommandationStr();
if (resetRec) {
printf("-I- %s\n", resetRec);
}
return FLINT_SUCCESS;
}
#else
reportErr(true, FLINT_NO_MFA2);
return FLINT_FAILED;
#endif
}
/***********************
* Class: QuerySubCommand
**********************/
bool QuerySubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 1, (int)_flintParams.cmd_params.size());
return false;
}
if ((_flintParams.cmd_params.size() == 1) && _flintParams.cmd_params[0] != "full") {
reportErr(true, FLINT_INVALID_OPTION_ERROR, _flintParams.cmd_params[0].c_str(), _name.c_str(), "full");
return false;
}
return true;
}
bool QuerySubCommand::checkMac(u_int64_t mac, string& warrStr)
{
if ((mac >> 40) & 0x1) {
warrStr = FLINT_MULTI_BIT_WARNING;
return false;
}
if (mac >> 48) {
warrStr = FLINT_MORE_48_BITS_WARNING;
return false;
}
return true;
}
bool QuerySubCommand::displayFs2Uids(const fw_info_t& fwInfo)
{
const char *mac_indent = "";
bool ibDev;
bool ethDev;
FwOperations::SetDevFlags(fwInfo.fw_info.chip_type, fwInfo.fw_info.dev_type, (fw_img_type)fwInfo.fw_type, ibDev, ethDev);
//setDevFlags(fwInfo, ibDev, ethDev);
int numPorts = 2;
if ((fwInfo.fw_info.chip_type == CT_IS4 || fwInfo.fw_info.chip_type == CT_SWITCHX)) {
numPorts = 0;
}
//we do not support cards with one port anymore.
// GUIDS:
if (ibDev) {
//report("GUID Des: Node Port1 ");
printf("Description: Node ");
if (numPorts > 0) {
printf("Port1 ");
}
if (numPorts > 1) {
printf("Port2 ");
}
printf("Sys image\n");
printf("GUIDs: ");
for (u_int32_t i = 0; i < GUIDS; i++) {
if ((i == 1 && numPorts < 1) ||
(i == 2 && numPorts < 2)) {
continue;
}
printf(GUID_FORMAT " ", fwInfo.fs2_info.guids[i].h, fwInfo.fs2_info.guids[i].l);
}
if (numPorts > 0) {
mac_indent = " ";
}
}
// MACS:
if (ethDev) {
if (fwInfo.fs2_info.guid_num == 6) {
if (!ibDev) {
printf("Description: %s Port1 Port2\n", mac_indent);
} else if (fwInfo.fw_info.chip_type == CT_SWITCHX) {
printf("\nDescription: Base Switch\n");
} else {
printf("\n");
}
printf("MACs: %s ", mac_indent);
for (u_int32_t i = GUIDS; i < 6; i++) {
printf(" " MAC_FORMAT, fwInfo.fs2_info.guids[i].h, fwInfo.fs2_info.guids[i].l);
}
for (u_int32_t i = GUIDS; i < 6; i++) {
u_int64_t mac = (((u_int64_t)fwInfo.fs2_info.guids[i].h) << 32) | fwInfo.fs2_info.guids[i].l;
string warrStr;
if (!fwInfo.fs2_info.blank_guids && !checkMac(mac, warrStr)) {
if (i == GUIDS) {
printf("\n\n");
}
printf(FLINT_BAD_MAC_ADRESS_WARNING, fwInfo.fs2_info.guids[i].h, fwInfo.fs2_info.guids[i].l, warrStr.c_str());
}
}
} else {
printf(FLINT_MAC_ENTRIES_WARNING, 6, fwInfo.fs2_info.guid_num);
}
}
printf("\n");
return true;
}
#define NA_STR "N/A"
#define BASE_STR "Base"
#define PRINT_FS3_OR_NEWER_UID(uid1, str, printStep, isGuid) \
if (uid1.uid) { \
if (isGuid) { \
printf("%-18s %016" U64H_FMT_GEN, str, uid1.uid); \
} else { \
printf("%-18s %012" U64H_FMT_GEN " ", str, uid1.uid); \
} \
} else { \
printf("%-18s %-16s", str, NA_STR); \
} \
if (uid1.num_allocated) { \
printf(" %d", uid1.num_allocated); \
} else { \
printf(" %s", NA_STR); \
} \
if (printStep) { \
if (uid1.step) { \
printf(" %d", uid1.step); \
} else { \
printf(" %s", NA_STR); \
} \
} \
printf("\n");
static inline void printFs3OrNewerUids(struct fs3_uid_entry uid, struct fs3_uid_entry orig_uid, string guidMac, bool printStep)
{
string prefix = BASE_STR + string(" ") + guidMac + ":";
bool isGuid = guidMac.find("GUID") != string::npos ? true : false;
PRINT_FS3_OR_NEWER_UID(uid, prefix.c_str(), printStep, isGuid);
if (uid.uid != orig_uid.uid || uid.num_allocated != orig_uid.num_allocated || (printStep && uid.step != orig_uid.step)) {
// Print MFG UIDs as well
prefix = "Orig " + prefix;
PRINT_FS3_OR_NEWER_UID(orig_uid, prefix.c_str(), printStep, isGuid);
}
}
bool QuerySubCommand::displayFs3Uids(const fw_info_t& fwInfo)
{
if (fwInfo.fs3_info.fs3_uids_info.valid_field) {
// new GUIDs format
printf("Description: UID GuidsNumber\n");
printFs3OrNewerUids(fwInfo.fs3_info.fs3_uids_info.cx4_uids.base_guid, fwInfo.fs3_info.orig_fs3_uids_info.cx4_uids.base_guid, "GUID", false);
printFs3OrNewerUids(fwInfo.fs3_info.fs3_uids_info.cx4_uids.base_mac, fwInfo.fs3_info.orig_fs3_uids_info.cx4_uids.base_mac, "MAC", false);
} else {
printf("Description: UID GuidsNumber Step\n");
string firstGuid = (fwInfo.fw_info.chip_type != CT_SWITCH_IB) ? "GUID1" : "GUID";
string firstMac = (fwInfo.fw_info.chip_type != CT_SWITCH_IB) ? "MAC1" : "MAC";
printFs3OrNewerUids(fwInfo.fs3_info.fs3_uids_info.cib_uids.guids[0], fwInfo.fs3_info.orig_fs3_uids_info.cib_uids.guids[0], firstGuid, true);
if (fwInfo.fw_info.chip_type != CT_SWITCH_IB) {
printFs3OrNewerUids(fwInfo.fs3_info.fs3_uids_info.cib_uids.guids[1], fwInfo.fs3_info.orig_fs3_uids_info.cib_uids.guids[1], "GUID2", true);
}
printFs3OrNewerUids(fwInfo.fs3_info.fs3_uids_info.cib_uids.macs[0], fwInfo.fs3_info.orig_fs3_uids_info.cib_uids.macs[0], firstMac, true);
if (fwInfo.fw_info.chip_type != CT_SWITCH_IB) {
printFs3OrNewerUids(fwInfo.fs3_info.fs3_uids_info.cib_uids.macs[1], fwInfo.fs3_info.orig_fs3_uids_info.cib_uids.macs[1], "MAC2", true);
}
}
return true;
}
string QuerySubCommand::printSecurityAttrInfo(u_int32_t m)
{
string attr = "";
if (m & SMM_SECURE_FW) {
attr += "secure-fw";
} else if (m & SMM_SIGNED_FW) {
attr += "signed-fw";
} else {
attr += NA_STR;
return attr;
}
if (m & SMM_DEBUG_FW) {
attr += ", debug";
}
if (m & SMM_DEV_FW) {
attr += ", dev";
}
if (m & SMM_CS_TOKEN) {
attr += ", cs-token";
}
if (m & SMM_DBG_TOKEN) {
attr += ", dbg-token";
}
return attr;
}
FlintStatus QuerySubCommand::printImageInfo(const fw_info_t& fwInfo)
{
bool isFs4 = (fwInfo.fw_type == FIT_FS4) ? true : false;
FwVersion image_version = FwOperations::createFwVersion(&fwInfo.fw_info);
printf("Image type: %s\n", fwImgTypeToStr(fwInfo.fw_type));
if (fwInfo.fw_info.isfu_major) {
printf("FW ISSU Version: %d\n", fwInfo.fw_info.isfu_major);
}
if (image_version.is_set()) {
printf("FW Version: %s\n",
image_version.get_fw_version(
VERSION_FORMAT(fwInfo.fw_info.fw_ver[1])).c_str());
}
if (fwInfo.fw_info.fw_rel_date[0] || fwInfo.fw_info.fw_rel_date[1] || fwInfo.fw_info.fw_rel_date[2]) {
printf("FW Release Date: %x.%x.%x\n", fwInfo.fw_info.fw_rel_date[0], fwInfo.fw_info.fw_rel_date[1], \
fwInfo.fw_info.fw_rel_date[2]);
}
if (fwInfo.fw_info.min_fit_ver[0] || fwInfo.fw_info.min_fit_ver[1] \
|| fwInfo.fw_info.min_fit_ver[2] || fwInfo.fw_info.min_fit_ver[3]) {
printf("Min FIT Version: %d.%d.%d.%d\n", fwInfo.fw_info.min_fit_ver[0], \
fwInfo.fw_info.min_fit_ver[1], fwInfo.fw_info.min_fit_ver[2], fwInfo.fw_info.min_fit_ver[3]);
}
if ((fwInfo.fw_info.mic_ver[0] || fwInfo.fw_info.mic_ver[1] || fwInfo.fw_info.mic_ver[2])) {
printf("MIC Version: %d.%d.%d\n", fwInfo.fw_info.mic_ver[0], \
fwInfo.fw_info.mic_ver[1], fwInfo.fw_info.mic_ver[2]);
}
if (strlen(fwInfo.fw_info.product_ver)) {
printf("Product Version: %s\n", fwInfo.fw_info.product_ver);
}
if (fwInfo.fw_info.roms_info.exp_rom_found) {
displayExpRomInfo(fwInfo.fw_info.roms_info, "Rom Info: ");
}
char* imageVSD = (char*)fwInfo.fs3_info.image_vsd;
char* deviceVSD = NULL;
if (isFs4) {
deviceVSD = (char*)fwInfo.fs3_info.deviceVsd;
}
else {
deviceVSD = (char*)fwInfo.fw_info.vsd;
}
if (strlen(imageVSD) == 0) {
if (deviceVSD == NULL || strlen(deviceVSD) == 0) {
imageVSD = (char*)NA_STR;
}
else {
imageVSD = deviceVSD;
}
}
printf("Image VSD: %s\n", imageVSD);
printf("PSID: %s\n", fwInfo.fw_info.psid);
printf("Security Attributes: %s\n", printSecurityAttrInfo(fwInfo.fs3_info.security_mode).c_str());
string updateMethod = "Legacy";
if (fwInfo.fs3_info.security_mode & SMM_MCC_EN) {
updateMethod = "fw_ctrl";
}
printf("Default Update Method: %s\n", updateMethod.c_str());
return FLINT_SUCCESS;
}
FlintStatus QuerySubCommand::printInfo(const fw_info_t& fwInfo, bool fullQuery)
{
bool isFs2 = (fwInfo.fw_type == FIT_FS2) ? true : false;
bool isFs3 = (fwInfo.fw_type == FIT_FS3) ? true : false;
bool isFs4 = (fwInfo.fw_type == FIT_FS4) ? true : false;
bool isFsCtrl = (fwInfo.fw_type == FIT_FSCTRL) ? true : false;
FwOperations *ops = (_flintParams.device_specified) ? _fwOps : _imgOps;
FwVersion image_version = FwOperations::createFwVersion(&fwInfo.fw_info);
FwVersion running_version = FwOperations::createRunningFwVersion(&fwInfo.fw_info);
printf("Image type: %s\n", fwImgTypeToStr(fwInfo.fw_type));
if (fwInfo.fw_info.isfu_major) {
printf("FW ISSU Version: %d\n", fwInfo.fw_info.isfu_major);
}
if (image_version.is_set()) {
printf("FW Version: %s\n",
image_version.get_fw_version(
VERSION_FORMAT(fwInfo.fw_info.fw_ver[1])).c_str());
if (nextBootFwVer) {
// if nextBootFwVer is true, no need to print all the other values.
return FLINT_SUCCESS;
}
if (image_version != running_version && running_version.is_set()) {
printf("FW Version(Running): %s\n",
running_version.get_fw_version(
VERSION_FORMAT(fwInfo.fw_info.running_fw_ver[1])).c_str());
}
} else if (nextBootFwVer) {
// if nextBootFwVer is true, and no next boot fw version, print running version (this version is next_boot_fw_ver as well)
printf("FW Version: %s\n",
running_version.get_fw_version(
VERSION_FORMAT(fwInfo.fw_info.running_fw_ver[1])).c_str());
return FLINT_SUCCESS;
}
if (fwInfo.fw_info.fw_rel_date[0] || fwInfo.fw_info.fw_rel_date[1] || fwInfo.fw_info.fw_rel_date[2]) {
printf("FW Release Date: %x.%x.%x\n", fwInfo.fw_info.fw_rel_date[0], fwInfo.fw_info.fw_rel_date[1], \
fwInfo.fw_info.fw_rel_date[2]);
}
if (fullQuery) {
// there is no full query atm just quick query
if (fwInfo.fw_info.min_fit_ver[0] || fwInfo.fw_info.min_fit_ver[1] \
|| fwInfo.fw_info.min_fit_ver[2] || fwInfo.fw_info.min_fit_ver[3]) {
printf("Min FIT Version: %d.%d.%d.%d\n", fwInfo.fw_info.min_fit_ver[0], \
fwInfo.fw_info.min_fit_ver[1], fwInfo.fw_info.min_fit_ver[2], fwInfo.fw_info.min_fit_ver[3]);
}
if ((fwInfo.fw_info.mic_ver[0] || fwInfo.fw_info.mic_ver[1] || fwInfo.fw_info.mic_ver[2])) {
printf("MIC Version: %d.%d.%d\n", fwInfo.fw_info.mic_ver[0], \
fwInfo.fw_info.mic_ver[1], fwInfo.fw_info.mic_ver[2]);
}
if (isFs2) {
if (fwInfo.fs2_info.config_sectors) {
printf("Config Sectors: %d\n", fwInfo.fs2_info.config_sectors);
}
if (fwInfo.fs2_info.config_pad) {
printf("Config Pad: %d\n", fwInfo.fs2_info.config_pad);
}
if (strlen(fwInfo.fs2_info.prs_name)) {
printf("PRS Name: %s\n", fwInfo.fs2_info.prs_name);
}
} else {
// FS3
if (strlen(fwInfo.fs3_info.prs_name)) {
printf("PRS Name: %s\n", fwInfo.fs3_info.prs_name);
}
if (strlen(fwInfo.fs3_info.orig_prs_name)) {
printf("Orig PRS Name: %s\n", fwInfo.fs3_info.orig_prs_name);
}
if (strlen(fwInfo.fs3_info.name)) {
printf("Part Number: %s\n", fwInfo.fs3_info.name);
}
if (strlen(fwInfo.fs3_info.description)) {
printf("Description: %s\n", fwInfo.fs3_info.description);
}
}
}
if (strlen(fwInfo.fw_info.product_ver)) {
printf("Product Version: %s\n", fwInfo.fw_info.product_ver);
}
if (fwInfo.fw_info.roms_info.exp_rom_found) {
displayExpRomInfo(fwInfo.fw_info.roms_info, "Rom Info: ");
}
else if (_flintParams.skip_rom_query) {
printf("Rom Info: type=UEFI version=skipped cpu=skipped\n");
printf(" type=PXE version=skipped devid=skipped cpu=skipped\n");
printf(" type=NVMe version=skipped devid=skipped cpu=skipped\n");
}
if (isFs2) {
printf("Device ID: %d\n", fwInfo.fw_info.dev_type);
}
if (isFs2 && fwInfo.fs2_info.access_key_exists) {
printf("HW Access Key: ");
if (fwInfo.fs2_info.access_key_value.l || fwInfo.fs2_info.access_key_value.h) {
printf("Enabled\n");
} else {
printf("Disabled\n");
}
}
if (!isFs2) {
/*i.e its fs3/fs4*/
if (!displayFs3Uids(fwInfo)) {
return FLINT_FAILED;
}
} else {
if (!displayFs2Uids(fwInfo)) {
return FLINT_FAILED;
}
}
// VSD, PSID
if (!fwInfo.fw_info.vsd_vendor_id || fwInfo.fw_info.vsd_vendor_id == MELLANOX_VENDOR_ID) {
if (!isFs2) {
char *imageVSD = (char*)fwInfo.fs3_info.image_vsd;
char* deviceVSD = NULL;
if (_flintParams.device_specified == false && _flintParams.image_specified == true) {
deviceVSD = (char*)fwInfo.fw_info.vsd;
}
else if (isFs4 && !_flintParams.no_fw_ctrl && !_flintParams.override_cache_replacement) {
deviceVSD = (char*)fwInfo.fs3_info.deviceVsd;
}
else {
deviceVSD = (char*)fwInfo.fw_info.vsd;
}
if (strlen(imageVSD) == 0) {
imageVSD = (char*)NA_STR;
}
if (strlen(deviceVSD) == 0) {
deviceVSD = (char*)NA_STR;
}
printf("Image VSD: %s\n", imageVSD);
printf("Device VSD: %s\n", deviceVSD);
printf("PSID: %s\n", fwInfo.fw_info.psid);
if (strncmp(fwInfo.fw_info.psid, fwInfo.fs3_info.orig_psid, 13) != 0) {
if (strlen(fwInfo.fs3_info.orig_psid)) {
printf("Orig PSID: %s\n", fwInfo.fs3_info.orig_psid);
} else {
printf("Orig PSID: %s\n", NA_STR);
}
}
} else {
printf("VSD: %s\n", fwInfo.fw_info.vsd);
printf("PSID: %s\n", fwInfo.fw_info.psid);
}
} else {
printf(FLINT_NOT_MLNX_FW_WARNING, fwInfo.fw_info.vsd_vendor_id);
}
if (isFs3 || isFs4 || isFsCtrl) {
printf("Security Attributes: %s\n",
printSecurityAttrInfo(fwInfo.fs3_info.security_mode).c_str());
}
if ((isFs3 || isFs4 || isFsCtrl) && fullQuery) {
string updateMethod = "Legacy";
if (fwInfo.fs3_info.security_mode & SMM_MCC_EN) {
updateMethod = "fw_ctrl";
}
printf("Default Update Method: %s\n", updateMethod.c_str());
}
if (fullQuery) {
bool IsSupported = ops->GetSecureBootInfo();
if (IsSupported) {
unsigned int index = (unsigned int)fwInfo.fs3_info.life_cycle;
if (index >= NUM_OF_LIFE_CYCLES) {
reportErr(true, "The life cycle value is out of range: %u", index);
}
else {
printf("Life cycle: %s\n", life_cycle_strings[index]);
}
printf("Secure boot: %s\n", fwInfo.fs3_info.sec_boot == 1 ? "Enabled" : "Disabled");
}
}
if (isFs2 && fwInfo.fs2_info.blank_guids) {
//blankGuids only exsists in FS2 image type in mlxfwops why?
printf(FLINT_BLANK_GUIDS_WARNING);
}
return FLINT_SUCCESS;
}
QuerySubCommand::QuerySubCommand()
{
_name = "query";
_desc = "Query misc. flash/firmware characteristics, use \"full\" to get more information.";
_extendedDesc = "Query miscellaneous FW and flash parameters \n"
"Display FW Version, GUIDs, PSID, and other info";
_flagLong = "query";
_flagShort = "q";
_param = "[full]";
_paramExp = "None";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " query";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 1;
_cmdType = SC_Query;
_mccSupported = true;
}
QuerySubCommand:: ~QuerySubCommand()
{
}
FlintStatus QuerySubCommand::queryMFA2()
{
#ifndef NO_MSTARCHIVE
if (_flintParams.use_psid == false) {
reportErr(true, "Must supply \"--psid\" flag while querying MFA2 archive\n");
return FLINT_FAILED;
}
char* psid = (char*)_flintParams.psid.c_str();
map_string_to_component matchingComponentsMap = _mfa2Pkg->getMatchingComponents(psid, -1);
u_int32_t matchingSize = matchingComponentsMap.size();
if (matchingSize == 0) {
reportErr(true, "No matching binaries found for MFA2 %s\n", _flintParams.image.c_str());
return FLINT_FAILED;
}
else {
int i = 1;
u_int8_t fs4_image_signature[] = { 0x4D, 0x54, 0x46, 0x57, 0xAB, 0xCD, 0xEF, 0x00, 0xFA, 0xDE, 0x12, 0x34, 0x56, 0x78, 0xDE, 0xAD };
u_int8_t fs3_image_signature[] = { 0x4D, 0x54, 0x46, 0x57, 0x8C, 0xDF, 0xD0, 0x00, 0xDE, 0xAD, 0x92, 0x70, 0x41, 0x54, 0xBE, 0xEF };
map_string_to_component::iterator it = matchingComponentsMap.begin();
printf("\n*******************************\n");
for (u_int32_t index = 0; index < matchingSize && it != matchingComponentsMap.end(); index++, it++) {
const ComponentDescriptor & compDescr = it->second.getComponentDescriptor();
u_int8_t deviceMajorVer = compDescr.getVersionExtension().getMajor();
vector<u_int8_t> componentBuffer;
_mfa2Pkg->unzipComponent(matchingComponentsMap, index, componentBuffer);
char errBuff[ERR_BUFF_SIZE] = { 0 };
string fileName = "/tmp/temp.bin"; // Get temp name
if (deviceMajorVer >= 16) {
for (u_int8_t i = 0; i < sizeof(fs4_image_signature); i++) {
componentBuffer[i] = fs4_image_signature[i];
}
}
else {
for (u_int8_t i = 0; i < sizeof(fs3_image_signature); i++) {
componentBuffer[i] = fs3_image_signature[i];
}
}
writeImageToFile(fileName.c_str(), componentBuffer.data(), componentBuffer.size());
_flintParams.image_specified = true;
_flintParams.image = fileName;
_imgOps = FwOperations::FwOperationsCreate((void*)_flintParams.image.c_str(), NULL, NULL, FHT_FW_FILE, errBuff, ERR_BUFF_SIZE);
fw_info_t fwInfo;
if (!_imgOps->FwQuery(&fwInfo, true, false, true, true)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "image", _flintParams.image.c_str(), _imgOps->err());
return FLINT_FAILED;
}
printf("Component %d\n", i++);
if (printImageInfo(fwInfo) == FLINT_FAILED) {
return FLINT_FAILED;
}
printf("*******************************\n");
}
}
#endif
return FLINT_SUCCESS;
}
FlintStatus QuerySubCommand::executeCommand()
{
if (_flintParams.image_specified) {
#ifndef NO_MSTARCHIVE
string mfa2file = _flintParams.image;
_mfa2Pkg = MFA2::LoadMFA2Package(mfa2file);
if (_mfa2Pkg != NULL) {
_flintParams.mfa2_specified = true;
return queryMFA2();
}
#endif
}
if (_flintParams.low_cpu) {
set_increase_poll_time(1);
}
if (_flintParams.next_boot_fw_ver) {
nextBootFwVer = true;
}
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
fw_info_t fwInfo;
FwOperations *ops;
bool fullQuery = false;
//check on what we are wroking
ops = (_flintParams.device_specified) ? _fwOps : _imgOps;
if (!ops->FwQuery(&fwInfo, !_flintParams.skip_rom_query, _flintParams.striped_image)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, _flintParams.device_specified ? "Device" : "image",
_flintParams.device_specified ? _flintParams.device.c_str() : _flintParams.image.c_str(), ops->err());
return FLINT_FAILED;
}
//print fw_info nicely to the user
// we actually dont use "regular" query , just quick
//ORENK - no use to display quick query message to the user if we dont do it in any other way
if (_flintParams.cmd_params.size() == 1) {
fullQuery = true;
}
return printInfo(fwInfo, fullQuery);
}
/***********************
* Class: ImageReactivationSubCommand
***********************/
ImageReactivationSubCommand::ImageReactivationSubCommand()
{
_name = "image_reactivation";
_desc = "Reactivate previous flash image. For FW controlled devices only.";
_extendedDesc = "Reactivate previous flash image by moving the magic pattern.";
_flagLong = "image_reactivate";
_flagShort = "ir";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " image_reactivate";
_v = Wtv_Dev;
_maxCmdParamNum = 0;
_cmdType = SC_Image_Reactivation;
_mccSupported = true;
}
bool ImageReactivationSubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() != 0) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 0, (int)_flintParams.cmd_params.size());
return false;
}
if (_flintParams.no_fw_ctrl) {
reportErr(true, FLINT_INVALID_FLAG_WITH_CMD_ERROR, "-no_fw_ctrl", "image_reactivation");
return false;
}
if (_flintParams.override_cache_replacement) {
reportErr(true, FLINT_INVALID_FLAG_WITH_CMD_ERROR, "-ocr", "image_reactivation");
return false;
}
return true;
}
ImageReactivationSubCommand::~ImageReactivationSubCommand()
{
}
FlintStatus ImageReactivationSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
fw_info_t fwInfo;
FwOperations* ops = _fwOps;
if (!ops->FwQuery(&fwInfo)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "Device", _flintParams.device.c_str(), ops->err());
return FLINT_FAILED;
}
if (!_fwOps->FwReactivateImage()) {
reportErr(true, FLINT_FAILED_IMAGE_REACTIVATION_ERROR, _flintParams.device.c_str(), ops->err());
return FLINT_FAILED;
}
printf("\n-I- FW Image Reactivation succeeded.\n\n");
return FLINT_SUCCESS;
}
/***********************
* Class: VerifySubCommand
***********************/
VerifySubCommand::VerifySubCommand()
{
_name = "verify";
_desc = "Verify entire flash, use \"showitoc\" to see ITOC headers in FS3/FS4 image only.";
_extendedDesc = "Verify entire flash.";
_flagLong = "verify";
_flagShort = "v";
_param = "[showitoc]";
_paramExp = "None";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " v";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 1;
_cmdType = SC_Verify;
}
VerifySubCommand:: ~VerifySubCommand()
{
}
bool VerifySubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 0, (int)_flintParams.cmd_params.size());
return false;
}
if ((_flintParams.cmd_params.size() == 1) && _flintParams.cmd_params[0] != "showitoc") {
reportErr(true, FLINT_INVALID_OPTION_ERROR, _flintParams.cmd_params[0].c_str(), _name.c_str(), "swhoitoc");
return false;
}
return true;
}
FlintStatus VerifySubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
FwOperations *ops;
bool showItoc = (_flintParams.cmd_params.size() == 1) ? true : false;
//check on what we are wroking
int opaque = 0;
ProgressCallBackAdvSt advProgress;
advProgress.func = (f_prog_func_adv) & advProgressFunc;
advProgress.opaque = &opaque;
ops = (_flintParams.device_specified) ? _fwOps : _imgOps;
FwOperations::ExtVerifyParams verifyParams(&verifyCbFunc);
verifyParams.isStripedImage = _flintParams.striped_image;
verifyParams.showItoc = showItoc;
verifyParams.progressFuncAdv = &advProgress;
if (!ops->FwVerifyAdv(verifyParams)) {
printf("\n\n");
reportErr(true, FLINT_CMD_VERIFY_ERROR, ops->err());
return FLINT_FAILED;
}
//get status of blank guids in fs2 only can either bring from FwVerify as another parameter. ask mohammad
if (ops->FwType() == FIT_FS2) {
fw_info_t fwInfo;
if (!ops->FwQuery(&fwInfo, true, _flintParams.striped_image)) {
printf("\n\n");
reportErr(true, "Failed to get Guids status. %s\n", ops->err());
return FLINT_FAILED;
}
if (fwInfo.fs2_info.blank_guids) {
printf("\n\n");
reportErr(true, FLINT_CMD_VERIFY_ERROR, "BLANK GUIDS");
return FLINT_FAILED;
}
}
printf("\n-I- FW image verification succeeded. Image is bootable.\n\n");
return FLINT_SUCCESS;
}
/***********************
* Class: SwResetSubCommand
**********************/
SwResetSubCommand::SwResetSubCommand()
{
_name = "swreset";
_desc = "SW reset the target switch device."
"This command is supported only in the In-Band access method.";
_extendedDesc = "SW reset the target switch device. This command is supported only in the In-Band"
" access method.";
_flagLong = "swreset";
_flagShort = "";
_param = "";
_paramExp = "None";
_example = "None";
_v = Wtv_Dev;
_maxCmdParamNum = 0;
_cmdType = SC_Swreset;
}
SwResetSubCommand:: ~SwResetSubCommand()
{
}
bool SwResetSubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() != 0) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 0, (int)_flintParams.cmd_params.size());
return false;
}
return true;
}
FlintStatus SwResetSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
printf("-I- Sending reset command to device %s ...\n", _flintParams.device.c_str());
if (!_fwOps->FwSwReset()) {
reportErr(true, FLINT_SWRESET_ERROR, _fwOps->err());
return FLINT_FAILED;
}
printf("-I- Reset command accepted by the device.\n");
return FLINT_SUCCESS;
}
/***********************
* Class: BromSubCommand
**********************/
BromSubCommand::BromSubCommand()
{
_name = "brom";
_desc = "Burn the specified ROM file on the flash.";
_extendedDesc = "Burn the specified exp-ROM on the flash.";
_flagLong = "brom";
_flagShort = "";
_param = "<ROM-file>";
_paramExp = "file: The exp-ROM file.";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " brom exp-rom.rom";
_v = Wtv_Dev_Or_Img;
_cmdType = SC_Brom;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
memset(&_info, 0, sizeof(_info));
memset(&_romsInfo, 0, sizeof(_romsInfo));
}
BromSubCommand:: ~BromSubCommand()
{
closeLog();
_fRom.close();
}
FlintStatus BromSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
FwOperations *ops = _flintParams.device_specified ? _fwOps : _imgOps;
// query device
if (!ops->FwQuery(&_info)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, "Device", _flintParams.device.c_str(),
ops->err());
return FLINT_FAILED;
}
// get roms info
if (!_fRom.open(_flintParams.cmd_params[0].c_str())) {
reportErr(true, FLINT_BROM_ERROR, _fRom.err());
return FLINT_FAILED;
}
if (!getRomsInfo(&_fRom, _romsInfo)) {
return FLINT_FAILED;
}
//check devids
if ((_romsInfo.num_of_exp_rom > 0) && (_info.fw_info.dev_type)
&& (_romsInfo.exp_rom_com_devid != EXP_ROM_GEN_DEVID) \
&& (_romsInfo.exp_rom_com_devid != MISS_MATCH_DEV_ID)
&& (_info.fw_info.dev_type != _romsInfo.exp_rom_com_devid)) {
printf("-W- Image file ROM: FW is for device %d, but Exp-ROM is for device %d\n", \
_info.fw_info.dev_type, _romsInfo.exp_rom_com_devid);
if (!askUser()) {
return FLINT_FAILED;
}
}
char romVer1[50], romVer2[50];
printf("\n");
const char *infoStr = " Current ROM info on flash: ";
const char *infoStr2 = " New ROM info: ";
if (_info.fw_info.roms_info.num_of_exp_rom > 0) {
displayExpRomInfo(_info.fw_info.roms_info, infoStr);
sprintf(romVer1, "%s", getExpRomVerStr(_info.fw_info.roms_info.rom_info[0]).c_str());
} else {
printf("%s", infoStr);
snprintf(romVer1, 50, "N/A");
printf("%s\n", romVer1);
}
displayExpRomInfo(_romsInfo, infoStr2);
sprintf(romVer2, "%s", getExpRomVerStr(_romsInfo.rom_info[0]).c_str());
//add new line to space up before showing burn precentage
printf("\n");
//print correct msg to log
if (_info.fw_info.roms_info.num_of_exp_rom != 0) {
print_line_to_log("Current ROM version on flash (1st ROM of %d): %s, New ROM version (1st ROM of %d): %s\n", \
_info.fw_info.roms_info.num_of_exp_rom, romVer1, _romsInfo.num_of_exp_rom, romVer2);
} else {
print_line_to_log("Current ROM version on flash: %s, New ROM version(1st ROM of %d): %s\n", romVer1, _romsInfo.num_of_exp_rom, romVer2);
}
// burn the rom
printf("-I- Preparing to burn ROM ...\n");
if (!ops->FwBurnRom(&_fRom, _flintParams.allow_rom_change, true, bromCbFunc)) {
reportErr(true, FLINT_BROM_ERROR, ops->err());
return FLINT_FAILED;
}
bromCbFunc(101);
printf("\n");
const char *resignStr = ops->FwGetReSignMsgStr();
if (resignStr) {
printf("%s", resignStr);
}
write_result_to_log(FLINT_SUCCESS, "", _flintParams.log_specified);
return FLINT_SUCCESS;
}
/***********************
* Class: Delete ROM
**********************/
DromSubCommand::DromSubCommand()
{
_name = "drom";
_desc = "Remove the ROM section from the flash.";
_extendedDesc = "Remove the exp-ROM from the flash if it is existing.";
_flagLong = "drom";
_flagShort = "";
_param = "";
_paramExp = "None";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " drom";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 0;
_cmdType = SC_Drom;
}
DromSubCommand:: ~DromSubCommand()
{
}
bool DromSubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() != 0) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 0, (int)_flintParams.cmd_params.size());
return false;
}
return true;
}
FlintStatus DromSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
// leave an empty line before printing from callback
FwOperations *ops = _flintParams.device_specified ? _fwOps : _imgOps;
printf("\n");
printf("-I- Preparing to remove ROM ...\n");
if (!ops->FwDeleteRom(_flintParams.allow_rom_change, dromCbFunc)) {
reportErr(true, FLINT_DROM_ERROR, ops->err());
return FLINT_FAILED;
}
dromCbFunc(101);
const char *resignStr = ops->FwGetReSignMsgStr();
if (resignStr) {
printf("%s", resignStr);
}
return FLINT_SUCCESS;
}
/***********************
* Class: Read ROM
**********************/
RromSubCommand::RromSubCommand()
{
_name = "rrom";
_desc = "Read the ROM section from the flash.";
_extendedDesc = "Read the exp-ROM from the flash if it is existing.";
_flagLong = "rrom";
_flagShort = "";
_param = "<out-file>";
_paramExp = "file: filename to write the exp-ROM to.";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " rrom exp-rom.rom";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Rrom;
}
RromSubCommand:: ~RromSubCommand()
{
}
bool RromSubCommand::verifyParams()
{
FILE *file;
if ((file = fopen(_flintParams.cmd_params[0].c_str(), "r")) != NULL) {
fclose(file);
printf(
"\n-W- The given ROM file is existing, you are going to overwrite it.\n");
if (!askUser()) {
return false;
}
}
return true;
}
FlintStatus RromSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
//get the rom sector if present.
std::vector<u_int8_t> romSect;
FwOperations *ops = _flintParams.device_specified ? _fwOps : _imgOps;
if (!ops->FwReadRom(romSect)) {
reportErr(true, FLINT_READ_ROM_ERROR, ops->err());
return FLINT_FAILED;
}
//TOCPUn(&(romSect[0]), romSect.size()/4);
if (!writeToFile(_flintParams.cmd_params[0], romSect)) {
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class:
**********************/
BbSubCommand::BbSubCommand()
{
_name = "bb";
_desc = "Burn Block - Burns the given image as is. No checks are done.";
_extendedDesc = "Burns entire flash verbatim from raw binary image. No checks are done on the flash or on the"
" given image file. No fields (such as VSD or Guids) are read from flash.";
_flagLong = "bb";
_flagShort = "";
_param = "";
_paramExp = "None";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " -i image1.bin bb";
_v = Wtv_Dev_And_Img;
_maxCmdParamNum = 0;
_cmdType = SC_Bb;
}
BbSubCommand:: ~BbSubCommand()
{
closeLog();
}
bool BbSubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() != 0) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 0, (int)(_flintParams.cmd_params.size()));
return false;
}
printf("\n Note: This option is only recommended for advanced users. Press Yes to continue");
if (!askUser()) {
return false;
}
return true;
}
FlintStatus BbSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_fwOps->FwType() == FIT_FS3) {
reportErr(true, FLINT_FS3_BB_ERROR);
return FLINT_FAILED;
}
printf("\n");
printf("Block burn: The given image will be burnt as is. No fields (such\n");
printf("as GUIDS,VSD) are taken from current image on flash.\n");
printf("Burn process will not be failsafe. No checks will be performed.\n");
printf("ALL flash, including the Invariant Sector will be overwritten.\n");
printf("If this process fails, computer may remain in an inoperable state.\n");
if (!askUser()) {
return FLINT_FAILED;
}
ProgressCallBack progressFunc = _flintParams.silent == true ? (ProgressCallBack)NULL : &burnBCbFunc;
if (!_fwOps->FwBurnBlock(_imgOps, progressFunc)) {
reportErr(true, "Non failsafe burn failed: %s\n", _fwOps->err());
return FLINT_FAILED;
}
printf("\n");
write_result_to_log(FLINT_SUCCESS, "", _flintParams.log_specified);
return FLINT_SUCCESS;
}
/***********************
* Class:
**********************/
SgSubCommand::SgSubCommand()
{
_name = "sg";
_desc = "Set GUIDs.";
_extendedDesc = "Set GUIDs/MACs/UIDs in the given device/image.\n"
"Use -guid(s), -mac(s) and -uid(s) flags to set the desired values.\n"
"- On pre-ConnectX devices, the sg command is used in production to apply GUIDs/MACs values to"
" cards that were pre-burnt with blank GUIDs. It is not meant for use in field.\n"
"- On 4th generation devices, this command can operate on both image file and image on flash.\n"
"If the GUIDs/MACs/UIDs in the image on flash are non-blank, flint will re-burn the current"
" image using the given GUIDs/MACs/UIDs.";
_flagLong = "sg";
_flagShort = "";
_param = "[guids_num=<num|num_port1,num_port2> step_size=<size|size_port1,size_port2>] | [nocrc]";
_paramExp = "nocrc: (optional) When specified the flint would not update the full image crc after changing the guids\n"
"guids_num: (optional) number of GUIDs to be allocated per physical port (FS3 Only)\n"
"step_size: (optional) step size between GUIDs (FS3 Only)\n"
"Note: guids_num/step_size values can be specified per port or for both ports";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " -guid 0x0002c9000100d050 sg" "\n"
FLINT_NAME " -d " MST_DEV_EXAMPLE4 " -guid 0x0002c9000100d050 -mac 0x0002c900d050 sg";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 2;
_cmdType = SC_Sg;
_ops = NULL;
_mccSupported = true;
memset(&_info, 0, sizeof(_info));
memset(&_sgParams, 0, sizeof(_sgParams));
memset(&(_sgParams.numOfGUIDsPP), 0xff, sizeof(_sgParams.numOfGUIDsPP));
memset(&(_sgParams.stepSizePP), 0xff, sizeof(_sgParams.stepSizePP));
_sgParams.usePPAttr = true;
}
SgSubCommand:: ~SgSubCommand()
{
}
bool SgSubCommand::verifyParams()
{
if ((_flintParams.cmd_params.size() == 1 && _flintParams.cmd_params[0] != "nocrc") || \
(_flintParams.cmd_params.size() == 2 && \
!extractUIDArgs(_flintParams.cmd_params, _sgParams.numOfGUIDsPP, _sgParams.stepSizePP))) {
reportErr(true, "The sg parameter should be \"nocrc\", \"guids_num=<num> step_size=<size>\" or nothing\n");
return false;
}
if (_flintParams.cmd_params.size() > 2) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 1, (int)_flintParams.cmd_params.size());
return false;
}
if (!(_flintParams.guid_specified || _flintParams.guids_specified || \
_flintParams.uid_specified || \
_flintParams.mac_specified || _flintParams.macs_specified)) {
reportErr(true, FLINT_COMMAND_FLAGS_ERROR, _name.c_str(), "GUIDs / MACs / UID (using command line flags -guid(s) / -mac(s) / -uid)");
return false;
}
if ((_flintParams.guid_specified || _flintParams.guids_specified) && (_flintParams.uid_specified)) {
reportErr(true, FLINT_COMMAND_FLAGS_ERROR, _name.c_str(), "either GUIDs / UIDs (using command line flags -guid(s) / -uid)");
return false;
}
if ((_flintParams.mac_specified || _flintParams.macs_specified) && (_flintParams.uid_specified)) {
reportErr(true, FLINT_COMMAND_FLAGS_ERROR, _name.c_str(), "either MACs / UIDs (using command line flags -mac(s) / -uid)");
return false;
}
if (_flintParams.guid_specified && _flintParams.guids_specified) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-guids", "-guid");
return false;
}
if (_flintParams.mac_specified && _flintParams.macs_specified) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "-macs", "-mac");
return false;
}
_sgParams.guidsSpecified = _flintParams.guid_specified || _flintParams.guids_specified;
_sgParams.macsSpecified = _flintParams.mac_specified || _flintParams.macs_specified;
_sgParams.uidSpecified = _flintParams.uid_specified;
_sgParams.updateCrc = !(_flintParams.cmd_params.size() == 1);
_sgParams.stripedImage = _flintParams.striped_image;
return true;
}
void SgSubCommand::setUserGuidsAndMacs()
{
// _sgParams.userGuids contains either guids and macs (or just guids) or just uids
// we are required to specifiy to mlxfwops a guid vector of MAX_GUIDS size regardless if user gives only guids
// or only macs or uids
if (_sgParams.guidsSpecified) {
_sgParams.userGuids = _flintParams.user_guids;
}
if (_sgParams.macsSpecified) {
if (!_sgParams.guidsSpecified) {
//it inits the guids with zeroes but mlxfwops will set them to 0xffff
//can set default init if needed
_sgParams.userGuids.resize(GUIDS);
}
_sgParams.userGuids.push_back(_flintParams.user_macs[0]);
_sgParams.userGuids.push_back(_flintParams.user_macs[1]);
}
if (_sgParams.uidSpecified) {
_sgParams.userGuids.resize(0);
_sgParams.userGuids.push_back(_flintParams.baseUid);
}
_sgParams.userGuids.resize(MAX_GUIDS);
}
bool SgSubCommand::CheckSetGuidsFlags()
{
bool ibDev;
bool ethDev;
FwOperations::SetDevFlags(_info.fw_info.chip_type, _info.fw_info.dev_type, (fw_img_type)_info.fw_type, ibDev, ethDev);
//setDevFlags(_info, ibDev,ethDev);
if (_sgParams.macsSpecified || _sgParams.guidsSpecified || _sgParams.uidSpecified) {
if (!checkGuidsFlags(_info.fw_info.dev_type, _info.fw_type, \
_sgParams.guidsSpecified, _sgParams.macsSpecified, _sgParams.uidSpecified, ibDev, ethDev)) {
return false;
}
} else {
printf("-E- ");
printMissingGuidErr(ibDev, ethDev);
printf("\n");
return false;
}
return true;
}
FlintStatus SgSubCommand::sgFs2()
{
//different behaviours for fs2 device with blank guids and fs2 device with guids or image
//different behaviour if isfailesafe or not
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 1, _flintParams.cmd_params.size());
}
if (_flintParams.device_specified && !_info.fs2_info.blank_guids) {
// 2- FS2 device with no blank Guids
printf(FLINT_SET_GUIDS_WARRNING);
}
if (!CheckSetGuidsFlags()) {
return FLINT_FAILED;
}
if (_flintParams.image_specified || !_info.fs2_info.blank_guids) {
//report guid changes
bool ethDev;
bool ibDev;
FwOperations::SetDevFlags(_info.fw_info.chip_type, _info.fw_info.dev_type, (fw_img_type)_info.fw_type, ibDev, ethDev);
//setDevFlags(_info, ibDev, ethDev);
//decide what are our new guids/macs
guid_t *new_guids = (_sgParams.guidsSpecified || _sgParams.uidSpecified) ? &_sgParams.userGuids[0] : &_info.fs2_info.guids[0];
guid_t *new_macs = _sgParams.macsSpecified ? &_sgParams.userGuids[GUIDS] : &_info.fs2_info.guids[GUIDS];
if (!reportGuidChanges(new_guids, new_macs, &_info.fs2_info.guids[0], &_info.fs2_info.guids[GUIDS], ibDev, \
ethDev, _info.fs2_info.guid_num)) {
return FLINT_FAILED;
}
}
if (!_ops->FwSetGuids(_sgParams, &verifyCbFunc, &burnCbFs2Func)) {
reportErr(true, FLINT_SG_GUID_ERROR, _ops->err());
return FLINT_FAILED;
}
burnCbFs2Func(101);
return FLINT_SUCCESS;
}
#define FW_RESET_MSG "To load new configuration run mstfwreset or reboot machine"
FlintStatus SgSubCommand::sgFs3()
{
if (!CheckSetGuidsFlags()) {
return FLINT_FAILED;
}
if (_flintParams.guids_specified || _flintParams.macs_specified) {
string flag = _flintParams.guids_specified ? "-guids" : "-macs";
reportErr(true, FLINT_NOT_SUPP_UID_FLAG_ERROR, flag.c_str());
return FLINT_FAILED;
}
// TODO: create method that checks the flags for FS3/FS2
if (_info.fw_info.chip_type == CT_CONNECT_IB || _info.fw_info.chip_type == CT_SWITCH_IB) {
if (!_flintParams.uid_specified) {
reportErr(true, FLINT_NO_UID_FLAG_ERROR);
return FLINT_FAILED;
}
// for connectib we just need the base guid so we put it in the first location.
_sgParams.userGuids.resize(1);
_sgParams.userGuids[0] = _flintParams.baseUid;
} else {
if (!_flintParams.uid_specified && !_flintParams.guid_specified && !_flintParams.mac_specified) {
reportErr(true, FLINT_NO_GUID_MAC_FLAGS_ERROR);
return FLINT_FAILED;
}
if (_flintParams.uid_specified) {
_sgParams.userGuids.resize(1);
_sgParams.userGuids[0] = _flintParams.baseUid;
} else {
// guids and/or macs were specified
guid_t tmpGuid;
tmpGuid.h = 0;
tmpGuid.l = 0;
_sgParams.userGuids.resize(2);
_sgParams.userGuids[0] = _sgParams.guidsSpecified ? _flintParams.user_guids[0] : tmpGuid;
_sgParams.userGuids[1] = _sgParams.macsSpecified ? _flintParams.user_macs[0] : tmpGuid;
}
}
if (!_ops->FwSetGuids(_sgParams, &verifyCbFunc)) {
reportErr(true, FLINT_SG_UID_ERROR, _ops->err());
return FLINT_FAILED;
}
if (_flintParams.device_specified) {
printf("-I- %s\n", FW_RESET_MSG);
}
return FLINT_SUCCESS;
}
FlintStatus SgSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
// query device
_ops = _flintParams.device_specified ? _fwOps : _imgOps;
bool stripedImage = _flintParams.striped_image && _flintParams.image_specified;
if (!_ops->FwQuery(&_info, true, stripedImage)) {
reportErr(true, FLINT_SG_GUID_ERROR, _ops->err());
return FLINT_FAILED;
}
setUserGuidsAndMacs();
if (_info.fw_type == FIT_FS2) {
return sgFs2();
}
return sgFs3();
}
/*****************************
* Class: Set Manufacture GUIDs
*****************************/
SmgSubCommand::SmgSubCommand()
{
_name = "smg";
_desc = "Set manufacture GUIDs (For FS3/FS4 image only).";
_extendedDesc = "Set manufacture GUID, Set manufacture GUIDs in the given FS3/FS4 image.\n"
"Use -uid flag to set the desired GUIDs, intended for production use only.";
_flagLong = "smg";
_flagShort = "";
_param = "[guids_num=<num|num_port1,num_port2> step_size=<size|size_port1,size_port2>]";
_paramExp = "guids_num: (optional) number of GUIDs to be allocated per physical port\n"
"step_size: (optional) step size between GUIDs\n"
"Note: guids_num/step_size values can be specified per port or for both ports";
_example = FLINT_NAME " -i fw_image.bin -uid 0x0002c9000100d050 smg"
#ifndef __WIN__
"\n" FLINT_NAME " -d " MST_DEV_EXAMPLE3 " -uid 0x0002c9000100d050 smg (should be used when device is idle)"
#endif
"\n" FLINT_NAME " -d " MST_DEV_EXAMPLE4 " -guid 0x0002c9000100d050 -mac 0x0002c900d050 smg (should be used when device is idle)";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 2;
_cmdType = SC_Smg;
_ops = NULL;
memset(&_baseGuid, 0, sizeof(_baseGuid));
memset(&_info, 0, sizeof(_info));
memset(&(_baseGuid.num_of_guids_pp), 0xff, sizeof(_baseGuid.num_of_guids_pp));
memset(&(_baseGuid.step_size_pp), 0xff, sizeof(_baseGuid.step_size_pp));
_baseGuid.use_pp_attr = 1;
}
SmgSubCommand:: ~SmgSubCommand()
{
}
bool SmgSubCommand::verifyParams()
{
if (!_flintParams.uid_specified && !_flintParams.guid_specified && !_flintParams.mac_specified) {
reportErr(true, FLINT_COMMAND_FLAGS_ERROR, _name.c_str(), "\"-uid or -guid/-mac\" flags");
return false;
}
if (_flintParams.guids_specified) {
reportErr(true, FLINT_INVALID_OPTION_ERROR, "\"-guids\"", _name.c_str(), "\"-guid\"");
return false;
}
if (_flintParams.macs_specified) {
reportErr(true, FLINT_INVALID_OPTION_ERROR, "\"-macs\"", _name.c_str(), "\"-mac\"");
return false;
}
if (_flintParams.uid_specified && (_flintParams.guid_specified || _flintParams.mac_specified)) {
reportErr(true, FLINT_INVALID_FLAG_WITH_FLAG_ERROR, "\"-uid\"", "\"-guid\"/-mac\"");
return false;
}
if (_flintParams.cmd_params.size() != 0 && _flintParams.cmd_params.size() != 2) {
reportErr(true, FLINT_CMD_ARGS_ERROR4, _name.c_str(), 0, 2, _flintParams.cmd_params.size());
return false;
}
if (_flintParams.cmd_params.size() == 2 && \
!extractUIDArgs(_flintParams.cmd_params, _baseGuid.num_of_guids_pp, _baseGuid.step_size_pp)) {
return false;
}
if (_flintParams.uid_specified) {
_baseGuid.set_mac_from_guid = true;
}
_baseGuid.base_guid_specified = _flintParams.uid_specified || _flintParams.guid_specified;
if (_baseGuid.base_guid_specified) {
_baseGuid.base_guid = _flintParams.uid_specified ? _flintParams.baseUid : _flintParams.user_guids[0];
}
_baseGuid.base_mac_specified = _flintParams.mac_specified;
if (_baseGuid.base_mac_specified) {
_baseGuid.base_mac = _flintParams.user_macs[0];
}
//printf("-D-"GUID_FORMAT"\n", _baseGuid.h, _baseGuid.l);
return true;
}
FlintStatus SmgSubCommand::executeCommand()
{
if (preFwOps()) {
return FLINT_FAILED;
}
_ops = _flintParams.device_specified ? _fwOps : _imgOps;
//TODO: dispaly MFG guid changes
bool stripedImage = _flintParams.striped_image && _flintParams.image_specified;
if (!_ops->FwQuery(&_info, true, stripedImage)) {
reportErr(true, FLINT_MFG_ERROR, _ops->err());
return FLINT_FAILED;
}
if (_info.fw_info.chip_type == CT_CONNECT_IB || _info.fw_info.chip_type == CT_SWITCH_IB) {
if (!_flintParams.uid_specified) {
reportErr(true, "Can not set GUIDs/MACs: uid is not specified, please run with -uid flag.\n");
return FLINT_FAILED;
}
} else {
if (!_flintParams.uid_specified && !_flintParams.guid_specified && !_flintParams.mac_specified) {
reportErr(true, "Can not set GUIDs/MACs: GUIDs/MACs are not specified, please run with -uid/-guid/-mac flags.\n");
return FLINT_FAILED;
}
}
bool ret;
ret = _ops->FwSetMFG(_baseGuid, &verifyCbFunc);
if (!ret) {
reportErr(true, FLINT_MFG_ERROR, _ops->err());
return FLINT_FAILED;
}
if (_flintParams.device_specified && _info.fw_type != FIT_FS2) {
printf("-I- %s\n", FW_RESET_MSG);
}
return FLINT_SUCCESS;
}
/***********************
* Class: Set Vpd Subcommand
**********************/
SetVpdSubCommand::SetVpdSubCommand()
{
_name = "set vpd";
_desc = "Set read-only VPD (For FS3/FS4 image only).";
_extendedDesc = "Set Read-only VPD, Set VPD in the given FS3/FS4 image, intended for production use only.";
_flagLong = "set_vpd";
_flagShort = "";
_param = "[vpd file]";
_paramExp = "vpd file: bin file containing the vpd data";
_example = FLINT_NAME " -i fw_image.bin set_vpd vpd.bin"
#ifndef __WIN__
"\n" FLINT_NAME " -d " MST_DEV_EXAMPLE3 " -override_cache_replacement set_vpd vpd.bin (should be used when device is idle)"
#endif
;
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Set_Vpd;
}
SetVpdSubCommand:: ~SetVpdSubCommand()
{
}
FlintStatus SetVpdSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
FwOperations *ops = _flintParams.device_specified ? _fwOps : _imgOps;
if (!ops->FwSetVPD((char*)_flintParams.cmd_params[0].c_str(), &verifyCbFunc)) {
reportErr(true, FLINT_VPD_ERROR, ops->err());
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class: SetPublicKeysSubcommand
**********************/
SetPublicKeysSubCommand::SetPublicKeysSubCommand()
{
_name = "set public keys";
_desc = "Set Public Keys (For FS3/FS4 image only).";
_extendedDesc = "Set Public Keys in the given FS3/FS4 image.";
_flagLong = "set_public_keys";
_flagShort = "";
_param = "[public keys binary file]";
_paramExp = "public keys file: bin file containing the public keys data";
_example = FLINT_NAME " -i fw_image.bin set_public_keys publickeys.bin";
_v = Wtv_Img;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Set_Public_Keys;
}
SetPublicKeysSubCommand:: ~SetPublicKeysSubCommand()
{
}
FlintStatus SetPublicKeysSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
FwOperations *ops = _imgOps;
if (!ops->FwSetPublicKeys((char*)_flintParams.cmd_params[0].c_str(), &verifyCbFunc)) {
reportErr(true, FLINT_SET_PUBLIC_KEYS_ERROR, ops->err());
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class: SetForbiddenVersionsSubcommand
**********************/
SetForbiddenVersionsSubCommand::SetForbiddenVersionsSubCommand()
{
_name = "set forbidden versions";
_desc = "Set Forbidden Versions (For FS3/FS4 image only).";
_extendedDesc = "Set Forbidden Versions in the given FS3/FS4 image.";
_flagLong = "set_forbidden_versions";
_flagShort = "";
_param = "[forbidden versions binary file]";
_paramExp = "forbidden versions file: bin file containing the forbidden versions data";
_example = FLINT_NAME " -i fw_image.bin set_forbidden_versions forbidden_versions.bin";
_v = Wtv_Img;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Set_Forbidden_Versions;
}
SetForbiddenVersionsSubCommand:: ~SetForbiddenVersionsSubCommand()
{
}
FlintStatus SetForbiddenVersionsSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
FwOperations *ops = _imgOps;
if (!ops->FwSetForbiddenVersions((char*)_flintParams.cmd_params[0].c_str(), &verifyCbFunc)) {
reportErr(true, FLINT_SET_FORBIDDEN_VERSIONS_ERROR, ops->err());
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class: Set VSD
**********************/
SvSubCommand::SvSubCommand()
{
_name = "sv";
_desc = "Set the VSD.";
_extendedDesc = "Set VSD in the given device/image.\n"
"Use -vsd flag to set the desired VSD string.";
_flagLong = "sv";
_flagShort = "";
_param = "";
_paramExp = "None";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " -vsd VSD_STRING sv"
#ifndef __WIN__
"\n" FLINT_NAME " -d " MST_DEV_EXAMPLE3 " -vsd VSD_STRING -override_cache_replacement sv (should be used when device is idle)\n"
#endif
;
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 0;
_cmdType = SC_Sv;
}
SvSubCommand:: ~SvSubCommand()
{
}
bool SvSubCommand::verifyParams()
{
if (!_flintParams.vsd_specified) {
reportErr(true, FLINT_COMMAND_FLAGS_ERROR, _name.c_str(), "\"-vsd\"");
return false;
}
// we verify that -vsd has a parameter in the cmd parser
return true;
}
FlintStatus SvSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
FwOperations *ops = _flintParams.device_specified ? _fwOps : _imgOps;
if (!ops->FwSetVSD((char*)_flintParams.vsd.c_str(), &vsdCbFunc, &verifyCbFunc)) {
reportErr(true, FLINT_VSD_ERROR, ops->err());
return FLINT_FAILED;
}
if (ops->FwType() == FIT_FS2) {
// print "restoring signature" on FS2 to be consistent with FS3 output
vsdCbFunc(101);
}
return FLINT_SUCCESS;
}
/*******************************
* Class: Read Image SubCommand
******************************/
RiSubCommand::RiSubCommand()
{
_name = "ri";
_desc = "Read the fw image on the flash.";
_extendedDesc = "Read the FW image from flash and write it to a file.";
_flagLong = "ri";
_flagShort = "";
_param = "<out-file>";
_paramExp = "file: filename to write the image to (raw binary).";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " ri file.bin";
_v = Wtv_Dev;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Ri;
}
RiSubCommand:: ~RiSubCommand()
{
}
FlintStatus RiSubCommand::executeCommand()
{
//init fw operation object
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
// Check if we have permission to write to file
FILE *fh;
if ((fh = fopen(_flintParams.cmd_params[0].c_str(), "wb")) == NULL) {
reportErr(true, "Can not open %s: %s\n", _flintParams.cmd_params[0].c_str(), strerror(errno));
return FLINT_FAILED;
} else {
fclose(fh);
}
u_int32_t imgSize;
//on first call we get the image size
if (!_fwOps->FwReadData(NULL, &imgSize)) {
reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err());
return FLINT_FAILED;
}
std::vector<u_int8_t> imgBuff(imgSize);
//on second call we fill it
if (!_fwOps->FwReadData((void*)(&imgBuff[0]), &imgSize)) {
reportErr(true, FLINT_IMAGE_READ_ERROR, _fwOps->err());
return FLINT_FAILED;
}
return writeImageToFile(_flintParams.cmd_params[0].c_str(), &(imgBuff[0]), imgSize);
}
/***********************
* Class: Dump Conf SubCommand
**********************/
DcSubCommand::DcSubCommand()
{
_name = "dc";
_desc = "Dump Configuration: print fw configuration file for the given image.";
_extendedDesc = "Print (to screen or to a file) the FW configuration text file used by the image generation process.\n"
"This command would fail if the image does not contain a FW configuration section."
" Existence of this section depends on the version of the image generation tool.";
_flagLong = "dc";
_flagShort = "";
_param = "[out-file]";
_paramExp = "file: (optional) filename to write the dumped configuration to. If not given,"
" the data is printed to screen";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " dc";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 1;
_cmdType = SC_Dc;
}
DcSubCommand:: ~DcSubCommand()
{
}
bool DcSubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 1, (int)_flintParams.cmd_params.size());
return false;
}
return true;
}
FlintStatus DcSubCommand::executeCommand()
{
FwOperations *ops;
//init fw operation object
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
//check on what we are wroking
ops = (_flintParams.device_specified) ? _fwOps : _imgOps;
const char *file = _flintParams.cmd_params.size() == 1 ? _flintParams.cmd_params[0].c_str() : (const char*) NULL;
if (!ops->FwGetSection((ops->FwType() == FIT_FS2) ? (int)H_FW_CONF : (int)FS3_DBG_FW_INI, _sect, _flintParams.striped_image)) {
reportErr(true, FLINT_DUMP_ERROR, "Fw Configuration", ops->err());
return FLINT_FAILED;
}
if (!dumpFile(file, _sect, "Fw Configuration")) {
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class:Dump Hash SubCommand
**********************/
DhSubCommand::DhSubCommand()
{
_name = "dh";
_desc = "Dump Hash: dump the hash if it is integrated in the FW image";
_extendedDesc = "Print (to screen or to a file) the HASH text file used by the FW.\n"
"This command would fail if the image does not contain a Hash file.";
_flagLong = "dh";
_flagShort = "";
_param = "[out-file]";
_paramExp = "file - (optional) filename to write the dumped tracer hash file to. If not given,"
" the data is printed to screen";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " dh hash.csv";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 1;
_cmdType = SC_Dh;
}
DhSubCommand:: ~DhSubCommand()
{
}
bool DhSubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 1, (int)_flintParams.cmd_params.size());
return false;
}
return true;
}
FlintStatus DhSubCommand::executeCommand()
{
FwOperations *ops;
//init fw operation object
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
//check on what we are wroking
ops = (_flintParams.device_specified) ? _fwOps : _imgOps;
const char *file = _flintParams.cmd_params.size() == 1 ? _flintParams.cmd_params[0].c_str() : (const char*)NULL;
if (!ops->FwGetSection(H_HASH_FILE, _sect, _flintParams.striped_image)) {
reportErr(true, FLINT_DUMP_ERROR, "Hash file", ops->err());
return FLINT_FAILED;
}
if (!dumpFile(file, _sect, "Fw Configuration")) {
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class:Set Key SubCommand
**********************/
SetKeySubCommand::SetKeySubCommand()
{
_name = "set_key";
_desc = "Set/Update the HW access key which is used to enable/disable access to HW.\n"
"The key can be provided in the command line or interactively typed after the command is given\n"
"NOTE: The new key is activated only after the device is reset.";
_extendedDesc = "Set/Update the HW access key which is used to enable/disable access to HW.";
_flagLong = "set_key";
_flagShort = "";
_param = "[key]";
_paramExp = "key: (optional) The new key you intend to set (in hex).";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " set_key 1234deaf5678";
_v = Wtv_Dev;
_maxCmdParamNum = 1;
_cmdType = SC_Set_Key;
_getKeyInter = false;
memset(&_userKey, 0, sizeof(_userKey));
}
SetKeySubCommand:: ~SetKeySubCommand()
{
}
bool SetKeySubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 1, (int)_flintParams.cmd_params.size());
return false;
}
_getKeyInter = (_flintParams.cmd_params.size() == 0);
return true;
}
bool SetKeySubCommand::getKeyInteractively()
{
char keyArr[MAX_PASSWORD_LEN + 1] = {0};
getPasswordFromUser("Enter Key ", keyArr);
if (strlen(keyArr) == 0) {
reportErr(true, FLINT_INVALID_PASSWORD);
return false;
}
if (!getGUIDFromStr(keyArr, _userKey, \
"Invalid Key syntax, it should contain only hexa numbers and of appropriate length.")) {
return false;
}
// verify key
hw_key_t verKey;
getPasswordFromUser("Verify Key ", keyArr);
if (!getGUIDFromStr(keyArr, verKey, \
"Invalid Key syntax, it should contain only hexa numbers and of appropriate length.")) {
return false;
}
if (_userKey.h != verKey.h || _userKey.l != verKey.l) {
reportErr(true, FLINT_SET_KEY_ERROR, "The keys you entered did not match.");
return false;
}
return true;
}
FlintStatus SetKeySubCommand::executeCommand()
{
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_getKeyInter) {
if (!getKeyInteractively()) {
return FLINT_FAILED;
}
} else {
if (!getGUIDFromStr(_flintParams.cmd_params[0], _userKey, \
"Invalid Key syntax, it should contain only hexa numbers and of appropriate length.")) {
return FLINT_FAILED;
}
}
if (((Flash*)_io)->is_fifth_gen()) {
if (((Flash*)_io)->get_cr_space_locked()) {
printf("-I- HW access already disabled\n");
return FLINT_SUCCESS;
}
// In 5th gen treat set as disable hw access
u_int64_t key = ((u_int64_t)_userKey.h << 32) | _userKey.l;
if (!((Flash*)_io)->disable_hw_access(key)) {
reportErr(true, FLINT_GEN_COMMAND_ERROR, _name.c_str(), _io->err());
return FLINT_FAILED;
}
printf("-I- Secure Host was enabled successfully on the device.\n");
} else {
_io->close();
delete _io;
_io = NULL;
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (!_fwOps->FwSetAccessKey(_userKey, &setKeyCbFunc)) {
reportErr(true, FLINT_SET_KEY_ERROR, _fwOps->err());
return FLINT_FAILED;
}
setKeyCbFunc(101);
printf("\n-I- New key was updated successfully in the flash. " \
"In order to activate the new key you should reboot or restart the driver.\n");
}
return FLINT_SUCCESS;
}
/***********************
* Class:HwAccess SubCommand
**********************/
HwAccessSubCommand::HwAccessSubCommand()
{
_name = "hw_access";
_desc = "Enable/disable the access to the HW.\n"
"The key can be provided in the command line or interactively typed after the command is given";
_extendedDesc = "Enable/disable the access to the HW.";
_flagLong = "hw_access";
_flagShort = "";
_param = "<enable|disable> [key]";
_paramExp = "<enable/disable>: Specify if you intend to disable or enable the HW access.\n"
"You will be asked to type a key when you try to enable HW access.\n"
"key: The key you intend to use for enabling the HW access, or disabling it in 5th Gen devices.\n"
"Key format consists of at most 16 Hexadecimal digits.";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " hw_access enable";
_v = Wtv_Dev;
_maxCmdParamNum = 2;
_cmdType = SC_Hw_Access;
}
HwAccessSubCommand:: ~HwAccessSubCommand()
{
}
bool HwAccessSubCommand::verifyParams()
{
if (_flintParams.cmd_params.size() == 0) {
reportErr(true, FLINT_MISSED_ARG_ERROR, "<disable/enable>", _name.c_str());
return false;
}
if (_flintParams.cmd_params.size() > 2) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 2, (int)_flintParams.cmd_params.size());
return false;
}
if (_flintParams.cmd_params[0] != "enable" && _flintParams.cmd_params[0] != "disable") {
reportErr(true, FLINT_INVALID_OPTION_ERROR, _flintParams.cmd_params[0].c_str(), _name.c_str(), "enable or disable");
return false;
}
return true;
}
FlintStatus HwAccessSubCommand::disableHwAccess()
{
if (((Flash*)_io)->get_cr_space_locked()) {
printf("-I- HW access already disabled\n");
} else {
if (((Flash*)_io)->is_fifth_gen()) {
SubCommand *setKey = new SetKeySubCommand();
_flintParams.cmd_params.erase(_flintParams.cmd_params.begin());
setKey->setParams(_flintParams);
FlintStatus rc = setKey->executeCommand();
delete setKey;
return rc;
} else {
if (!((Flash*)_io)->disable_hw_access()) {
printf(FLINT_GEN_COMMAND_ERROR, _name.c_str(), _io->err());
return FLINT_FAILED;
}
}
}
return FLINT_SUCCESS;
}
FlintStatus HwAccessSubCommand::enableHwAccess()
{
u_int64_t key;
if (((Flash*)_io)->get_cr_space_locked() == 0) {
printf("-I- HW access already enabled\n");
} else {
hw_key_t keyStruct;
//now we need to get the key from the user (either given in the parameters or we get it during runtime)
if (_flintParams.cmd_params.size() == 2) {
if (!getGUIDFromStr(_flintParams.cmd_params[1], keyStruct, \
"Invalid Key syntax, it should contain only hexa numbers and of appropriate length.")) {
return FLINT_FAILED;
}
} else {//we need to get the key from user during runtime
char keyArr[MAX_PASSWORD_LEN + 1] = {0};
getPasswordFromUser("Enter Key ", keyArr);
if (strlen(keyArr) == 0) {
reportErr(true, FLINT_INVALID_PASSWORD);
return FLINT_FAILED;
}
if (!getGUIDFromStr(keyArr, keyStruct, \
"Invalid Key syntax, it should contain only hexa numbers and of appropriate length.")) {
return FLINT_FAILED;
}
}
key = ((u_int64_t)keyStruct.h << 32) | keyStruct.l;
if (!((Flash*)_io)->enable_hw_access(key)) {
reportErr(true, FLINT_GEN_COMMAND_ERROR, _name.c_str(), _io->err());
return FLINT_FAILED;
}
printf("-I- The Secure Host was disabled successfully on the device.\n");
}
return FLINT_SUCCESS;
}
FlintStatus HwAccessSubCommand::executeCommand()
{
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_flintParams.cmd_params[0] == "disable") {
return disableHwAccess();
}
//else its enable hw access
return enableHwAccess();
}
/***********************
* Class: Hw SubCommand
**********************/
HwSubCommand::HwSubCommand()
{
#ifndef EXTERNAL
_name = "hw";
_desc = "Set/query HW info and flash attributes.";
_extendedDesc = "Access HW info and flash attributes.";
_flagLong = "hw";
_flagShort = "";
_param = "<query|set> [ATTR=VAL]";
_paramExp = "query: query HW info\n"
"set [ATTR=VAL]: set flash attribure\n"
"Supported attributes:\n"
" QuadEn: can be 0 or 1\n"
" DummyCycles: can be [1..15]\n"
" Flash[0|1|2|3].WriteProtected can be:\n"
" <Top|Bottom>,<1|2|4|8|16|32|64>-<Sectors|SubSectors>";
_example = "flint -d " MST_DEV_EXAMPLE1 " hw query\n"
FLINT_NAME " -d " MST_DEV_EXAMPLE1 " hw set QuadEn=1\n"
FLINT_NAME " -d " MST_DEV_EXAMPLE1 " hw set Flash1.WriteProtected=Top,1-SubSectors";
#else
_name = "Hw";
_desc = "Query HW info and flash attributes.";
_extendedDesc = "Query HW info and flash attributes.";
_flagLong = "hw";
_flagShort = "";
_param = "query";
_paramExp = "query";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " hw query";
#endif
_v = Wtv_Dev;
_maxCmdParamNum = 2;
_minCmdParamNum = 1;
_cmdType = SC_Hw;
}
HwSubCommand:: ~HwSubCommand()
{
}
bool HwSubCommand::verifyParams()
{
#ifdef EXTERNAL
if (_flintParams.cmd_params.size() != 1) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 1, (int)_flintParams.cmd_params.size());
return false;
}
if (_flintParams.cmd_params[0] != "query") {
reportErr(true, FLINT_INVALID_OPTION_ERROR, _flintParams.cmd_params[0].c_str(), _name.c_str(), "query");
return false;
}
#else
if (_flintParams.cmd_params.size() > 2 || _flintParams.cmd_params.size() == 0) {
reportErr(true, FLINT_CMD_ARGS_ERROR2, _name.c_str(), 2, (int)_flintParams.cmd_params.size());
return false;
}
if ((_flintParams.cmd_params[0] != "query") && (_flintParams.cmd_params[0] != "set")) {
reportErr(true, FLINT_INVALID_OPTION_ERROR, _flintParams.cmd_params[0].c_str(), _name.c_str(), "query or set");
return false;
}
if ((_flintParams.cmd_params[0] == "set") && (_flintParams.cmd_params.size() != 2)) {
reportErr(true, FLINT_CMD_ARGS_ERROR, _name.c_str(), 2, (int)_flintParams.cmd_params.size());
return false;
}
#endif
return true;
}
FlintStatus HwSubCommand::printAttr(const ext_flash_attr_t& attr)
{
printf("HW Info:\n");
printf(" HwDevId %d\n", attr.hw_dev_id);
printf(" HwRevId 0x%x\n", attr.rev_id);
printf("Flash Info:\n");
if (attr.type_str != NULL) {
// we don't print the flash type in old devices
printf(" Type %s\n", attr.type_str);
}
printf(" TotalSize 0x%x\n", attr.size);
printf(" Banks 0x%x\n", attr.banks_num);
printf(" SectorSize 0x%x\n", attr.sector_size);
printf(" WriteBlockSize 0x%x\n", attr.block_write);
printf(" CmdSet 0x%x\n", attr.command_set);
// Quad EN query
if (attr.quad_en_support) {
switch (attr.mf_get_quad_en_rc) {
case MFE_OK:
printf(" " QUAD_EN_PARAM " %d\n", attr.quad_en);
break;
case MFE_MISMATCH_PARAM:
printf("-E- There is a mismatch in the " QUAD_EN_PARAM " attribute between the flashes attached to the device\n");
break;
case MFE_NOT_SUPPORTED_OPERATION:
break;
default:
printf("Failed to get " QUAD_EN_PARAM " attribute: %s (%s)", \
errno == 0 ? "" : strerror(errno), mf_err2str(attr.mf_get_quad_en_rc));
return FLINT_FAILED;
}
}
// Dummy Cycles query
if (attr.dummy_cycles_support) {
switch (attr.mf_get_dummy_cycles_rc) {
case MFE_OK:
printf(" " DUMMY_CYCLES_PARAM " %d\n", attr.dummy_cycles);
break;
case MFE_MISMATCH_PARAM:
printf("-E- There is a mismatch in the " DUMMY_CYCLES_PARAM " attribute between the flashes attached to the device\n");
break;
case MFE_NOT_SUPPORTED_OPERATION:
break;
default:
printf("Failed to get " DUMMY_CYCLES_PARAM " attribute: %s (%s)", \
errno == 0 ? "" : strerror(errno), mf_err2str(attr.mf_get_dummy_cycles_rc));
return FLINT_FAILED;
}
}
// Flash write protected info query
if (attr.write_protect_support) {
int bank;
int rc;
for (bank = 0; bank < attr.banks_num; bank++) {
write_protect_info_t protect_info = attr.protect_info_array[bank];
rc = attr.mf_get_write_protect_rc_array[bank];
if (rc == MFE_OK) {
printf(" " FLASH_NAME "%d." WRITE_PROTECT " ", bank);
if (protect_info.sectors_num != 0) {
printf("%s,", (protect_info.is_bottom ? WP_BOTTOM_STR : WP_TOP_STR));
printf("%d-", protect_info.sectors_num);
printf("%s\n", (protect_info.is_subsector ? WP_SUBSEC_STR : WP_SEC_STR));
} else {
printf(WP_DISABLED_STR "\n");
}
} else {
if (rc != MFE_NOT_SUPPORTED_OPERATION) {
// We ignore the read when operation is not supported!
printf("Failed to get write_protected info: %s (%s)", errno == 0 ? "" : strerror(errno), mf_err2str(rc));
return FLINT_FAILED;
}
}
}
}
return FLINT_SUCCESS;
}
FlintStatus HwSubCommand::executeCommand()
{
//init fw operation object
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (_flintParams.cmd_params[0] == "set") {
char *cmdParam = strcpy(new char[_flintParams.cmd_params[1].size() + 1],
_flintParams.cmd_params[1].c_str());
char *paramName, *paramValStr;
paramName = strtok(cmdParam, "=");
paramValStr = strtok(NULL, "=");
//printf("-D- param_name = %s, param_val_str=%s, cmdParam=%s\n", paramName, paramValStr, cmdParam);
if (paramName == NULL || paramValStr == NULL) {
delete[] cmdParam;
reportErr(true, FLINT_HW_SET_ARGS_ERROR, _flintParams.cmd_params[1].c_str());
return FLINT_FAILED;
}
if (!((Flash*) _io)->set_attr(paramName, paramValStr)) {
delete[] cmdParam;
reportErr(true, FLINT_HW_COMMAND_ERROR, "set", _io->err());
return FLINT_FAILED;
}
printf("-I- %s parameter was set successfully\n", paramName);
delete[] cmdParam;
} else {
ext_flash_attr_t attr;
attr.type_str = (char*)NULL;
if (!((Flash*) _io)->get_attr(attr)) {
reportErr(true, FLINT_HW_COMMAND_ERROR, "query", _io->err());
if (attr.type_str) {
delete[] attr.type_str;
}
return FLINT_FAILED;
}
FlintStatus rc = printAttr(attr);
//str is allocated in get_attr
if (attr.type_str) {
delete[] attr.type_str;
}
if (rc == FLINT_FAILED) {
return FLINT_FAILED;
}
}
return FLINT_SUCCESS;
}
/**************************
* Class: Erase SubCommand
*************************/
EraseSubCommand::EraseSubCommand()
{
_name = "erase";
_desc = "Erases sector.";
_extendedDesc = "Erases a sector that contains specified address.";
_flagLong = "erase";
_flagShort = "e";
_param = "<addr>";
_paramExp = "addr - address of word in sector that you want to erase.";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " erase 0x10000";
_v = Wtv_Dev;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Erase;
}
EraseSubCommand:: ~EraseSubCommand()
{
}
FlintStatus EraseSubCommand::executeCommand()
{
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
u_int32_t addr;
char *addrStr = strcpy(new char[_flintParams.cmd_params[0].size() + 1], _flintParams.cmd_params[0].c_str());
char *endp;
// Address of sector to erase
addr = strtoul(addrStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_ADDR_ERROR, _flintParams.cmd_params[0].c_str());
delete[] addrStr;
return FLINT_FAILED;
}
delete[] addrStr;
// Erase
if (!((Flash*)_io)->erase_sector(addr)) {
reportErr(true, FLINT_ERASE_SEC_ERROR, _io->err());
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/*****************************
* Class: Read Dword SubCommand
*****************************/
RwSubCommand::RwSubCommand()
{
_name = "rw";
_desc = "Read one dword from flash";
_extendedDesc = "Read one dword from flash.";
_flagLong = "rw";
_flagShort = "";
_param = "<addr>";
_paramExp = "addr - address of word to read";
_example = "flint -d " MST_DEV_EXAMPLE1 " rw 0x20";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 1;
_minCmdParamNum = 1;
_cmdType = SC_Rw;
}
RwSubCommand:: ~RwSubCommand()
{
}
FlintStatus RwSubCommand::executeCommand()
{
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
u_int32_t addr;
u_int32_t data;
char *addrStr = strcpy(new char[_flintParams.cmd_params[0].size() + 1], _flintParams.cmd_params[0].c_str());
char *endp;
addr = strtoul(addrStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_ADDR_ERROR, _flintParams.cmd_params[0].c_str());
delete[] addrStr;
return FLINT_FAILED;
}
delete[] addrStr;
if (_flintParams.device_specified ? !((Flash*)_io)->read(addr, &data) \
: !((FImage*)_io)->read(addr, &data)) {
reportErr(true, FLINT_FLASH_READ_ERROR, _io->err());
return FLINT_FAILED;
}
printf("0x%08x\n", (unsigned int)__cpu_to_be32(data));
return FLINT_SUCCESS;
}
/******************************
* Class: Write Dword Subcommand
******************************/
WwSubCommand::WwSubCommand()
{
_name = "ww";
_desc = "Write one dword to flash";
_extendedDesc = "Write one dword to flash.\n"
"Note that the utility will read an entire flash sector,"
" modify one word and write the sector back. This may take a few seconds.";
_flagLong = "ww";
_flagShort = "";
_param = "<addr> <data>";
_paramExp = "addr - address of word\n"
"data - value of word";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " ww 0x10008 0x5a445a44";
_v = Wtv_Dev;
_maxCmdParamNum = 2;
_minCmdParamNum = 2;
_cmdType = SC_Ww;
}
WwSubCommand:: ~WwSubCommand()
{
}
FlintStatus WwSubCommand::executeCommand()
{
//init fw operation object
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
u_int32_t addr;
u_int32_t data;
char *addrStr = strcpy(new char[_flintParams.cmd_params[0].size() + 1], _flintParams.cmd_params[0].c_str());
char *dataStr = strcpy(new char[_flintParams.cmd_params[1].size() + 1], _flintParams.cmd_params[1].c_str());
char *endp;
addr = strtoul(addrStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_ADDR_ERROR, _flintParams.cmd_params[0].c_str());
delete[] addrStr;
delete[] dataStr;
return FLINT_FAILED;
}
data = strtoul(dataStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_DATA_ERROR, _flintParams.cmd_params[1].c_str());
delete[] addrStr;
delete[] dataStr;
return FLINT_FAILED;
}
delete[] addrStr;
delete[] dataStr;
data = __cpu_to_be32(data);
if (!((Flash*)_io)->write(addr, data)) {
reportErr(true, FLINT_FLASH_WRITE_ERROR, _io->err());
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***************************************
* Class: Write Dword No Erase SubCommand
***************************************/
WwneSubCommand::WwneSubCommand()
{
_name = "wwne";
_desc = "Write one dword to flash without sector erase";
_extendedDesc = "Write one dword to flash without sector erase.\n"
"Note that the result of operation is undefined and depends on flash type."
" Usually \"bitwise AND\" (&) between specified word and previous flash contents will be"
" written to specified address.";
_flagLong = "wwne";
_flagShort = "";
_param = "<addr> <data>";
_paramExp = "addr - address of word\n"
"data - value of word";
_example = "flint -d " MST_DEV_EXAMPLE1 " wwne 0x10008 0x5a445a44";
_v = Wtv_Dev;
_maxCmdParamNum = 2;
_minCmdParamNum = 2;
_cmdType = SC_Wwne;
}
WwneSubCommand:: ~WwneSubCommand()
{
}
FlintStatus WwneSubCommand::executeCommand()
{
//init fw operation object
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
u_int32_t addr;
u_int32_t data;
char *addrStr = strcpy(new char[_flintParams.cmd_params[0].size() + 1], _flintParams.cmd_params[0].c_str());
char *dataStr = strcpy(new char[_flintParams.cmd_params[1].size() + 1], _flintParams.cmd_params[1].c_str());
char *endp;
addr = strtoul(addrStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_ADDR_ERROR, _flintParams.cmd_params[0].c_str());
delete[] addrStr;
delete[] dataStr;
return FLINT_FAILED;
}
data = strtoul(dataStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_DATA_ERROR, _flintParams.cmd_params[1].c_str());
delete[] addrStr;
delete[] dataStr;
return FLINT_FAILED;
}
delete[] addrStr;
delete[] dataStr;
data = __cpu_to_be32(data);
if (!((Flash*)_io)->write(addr, &data, 4, true)) {
reportErr(true, FLINT_FLASH_WRITE_ERROR, _io->err());
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/**************************************
* Class:Write Block SubCommand
**************************************/
WbSubCommand::WbSubCommand()
{
_name = "wb";
_desc = "Write a data block to flash.";
_extendedDesc = "Write a block of data to the flash.";
_flagLong = "wb";
_flagShort = "";
_param = "<data-file> <addr>";
_paramExp = "data-file - file that contains the data to be written\n"
"addr - address to write the block to\n";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " wb myData.bin 0x0";
_v = Wtv_Dev;
_maxCmdParamNum = 2;
_minCmdParamNum = 2;
_cmdType = SC_Wb;
}
WbSubCommand:: ~WbSubCommand()
{
}
bool WbSubCommand::extractData(const std::vector<string>& cmdParams, u_int32_t *addr, std::vector<u_int8_t>& data)
{
// get address
char *endp;
char *addrStr = strcpy(new char[cmdParams[1].size() + 1], cmdParams[1].c_str());
*addr = strtoul(addrStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_ADDR_ERROR, cmdParams[1].c_str());
delete[] addrStr;
return false;
}
delete[] addrStr;
// get data
FImage img;
if (!img.open(cmdParams[0].c_str())) {
reportErr(true, FLINT_WB_FILE_ERROR, cmdParams[0].c_str(), img.err());
return false;
}
//copy data to vector
data.resize(img.getBufLength());
if (!img.getBuf()) {
reportErr(true, FLINT_IMAGE_READ_ERROR, img.err());
return false;
}
memcpy(&data[0], img.getBuf(), img.getBufLength());
return true;
}
FlintStatus WbSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
u_int32_t addr;
std::vector<u_int8_t> data;
if (!extractData(_flintParams.cmd_params, &addr, data)) {
return FLINT_FAILED;
}
//printf("-D- writing to addr:0x%08x %lu bytes\n",addr , data.size());
if (!_fwOps->FwWriteBlock(addr, data, wbCbFunc)) {
reportErr(true, FLINT_WB_ERROR, _fwOps->err());
return FLINT_FAILED;
}
wbCbFunc(101);
return FLINT_SUCCESS;
}
/**************************************
* Class:Write Block No Erase SubCommand
**************************************/
WbneSubCommand::WbneSubCommand()
{
_name = "wbne";
_desc = "Write a data block to flash without sector erase.";
_extendedDesc = "Write a block of data to the flash without erasing.";
_flagLong = "wbne";
_flagShort = "";
_param = "<addr> <size> <data ...>";
_paramExp = "addr - address of block\n"
"size - size of data to write in bytes\n"
"data - data to write - space separated dwords";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " wbne 0x10000 12 0x30000 0x76800 0x5a445a44";
_v = Wtv_Dev;
_minCmdParamNum = 3;
_cmdType = SC_Wbne;
}
WbneSubCommand:: ~WbneSubCommand()
{
}
bool WbneSubCommand::writeBlock(u_int32_t addr, std::vector<u_int32_t> dataVec)
{
//we should work only on flash.
//check if flash is big enough
if (addr + (dataVec.size() * 4) > ((Flash*)_io)->get_size()) {
reportErr(true, "Writing %#x bytes from address %#x is out of flash limits (%#x bytes)\n",
(unsigned int)(dataVec.size() * 4), (unsigned int)addr, (unsigned int)_io->get_size());
return false;
}
if (!((Flash*)_io)->write(addr, &dataVec[0], (dataVec.size() * 4), true)) {
reportErr(true, FLINT_FLASH_WRITE_ERROR, _io->err());
return false;
}
return true;
}
bool WbneSubCommand::extractData(const std::vector<string>& cmdParams, u_int32_t *addr, std::vector<u_int32_t>& data)
{
char *endp;
char *addrStr = strcpy(new char[cmdParams[0].size() + 1], cmdParams[0].c_str());
*addr = strtoul(addrStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_ADDR_ERROR, cmdParams[0].c_str());
delete[] addrStr;
return false;
}
delete[] addrStr;
char *sizeStr = strcpy(new char[cmdParams[1].size() + 1], cmdParams[1].c_str());
u_int32_t size = strtoul(sizeStr, &endp, 0);
if (*endp || size % 4 || size / 4 != (cmdParams.size() - 2)) {
reportErr(true, FLINT_INVALID_SIZE_ERROR, sizeStr);
delete[] sizeStr;
return false;
}
delete[] sizeStr;
for (u_int32_t i = 2; i < cmdParams.size(); i++) {
char *dataStr = strcpy(new char[cmdParams[i].size() + 1], cmdParams[i].c_str());
data.push_back(__cpu_to_be32(strtoul(dataStr, &endp, 0)));
if (*endp) {
reportErr(true, FLINT_INVALID_DATA_ERROR, dataStr);
delete[] dataStr;
return false;
}
delete[] dataStr;
}
return true;
}
FlintStatus WbneSubCommand::executeCommand()
{
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
u_int32_t addr;
std::vector<u_int32_t> data;
if (!extractData(_flintParams.cmd_params, &addr, data)) {
return FLINT_FAILED;
}
//printf("-D- writing to addr:0x%08x %lu bytes\n",addr , data.size()*4);
if (!writeBlock(addr, data)) {
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class: ReadBlock
**********************/
RbSubCommand::RbSubCommand()
{
_name = "rb";
_desc = "Read a data block from flash";
_extendedDesc = "Read a data block from the flash and write it to a file or to screen.";
_flagLong = "rb";
_flagShort = "";
_param = "<addr> <size> [out-file]";
_paramExp = "addr - address of block\n"
"size - size of data to read in bytes\n"
"file - filename to write the block (raw binary). If not given, the data is printed to screen";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " rb 0x10000 100 file.bin";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 3;
_minCmdParamNum = 2;
_cmdType = SC_Rb;
}
RbSubCommand:: ~RbSubCommand()
{
}
bool RbSubCommand::readBlock(u_int32_t addr, std::vector<u_int8_t>& buff, bool isFlash)
{
FwOperations *ops = isFlash ? _fwOps : _imgOps;
if (!ops->FwReadBlock(addr, buff.size(), buff)) {
reportErr(true, FLINT_IMAGE_READ_ERROR, ops->err());
return false;
}
return true;
}
bool RbSubCommand::printToScreen(const std::vector<u_int8_t>& buff)
{
for (u_int32_t i = 0; i < buff.size(); i += 4) {
u_int32_t word = *((u_int32_t*)(&buff[0] + i));
word = __be32_to_cpu(word);
printf("0x%08x ", word);
}
printf("\n");
return true;
}
FlintStatus RbSubCommand::executeCommand()
{
//init fw operation object
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
bool wTF = _flintParams.cmd_params.size() == 3 ? true : false;
//extract address and size to read from cmdline
u_int32_t addr;
u_int32_t size;
char *endp;
char *addrStr = strcpy(new char[_flintParams.cmd_params[0].size() + 1], _flintParams.cmd_params[0].c_str());
addr = strtoul(addrStr, &endp, 0);
if (*endp) {
reportErr(true, FLINT_INVALID_ADDR_ERROR, _flintParams.cmd_params[0].c_str());
delete[] addrStr;
return FLINT_FAILED;
}
delete[] addrStr;
char *sizeStr = strcpy(new char[_flintParams.cmd_params[1].size() + 1], _flintParams.cmd_params[1].c_str());
size = strtoul(sizeStr, &endp, 0);
if (*endp || size % 4) {
reportErr(true, FLINT_INVALID_SIZE_ERROR, sizeStr);
delete[] sizeStr;
return FLINT_FAILED;
}
delete[] sizeStr;
//init byte vector and fill it with data
std::vector<u_int8_t> data(size);
if (!readBlock(addr, data, _flintParams.device_specified)) {
return FLINT_FAILED;
}
//print either to file or to screen
FlintStatus rc;
if (wTF) {
rc = writeToFile(_flintParams.cmd_params[2], data) == true ? FLINT_SUCCESS : FLINT_FAILED;
} else {
rc = printToScreen(data) == true ? FLINT_SUCCESS : FLINT_FAILED;
}
return rc;
}
/***********************
* Class: ClearSemaphore
**********************/
ClearSemSubCommand::ClearSemSubCommand()
{
_name = "clear_semaphore";
_desc = "Clear flash semaphore.";
_extendedDesc = "Clear flash semaphore.";
_flagLong = "clear_semaphore";
_flagShort = "";
_param = "";
_paramExp = "";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " -clear_semaphore";
_v = Wtv_Dev;
_maxCmdParamNum = 0;
_cmdType = SC_Clear_Sem;
}
ClearSemSubCommand:: ~ClearSemSubCommand()
{
}
FlintStatus ClearSemSubCommand::executeCommand()
{
_flintParams.clear_semaphore = true;
return preFwAccess();
}
/***********************
* Class: RomQuery
**********************/
RomQuerySubCommand::RomQuerySubCommand()
{
_name = "qrom";
_desc = "query ROM image.";
_extendedDesc = "query ROM image.";
_flagLong = "qrom";
_flagShort = "";
_param = "";
_paramExp = "";
_example = FLINT_NAME " -i ROM_image.bin qrom ";
_v = Wtv_Img;
_maxCmdParamNum = 0;
_cmdType = SC_Qrom;
memset(&_romsInfo, 0, sizeof(_romsInfo));
}
RomQuerySubCommand:: ~RomQuerySubCommand()
{
}
FlintStatus RomQuerySubCommand::executeCommand()
{
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
getRomsInfo(_io, _romsInfo);
if (_romsInfo.exp_rom_err_msg_valid != 0) {
reportErr(true, FLINT_ROM_QUERY_ERROR, _flintParams.image.c_str(), _romsInfo.exp_rom_err_msg);
return FLINT_FAILED;
}
displayExpRomInfo(_romsInfo, "Rom Info: ");
return FLINT_SUCCESS;
}
/***********************
* Class: ResetCfg
**********************/
ResetCfgSubCommand::ResetCfgSubCommand()
{
_name = "reset_cfg";
_desc = "reset non-volatile configuration.";
_extendedDesc = "reset non-volatile configuration to their default value.";
_flagLong = "reset_cfg";
_flagShort = "r";
_param = "";
_paramExp = "";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " reset_cfg";
_v = Wtv_Dev;
_maxCmdParamNum = 0;
_cmdType = SC_ResetCfg;
}
ResetCfgSubCommand:: ~ResetCfgSubCommand()
{
}
FlintStatus ResetCfgSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
printf("-W- Resetting device configuration using Flint should be done as a last resort.\n");
printf("-W- Please attempt to reset configuration via mlxconfig tool if possible.\n");
printf("-W- Only proceed if you know what you are doing.\n");
if (!askUser("reset non-volatile configuration")) {
return FLINT_FAILED;
}
printf("Resetting...");
if (!_fwOps->FwResetNvData()) {
printf(" Failed!\n");
reportErr(true, FLINT_RESET_CFG_ERROR, _fwOps->err());
return FLINT_FAILED;
}
printf(" SUCCESS!\n");
printf("\n-I- Configuration were successfully reset. reboot or restart the driver is required.\n");
return FLINT_SUCCESS;
}
/***********************
* Class: FixImage
**********************/
FiSubCommand::FiSubCommand()
{
_name = "fix image";
_desc = "fix image on N25Q0XX flash.";
_extendedDesc = "fix image on N25Q0XX flash.(shifting all device data sectors)";
_flagLong = "fi";
_flagShort = "";
_param = "";
_paramExp = "";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " fi";
_v = Wtv_Dev;
_maxCmdParamNum = 0;
_cmdType = SC_Fix_Img;
}
FiSubCommand:: ~FiSubCommand()
{
}
FlintStatus FiSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
if (!askUser("Fix device fw?")) {
return FLINT_FAILED;
}
if (!_fwOps->FwShiftDevData(&verifyCbFunc)) {
reportErr(true, FLINT_FIX_IMG_ERROR, _fwOps->err());
return FLINT_FAILED;
}
printf("\n-I- Fw was successfully fixed. reboot or restart the driver is required.\n");
return FLINT_SUCCESS;
}
/***********************
* Class: CheckSum
**********************/
CheckSumSubCommand::CheckSumSubCommand()
{
_name = "checksum";
_desc = "perform MD5 checksum on FW.";
_extendedDesc = "perform an MD5 checksum on relevant(non-persistent between FW upgrades) data on device/image.";
_flagLong = "checksum";
_flagShort = "cs";
_param = "";
_paramExp = "";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " checksum";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 0;
_cmdType = SC_Check_Sum;
memset(_checkSum, 0, sizeof(_checkSum));
}
CheckSumSubCommand:: ~CheckSumSubCommand()
{
}
bool CheckSumSubCommand::extractChecksumFromStr(string str, u_int8_t checkSum[16])
{
char ptr[2];
int i = 15;
if (str.size() < 2) {
reportErr(true, FLINT_CHECKSUM_LEN_ERROR);
return false;
}
if (!strncasecmp(str.c_str(), "0x", 2)) {
// str starts with 0x or 0X, remove prefix
str = &(str.c_str()[2]);
}
if (str.size() != 32) {
reportErr(true, FLINT_CHECKSUM_LEN_ERROR);
return false;
}
stringstream ss(str);
while (i >= 0) {
ss.read(ptr, 2);
if (!isxdigit(ptr[0]) || !isxdigit(ptr[1])) {
reportErr(true, FLINT_CHECKSUM_HEX_ERROR);
return false;
}
checkSum[i] = (u_int8_t)strtoul(ptr, NULL, 16);
if (!checkSum[i] && strncmp(ptr, "00", 2)) {
reportErr(true, FLINT_CHECKSUM_PARSE_ERROR);
return false;
}
i--;
}
return true;
}
string CheckSumSubCommand::checkSum2Str(u_int8_t chksm[16])
{
stringstream ss;
for (int i = 15; i >= 0; i--) {
char chunk[3];
snprintf(chunk, 3, "%02x", chksm[i]);
ss << chunk;
}
string s = ss.str();
return s;
}
FlintStatus CheckSumSubCommand::executeCommand()
{
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
FwOperations *ops = _fwOps ? _fwOps : _imgOps;
printf("-I- Calculating Checksum ...\n");
if (!ops->FwCalcMD5(_checkSum)) {
reportErr(true, FLINT_CHECKSUM_ERROR, (_flintParams.device_specified ? "device" : "image"), ops->err());
return FLINT_FAILED;
}
// just print it!
printf("Checksum: %s\n", checkSum2Str(_checkSum).c_str());
return FLINT_SUCCESS;
}
/***********************
* Class: TimeStamp
**********************/
TimeStampSubCommand::TimeStampSubCommand()
{
_name = "time stamp";
_desc = "FW time stamping.";
_extendedDesc = "set/query/reset time stamp on device/image.";
_flagLong = "timestamp";
_flagShort = "ts";
_param = "<set|query|reset> [timestamp] [FW version]";
_paramExp = "set <timestamp> [FW version] : set the specified timestamp. if set on device FW version must be specified\n"
"timestamp should comply with ISO 8601 format and provided with UTC timezone: YYYY-MM-DDThh:mm:ssZ\n"
"query : query device/image to view the timestamp\n"
"reset : reset the timestamp, remove the timestamp from device/image.\n";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE4 " ts set 2015-12-24T14:52:33Z 14.12.1100\n"
FLINT_NAME " -d " MST_DEV_EXAMPLE4 " ts reset\n"
FLINT_NAME " -i ./fw4115.bin ts set\n"
FLINT_NAME " -i ./fw4115.bin ts query";
_v = Wtv_Dev_Or_Img;
_maxCmdParamNum = 3;
_minCmdParamNum = 1;
_cmdType = SC_Time_Stamp;
memset(&_userFwVer, 0, sizeof(_userFwVer));
memset(&_userTsEntry, 0, sizeof(_userTsEntry));
_operation = TS_No_Command;
_ops = (FwOperations*)NULL;
_mccSupported = true;
}
TimeStampSubCommand:: ~TimeStampSubCommand()
{
}
bool TimeStampSubCommand::parseFwVersion(string verStr)
{
unsigned int major = 0;
unsigned int minor = 0;
unsigned int subminor = 0;
int count = sscanf(verStr.c_str(), "%02d.%02d.%04d", &major, &minor, &subminor);
if (count != 3) {
count = sscanf(verStr.c_str(), "%02d.%04d.%04d", &major, &minor, &subminor);
if (count != 3) {
reportErr(true, "Failed to parse FW version. expected format: MM.mm.ssss\n");
return false;
}
}
_userFwVer.fw_ver_major = major;
_userFwVer.fw_ver_minor = minor;
_userFwVer.fw_ver_subminor = subminor;
//printf("-D- Fw version: %d.%d.%d\n", _userFwVer.fw_ver_major, _userFwVer.fw_ver_minor, _userFwVer.fw_ver_subminor);
return true;
}
#define BCD2_TO_NUM(bcd) \
((((bcd) >> 4 & 0xf) * 10) + ((bcd) & 0xf))
#define BCD4_TO_NUM(bcd) \
((BCD2_TO_NUM((bcd) >> 8 & 0xff) * 100) + (BCD2_TO_NUM((bcd) & 0xff)))
#define NUM2_TO_BCD(num) \
((((num) / 10) * 16) + ((num) % 10))
#define NUM4_TO_BCD(num) \
((NUM2_TO_BCD((num) / 100) * 256) + NUM2_TO_BCD((num) % 100))
u_int8_t TimeStampSubCommand::getDaysInMonth(u_int16_t year, u_int8_t month)
{
u_int8_t days = 0;
bool isLeapYear = year % 4 == 0; // evenly divisible by 4
isLeapYear &= (year % 100 != 0) || (year % 400 == 0); // not evenly divided by 100 or evenly divisible by 400
switch (month) {
case 2:
days = isLeapYear ? 29 : 28;
break;
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
days = 31;
break;
default:
break;
}
return days;
}
void TimeStampSubCommand::getMachineUTCTime()
{
time_t rawTime;
struct tm *timeInfo;
time(&rawTime);
timeInfo = gmtime(&rawTime);
if (!timeInfo) {
reportErr(true, "gmtime returned NULL. Can't get machine's UTC time.");
return;
}
_userTsEntry.ts_year = NUM4_TO_BCD(timeInfo->tm_year + 1900);
_userTsEntry.ts_month = NUM2_TO_BCD(timeInfo->tm_mon + 1);
_userTsEntry.ts_day = NUM2_TO_BCD(timeInfo->tm_mday);
_userTsEntry.ts_hour = NUM2_TO_BCD(timeInfo->tm_hour);
_userTsEntry.ts_minutes = NUM2_TO_BCD(timeInfo->tm_min);
_userTsEntry.ts_seconds = NUM2_TO_BCD(timeInfo->tm_sec);
//printf("-D- timestamp: %04x-%02x-%02xT%02x:%02x:%02x\n", _userTsEntry.ts_year, _userTsEntry.ts_month,
// _userTsEntry.ts_day, _userTsEntry.ts_hour, _userTsEntry.ts_minutes, _userTsEntry.ts_seconds);
return;
}
bool TimeStampSubCommand::parseTimeStamp(string tsStr)
{
unsigned int year = 0;
unsigned int month = 0;
unsigned int day = 0;
unsigned int hour = 0;
unsigned int minutes = 0;
unsigned int seconds = 0;
if (*tsStr.rbegin() != 'Z') {
reportErr(true, "Failed to parse timestamp: Timestamp timezone must be UTC. format should be: YYYY-MM-DDThh:mm:ssZ\n");
return false;
}
// scan and store
int count = sscanf(tsStr.c_str(), "%04d-%02d-%02dT%02d:%02d:%02dZ", &year, &month, &day, &hour, &minutes, &seconds);
if (count != 6) {
reportErr(true, "Failed to parse timestamp: input should be compliant to the following ISO 8601 format: YYYY-MM-DDThh:mm:ssZ\n");
return false;
}
// check time args
if (month == 0 || month > 12) {
reportErr(true, "Failed to parse timestamp: illegal month value (%d)\n", month);
return false;
}
if (day > getDaysInMonth(year, month)) {
reportErr(true, "Failed to parse timestamp: illegal day value (%d)\n", day);
return false;
}
if (hour > 23 || minutes > 59 || seconds > 59) {
reportErr(true, "Failed to parse timestamp: illegal time value (%02d:%02d:%02d)\n", hour, minutes, seconds);
return false;
}
// store as BCD
_userTsEntry.ts_year = NUM4_TO_BCD(year);
_userTsEntry.ts_month = NUM2_TO_BCD(month);
_userTsEntry.ts_day = NUM2_TO_BCD(day);
_userTsEntry.ts_hour = NUM2_TO_BCD(hour);
_userTsEntry.ts_minutes = NUM2_TO_BCD(minutes);
_userTsEntry.ts_seconds = NUM2_TO_BCD(seconds);
//printf("-D- timestamp: %04x-%02x-%02xT%02x:%02x:%02x\n", _userTsEntry.ts_year, _userTsEntry.ts_month,
// _userTsEntry.ts_day, _userTsEntry.ts_hour, _userTsEntry.ts_minutes, _userTsEntry.ts_seconds);
return true;
}
bool TimeStampSubCommand::verifyParams()
{
if (_flintParams.cmd_params[0] == "query") {
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, "query operation requires no arguments.\n");
return false;
}
_operation = TimeStampSubCommand::TS_Query;
} else if (_flintParams.cmd_params[0] == "set") {
if (_flintParams.image_specified && _flintParams.cmd_params.size() > 2) {
reportErr(true, "too many arguments for set operation on image.\n");
return false;
} else if (_flintParams.device_specified && _flintParams.cmd_params.size() != 3) {
reportErr(true, "set operation on device requires timestamp and FW version arguments.\n\n");
return false;
}
_operation = TimeStampSubCommand::TS_Set;
// attempt to parse timestamp and fw version
if (_flintParams.image_specified && _flintParams.cmd_params.size() == 1) {
// take time from machine
getMachineUTCTime();
} else if (!parseTimeStamp(_flintParams.cmd_params[1])) {
return false;
}
if (_flintParams.device_specified && !parseFwVersion(_flintParams.cmd_params[2])) {
return false;
}
} else if (_flintParams.cmd_params[0] == "reset") {
if (_flintParams.cmd_params.size() > 1) {
reportErr(true, "erase operation requires no arguments.\n");
return false;
}
_operation = TimeStampSubCommand::TS_Reset;
} else {
reportErr(true, "Unknown operation, allowed operations: query/set/reset.\n");
return false;
}
return true;
}
void TimeStampSubCommand::printTsAndFwVer(string prefix, struct tools_open_ts_entry& tsEntry, struct tools_open_fw_version& fwVer)
{
printf("%-24s: %04x-%02x-%02xT%02x:%02x:%02xZ %02d.%02d.%04d\n", prefix.c_str(), tsEntry.ts_year, tsEntry.ts_month, tsEntry.ts_day,
tsEntry.ts_hour, tsEntry.ts_minutes, tsEntry.ts_seconds,
fwVer.fw_ver_major, fwVer.fw_ver_minor, fwVer.fw_ver_subminor);
}
bool TimeStampSubCommand::queryTs()
{
struct tools_open_ts_entry tsEntry;
struct tools_open_fw_version fwVer;
memset(&tsEntry, 0, sizeof(tsEntry));
memset(&fwVer, 0, sizeof(fwVer));
// get and Print Current Running FW TS in case of device
if (_flintParams.device_specified) {
if (!_ops->FwQueryTimeStamp(tsEntry, fwVer, true)) {
printf("%-24s: N/A. %s\n", "Current timestamp", _ops->err());
} else {
printTsAndFwVer("Current timestamp", tsEntry, fwVer);
}
}
// get and print next FW timestamp
if (!_ops->FwQueryTimeStamp(tsEntry, fwVer, false)) {
printf("%-24s: N/A. %s\n", "Next timestamp", _ops->err());
} else {
printTsAndFwVer("Next timestamp", tsEntry, fwVer);
}
return true;
}
bool TimeStampSubCommand::setTs()
{
if (!_ops->FwSetTimeStamp(_userTsEntry, _userFwVer)) {
reportErr(false, "%s", _ops->err());
return false;
}
return true;
}
bool TimeStampSubCommand::resetTs()
{
if (!_ops->FwResetTimeStamp()) {
reportErr(false, "%s", _ops->err());
return false;
}
return true;
}
FlintStatus TimeStampSubCommand::executeCommand()
{
bool rc;
if (preFwOps() == FLINT_FAILED) {
return FLINT_FAILED;
}
_ops = _flintParams.device_specified ? _fwOps : _imgOps;
fw_info_t fwInfo;
if (!_ops->FwQuery(&fwInfo)) {
reportErr(true, FLINT_FAILED_QUERY_ERROR, _flintParams.device_specified ? "Device" : "Image",
_flintParams.device_specified ? _flintParams.device.c_str() : _flintParams.image.c_str(), _ops->err());
return FLINT_FAILED;
}
chip_type_t chip = fwInfo.fw_info.chip_type;
bool IsValidDevice = (chip == CT_CONNECTX4 || chip == CT_CONNECTX4_LX);
switch (_operation) {
case TimeStampSubCommand::TS_Set:
if (!IsValidDevice) {
reportErr(true, "Failed to perform timestamp set operation. Failed to set timestamp. Time stamping not supported by FW.\n");
return FLINT_FAILED;
}
rc = setTs();
break;
case TimeStampSubCommand::TS_Query:
if (!IsValidDevice) {
printf("Current timestamp : N/A. Failed to query timestamp. Time stamping not supported by FW.\n");
printf("Next timestamp : N/A. Failed to query timestamp. Time stamping not supported by FW.\n");
return FLINT_FAILED;
}
rc = queryTs();
break;
case TimeStampSubCommand::TS_Reset:
if (!IsValidDevice) {
reportErr(true, "Failed to perform timestamp reset operation. Failed to reset timestamp. Time stamping not supported by FW.\n");
return FLINT_FAILED;
}
rc = resetTs();
break;
default:
// should not be reached
reportErr(true, "Failed to perform timestamp operation: Unknown Error\n");
return FLINT_FAILED;
}
if (!rc) {
printf("-E- Failed to perform timestamp %s operation. %s\n", _flintParams.cmd_params[0].c_str(), _errBuff);
return FLINT_FAILED;
}
return FLINT_SUCCESS;
}
/***********************
* Class: CacheImage
**********************/
CacheImageSubCommand::CacheImageSubCommand()
{
_name = "cache image";
_desc = "cache FW image(Windows only).";
_extendedDesc = "cache the FW image using Mellanox driver to allow faster FW load time upon loading the driver(Windows only).";
_flagLong = "cache_image";
_flagShort = "ci";
_param = "";
_paramExp = "";
_example = FLINT_NAME " -d " MST_DEV_EXAMPLE1 " cache_image";
_v = Wtv_Dev;
_maxCmdParamNum = 0;
_minCmdParamNum = 0;
_cmdType = SC_Cache_Image;
}
CacheImageSubCommand:: ~CacheImageSubCommand()
{
}
FlintStatus CacheImageSubCommand::executeCommand()
{
#ifdef __WIN__
int rc;
if (preFwAccess() == FLINT_FAILED) {
return FLINT_FAILED;
}
rc = wdcif_send_image_cache_request(((Flash*)_io)->getMfileObj());
if (rc) {
reportErr(true, FLINT_CACHE_IMAGE_ERROR, wdcif_err_str(rc));
return FLINT_FAILED;
}
printf("\n-I- FW was successfully cached by driver.\n");
return FLINT_SUCCESS;
#else
reportErr(true, FLINT_WIN_ONLY_SUPP_ERROR, _name.c_str());
return FLINT_FAILED;
#endif
}