| /* |
| * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & |
| * AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // NSM: Nvidia Message type |
| // - Diagnostics [Type 4] |
| |
| #include "nsm_diag_cmd.hpp" |
| |
| #include "base.h" |
| #include "debug-token.h" |
| #include "debug-token/error.h" |
| #include "debug-token/tlv.h" |
| #include "debug-token/types.h" |
| #include "diagnostics.h" |
| #include "platform-environmental.h" |
| |
| #include "cmd_helper.hpp" |
| #include "nsm_base.hpp" |
| #include "utils.hpp" |
| |
| #include <CLI/CLI.hpp> |
| |
| #include <ctime> |
| |
| namespace nsmtool |
| { |
| |
| namespace diag |
| { |
| |
| namespace |
| { |
| |
| using namespace nsmtool::helper; |
| std::vector<std::unique_ptr<CommandInterface>> commands; |
| |
| } // namespace |
| |
| class GetDeviceDiagnostics : public CommandInterface |
| { |
| public: |
| GetDeviceDiagnostics() = delete; |
| GetDeviceDiagnostics(const GetDeviceDiagnostics&) = delete; |
| GetDeviceDiagnostics(GetDeviceDiagnostics&&) = default; |
| GetDeviceDiagnostics& operator=(const GetDeviceDiagnostics&) = delete; |
| GetDeviceDiagnostics& operator=(GetDeviceDiagnostics&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit GetDeviceDiagnostics(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| app->add_option("-s, --segmentId", segment_id, "Segment Id") |
| ->required(); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_device_diagnostics_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_get_device_diagnostics_req(instanceId, segment_id, |
| request); |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_ERROR; |
| std::vector<uint8_t> seg_data(65535, 0); |
| uint16_t seg_data_size; |
| uint8_t next_segment_id; |
| uint16_t reason_code; |
| |
| auto rc = decode_get_device_diagnostics_resp( |
| responsePtr, payloadLength, &cc, &reason_code, seg_data.data(), |
| &seg_data_size, &next_segment_id); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n" |
| << payloadLength << "...." |
| << (sizeof(struct nsm_msg_hdr) + |
| sizeof(struct nsm_get_device_diagnostics_resp)); |
| } |
| |
| ordered_json result; |
| result["Completion Code"] = cc; |
| result["Segment Data Size"] = seg_data_size; |
| result["Next Segment Id"] = next_segment_id; |
| result["Segment Data"] = std::string( |
| std::bit_cast<const char*>(seg_data.data()), seg_data_size); |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t segment_id; |
| }; |
| |
| class QueryTokenParameters : public CommandInterface |
| { |
| public: |
| ~QueryTokenParameters() = default; |
| QueryTokenParameters() = delete; |
| QueryTokenParameters(const QueryTokenParameters&) = delete; |
| QueryTokenParameters(QueryTokenParameters&&) = default; |
| QueryTokenParameters& operator=(const QueryTokenParameters&) = delete; |
| QueryTokenParameters& operator=(QueryTokenParameters&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit QueryTokenParameters(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = app->add_option_group( |
| "Required", |
| "Query token parameters for the specified token opcode"); |
| ccOptionGroup->add_option( |
| "-o,--opcode", tokenOpcode, |
| "query token parameters for the specified token opcode"); |
| ccOptionGroup->require_option(1); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_query_token_parameters_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_query_token_parameters_req( |
| instanceId, static_cast<nsm_debug_token_opcode>(tokenOpcode), |
| request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| struct nsm_debug_token_request token_request; |
| |
| auto rc = decode_nsm_query_token_parameters_resp( |
| responsePtr, payloadLength, &cc, &reason_code, &token_request); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| result["Token request version"] = |
| static_cast<uint32_t>(token_request.token_request_version); |
| result["Token request size"] = |
| static_cast<uint32_t>(token_request.token_request_size); |
| result["Device UUID"] = bytesToHexString(token_request.device_uuid, 8); |
| switch (token_request.device_type) |
| { |
| case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_EROT: |
| result["Device type"] = "ERoT"; |
| break; |
| case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_GPU: |
| result["Device type"] = "GPU"; |
| break; |
| case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_NVSWITCH: |
| result["Device type"] = "NVSwitch"; |
| break; |
| case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_CX7: |
| result["Device type"] = "CX7"; |
| break; |
| case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_MCU: |
| result["Device type"] = "MCU"; |
| break; |
| case NSM_DEBUG_TOKEN_DEVICE_TYPE_ID_CX8: |
| result["Device type"] = "CX8"; |
| break; |
| default: |
| result["Device type"] = |
| "Invalid value: " + |
| std::to_string(token_request.device_type); |
| break; |
| } |
| result["Device index"] = |
| static_cast<uint32_t>(token_request.device_index); |
| switch (token_request.status) |
| { |
| case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_OK: |
| result["Status"] = "OK"; |
| break; |
| case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_TOKEN_ALREADY_APPLIED: |
| result["Status"] = "Token already applied"; |
| break; |
| case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_TOKEN_NOT_SUPPORTED: |
| result["Status"] = "Token not supported"; |
| break; |
| case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_NO_KEY_CONFIGURED: |
| result["Status"] = "No key configured"; |
| break; |
| case NSM_DEBUG_TOKEN_CHALLENGE_QUERY_STATUS_INTERFACE_NOT_ALLOWED: |
| result["Status"] = "Interface not allowed"; |
| break; |
| default: |
| result["Status"] = "Invalid value: " + |
| std::to_string(token_request.status); |
| break; |
| } |
| switch (token_request.token_opcode) |
| { |
| case NSM_DEBUG_TOKEN_OPCODE_RMCS: |
| result["Token opcode"] = "RMCS"; |
| break; |
| case NSM_DEBUG_TOKEN_OPCODE_RMDT: |
| result["Token opcode"] = "RMDT"; |
| break; |
| case NSM_DEBUG_TOKEN_OPCODE_CRCS: |
| result["Token opcode"] = "CRCS"; |
| break; |
| case NSM_DEBUG_TOKEN_OPCODE_CRDT: |
| result["Token opcode"] = "CRDT"; |
| break; |
| case NSM_DEBUG_TOKEN_OPCODE_LINKX_FRC: |
| result["Token opcode"] = "LINKX_FRC"; |
| break; |
| default: |
| result["Token opcode"] = |
| "Invalid value: " + |
| std::to_string(token_request.token_opcode); |
| break; |
| } |
| result["Keypair UUID"] = bytesToHexString(token_request.keypair_uuid, |
| 16); |
| result["Base MAC"] = bytesToHexString(token_request.base_mac, 8); |
| result["PSID"] = bytesToHexString(token_request.psid, 16); |
| result["FW version"] = std::to_string(token_request.fw_version[0]) + |
| "." + |
| std::to_string(token_request.fw_version[1] << 8 | |
| token_request.fw_version[2]) + |
| "." + |
| std::to_string(token_request.fw_version[3] << 8 | |
| token_request.fw_version[4]); |
| result["Source address"] = |
| bytesToHexString(token_request.source_address, 16); |
| result["Session ID"] = static_cast<uint32_t>(token_request.session_id); |
| result["Challenge version"] = token_request.challenge_version; |
| result["Challenge"] = bytesToHexString(token_request.challenge, 32); |
| |
| DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t tokenOpcode; |
| }; |
| |
| /** @class QueryResetStatistics |
| * @brief Command to query reset statistics. |
| */ |
| class QueryResetStatistics : public CommandInterface |
| { |
| public: |
| ~QueryResetStatistics() = default; |
| QueryResetStatistics() = delete; |
| QueryResetStatistics(const QueryResetStatistics&) = delete; |
| QueryResetStatistics(QueryResetStatistics&&) = default; |
| QueryResetStatistics& operator=(const QueryResetStatistics&) = delete; |
| QueryResetStatistics& operator=(QueryResetStatistics&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| private: |
| class QueryResetMetricsAggregateResponseParser : |
| public AggregateResponseParser |
| { |
| private: |
| int handleSampleData(uint8_t tag, const uint8_t* data, size_t data_len, |
| ordered_json& sample_json) final |
| { |
| // Static member initialization |
| const std::unordered_map<uint8_t, std::string> tagToPropertyMap = { |
| {0, "PF_FLR_ResetEntryCount"}, |
| {1, "PF_FLR_ResetExitCount"}, |
| {2, "ConventionalResetEntryCount"}, |
| {3, "ConventionalResetExitCount"}, |
| {4, "FundamentalResetEntryCount"}, |
| {5, "FundamentalResetExitCount"}, |
| {6, "IRoTResetExitCount"}, |
| {7, "LastResetType"}, |
| {8, "BootReason"}}; |
| |
| auto it = tagToPropertyMap.find(tag); |
| if (it == tagToPropertyMap.end()) |
| { |
| // Unknown tag; skip processing |
| return NSM_SW_ERROR_DATA; |
| } |
| |
| const std::string& property = it->second; |
| |
| // Handle LastResetType (enum8) |
| if (property == "LastResetType") |
| { |
| uint8_t resetType; |
| if (decode_reset_enum_data(data, data_len, &resetType) != |
| NSM_SW_SUCCESS) |
| { |
| return NSM_SW_ERROR_LENGTH; |
| } |
| // Include the tag in the JSON |
| sample_json["Tag"] = static_cast<int>(tag); |
| sample_json["Property"] = property; |
| sample_json["Value"] = resetType; |
| } |
| else if (property == "BootReason") |
| { |
| // Handle boot reason counter (uint64_t) |
| std::array<uint64_t, 4> counterVal; |
| if (decode_reset_count_256data( |
| data, data_len, counterVal.data(), counterVal.size()) != |
| NSM_SW_SUCCESS) |
| { |
| return NSM_SW_ERROR_LENGTH; |
| } |
| |
| // Include the tag in the JSON |
| sample_json["Tag"] = static_cast<int>(tag); |
| sample_json["Property"] = property; |
| sample_json["Value0to63"] = counterVal[0]; |
| sample_json["Value64to127"] = counterVal[1]; |
| sample_json["Value128to191"] = counterVal[2]; |
| sample_json["Value192to255"] = counterVal[3]; |
| } |
| else |
| { |
| // Handle reset count (uint16_t) |
| uint16_t count; |
| if (decode_reset_count_data(data, data_len, &count) != |
| NSM_SW_SUCCESS) |
| { |
| return NSM_SW_ERROR_LENGTH; |
| } |
| |
| // Include the tag in the JSON |
| sample_json["Tag"] = static_cast<int>(tag); |
| sample_json["Property"] = property; |
| sample_json["Value"] = count; |
| } |
| |
| return NSM_SW_SUCCESS; |
| } |
| }; |
| |
| public: |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_common_req)); |
| auto requestPtr = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| |
| // Encode the request message |
| auto rc = encode_get_device_reset_statistics_req(instanceId, |
| requestPtr); |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| QueryResetMetricsAggregateResponseParser{}.parseAggregateResponse( |
| responsePtr, payloadLength); |
| } |
| }; |
| |
| class ProvideToken : public CommandInterface |
| { |
| public: |
| ~ProvideToken() = default; |
| ProvideToken() = delete; |
| ProvideToken(const ProvideToken&) = delete; |
| ProvideToken(ProvideToken&&) = default; |
| ProvideToken& operator=(const ProvideToken&) = delete; |
| ProvideToken& operator=(ProvideToken&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit ProvideToken(const char* type, const char* name, CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = |
| app->add_option_group("Required", "Install specified token data"); |
| ccOptionGroup->add_option( |
| "-t,--token", tokenHexstring, |
| "hexadecimal string containing token data to be installed"); |
| ccOptionGroup->require_option(1); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_common_req_v2) + |
| tokenHexstring.size() / 2); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| |
| std::vector<uint8_t> token; |
| for (size_t i = 0; i < tokenHexstring.length(); i += 2) |
| { |
| std::string byteString = tokenHexstring.substr(i, 2); |
| uint8_t byte = (uint8_t)strtoul(byteString.c_str(), NULL, 16); |
| token.push_back(byte); |
| } |
| |
| auto rc = encode_nsm_provide_token_req(instanceId, token.data(), |
| token.size(), request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| |
| auto rc = decode_nsm_provide_token_resp(responsePtr, payloadLength, &cc, |
| &reason_code); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| |
| DisplayInJson(result); |
| } |
| |
| private: |
| std::string tokenHexstring; |
| }; |
| |
| class DisableTokens : public CommandInterface |
| { |
| public: |
| ~DisableTokens() = default; |
| DisableTokens() = delete; |
| DisableTokens(const DisableTokens&) = delete; |
| DisableTokens(DisableTokens&&) = default; |
| DisableTokens& operator=(const DisableTokens&) = delete; |
| DisableTokens& operator=(DisableTokens&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit DisableTokens(const char* type, const char* name, CLI::App* app) : |
| CommandInterface(type, name, app) |
| {} |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_disable_tokens_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| |
| auto rc = encode_nsm_disable_tokens_req(instanceId, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| |
| auto rc = decode_nsm_disable_tokens_resp(responsePtr, payloadLength, |
| &cc, &reason_code); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| |
| DisplayInJson(result); |
| } |
| }; |
| |
| class QueryTokenStatus : public CommandInterface |
| { |
| public: |
| ~QueryTokenStatus() = default; |
| QueryTokenStatus() = delete; |
| QueryTokenStatus(const QueryTokenStatus&) = delete; |
| QueryTokenStatus(QueryTokenStatus&&) = default; |
| QueryTokenStatus& operator=(const QueryTokenStatus&) = delete; |
| QueryTokenStatus& operator=(QueryTokenStatus&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit QueryTokenStatus(const char* type, const char* name, |
| CLI::App* app) : CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = app->add_option_group( |
| "Required", "Query token status for the specified token type"); |
| ccOptionGroup->add_option( |
| "-t,--type", tokenType, |
| "query token status for the specified token type"); |
| ccOptionGroup->require_option(1); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_query_token_status_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_query_token_status_req( |
| instanceId, static_cast<nsm_debug_token_type>(tokenType), request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| nsm_debug_token_status status; |
| nsm_debug_token_status_additional_info additionalInfo; |
| nsm_debug_token_type tokenType; |
| uint32_t timeLeft; |
| |
| auto rc = decode_nsm_query_token_status_resp( |
| responsePtr, payloadLength, &cc, &reason_code, &status, |
| &additionalInfo, &tokenType, &timeLeft); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| switch (status) |
| { |
| case NSM_DEBUG_TOKEN_STATUS_DEBUG_SESSION_ENDED: |
| result["Status"] = "Debug session ended"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_OPERATION_FAILURE: |
| result["Status"] = "Operation failure"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_DEBUG_SESSION_ACTIVE: |
| result["Status"] = "Debug session active"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_NO_TOKEN_APPLIED: |
| result["Status"] = "No token applied"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_CHALLENGE_PROVIDED: |
| result["Status"] = "Challenge provided"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_INSTALLATION_TIMEOUT: |
| result["Status"] = "Installation timeout"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_TOKEN_TIMEOUT: |
| result["Status"] = "Token timeout"; |
| break; |
| default: |
| result["Status"] = "Invalid value: " + std::to_string(status); |
| break; |
| } |
| switch (additionalInfo) |
| { |
| case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_NONE: |
| result["Additional info"] = "None"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_NO_DEBUG_SESSION: |
| result["Additional info"] = "No debug session"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_FIRMWARE_NOT_SECURED: |
| result["Additional info"] = "Firmware not secured"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_DEBUG_SESSION_END_REQUEST_NOT_ACCEPTED: |
| result["Additional info"] = |
| "Debug session end request not accepted"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_DEBUG_SESSION_QUERY_DISALLOWED: |
| result["Additional info"] = "Debug session query disallowed"; |
| break; |
| case NSM_DEBUG_TOKEN_STATUS_ADDITIONAL_INFO_DEBUG_SESSION_ACTIVE: |
| result["Additional info"] = "Debug session active"; |
| break; |
| default: |
| result["Additional info"] = "Invalid value: " + |
| std::to_string(additionalInfo); |
| break; |
| } |
| switch (tokenType) |
| { |
| case NSM_DEBUG_TOKEN_TYPE_FRC: |
| result["Token type"] = "FRC"; |
| break; |
| case NSM_DEBUG_TOKEN_TYPE_CRCS: |
| result["Token type"] = "CRCS"; |
| break; |
| case NSM_DEBUG_TOKEN_TYPE_CRDT: |
| result["Token type"] = "CRDT"; |
| break; |
| case NSM_DEBUG_TOKEN_TYPE_DEBUG_FIRMWARE: |
| result["Token type"] = "Debug firmware"; |
| break; |
| default: |
| result["Token type"] = "Invalid value: " + |
| std::to_string(tokenType); |
| break; |
| } |
| result["Time left"] = timeLeft; |
| |
| DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t tokenType; |
| }; |
| |
| class QueryDeviceIds : public CommandInterface |
| { |
| public: |
| ~QueryDeviceIds() = default; |
| QueryDeviceIds() = delete; |
| QueryDeviceIds(const QueryDeviceIds&) = delete; |
| QueryDeviceIds(QueryDeviceIds&&) = default; |
| QueryDeviceIds& operator=(const QueryDeviceIds&) = delete; |
| QueryDeviceIds& operator=(QueryDeviceIds&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit QueryDeviceIds(const char* type, const char* name, CLI::App* app) : |
| CommandInterface(type, name, app) |
| {} |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_query_device_ids_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| |
| auto rc = encode_nsm_query_device_ids_req(instanceId, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| size_t device_id_len; |
| |
| auto rc = decode_nsm_query_device_ids_resp(responsePtr, payloadLength, |
| &cc, &reason_code, nullptr, |
| &device_id_len); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| std::vector<uint8_t> device_id(device_id_len); |
| rc = decode_nsm_query_device_ids_resp(responsePtr, payloadLength, &cc, |
| &reason_code, device_id.data(), |
| &device_id_len); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| result["Device ID"] = bytesToHexString(device_id.data(), device_id_len); |
| |
| DisplayInJson(result); |
| } |
| }; |
| |
| class EnableDisableWriteProtected : public CommandInterface |
| { |
| public: |
| ~EnableDisableWriteProtected() = default; |
| EnableDisableWriteProtected() = delete; |
| EnableDisableWriteProtected(const EnableDisableWriteProtected&) = delete; |
| EnableDisableWriteProtected(EnableDisableWriteProtected&&) = default; |
| EnableDisableWriteProtected& |
| operator=(const EnableDisableWriteProtected&) = delete; |
| EnableDisableWriteProtected& |
| operator=(EnableDisableWriteProtected&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit EnableDisableWriteProtected(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto writeProtectedGroup = app->add_option_group( |
| "Required", |
| "Data Index and Value for which write protected will be set."); |
| |
| dataId = 0; |
| writeProtectedGroup->add_option( |
| "-d, --dataId", dataId, |
| "Data Index of write protected:\n" |
| "128: Retimer EEPROM\n" |
| "129: Baseboard FRU EEPROM\n" |
| "130: PEX SW EEPROM\n" |
| "131: NvSWs EEPROM\n" |
| "133: NvSW EEPROM 1\n" |
| "134: NvSW EEPROM 2\n" |
| "160: GPUs 1-4 SPI Flash\n" |
| "161: GPUs 5-8 SPI Flash\n" |
| "162-169: Individual GPU SPI flash 1-8\n" |
| "170: GPUs SPI Flash\n" |
| "176: HMC SPI Flash\n" |
| "183: CX8s SPI Flash\n" |
| "192-199: Retimer EEPROM 1-8\n" |
| "224-231: CPU SPI Flash 1-8\n" |
| "232: CX7 FRU EEPROM\n" |
| "233: HMC FRU EEPROM\n"); |
| value = 0; |
| writeProtectedGroup->add_option("-V, --value", value, |
| "Disable - 0 / Enable - 1"); |
| writeProtectedGroup->require_option(2); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_enable_disable_wp_req)); |
| int rc = NSM_SW_ERROR; |
| switch ((diagnostics_enable_disable_wp_data_index)dataId) |
| { |
| case RETIMER_EEPROM: |
| case BASEBOARD_FRU_EEPROM: |
| case PEX_SW_EEPROM: |
| case NVSW_EEPROM_BOTH: |
| case NVSW_EEPROM_1: |
| case NVSW_EEPROM_2: |
| case GPU_1_4_SPI_FLASH: |
| case GPU_5_8_SPI_FLASH: |
| case GPU_SPI_FLASH_1: |
| case GPU_SPI_FLASH_2: |
| case GPU_SPI_FLASH_3: |
| case GPU_SPI_FLASH_4: |
| case GPU_SPI_FLASH_5: |
| case GPU_SPI_FLASH_6: |
| case GPU_SPI_FLASH_7: |
| case GPU_SPI_FLASH_8: |
| case GPU_SPI_FLASH: |
| case HMC_SPI_FLASH: |
| case CX8_SPI_FLASH: |
| case RETIMER_EEPROM_1: |
| case RETIMER_EEPROM_2: |
| case RETIMER_EEPROM_3: |
| case RETIMER_EEPROM_4: |
| case RETIMER_EEPROM_5: |
| case RETIMER_EEPROM_6: |
| case RETIMER_EEPROM_7: |
| case RETIMER_EEPROM_8: |
| case CPU_SPI_FLASH_1: |
| case CPU_SPI_FLASH_2: |
| case CPU_SPI_FLASH_3: |
| case CPU_SPI_FLASH_4: |
| case CPU_SPI_FLASH_5: |
| case CPU_SPI_FLASH_6: |
| case CPU_SPI_FLASH_7: |
| case CPU_SPI_FLASH_8: |
| case CX7_FRU_EEPROM: |
| case HMC_FRU_EEPROM: |
| { |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| rc = encode_enable_disable_wp_req( |
| instanceId, |
| (diagnostics_enable_disable_wp_data_index)dataId, value, |
| request); |
| } |
| break; |
| default: |
| std::cerr << "Invalid Data Id \n"; |
| break; |
| } |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_ERROR; |
| uint16_t reason_code = ERR_NULL; |
| |
| auto rc = decode_enable_disable_wp_resp(responsePtr, payloadLength, &cc, |
| &reason_code); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n" |
| << payloadLength << "...." |
| << (sizeof(nsm_msg_hdr) + sizeof(nsm_common_resp)); |
| |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion Code"] = cc; |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t dataId; |
| uint8_t value; |
| }; |
| |
| class ResetNetworkDevice : public CommandInterface |
| { |
| public: |
| ~ResetNetworkDevice() = default; |
| ResetNetworkDevice() = delete; |
| ResetNetworkDevice(const ResetNetworkDevice&) = delete; |
| ResetNetworkDevice(ResetNetworkDevice&&) = default; |
| ResetNetworkDevice& operator=(const ResetNetworkDevice&) = delete; |
| ResetNetworkDevice& operator=(ResetNetworkDevice&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit ResetNetworkDevice(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto resetNDOptionGroup = app->add_option_group( |
| "Required", "Mode for reseting the network device."); |
| |
| mode = 0; |
| resetNDOptionGroup->add_option( |
| "-M, --mode", mode, "set mode while resetting network device"); |
| resetNDOptionGroup->require_option(1); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_reset_network_device_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_reset_network_device_req(instanceId, mode, request); |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| auto rc = decode_reset_network_device_resp(responsePtr, payloadLength, |
| &cc, &reason_code); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion Code"] = cc; |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t mode; |
| }; |
| |
| class GetNetworkDeviceDebugInfo : public CommandInterface |
| { |
| public: |
| ~GetNetworkDeviceDebugInfo() = default; |
| GetNetworkDeviceDebugInfo() = delete; |
| GetNetworkDeviceDebugInfo(const GetNetworkDeviceDebugInfo&) = delete; |
| GetNetworkDeviceDebugInfo(GetNetworkDeviceDebugInfo&&) = default; |
| GetNetworkDeviceDebugInfo& |
| operator=(const GetNetworkDeviceDebugInfo&) = delete; |
| GetNetworkDeviceDebugInfo& operator=(GetNetworkDeviceDebugInfo&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit GetNetworkDeviceDebugInfo(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto getNetworkDeviceDebugInfoOptionGroup = app->add_option_group( |
| "Required", "Get network device debug information options."); |
| |
| debugInfoType = 0; |
| recordHandle = 0; |
| getNetworkDeviceDebugInfoOptionGroup->add_option( |
| "-t, --debugInfoType", debugInfoType, |
| "Debug information type [0-Device info, 1-FW runtime data, 2-FW saved dump info and 3-Device dump]"); |
| getNetworkDeviceDebugInfoOptionGroup->add_option( |
| "-r, --recordHandle", recordHandle, |
| "Record handle for fetching the debug info chunk."); |
| getNetworkDeviceDebugInfoOptionGroup->require_option(2); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_network_device_debug_info_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_get_network_device_debug_info_req( |
| instanceId, debugInfoType, recordHandle, request); |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| uint16_t segDataSize = 0; |
| uint32_t nextHandle = 0; |
| std::vector<uint8_t> segData(65535, 0); |
| |
| auto rc = decode_get_network_device_debug_info_resp( |
| responsePtr, payloadLength, &cc, &reasonCode, &segDataSize, |
| segData.data(), &nextHandle); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| result["Segment Data Length"] = static_cast<uint16_t>(segDataSize); |
| result["Next Record Handle"] = static_cast<uint32_t>(nextHandle); |
| if (segDataSize != 0) |
| result["Segment Data"] = "Data received"; |
| else |
| result["Segment Data"] = "No data received"; |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t debugInfoType; |
| uint32_t recordHandle; |
| }; |
| |
| class EraseTrace : public CommandInterface |
| { |
| public: |
| ~EraseTrace() = default; |
| EraseTrace() = delete; |
| EraseTrace(const EraseTrace&) = delete; |
| EraseTrace(EraseTrace&&) = default; |
| EraseTrace& operator=(const EraseTrace&) = delete; |
| EraseTrace& operator=(EraseTrace&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_erase_trace_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_erase_trace_req(instanceId, request); |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| uint8_t resStatus = 0; |
| |
| auto rc = decode_erase_trace_resp(responsePtr, payloadLength, &cc, |
| &reasonCode, &resStatus); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| switch (resStatus) |
| { |
| case ERASE_TRACE_NO_DATA_ERASED: |
| result["Result status"] = |
| "0: No data was erased, FLASH storage is empty."; |
| break; |
| case ERASE_TRACE_DATA_ERASED: |
| result["Result status"] = "1: Flash storage is erased."; |
| break; |
| case ERASE_TRACE_DATA_ERASE_INPROGRESS: |
| result["Result status"] = |
| "2: Flash storage erase is in progress."; |
| break; |
| default: |
| result["Result status"] = "Unknown value"; |
| break; |
| } |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| }; |
| |
| class GetNetworkDeviceLogInfo : public CommandInterface |
| { |
| public: |
| ~GetNetworkDeviceLogInfo() = default; |
| GetNetworkDeviceLogInfo() = delete; |
| GetNetworkDeviceLogInfo(const GetNetworkDeviceLogInfo&) = delete; |
| GetNetworkDeviceLogInfo(GetNetworkDeviceLogInfo&&) = default; |
| GetNetworkDeviceLogInfo& operator=(const GetNetworkDeviceLogInfo&) = delete; |
| GetNetworkDeviceLogInfo& operator=(GetNetworkDeviceLogInfo&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit GetNetworkDeviceLogInfo(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto getNetworkDeviceDebugInfoOptionGroup = app->add_option_group( |
| "Required", "Get network device log information options."); |
| |
| recordHandle = 0; |
| getNetworkDeviceDebugInfoOptionGroup->add_option( |
| "-r, --recordHandle", recordHandle, |
| "Record handle for fetching the log info chunk."); |
| getNetworkDeviceDebugInfoOptionGroup->require_option(1); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + sizeof(nsm_get_network_device_log_info_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_get_network_device_log_info_req(instanceId, |
| recordHandle, request); |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| uint32_t nextHandle = 0; |
| uint16_t logInfoSize = 0; |
| struct nsm_device_log_info_breakdown logInfo; |
| std::vector<uint8_t> logData(65535, 0); |
| |
| auto rc = decode_get_network_device_log_info_resp( |
| responsePtr, payloadLength, &cc, &reasonCode, &nextHandle, &logInfo, |
| logData.data(), &logInfoSize); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| result["Next Record Handle"] = static_cast<uint32_t>(nextHandle); |
| result["Lost Events"] = static_cast<uint16_t>(logInfo.lost_events); |
| auto syncedTime = static_cast<uint8_t>(logInfo.synced_time); |
| if (syncedTime == 0) |
| result["Synced Time"] = "Boot - Time measured since bootup"; |
| else if (syncedTime == 1) |
| result["Synced Time"] = "Synced - Time was synced by the host"; |
| else |
| result["Synced Time"] = "Unknown"; |
| |
| result["Time High"] = static_cast<uint32_t>(logInfo.time_high); |
| result["Time low"] = static_cast<uint32_t>(logInfo.time_low); |
| result["Log Entry Prefix"] = |
| static_cast<uint32_t>(logInfo.entry_prefix); |
| result["Log Entry Suffix"] = |
| static_cast<uint32_t>(logInfo.entry_suffix); |
| result["Number of Dwords in log entry"] = |
| static_cast<uint8_t>(logInfo.length); |
| |
| if (logInfoSize != 0) |
| result["Log Information"] = "Data received"; |
| else |
| result["Log Information"] = "No Data received"; |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint32_t recordHandle; |
| }; |
| |
| class EraseDebugInfo : public CommandInterface |
| { |
| public: |
| ~EraseDebugInfo() = default; |
| EraseDebugInfo() = delete; |
| EraseDebugInfo(const EraseDebugInfo&) = delete; |
| EraseDebugInfo(EraseDebugInfo&&) = default; |
| EraseDebugInfo& operator=(const EraseDebugInfo&) = delete; |
| EraseDebugInfo& operator=(EraseDebugInfo&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit EraseDebugInfo(const char* type, const char* name, CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto eraseDebugInfoOptionGroup = |
| app->add_option_group("Required", "Erase debug info options."); |
| |
| infoType = 0; |
| eraseDebugInfoOptionGroup->add_option( |
| "-t, --infoType", infoType, |
| "Debug information type [0-FW saved debug info]"); |
| eraseDebugInfoOptionGroup->require_option(1); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_erase_debug_info_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_erase_debug_info_req(instanceId, infoType, request); |
| return {rc, requestMsg}; |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| uint8_t resStatus = 0; |
| |
| auto rc = decode_erase_debug_info_resp(responsePtr, payloadLength, &cc, |
| &reasonCode, &resStatus); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| switch (resStatus) |
| { |
| case ERASE_TRACE_NO_DATA_ERASED: |
| result["Result status"] = |
| "0: No data was erased, FLASH storage is empty."; |
| break; |
| case ERASE_TRACE_DATA_ERASED: |
| result["Result status"] = "1: Flash storage is erased."; |
| break; |
| case ERASE_TRACE_DATA_ERASE_INPROGRESS: |
| result["Result status"] = |
| "2: Flash storage erase is in progress."; |
| break; |
| default: |
| result["Result status"] = "Unknown value"; |
| break; |
| } |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t infoType; |
| }; |
| |
| class GetDeviceDebugParameters : public CommandInterface |
| { |
| public: |
| ~GetDeviceDebugParameters() = default; |
| GetDeviceDebugParameters() = delete; |
| GetDeviceDebugParameters(const GetDeviceDebugParameters&) = delete; |
| GetDeviceDebugParameters(GetDeviceDebugParameters&&) = default; |
| GetDeviceDebugParameters& |
| operator=(const GetDeviceDebugParameters&) = delete; |
| GetDeviceDebugParameters& operator=(GetDeviceDebugParameters&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit GetDeviceDebugParameters(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto getDeviceDebugParametersOptionGroup = app->add_option_group( |
| "Required", "Get device debug parameters options."); |
| |
| debugConfigurationType = 0; |
| portNumber = 0; |
| parameterIndex = 0; |
| parameterSubIndex = 0; |
| getDeviceDebugParametersOptionGroup->add_option( |
| "-t, --configType", debugConfigurationType, |
| "Debug configuration type [0-Network interface mode]"); |
| getDeviceDebugParametersOptionGroup->add_option( |
| "-p, --portNumber", portNumber, "Port number"); |
| getDeviceDebugParametersOptionGroup->add_option( |
| "-i, --parameterIndex", parameterIndex, "Parameter index (ID)"); |
| getDeviceDebugParametersOptionGroup->add_option( |
| "-s, --parameterSubId", parameterSubIndex, "Parameter sub ID"); |
| getDeviceDebugParametersOptionGroup->require_option(4); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + sizeof(nsm_get_device_debug_parameters_req)); |
| |
| struct nsm_debug_parameter_id parameterId; |
| nsm_debug_parameter_sub_id_bitfield parameterSubId; |
| parameterId.port_number = portNumber; |
| parameterId.index = parameterIndex; |
| parameterSubId.value = parameterSubIndex; |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_get_device_debug_parameters_req( |
| instanceId, debugConfigurationType, parameterId, parameterSubId, |
| request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t dataSize = 0; |
| std::vector<uint8_t> data(65535, 0); |
| |
| auto rc = decode_get_device_debug_parameters_resp( |
| responsePtr, payloadLength, &cc, &dataSize, data.data()); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| result["Data size"] = static_cast<uint16_t>(dataSize); |
| result["Debug Data"] = nsmtool::helper::bytesToHexString(data.data(), |
| dataSize); |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t debugConfigurationType; |
| uint16_t portNumber; |
| uint8_t parameterIndex; |
| uint32_t parameterSubIndex; |
| }; |
| |
| class SetDeviceDebugParameters : public CommandInterface |
| { |
| public: |
| ~SetDeviceDebugParameters() = default; |
| SetDeviceDebugParameters() = delete; |
| SetDeviceDebugParameters(const SetDeviceDebugParameters&) = delete; |
| SetDeviceDebugParameters(SetDeviceDebugParameters&&) = default; |
| SetDeviceDebugParameters& |
| operator=(const SetDeviceDebugParameters&) = delete; |
| SetDeviceDebugParameters& operator=(SetDeviceDebugParameters&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit SetDeviceDebugParameters(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto setDeviceDebugParametersOptionGroup = app->add_option_group( |
| "Required", "Set device debug parameters options."); |
| |
| debugConfigurationType = 0; |
| portNumber = 0; |
| parameterIndex = 0; |
| parameterSubIndex = 0; |
| dataSize = 0; |
| data = {}; |
| setDeviceDebugParametersOptionGroup->add_option( |
| "-t, --configType", debugConfigurationType, |
| "Debug configuration type [0-Network interface mode]"); |
| setDeviceDebugParametersOptionGroup->add_option( |
| "-p, --portNumber", portNumber, "Port number"); |
| setDeviceDebugParametersOptionGroup->add_option( |
| "-i, --parameterIndex", parameterIndex, "Parameter index (ID)"); |
| setDeviceDebugParametersOptionGroup->add_option( |
| "-s, --parameterSubId", parameterSubIndex, "Parameter sub ID"); |
| setDeviceDebugParametersOptionGroup->add_option("-d, --data", data, |
| "Data"); |
| setDeviceDebugParametersOptionGroup->require_option(5); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + sizeof(nsm_set_device_debug_parameters_req) + |
| data.size() - sizeof(uint8_t)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| |
| struct nsm_debug_parameter_id parameterId; |
| nsm_debug_parameter_sub_id_bitfield parameterSubId; |
| parameterId.port_number = portNumber; |
| parameterId.index = parameterIndex; |
| parameterSubId.value = parameterSubIndex; |
| dataSize = data.size(); |
| auto rc = encode_set_device_debug_parameters_req( |
| instanceId, debugConfigurationType, parameterId, parameterSubId, |
| dataSize, data.data(), request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| |
| auto rc = decode_set_device_debug_parameters_resp(responsePtr, |
| payloadLength, &cc); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t debugConfigurationType; |
| uint16_t portNumber; |
| uint8_t parameterIndex; |
| uint32_t parameterSubIndex; |
| uint8_t dataSize; |
| std::vector<uint8_t> data; |
| }; |
| |
| class InstallToken : public CommandInterface |
| { |
| public: |
| InstallToken() = delete; |
| InstallToken(const InstallToken&) = delete; |
| InstallToken(InstallToken&&) = default; |
| InstallToken& operator=(const InstallToken&) = delete; |
| InstallToken& operator=(InstallToken&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit InstallToken(const char* type, const char* name, CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = |
| app->add_option_group("Required", "Install specified token chunk"); |
| ccOptionGroup->add_option("-b,--bufferSize", bufferSize, |
| "buffer size of the target device"); |
| ccOptionGroup->add_option("-f,--file", filePath, |
| "path to the token file"); |
| ccOptionGroup->require_option(2); |
| } |
| |
| ~InstallToken() |
| { |
| if (fd >= 0) |
| { |
| close(fd); |
| } |
| } |
| |
| std::vector<uint8_t> createChunk() |
| { |
| size_t toRead = std::min(chunkSize, remaining); |
| std::vector<uint8_t> data(toRead); |
| auto bytesRead = read(fd, data.data(), toRead); |
| if (bytesRead < 0) |
| { |
| close(fd); |
| fd = -1; |
| throw std::runtime_error("Failed to read token file: " + |
| std::string(strerror(errno))); |
| } |
| data.resize(bytesRead); |
| return data; |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createChunkRequestMsg() |
| { |
| std::vector<uint8_t> data = createChunk(); |
| if (data.empty()) |
| { |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| sentChunkSize = data.size(); |
| remaining -= data.size(); |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_install_token_req) - 1 + |
| data.size()); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_install_token_req(instanceId, offset, data.size(), |
| remaining, data.data(), request); |
| offset += data.size(); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| if (bufferSize == 0) |
| { |
| std::cerr << "Buffer size is 0" << std::endl; |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| if (bufferSize > std::numeric_limits<uint16_t>::max()) |
| { |
| std::cerr << "Buffer size is too large (max is " |
| << std::numeric_limits<uint16_t>::max() |
| << "): " << bufferSize << std::endl; |
| return std::make_pair(NSM_SW_ERROR_LENGTH, std::vector<uint8_t>()); |
| } |
| fd = open(filePath.c_str(), O_RDONLY); |
| if (fd < 0) |
| { |
| std::cerr << "open error: " << strerror(errno) << std::endl; |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| int rc = lseek(fd, 0, SEEK_SET); |
| if (rc < 0) |
| { |
| std::cerr << "lseek error: " << rc << std::endl; |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| struct stat fileStat; |
| rc = fstat(fd, &fileStat); |
| if (rc < 0) |
| { |
| std::cerr << "fstat error: " << strerror(errno) << std::endl; |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| if (fileStat.st_size < 0) |
| { |
| std::cerr << "Invalid file size in fd" << std::endl; |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| |
| // Read and parse the 16-byte file header |
| constexpr size_t HEADER_SIZE = 16; |
| if (fileStat.st_size < static_cast<off_t>(HEADER_SIZE)) |
| { |
| std::cerr << "File too small to contain header (size: " |
| << fileStat.st_size << ", expected at least " |
| << HEADER_SIZE << " bytes)" << std::endl; |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| |
| std::array<uint8_t, HEADER_SIZE> header; |
| ssize_t bytesRead = read(fd, header.data(), HEADER_SIZE); |
| if (bytesRead != static_cast<ssize_t>(HEADER_SIZE)) |
| { |
| std::cerr << "Failed to read file header: " << strerror(errno) |
| << std::endl; |
| return std::make_pair(NSM_SW_ERROR_DATA, std::vector<uint8_t>()); |
| } |
| remaining = fileStat.st_size - HEADER_SIZE; |
| |
| chunkSize = NSM_DEBUG_TOKEN_INSTALL_CHUNK_SIZE(bufferSize); |
| return createChunkRequestMsg(); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| |
| auto rc = decode_nsm_install_token_resp(responsePtr, payloadLength, &cc, |
| &reasonCode); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << ", error=" |
| << debug_token::Error(reasonCode).to_string() |
| << std::endl; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reasonCode; |
| result["Chunk size"] = sentChunkSize; |
| result["Remaining"] = remaining; |
| |
| nsmtool::helper::DisplayInJson(result); |
| |
| if (remaining > 0) |
| { |
| auto [rc, requestMsg] = createChunkRequestMsg(); |
| if (rc != NSM_SW_SUCCESS) |
| { |
| return; |
| } |
| requestQueue.push_back(std::move(requestMsg)); |
| } |
| } |
| |
| private: |
| std::string filePath; |
| int fd{-1}; |
| uint32_t bufferSize{0}; |
| uint32_t chunkSize{0}; |
| uint32_t offset{0}; |
| uint32_t remaining{0}; |
| uint32_t sentChunkSize{0}; |
| }; |
| |
| class EraseToken : public CommandInterface |
| { |
| public: |
| ~EraseToken() = default; |
| EraseToken() = delete; |
| EraseToken(const EraseToken&) = delete; |
| EraseToken(EraseToken&&) = default; |
| EraseToken& operator=(const EraseToken&) = delete; |
| EraseToken& operator=(EraseToken&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit EraseToken(const char* type, const char* name, CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto eraseTokenOptionGroup = |
| app->add_option_group("Required", "Erase specified token"); |
| eraseTokenOptionGroup->add_option("-t,--type", tokenType, "token type"); |
| eraseTokenOptionGroup->require_option(1); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_erase_token_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_erase_token_req(instanceId, tokenType, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| |
| auto rc = decode_nsm_erase_token_resp(responsePtr, payloadLength, &cc, |
| &reasonCode); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << ", error=" |
| << debug_token::Error(reasonCode).to_string() |
| << std::endl; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reasonCode; |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| |
| private: |
| uint32_t tokenType; |
| }; |
| |
| class QueryToken : public CommandInterface |
| { |
| public: |
| ~QueryToken() = default; |
| QueryToken() = delete; |
| QueryToken(const QueryToken&) = delete; |
| QueryToken(QueryToken&&) = default; |
| QueryToken& operator=(const QueryToken&) = delete; |
| QueryToken& operator=(QueryToken&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_query_token_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_query_token_req(instanceId, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| std::vector<uint8_t> payload; |
| size_t payloadSize = 0; |
| auto rc = decode_nsm_query_token_resp(responsePtr, payloadLength, &cc, |
| &reasonCode, nullptr, |
| &payloadSize); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << ", error=" |
| << debug_token::Error(reasonCode).to_string() |
| << std::endl; |
| return; |
| } |
| |
| if (payloadSize > 0) |
| { |
| payload.resize(payloadSize); |
| rc = decode_nsm_query_token_resp(responsePtr, payloadLength, &cc, |
| &reasonCode, payload.data(), |
| &payloadSize); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << ", error=" |
| << debug_token::Error(reasonCode).to_string() |
| << std::endl; |
| return; |
| } |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reasonCode; |
| result["Data size"] = payloadSize; |
| if (payloadSize == 0) |
| { |
| nsmtool::helper::DisplayInJson(result); |
| return; |
| } |
| result["Raw data"] = bytesToHexString(payload.data(), payloadSize); |
| auto tlv = debug_token::tlv_decoder::Structure(payload); |
| auto types = tlv.getTypes(); |
| for (const auto& type : types) |
| { |
| if (type == debug_token::types::Common::InstallationStatus) |
| { |
| auto value = tlv.get(type).getValue<uint8_t>(); |
| result[debug_token::tlv_decoder::Item::getTypeName(type)] = |
| static_cast<bool>(value); |
| } |
| else if (type == debug_token::types::Common::ProcessingStatus) |
| { |
| auto value = tlv.get(type).getValue<uint8_t>(); |
| result[debug_token::tlv_decoder::Item::getTypeName(type)] = |
| static_cast<bool>(value); |
| } |
| else if (type == debug_token::types::Common::TokenTypeSubtypeList) |
| { |
| auto value = tlv.get(type).getValue<std::vector<uint32_t>>(); |
| if (value.size() % 2 != 0) |
| { |
| std::cerr << "Token type subtype list size is not even" |
| << std::endl; |
| auto value = tlv.get(type).getRawValue(); |
| result[debug_token::tlv_decoder::Item::getTypeName(type)] = |
| bytesToHexString(value.data(), value.size()); |
| } |
| else |
| { |
| ordered_json array; |
| for (size_t i = 0; i < value.size(); i += 2) |
| { |
| ordered_json pair; |
| pair.push_back(value[i]); |
| pair.push_back(value[i + 1]); |
| array.push_back(pair); |
| } |
| result[debug_token::tlv_decoder::Item::getTypeName(type)] = |
| array; |
| } |
| } |
| else |
| { |
| auto value = tlv.get(type).getRawValue(); |
| result[debug_token::tlv_decoder::Item::getTypeName(type)] = |
| bytesToHexString(value.data(), value.size()); |
| } |
| } |
| |
| nsmtool::helper::DisplayInJson(result); |
| } |
| }; |
| |
| void registerCommand(CLI::App& app) |
| { |
| auto diag = app.add_subcommand("diag", "Diagnostics type command"); |
| diag->require_subcommand(1); |
| |
| auto queryTokenParameters = diag->add_subcommand("QueryTokenParameters", |
| "Query token parameters"); |
| commands.push_back(std::make_unique<QueryTokenParameters>( |
| "diag", "QueryTokenParameters", queryTokenParameters)); |
| |
| auto provideToken = diag->add_subcommand("ProvideToken", "Provide token"); |
| commands.push_back( |
| std::make_unique<ProvideToken>("diag", "ProvideToken", provideToken)); |
| |
| auto disableTokens = diag->add_subcommand("DisableTokens", |
| "Disable tokens"); |
| commands.push_back(std::make_unique<DisableTokens>("diag", "DisableTokens", |
| disableTokens)); |
| |
| auto queryTokenStatus = diag->add_subcommand("QueryTokenStatus", |
| "Query token status"); |
| commands.push_back(std::make_unique<QueryTokenStatus>( |
| "diag", "QueryTokenStatus", queryTokenStatus)); |
| |
| auto queryDeviceIds = diag->add_subcommand("QueryDeviceIds", |
| "Query device IDs"); |
| commands.push_back(std::make_unique<QueryDeviceIds>( |
| "diag", "QueryDeviceIds", queryDeviceIds)); |
| |
| auto enableDisableWriteProtected = diag->add_subcommand( |
| "EnableDisableWriteProtected", "Enable/Disable WriteProtected"); |
| commands.push_back(std::make_unique<EnableDisableWriteProtected>( |
| "diag", "EnableDisableWriteProtected", enableDisableWriteProtected)); |
| |
| auto resetNetworkDevice = diag->add_subcommand("ResetNetworkDevice", |
| "Reset Network Device"); |
| commands.push_back(std::make_unique<ResetNetworkDevice>( |
| "diag", "ResetNetworkDevice", resetNetworkDevice)); |
| |
| auto getNetworkDeviceDebugInfo = diag->add_subcommand( |
| "GetNetworkDeviceDebugInfo", "Get Network Device Debug Info"); |
| commands.push_back(std::make_unique<GetNetworkDeviceDebugInfo>( |
| "diag", "GetNetworkDeviceDebugInfo", getNetworkDeviceDebugInfo)); |
| |
| auto eraseTrace = diag->add_subcommand("EraseTrace", "Erase Trace"); |
| commands.push_back( |
| std::make_unique<EraseTrace>("diag", "EraseTrace", eraseTrace)); |
| |
| auto getNetworkDeviceLogInfo = diag->add_subcommand( |
| "GetNetworkDeviceLogInfo", "Get Network Device Log Info"); |
| commands.push_back(std::make_unique<GetNetworkDeviceLogInfo>( |
| "diag", "GetNetworkDeviceLogInfo", getNetworkDeviceLogInfo)); |
| |
| auto eraseDebugInfo = diag->add_subcommand("EraseDebugInfo", |
| "Erase Debug Info"); |
| commands.push_back(std::make_unique<EraseDebugInfo>( |
| "diag", "EraseDebugInfo", eraseDebugInfo)); |
| |
| auto resetMetricsInfo = diag->add_subcommand("GetResetMetrcs", |
| "Get Reset MEtrics Info"); |
| commands.push_back(std::make_unique<QueryResetStatistics>( |
| "diag", "GetResetMetrcs", resetMetricsInfo)); |
| |
| auto getDeviceDiagnostics = diag->add_subcommand("GetDeviceDiagnostics", |
| "Get Device Diagnostics"); |
| commands.push_back(std::make_unique<GetDeviceDiagnostics>( |
| "diag", "GetDeviceDiagnostics", getDeviceDiagnostics)); |
| |
| auto getDeviceDebugParameters = diag->add_subcommand( |
| "GetDeviceDebugParameters", "Get Device Debug Parameters"); |
| commands.push_back(std::make_unique<GetDeviceDebugParameters>( |
| "diag", "GetDeviceDebugParameters", getDeviceDebugParameters)); |
| |
| auto setDeviceDebugParameters = diag->add_subcommand( |
| "SetDeviceDebugParameters", "Set Device Debug Parameters"); |
| commands.push_back(std::make_unique<SetDeviceDebugParameters>( |
| "diag", "SetDeviceDebugParameters", setDeviceDebugParameters)); |
| |
| auto installToken = diag->add_subcommand("InstallToken", "Install token"); |
| commands.push_back( |
| std::make_unique<InstallToken>("diag", "InstallToken", installToken)); |
| |
| auto eraseToken = diag->add_subcommand("EraseToken", "Erase token"); |
| commands.push_back( |
| std::make_unique<EraseToken>("diag", "EraseToken", eraseToken)); |
| |
| auto queryToken = diag->add_subcommand("QueryToken", "Query token"); |
| commands.push_back( |
| std::make_unique<QueryToken>("diag", "QueryToken", queryToken)); |
| } |
| |
| } // namespace diag |
| |
| } // namespace nsmtool |