rrcSmall/src/main.cpp
DataHoarder 3868034b6b
All checks were successful
continuous-integration/drone/push Build is passing
Update rrcc mappings for new set
2021-08-03 22:21:34 +02:00

1060 lines
59 KiB
C++

/*****************************************************************************
* Copyright (c) 2020, rrcSmall FM10K-Documentation Contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstring>
#include "ImageFormat.h"
#include "Registers.h"
#include "instructions/Load.h"
#include "OutputContext.h"
#include "instructions/End.h"
std::string ltrim(const std::string &s)
{
size_t start = s.find_first_not_of(" \n\r\t\f\v");
return (start == std::string::npos) ? "" : s.substr(start);
}
std::string rtrim(const std::string &s)
{
size_t end = s.find_last_not_of(" \n\r\t\f\v");
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
}
std::string trim(const std::string &s) {
return rtrim(ltrim(s));
}
void decodeImage(const std::string &fileName) {
std::ifstream image(fileName);
if (image.is_open()) {
std::vector<uint8_t> bytes;
while (!image.eof()) {
bytes.push_back(image.get());
}
auto imageObject = ImageFormat::fromBytes(bytes);
printf("SPEED: 0x%02x MODE: 0x%02x BOOT: 0x%08x\n", static_cast<uint32_t>(imageObject.getHeader().speed), static_cast<uint32_t>(imageObject.getHeader().mode),
imageObject.getHeader().baseAddress);
std::cout << "SIGNATURE: " << imageObject.imageSignature << "\n";
for (auto &k : imageObject.getBootConfig().getAllEntries()) {
std::cout << k << "\n";
}
OutputContext ctx(imageObject);
std::unordered_map<uint32_t, std::string> knownNames{
{0x1000, "load_bootCfg_pep_serialNumber"},
{0x1054, "load_bootCfg_customMac"},
{0x080600, "config_systimeClockSource"},
{0x080700, "config_startClocks"},
{0x080800, "config_pcie_pep_modes"},
{0x080900, "config_pcie_pep_enable"},
{0x083000, "config_?serdes?_pep"},
{0x084000, "reset_BSM_ARGS_init__ENTRYPOINT"},
{0x085a0c, "config_pep0_offsets"},
{0x085a58, "config_pep1_offsets"},
{0x085aa4, "config_pep2_offsets"},
{0x085af0, "config_pep3_offsets"},
{0x085b3c, "config_pep4_offsets"},
{0x085b88, "config_pep5_offsets"},
{0x085bd4, "config_pep6_offsets"},
{0x085c20, "config_pep7_offsets"},
{0x085c6c, "config_pep8_offsets"},
{0x088000, "load_bootCfg_pep0_vpd"},
{0x0881c7, "load_bootCfg_pep1_vpd"},
{0x08838e, "load_bootCfg_pep2_vpd"},
{0x088555, "load_bootCfg_pep3_vpd"},
{0x08871c, "load_bootCfg_pep4_vpd"},
{0x0888e3, "load_bootCfg_pep5_vpd"},
{0x088aaa, "load_bootCfg_pep6_vpd"},
{0x088c71, "load_bootCfg_pep7_vpd"},
{0x088e38, "load_bootCfg_pep8_vpd"},
{0x089000, "load_bootCfg_systimeClockSource"},
{0x089010, "load_bootCfg_pep0_mode"},
{0x089020, "load_bootCfg_pep2_mode"},
{0x089030, "load_bootCfg_pep4_mode"},
{0x089040, "load_bootCfg_pep6_mode"},
{0x089050, "load_bootCfg_pep0_enable"},
{0x089060, "load_bootCfg_pep1_enable"},
{0x089070, "load_bootCfg_pep2_enable"},
{0x089080, "load_bootCfg_pep3_enable"},
{0x089090, "load_bootCfg_pep4_enable"},
{0x0890a0, "load_bootCfg_pep5_enable"},
{0x0890b0, "load_bootCfg_pep6_enable"},
{0x0890c0, "load_bootCfg_pep7_enable"},
{0x0890d0, "load_bootCfg_pep8_enable"},
{0x0890e0, "load_bootCfg_GPIO_PIN14_DRIVE"},
{0x0890f0, "load_bootCfg_spiTransferMode"},
{0x089100, "load_bootCfg_spiTransferSpeed"},
{0x089120, "load_bootCfg_skipPcieInitialization"},
{0x089130, "load_bootCfg_pep_numberOfLanes"},
{0x0891f0, "load_bootCfg_pep_mgmtPep"},
{0x089230, "load_bootCfg_pep_vendor_device"},
{0x089260, "load_bootCfg_pep_subVendor_subDevice"},
{0x0892f0, "load_bootCfg_pep_gen"},
{0x089380, "load_bootCfg_pep_ASPMEnable"},
{0x0839fc, "lock_PCIE_SBUS_take"},
{0x083aac, "lock_PCIE_SBUS_release"},
{0x083900, "execute_SerialBus_PCIE_Command"},
{0x080b00, "mark_SOFT_RESET_ClocksStable_ColdReset"},
{0x081100, "init_MASTER_SPICO"},
{0x0812ac, "FAIL_init_MASTER_SPICO"},
{0x08a004, "load_MASTER_SPICO_FW"},
{0x081400, "init_SERDES"},
{0x081b8c, "FAIL_init_SERDES"},
{0x08c004, "load_SERDES_FW"},
//Merge function
{0x080004, ""},
{0x080008, ""},
{0x08000c, ""},
{0x08001c, ""},
{0x080038, ""},
{0x080068, ""},
{0x0870c4, ""},
//Unknown
{0x089110, "loc_089110_load_config_unknown_1"},
{0x089160, "loc_089160_load_config_unknown_9"},
{0x089190, "loc_089190_load_config_unknown_9"},
{0x0891c0, "loc_0891c0_load_config_unknown_9"},
{0x089220, "load_eeprom_major_version"},
{0x089290, "loc_089290_load_config_unknown_9"},
{0x0892c0, "loc_0892c0_load_config_unknown_9"},
{0x089320, "loc_089320_load_config_unknown_9"},
{0x089350, "loc_089350_load_config_unknown_9"},
{0x0893b0, "load_bootCfg_skipPcieInitialization_skipMemRepair"},
{0x080d00, "config_memRepair"},
{0x0893c0, "load_pcie_clkmon_settings"},
};
knownNames[imageObject.getHeader().baseAddress] = "__ENTRYPOINT";
std::unordered_map<uint32_t, std::string> comments{
{0x080260, "Setting BSM_ARGS means this will be called again when reset, BSM_SCRATCH[0x149] is set to ~ 084000"},
{0x084000, "XREF From BSM_ARGS"},
{0x080800, "Reset DEVICE_CFG to all 0"},
{0x080828, "set DEVICE_CFG.PCIeMode[0] to 1x8 (default 2x4)"},
{0x080850, "set DEVICE_CFG.PCIeMode[1] to 1x8 (default 2x4)"},
{0x080878, "set DEVICE_CFG.PCIeMode[2] to 1x8 (default 2x4)"},
{0x0808a0, "set DEVICE_CFG.PCIeMode[3] to 1x8 (default 2x4)"},
{0x08061c, "set DEVICE_CFG.SystimeClockSource to IEEE1588_REFCLK (default PCIE_REFCLK)"},
{0x080010, "set DEVICE_CFG.PCIeEnable[0..8] to enabled"},
{0x083958, "set SBUS_PCIE_COMMAND.Op to READ [0x21]"},
{0x083970, "set SBUS_PCIE_COMMAND.Op to WRITE [0x22]"},
};
std::unordered_map<uint32_t, std::string> registerRename{
{(uint32_t) KnownRegisters::MGMT_SCRATCH_0, "custom_RETURN_VALUE"},
{(uint32_t) KnownRegisters::MGMT_SCRATCH_1, "custom_RETURN_TO"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0, "api_SPI_LOCK_STATE"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 1, "api_PCIE_SBUS_LOCK_STATE"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 2, "api_SOFT_RESET_LOCK_STATE"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 3, "api_RECOVERY_STATUS_VECTOR"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 10, "api_PEP_MAC_BASE"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 100, "api_CUSTOM_MAC_BASE"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x0d9, "platform_FUNCTION_PCIeReset_enable"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x0da, "platform_FUNCTION_PCIeReset_disable"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x0db, "platform_FUNCTION_SERDES_InterruptCode_1"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x0dc, "platform_FUNCTION_SERDES_InterruptCode_0"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x12e, "param_SBUS_PCIE_REQUEST_-_SBUS_PCIE_RESPONSE"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x12f, "param_SBUS_PCIE_COMMAND_doRead"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x130, "param_SBUS_PCIE_COMMAND.DeviceAddress"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x131, "param_SBUS_PCIE_COMMAND.Register"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x132, "custom_param_RETURN_TO_SUCCESS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x133, "custom_param_RETURN_TO_FAILURE"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x139, "custom_PEP_ADDR_OFFSET"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x13a, "custom_PEP_offset_PCIE_PORTLOGIC"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x13c, "custom_PEP_CONFIG_numberOfLanes"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x141, "custom_PEP_CONFIG_serial0"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x142, "custom_PEP_CONFIG_serial1"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x143, "custom_PEP_CONFIG_mgmtPep"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x144, "custom_PEP_CONFIG_vendor_device"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x145, "custom_PEP_CONFIG_subVendor_subDevice"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x154, "custom_PEP_NUMBER"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x15a, "platform_PEP_skip_SRIOV_config"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x15b, "platform_PEP0_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x15c, "platform_PEP1_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x15d, "platform_PEP2_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x15e, "platform_PEP3_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x15f, "platform_PEP4_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x150, "platform_PEP5_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x151, "platform_PEP6_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x152, "platform_PEP7_PCIE_CLK_CTRL"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x164, "custom_PEP_CONFIG_gen"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x16b, "platform_PEP0_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x16c, "platform_PEP1_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x16d, "platform_PEP2_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x16e, "platform_PEP3_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x16f, "platform_PEP4_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x160, "platform_PEP5_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x161, "platform_PEP6_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x162, "platform_PEP7_something_counter"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x17f, "custom_PEP_CONFIG_ASPMEnable"},
/**
* api_BSM_STATUS: Step[0-7]
*
* Step 0x0D/0x0F: core = (bsmStatus >> 20 ) & 0xFFF;
* Step 0x0E: Master version ((bsmStatus >> 24) & 0x1), Master CRC ((bsmStatus >> 20) & 0x1), Serdes version ((bsmStatus >> 24) & 0x2), Serdes CRC ((bsmStatus >> 20) & 0x2)
* Step 0x11: host = (bsmStatus >> 16 ) & 0xF;
*/
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x190, "api_BSM_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x191, "api_EEPROM_IMAGE_VERSION"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x192, "api_MASTER_FW_VERSION"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x193, "api_SERDES_FW_VERSION"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x194, "api_SERDES_STATUS_1"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x195, "api_SERDES_STATUS_2"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x196, "api_SERDES_STATUS_3"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x197, "api_SERDES_STATUS_4"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x198, "api_PCIE_MASTER_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x199, "api_PCIE_SERDES_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1ae, "api_DE_COLD_RESET_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1af, "api_SBUS_RESET_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b0, "api_MEMORY_REPAIR_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b1, "api_MEMORY_INIT_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b2, "api_PCIE_PCS_DIS_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b3, "api_PCIE_MASTER_FW_DL_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b4, "api_PCIE_FW_CHECK_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b5, "api_PCIE_SERDES_FW_DL_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b6, "api_PCIE_SERDES_INIT_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b7, "api_PCIE_PCS_EN_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b8, "api_PCIE_DE_WARM_RESET_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b9, "api_PCIE_ISR_STATUS_0"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1ba, "api_PCIE_ISR_STATUS_1"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bb, "api_PCIE_ISR_STATUS_2"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bc, "api_PCIE_ISR_STATUS_3"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bd, "api_PCIE_ISR_STATUS_4"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1be, "api_PCIE_ISR_STATUS_5"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bf, "api_PCIE_ISR_STATUS_6"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c0, "api_PCIE_ISR_STATUS_7"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c1, "api_PCIE_ISR_STATUS_8"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c2, "api_SERDES_OOR_STATUS_PASS_1"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c3, "api_SERDES_OOR_STATUS_PASS_2"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c4, "api_SW_LOCK_ERR_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c5, "api_PCIE_EN_REFCLK_STATUS"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c6, "api_RE_RESET_MASK_STATUS_1"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c7, "api_RE_RESET_MASK_STATUS_2"},
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c8, "api_RE_RESET_ERR_STATUS"},
};
for(uint32_t i = 10; i < 200; ++i){
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
std::stringstream s;
s << "api_MASK_BSM_CONFIG_" << std::dec << i;
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
}
}
for(uint32_t i = 400; i < 410; ++i){
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
std::stringstream s;
s << "api_MASK_BSM_INIT_STATUS_" << std::dec << i;
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
}
}
for(uint32_t i = 430; i < 441; ++i){
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
std::stringstream s;
s << "api_MASK_BSM_INIT_STATUS_ARCHIVE_" << std::dec << i;
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
}
}
for(uint32_t i = 450; i < 452; ++i){
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
std::stringstream s;
s << "api_MASK_BSM_INIT_OOR_" << std::dec << i;
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
}
}
for (auto &r : registerRename) {
ctx.addRegister(Instruction::AddressWithOffset{r.first, 0}, r.second);
}
bool isKnownAssembler = false;
if (imageObject.imageSignature.find("rrc-as") != std::string::npos) {
//Known assembler
isKnownAssembler = true;
comments.clear();
knownNames.clear();
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_ADDR_OFFSET_3), 0}, "rrcc_STACK_POINTER");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_ADDR_OFFSET_2), 0}, "rrcc_FRAME_POINTER");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::MGMT_SCRATCH_0), 0}, "rrcc_SCRATCH_0");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::MGMT_SCRATCH_1), 0}, "rrcc_SCRATCH_1");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E0, 0}, "rrcc_RETURN_VALUE");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E1, 0}, "rrcc_RETURN_VALUE_EXTRA");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E2, 0}, "rrcc_P0");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E3, 0}, "rrcc_P1");
for(uint32_t i = 0; i < 16; ++i){
ctx.addRegister(Instruction::AddressWithOffset{i, 3}, "rrcc_STACK_POINTER+" +
std::to_string(i));
}
for(uint32_t i = 0; i < 16; ++i){
ctx.addRegister(Instruction::AddressWithOffset{i, 2}, "rrcc_FRAME_POINTER+" +
std::to_string(i));
}
for(uint32_t i = 0; i < 16; ++i){
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1F0 + i, 0}, "rrcc_R" +
std::to_string(i));
}
for (auto& i : imageObject.getInstructions()){
std::unique_ptr<Instruction::Instruction> decodedInstruction = nullptr;
std::unique_ptr<Instruction::Instruction> decodedInstruction2 = nullptr;
const Instruction::End* endPointer = nullptr;
if(i.second->getCommand() == Instruction::Instruction::CommandOp::END){
endPointer = reinterpret_cast<const Instruction::End*>(i.second.get());
if(endPointer->reserved == 0 || endPointer->reserved == 0xFFFFFF){
endPointer = nullptr;
}
}
if(endPointer == nullptr && imageObject.findConstInstructionByAddress(i.second->getEndAddress(), false) == nullptr){
decodedInstruction = Instruction::Instruction::decodeInstructionFromBytes(i.second->getEndAddress(), imageObject.getBaseImage());
if(decodedInstruction != nullptr && decodedInstruction->getCommand() == Instruction::Instruction::CommandOp::END){
endPointer = reinterpret_cast<const Instruction::End*>(decodedInstruction.get());
if(endPointer->reserved != endPointer->getAddress()){
endPointer = nullptr;
}
}
}
if(endPointer != nullptr){ //Found backwards pointer
bool hasMore = true;
ctx.setNop(endPointer->getAddress());
uint32_t functionEnd = endPointer->reserved - 4;
uint32_t nextAddress = endPointer->getEndAddress();
do{
decodedInstruction2 = Instruction::Instruction::decodeInstructionFromBytes(nextAddress, imageObject.getBaseImage());
if(decodedInstruction2 != nullptr && decodedInstruction2->getCommand() == Instruction::Instruction::CommandOp::LOAD){
auto loadPointer = reinterpret_cast<const Instruction::Load&>(*decodedInstruction2);
for(auto nopAddr = loadPointer.getAddress(); nopAddr < loadPointer.getEndAddress(); nopAddr += 4){
ctx.setNop(nopAddr);
}
uint32_t targetAddress = loadPointer.address;
std::string stringData;
for(auto& d : loadPointer.data){
uint8_t c = ((d >> 24) & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
c = ((d >> 16) & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
c = ((d >> 8) & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
c = (d & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
}
switch (loadPointer.addressOffset) {
case 0: //FunctionName
knownNames[targetAddress] = stringData;
break;
case 1: //Comment
std::string s = stringData;
size_t pos = 0;
std::string token;
while ((pos = s.find('\n')) != std::string::npos) {
token = s.substr(0, pos);
auto trimmed = trim(token);
if(!trimmed.empty()){
ctx.addComment(targetAddress, trimmed);
}
s.erase(0, pos + 1);
}
auto trimmed = trim(s);
if(!trimmed.empty()){
ctx.addComment(targetAddress, trimmed);
}
break;
}
nextAddress = loadPointer.getEndAddress();
hasMore = loadPointer.increment == 1;
}else{
break;
}
} while (hasMore);
}
}
}
for (auto &e : knownNames) {
ctx.addMapping(e.first, e.second);
}
for (auto &c : comments) {
ctx.addComment(c.first, c.second);
}
ctx.analyze();
uint32_t prevAddress = 0;
for (const auto &entry : imageObject.getInstructions()) {
const auto &instruction = entry.second;
if(ctx.isNop(instruction->getAddress())){
continue;
}else if (instruction->getAddress() < prevAddress) {
std::cout << "========== DECODE ERROR? ========== " << std::hex << std::setw(8) << std::setfill('0')
<< prevAddress << " - " << std::hex << std::setw(8) << std::setfill('0')
<< instruction->getAddress() << "\n";
} else if ((instruction->getAddress() - prevAddress) >= 4 &&
(instruction->getAddress() - prevAddress) < 1024) {
std::cout << "\n\n";
for (uint32_t addr = prevAddress; addr < instruction->getAddress(); addr += 4) {
if(ctx.isNop(addr)){
continue;
}
std::stringstream op;
std::string printable;
op << std::hex << std::setw(6) << std::setfill('0') << addr << " ";
for (uint32_t i = 0; i < 4; ++i) {
op << std::hex << std::setw(2) << std::setfill('0') << (uint32_t) bytes[addr + i] << " ";
if (bytes[addr + i] >= 0x20 && bytes[addr + i] < 0x7F) {
printable += bytes[addr + i];
} else {
printable += ".";
}
}
op << " " << printable << "\n";
std::cout << op.str();
}
} else if ((instruction->getAddress() - prevAddress) >= 1024) {
std::cout << "\n\n================ " << std::hex << std::setw(8) << std::setfill('0') << prevAddress
<< " - " << std::hex << std::setw(8) << std::setfill('0') << instruction->getAddress()
<< "\n";
}
if (!ctx.getLabel(instruction->getAddress(), false).empty()) {
std::cout << "\n\n; ================ FUNCTION " << ctx.getLabel(instruction->getAddress())
<< " ================\n";
}
std::cout << ctx.getInstructionString(*instruction);
prevAddress = instruction->getEndAddress();
}
}
}
void
patchImage(const std::string &originalImage, const std::string &settingsFile, const std::string &patchedImageFile) {
std::ifstream image(originalImage);
if (image.is_open()) {
std::vector<uint8_t> bytes;
while (!image.eof()) {
bytes.push_back(image.get());
}
auto imageObject = ImageFormat::fromBytes(bytes);
Configuration &config = imageObject.getModifiableBootConfig();
std::ifstream settings(settingsFile);
if (settings.is_open()) {
std::string line;
while (!settings.eof()) {
std::getline(settings, line);
config.addEntry(line);
}
//Do patch
if (imageObject.imageSignature.find(
"Image Generated with rrcBig_02.22. EEPROM Image Version: 0x0222 PCIe Master SPICO FW Version: 0x10130001 PCIe SerDes SPICO FW Version: 0x30550043") ==
std::string::npos) {
std::cout
<< "Could not find supported generation signature on original image. Patching will not proceed.\n";
return;
}
if (imageObject.imageSignature.find("rrcSmall") == std::string::npos) {
imageObject.imageSignature += " :: Patched by rrcSmall :: git.gammaspectra.live/FM10K/rrcSmall";
}
// =========== Patching Starts ===========
/*
For example, assume that the company ID is (Intel) 00-A0-C9 and the extension identifier is 23-45-67.
The register then contains:
PCIE_CFG_SPD_NUMBER_L = 0xFF234567 PCIE_CFG_SPD_NUMBER_H = 0x00A0C9FF
http://standards.ieee.org/regauth/oui/tutorials/EUI64.html
*/
// == is patching implemented. @ is absolute addressing, nothing relative to bank offsets
// ==@0x1000 LOAD 9x2 api.platform.config.switch.0.bootCfg.pep.%.serialNumber @ 0x120053/0x120054 + 0x100028/0x100029 BSM_SCRATCH[0x141]-BSM_SCRATCH[0x142] PCIE_CFG_SPD_NUMBER_L SerialNumber and PCIE_SM_AREA.SerialNumber
//
// ==@0x1054 LOAD 8 entries api.platform.config.switch.0.bootCfg.customMac.0-3
//
// 0x1408 LOAD 1 = 0x0 ???? BSM_SCRATCH[0x150] IF 1: JUMP 0x0814c8 ELSE: INIT DATA? call SBUS_PCIE_REQUEST
//
// these are written at ~000857d8
// 0x8000 LOAD PEP0 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x1f4]
// 0x81c7 LOAD PEP1 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x226]
// 0x838e LOAD PEP2 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x258]
// 0x8555 LOAD PEP3 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x28a]
// 0x871c LOAD PEP4 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x2bc]
// 0x88e3 LOAD PEP5 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x2ee]
// 0x8aaa LOAD PEP6 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x320]
// 0x8c71 LOAD PEP7 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x352]
// 0x8e38 LOAD PEP8 device config Vital Product Data PCIE_CFG_VPD_DATA BSM_SCRATCH[0x384]
//
// ==0x9000 LOAD 1 api.platform.config.switch.0.bootCfg.systimeClockSource
// ==0x9010 LOAD 1 api.platform.config.switch.0.bootCfg.pep.0.mode
// ==0x9020 LOAD 1 api.platform.config.switch.0.bootCfg.pep.2.mode
// ==0x9030 LOAD 1 api.platform.config.switch.0.bootCfg.pep.4.mode
// ==0x9040 LOAD 1 api.platform.config.switch.0.bootCfg.pep.6.mode
// ==0x9050 LOAD 1 api.platform.config.switch.0.bootCfg.pep.0.enable
// ==0x9060 LOAD 1 api.platform.config.switch.0.bootCfg.pep.1.enable
// ==0x9070 LOAD 1 api.platform.config.switch.0.bootCfg.pep.2.enable
// ==0x9080 LOAD 1 api.platform.config.switch.0.bootCfg.pep.3.enable
// ==0x9090 LOAD 1 api.platform.config.switch.0.bootCfg.pep.4.enable
// ==0x90a0 LOAD 1 api.platform.config.switch.0.bootCfg.pep.5.enable
// ==0x90b0 LOAD 1 api.platform.config.switch.0.bootCfg.pep.6.enable
// ==0x90c0 LOAD 1 api.platform.config.switch.0.bootCfg.pep.7.enable
// ==0x90d0 LOAD 1 api.platform.config.switch.0.bootCfg.pep.8.enable
// 0x90e0 LOAD 1 = 0x0 ???? (0-index) IF 1: GPIO_DATA.data[14] = 0 (drive to gnd), GPIO_CFG.Dir[14] = 1 (output), GPIO_CFG.OpenDrain[14] = 1 (open drain)
// (BSM_SCRATCH[0x149] = 0x00084000)
// ==0x90f0 LOAD 1 = 0x0 api.platform.config.switch.0.bootCfg.spiTransferMode BSM_SCRATCH[0x149] |= value << 30
// ==0x9100 LOAD 1 = 0x7 api.platform.config.switch.0.bootCfg.spiTransferSpeed BSM_SCRATCH[0x149] |= value << 27
// (BSM_ARGS = BSM_SCRATCH[0x149])
// 0x9110 LOAD 1 = 0x1 ???? do pcie init? IF 0: JUMP 0x081b78: OTHERWISE BIG BLOCK INIT?
// 0x9120 LOAD 1 = 0x0 api.platform.config.switch.0.bootCfg.skipPcieInitialization
//
// ==0x9130 LOAD 9 api.platform.config.switch.0.bootCfg.pep.0.numberOfLanes
// 0x9160 LOAD 9 0, 4, 0, 4 ... ???? BSM_SCRATCH[0x13d]
// 0x9190 LOAD 9 = 0x0 ???? BSM_SCRATCH[0x13e] IF NOT 0: BAR4allowed = 0 ELSE (OPTION 0x92c0)
// 0x91c0 LOAD 9 ???? BSM_SCRATCH[0x13f] IF 0: JUMP 0x084da0 ELSE: PCIE_CTRL.RxLaneflipEn = 1
// ==0x91f0 LOAD 9 bar4Allowed + api.platform.config.switch.0.bootCfg.mgmtPep
// 0x9220 LOAD 1 = 0 EEPROM Major version (0x0222, 02.22 < first 0)
// ==0x9230 LOAD 9 vendor/device
// ==0x9260 LOAD 9 subVendor/subDevice
// 0x9290 LOAD 9 = 0x0 ???? Set TEST settings? PCIE_PORTLOGIC BSM_SCRATCH[0x146] IF 1: JUMP 0x084d94, else (OPTION 0x9190)
// 0x92c0 LOAD 9 = 0x0 ???? BSM_SCRATCH[0x15a] IF 0: init SR_IOV something?
// ==0x92f0 LOAD 9 api.platform.config.switch.0.bootCfg.pep.0.gen
// 0x9320 LOAD 9 = 9x 0x000000FF ???? BSM_SCRATCH[0x155], (val & 0x000000ff) << 0x10 something PCIe value?
// 0x9350 LOAD 9 ???? BSM_SCRATCH[0x17e], (val & 0x000000ff) something PCIe value?
// ==0x9380 LOAD 9 api.platform.config.switch.0.bootCfg.pep.0.ASPMEnable BSM_SCRATCH[0x17f] IF NOT 0: JUMP ELSE SET PCIE_CFG_PCIE_LINK_CAP.ActiveStateLinkPMSupport = 0
//
// 0x93b0 LOAD 1 = 0x00 api.platform.config.switch.0.bootCfg.skipMemRepair
// 0x93c0 LOAD 1 = 0x492550f0 PCIE_CLK_CTRL |= (value & 0xfffff0f0)
// 0x93cc LOAD 1 = 0x0000000f PCIE_CLK_CTRL_2 = value & 0xf
// 0x93d8 LOAD 1 = 0x00000064 PCIE_WARM_RESET_DELAY = value
// 0x93e4 LOAD 1 = 0x00010005 PCIE_CLKMON_RATIO_CFG = value
// 0x93f0 LOAD 1 = 0x000f000a PCIE_CLKMON_TOLERANCE_CFG = value
// 0x93fc LOAD 1 = 0x000a03e8 PCIE_CLKMON_DEADLINES_CFG = value
auto baseOffsets = std::vector<uint32_t>{imageObject.getHeader().baseAddress,
(uint32_t) imageObject.getHeader().baseAddress +
0x40000}; //Target first and second bank
{
auto entry = config.getEntry("api.platform.config.switch.0.bootCfg.mgmtPep");
if (entry.type == Configuration::ConfigurationNode::Type::ValueInt && !entry.value.empty()) {
std::cout << "Patching bootCfg.mgmtPep and bootCfg.pep.bar4Allowed\n";
auto value = entry.getInteger();
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x91f0);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x02e) && load->data.size() == 9) {
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".bar4Allowed";
auto testEntry = config.getEntry(key.str());
bool bar4allowed = true;
if (testEntry.type == Configuration::ConfigurationNode::Type::ValueBool &&
!testEntry.value.empty()) {
bar4allowed = testEntry.getBool();
}
load->data[pepOffset] = bar4allowed && (pepOffset == value || value == -1);
//std::cout << " Patched PEP " << std::dec << pepOffset << " = 0x" << std::hex << std::setw(8) << std::setfill('0') << load->data[pepOffset] << " @ " << std::hex << std::setw(8) << std::setfill('0') << instruction->getAddress() << "\n";
std::cout << " Patched PEP " << std::dec << pepOffset << " = "
<< (load->data[pepOffset] ? "true" : "false") << " @ " << std::hex
<< std::setw(6) << std::setfill('0') << instruction->getAddress() << "\n";
}
}
}
}
}
}
{
auto &instruction = imageObject.findInstructionByAddress(0x1000);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x00a) && load->data.size() == 9 * 2) {
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".serialNumber";
auto entry = config.getEntry(key.str());
if (entry.type == Configuration::ConfigurationNode::Type::ValueText &&
!entry.value.empty()) {
auto value = entry.getEUI64ToInteger();
if (value.first == 0xFFFFFFFF && value.second == 0xFFFFFFFF) {
value.first &= 0xFF000100 | pepOffset;
value.second &= 0x000000FF;
}
load->data[pepOffset * 2] = value.first;
load->data[pepOffset * 2 + 1] = value.second;
}
}
}
}
}
{
auto &instruction = imageObject.findInstructionByAddress(0x1054);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x064) && load->data.size() == 4 * 2) {
for (uint32_t customMacOffset = 0; customMacOffset < 4; ++customMacOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.customMac." << std::dec << customMacOffset;
auto entry = config.getEntry(key.str());
if (entry.type == Configuration::ConfigurationNode::Type::ValueText &&
!entry.value.empty()) {
auto value = entry.getEUI64ToInteger();
if (value.first == 0xFFFFFFFF && value.second == 0xFFFFFFFF) {
value.first &= 0xFF000100 | customMacOffset;
value.second &= 0x000000FF;
}
load->data[customMacOffset * 2] = value.first;
load->data[customMacOffset * 2 + 1] = value.second;
}
}
}
}
}
{
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x9230);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x049) && load->data.size() == 9) {
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".vendorId";
auto vendorIdEntry = config.getEntry(key.str());
if (vendorIdEntry.type == Configuration::ConfigurationNode::Type::ValueInt &&
!vendorIdEntry.value.empty()) {
uint16_t vendorId = vendorIdEntry.getInteger();
key.str("");
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".deviceId";
auto deviceIdEntry = config.getEntry(key.str());
if (deviceIdEntry.type == Configuration::ConfigurationNode::Type::ValueInt &&
!deviceIdEntry.value.empty()) {
uint16_t deviceId = deviceIdEntry.getInteger();
load->data[pepOffset] = ((uint32_t) deviceId << 16) | vendorId;
}
}
}
}
}
}
}
{
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x9260);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x052) && load->data.size() == 9) {
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".subVendorId";
auto subVendorIdEntry = config.getEntry(key.str());
if (subVendorIdEntry.type == Configuration::ConfigurationNode::Type::ValueInt &&
!subVendorIdEntry.value.empty()) {
uint16_t subVendorId = subVendorIdEntry.getInteger();
key.str("");
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".subDeviceId";
auto subDeviceIdEntry = config.getEntry(key.str());
if (subDeviceIdEntry.type == Configuration::ConfigurationNode::Type::ValueInt &&
!subDeviceIdEntry.value.empty()) {
uint16_t subDeviceId = subDeviceIdEntry.getInteger();
load->data[pepOffset] = ((uint32_t) subDeviceId << 16) | subVendorId;
}
}
}
}
}
}
}
{
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x9130);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x01c) && load->data.size() == 9) {
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".numberOfLanes";
auto entry = config.getEntry(key.str());
if (entry.type == Configuration::ConfigurationNode::Type::ValueInt &&
!entry.value.empty()) {
uint32_t value = entry.getInteger();
if (load->data[pepOffset] != value) {
std::cout << "Patching " << key.str() << " = " << std::dec
<< load->data[pepOffset]
<< " -> " << std::dec << value << " @ " << std::hex << std::setw(6)
<< std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[pepOffset] = value;
}
}
}
}
}
}
{
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x92f0);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x075) && load->data.size() == 9) {
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset << ".gen";
auto entry = config.getEntry(key.str());
if (entry.type == Configuration::ConfigurationNode::Type::ValueInt &&
!entry.value.empty()) {
uint32_t value = entry.getInteger();
if (load->data[pepOffset] != value) {
std::cout << "Patching " << key.str() << " = " << std::dec
<< load->data[pepOffset]
<< " -> " << std::dec << value << " @ " << std::hex << std::setw(6)
<< std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[pepOffset] = value;
}
}
}
}
}
}
{
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x9380);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) getScratchRegister(0x096) && load->data.size() == 9) {
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset
<< ".ASPMEnable";
auto entry = config.getEntry(key.str());
if (entry.type == Configuration::ConfigurationNode::Type::ValueBool &&
!entry.value.empty()) {
bool value = entry.getBool();
if (load->data[pepOffset] != value) {
std::cout << "Patching " << key.str() << " = " << std::dec
<< load->data[pepOffset]
<< " -> " << std::dec << value << " @ " << std::hex << std::setw(6)
<< std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[pepOffset] = value;
}
}
}
}
}
}
{
for (uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset << ".enable";
auto entry = config.getEntry(key.str());
if (entry.type == Configuration::ConfigurationNode::Type::ValueBool && !entry.value.empty()) {
bool value = entry.getBool();
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(
baseOffset + 0x9050 + pepOffset * 0x10);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) KnownRegisters::MGMT_SCRATCH_0 &&
load->data.size() == 1) {
if (load->data[0] != value) {
std::cout << "Patching " << key.str() << " = " << std::dec << load->data[0]
<< " -> "
<< std::dec << value << " @ " << std::hex << std::setw(6)
<< std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[0] = value;
}
}
}
}
}
}
{
for (auto pepOffset : std::vector<uint32_t>{0, 2, 4, 6}) {
std::stringstream key;
key << "api.platform.config.switch.0.bootCfg.pep." << std::dec << pepOffset << ".mode";
auto entry = config.getEntry(key.str());
if (entry.type == Configuration::ConfigurationNode::Type::ValueBool && !entry.value.empty()) {
bool value = entry.getBool();
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(
baseOffset + 0x9010 + (pepOffset / 2) * 0x10);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) KnownRegisters::MGMT_SCRATCH_0 &&
load->data.size() == 1) {
if (load->data[0] != value) {
std::cout << "Patching " << key.str() << " = " << std::dec << load->data[0]
<< " -> " << std::dec << value << " @ " << std::hex << std::setw(6)
<< std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[0] = value;
}
}
}
}
}
}
{
auto entry = config.getEntry("api.platform.config.switch.0.bootCfg.systimeClockSource");
if (entry.type == Configuration::ConfigurationNode::Type::ValueBool && !entry.value.empty()) {
bool value = entry.getBool();
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x9000);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) KnownRegisters::MGMT_SCRATCH_0 && load->data.size() == 1) {
if (load->data[0] != value) {
std::cout << "Patching bootCfg.systimeClockSource" << " = " << std::dec
<< load->data[0] << " -> " << std::dec << value << " @ " << std::hex
<< std::setw(6) << std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[0] = value;
}
}
}
}
}
{
auto entry = config.getEntry("api.platform.config.switch.0.bootCfg.spiTransferMode");
if (entry.type == Configuration::ConfigurationNode::Type::ValueInt && !entry.value.empty()) {
uint32_t value = entry.getInteger();
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x90f0);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) KnownRegisters::MGMT_SCRATCH_0 && load->data.size() == 1) {
if (load->data[0] != value) {
std::cout << "Patching bootCfg.spiTransferMode" << " = " << std::dec
<< load->data[0] << " -> " << std::dec << value << " @ " << std::hex
<< std::setw(6) << std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[0] = value;
}
}
}
}
}
{
auto entry = config.getEntry("api.platform.config.switch.0.bootCfg.spiTransferSpeed");
if (entry.type == Configuration::ConfigurationNode::Type::ValueInt && !entry.value.empty()) {
uint32_t value = entry.getInteger();
for (auto baseOffset : baseOffsets) {
auto &instruction = imageObject.findInstructionByAddress(baseOffset + 0x9100);
if (instruction != nullptr &&
instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD) {
auto &load = reinterpret_cast<std::unique_ptr<Instruction::Load> &>(instruction);
if (load->address == (uint32_t) KnownRegisters::MGMT_SCRATCH_0 && load->data.size() == 1) {
if (load->data[0] != value) {
std::cout << "Patching bootCfg.spiTransferSpeed" << " = " << std::dec
<< load->data[0] << " -> " << std::dec << value << " @ " << std::hex
<< std::setw(6) << std::setfill('0') << instruction->getAddress() << "\n";
}
load->data[0] = value;
}
}
}
}
}
// =========== Patching Ends ===========
std::ofstream patchedImage(patchedImageFile);
if (patchedImage.is_open()) {
auto result = imageObject.toBytes();
for (auto c : result) {
patchedImage.put(c);
}
patchedImage.close();
settings.close();
image.close();
}
}
}
}
int main(int argc, char *argv[]) {
if (argc >= 2 && strcmp(argv[1], "decode") == 0) {
decodeImage(argv[2]);
return 0;
} else if (argc >= 4 && strcmp(argv[1], "encode") == 0) {
patchImage(argv[2], argv[3], argv[4]);
return 0;
} else {
std::cout << "Usage:\n";
std::cout << " decode: " << argv[0] << " decode nvmImage.bin > decoded.txt\n";
std::cout << " encode: " << argv[0] << " encode originalNvmImage.bin settings.cfg patchedNvmImage.bin\n";
return 1;
}
}