From ebbc3e7cd2086a9f62a857dffe9ab0bd1f5da768 Mon Sep 17 00:00:00 2001 From: Benjamin Dobell Date: Fri, 8 Mar 2013 00:00:52 +1100 Subject: - Removed legacy command line hard-coded partition name parameters. - As a result of the above two points, there are no "known boot partitions", and hence boot partitions are not automatically flashed last. - Made partitions flash in the order in order in which partition arguments are specified. Hence, it's recommended that you specify boot partitions last. - Added --usb-level argument that can be used for debugging libusbx, or flashing issues in general. - Removed generally non-functional firmware dumping behaviour. - Removed auto-resume functionality - Although this feature was definitely nice to have; I believe it may be responsible for flashing compatibility issues for a variety of devices. - As a result of the above. In order perform another action after a --no-reboot action, you must provide the --resume flag. - Heimdall Frontend also has support for specifying the --resume flag via a GUI. Heimdall Frontend also tries to keep track of your actions and enable "Resume" automatically after a "No Reboot" action. - Refactored quite a few of the actions, and code responsible for flashing (particularly PIT file flashing). - Bumped version to 1.4RC3 *however* this commit is not yet an official release candidate. It's still a WIP. In particular build files still have not been updated for Linux and OS X. --- heimdall/source/Arguments.cpp | 37 +-- heimdall/source/Arguments.h | 63 +++-- heimdall/source/BridgeManager.cpp | 230 +++++++--------- heimdall/source/BridgeManager.h | 31 ++- heimdall/source/ClosePcScreenAction.cpp | 45 +++- heimdall/source/DetectAction.cpp | 40 +++ heimdall/source/DownloadPitAction.cpp | 45 +++- heimdall/source/DumpAction.cpp | 158 ----------- heimdall/source/DumpAction.h | 34 --- heimdall/source/FlashAction.cpp | 451 +++++++++++++------------------- heimdall/source/Interface.cpp | 4 +- heimdall/source/Interface.h | 7 +- heimdall/source/PrintPitAction.cpp | 46 +++- heimdall/source/SendFilePartPacket.h | 5 + 14 files changed, 535 insertions(+), 661 deletions(-) delete mode 100644 heimdall/source/DumpAction.cpp delete mode 100644 heimdall/source/DumpAction.h (limited to 'heimdall/source') diff --git a/heimdall/source/Arguments.cpp b/heimdall/source/Arguments.cpp index 1c3a17e..7f2d9ee 100644 --- a/heimdall/source/Arguments.cpp +++ b/heimdall/source/Arguments.cpp @@ -24,20 +24,21 @@ #include "Interface.h" #include "Utility.h" +using namespace std; using namespace Heimdall; -FlagArgument *FlagArgument::ParseArgument(int argc, char **argv, int& argi) +FlagArgument *FlagArgument::ParseArgument(const std::string& name, int argc, char **argv, int& argi) { - return new FlagArgument(); + return new FlagArgument(name); } -StringArgument *StringArgument::ParseArgument(int argc, char **argv, int& argi) +StringArgument *StringArgument::ParseArgument(const std::string& name, int argc, char **argv, int& argi) { if (++argi < argc) { - return (new StringArgument(argv[argi])); + return (new StringArgument(name, argv[argi])); } else { @@ -48,7 +49,7 @@ StringArgument *StringArgument::ParseArgument(int argc, char **argv, int& argi) -UnsignedIntegerArgument *UnsignedIntegerArgument::ParseArgument(int argc, char **argv, int& argi) +UnsignedIntegerArgument *UnsignedIntegerArgument::ParseArgument(const std::string& name, int argc, char **argv, int& argi) { UnsignedIntegerArgument *unsignedIntegerArgument = nullptr; @@ -57,7 +58,7 @@ UnsignedIntegerArgument *UnsignedIntegerArgument::ParseArgument(int argc, char * unsigned int value; if (Utility::ParseUnsignedInt(value, argv[argi]) == kNumberParsingStatusSuccess) - unsignedIntegerArgument = new UnsignedIntegerArgument(value); + unsignedIntegerArgument = new UnsignedIntegerArgument(name, value); else Interface::Print("%s must be a positive integer.", argv[argi - 1]); } @@ -81,8 +82,8 @@ Arguments::Arguments(const map& argumentTypes, const map::const_iterator it = arguments.begin(); it != arguments.end(); it++) - delete it->second; + for (vector::const_iterator it = argumentVector.begin(); it != argumentVector.end(); it++) + delete *it; } bool Arguments::ParseArguments(int argc, char **argv, int argi) @@ -158,6 +159,10 @@ bool Arguments::ParseArguments(int argc, char **argv, int argi) } } + // We don't want to insert wild-cards into our argument map. + if (argumentName == "%d" || argumentName == "%s") + argumentName = nonwildcardArgumentName; + Argument *argument = nullptr; if (argumentTypeIt != argumentTypes.end()) @@ -165,15 +170,15 @@ bool Arguments::ParseArguments(int argc, char **argv, int argi) switch (argumentTypeIt->second) { case kArgumentTypeFlag: - argument = FlagArgument::ParseArgument(argc, argv, argi); + argument = FlagArgument::ParseArgument(argumentName, argc, argv, argi); break; case kArgumentTypeString: - argument = StringArgument::ParseArgument(argc, argv, argi); + argument = StringArgument::ParseArgument(argumentName, argc, argv, argi); break; case kArgumentTypeUnsignedInteger: - argument = UnsignedIntegerArgument::ParseArgument(argc, argv, argi); + argument = UnsignedIntegerArgument::ParseArgument(argumentName, argc, argv, argi); break; default: @@ -186,21 +191,19 @@ bool Arguments::ParseArguments(int argc, char **argv, int argi) Interface::Print("Unknown argument: %s\n\n", argv[argi]); } - // We don't want to insert wild-cards into our argument map. - if (argumentName == "%d" || argumentName == "%s") - argumentName = nonwildcardArgumentName; - if (argument) { - pair::iterator, bool> insertResult = arguments.insert(pair(argumentName, argument)); + pair::iterator, bool> insertResult = argumentMap.insert(pair(argumentName, argument)); if (!insertResult.second) { - Interface::Print("Duplicate argument: %s (%s)\n\n", argv[argi], insertResult.first->first.c_str()); + Interface::Print("Duplicate argument: %s (%s)\n\n", argv[argi], argumentName); delete argument; return (false); } + + argumentVector.push_back(argument); } else { diff --git a/heimdall/source/Arguments.h b/heimdall/source/Arguments.h index 17f31fa..b64028b 100644 --- a/heimdall/source/Arguments.h +++ b/heimdall/source/Arguments.h @@ -24,12 +24,11 @@ // C/C++ Standard Library #include #include +#include // Heimdall #include "Heimdall.h" -using namespace std; - namespace Heimdall { typedef enum @@ -37,20 +36,21 @@ namespace Heimdall kArgumentTypeFlag = 0, kArgumentTypeString, kArgumentTypeUnsignedInteger - } ArgumentType; class Argument { private: - ArgumentType argumentType; + std::string name; + ArgumentType type; protected: - Argument(ArgumentType argumentType) + Argument(const std::string& name, ArgumentType type) { - this->argumentType = argumentType; + this->name = name; + this->type = type; } public: @@ -59,9 +59,14 @@ namespace Heimdall { } - ArgumentType GetArgumentType(void) const + const std::string& GetName(void) const + { + return name; + } + + ArgumentType GetType(void) const { - return argumentType; + return type; } }; @@ -69,31 +74,31 @@ namespace Heimdall { private: - FlagArgument() : Argument(kArgumentTypeFlag) + FlagArgument(const std::string& name) : Argument(name, kArgumentTypeFlag) { } public: - static FlagArgument *ParseArgument(int argc, char **argv, int& argi); + static FlagArgument *ParseArgument(const std::string& name, int argc, char **argv, int& argi); }; class StringArgument : public Argument { private: - string value; + std::string value; - StringArgument(const string& value) : Argument(kArgumentTypeString) + StringArgument(const std::string& name, const std::string& value) : Argument(name, kArgumentTypeString) { this->value = value; } public: - static StringArgument *ParseArgument(int argc, char **argv, int& argi); + static StringArgument *ParseArgument(const std::string& name, int argc, char **argv, int& argi); - const string& GetValue(void) const + const std::string& GetValue(void) const { return (value); } @@ -105,14 +110,14 @@ namespace Heimdall unsigned int value; - UnsignedIntegerArgument(unsigned int value) : Argument(kArgumentTypeUnsignedInteger) + UnsignedIntegerArgument(const std::string& name, unsigned int value) : Argument(name, kArgumentTypeUnsignedInteger) { this->value = value; } public: - static UnsignedIntegerArgument *ParseArgument(int argc, char **argv, int& argi); + static UnsignedIntegerArgument *ParseArgument(const std::string& name, int argc, char **argv, int& argi); unsigned int GetValue(void) const { @@ -124,36 +129,38 @@ namespace Heimdall { private: - const map argumentTypes; - const map shortArgumentAliases; - const map argumentAliases; + const std::map argumentTypes; + const std::map shortArgumentAliases; + const std::map argumentAliases; - map arguments; + std::vector argumentVector; + std::map argumentMap; public: - Arguments(const map& argumentTypes, const map& shortArgumentAliases = (map()), - const map& argumentAliases = (map())); + Arguments(const std::map& argumentTypes, + const std::map& shortArgumentAliases = std::map(), + const std::map& argumentAliases = std::map()); ~Arguments(); // argi is the index of the first argument to parse. bool ParseArguments(int argc, char **argv, int argi); - const Argument *GetArgument(string argumentName) const + const Argument *GetArgument(std::string argumentName) const { - map::const_iterator it = arguments.find(argumentName); - return (it != arguments.end() ? it->second : nullptr); + std::map::const_iterator it = argumentMap.find(argumentName); + return (it != argumentMap.end() ? it->second : nullptr); } - const map& GetArgumentTypes(void) const + const std::map& GetArgumentTypes(void) const { return (argumentTypes); } - const map& GetArguments(void) const + const std::vector& GetArguments(void) const { - return (arguments); + return (argumentVector); } }; } diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp index aa7b969..8f1b32e 100644 --- a/heimdall/source/BridgeManager.cpp +++ b/heimdall/source/BridgeManager.cpp @@ -57,6 +57,7 @@ #define USB_CLASS_CDC_DATA 0x0A +using namespace libpit; using namespace Heimdall; const DeviceIdentifier BridgeManager::supportedDevices[BridgeManager::kSupportedDeviceCount] = { @@ -68,7 +69,7 @@ const DeviceIdentifier BridgeManager::supportedDevices[BridgeManager::kSupported enum { - kDumpBufferSize = 4096 + kDumpBufferSize = 4096, }; enum @@ -84,6 +85,11 @@ enum kReceivePacketMaxAttempts = 5 }; +enum +{ + kPitSizeMultiplicand = 4096 +}; + int BridgeManager::FindDeviceInterface(void) { Interface::Print("Detecting device...\n"); @@ -302,34 +308,7 @@ void BridgeManager::ReleaseDeviceInterface(void) Interface::Print("\n"); } -bool BridgeManager::CheckProtocol(void) const -{ - Interface::Print("Checking if protocol is initialised...\n"); - - DeviceTypePacket deviceTypePacket; - - if (!SendPacket(&deviceTypePacket, 150, false)) - { - Interface::Print("Protocol is not initialised.\n"); - return (false); - } - - unsigned char buffer[1024]; - memset(buffer, 0, sizeof(buffer)); - - SessionSetupResponse deviceTypeResponse; - - if (!ReceivePacket(&deviceTypeResponse, 150, false, buffer, sizeof(buffer))) - { - Interface::Print("Protocol is not initialised.\n\n"); - return (false); - } - - Interface::Print("Protocol is initialised.\n\n"); - return (true); -} - -bool BridgeManager::InitialiseProtocol(void) const +bool BridgeManager::InitialiseProtocol(void) { Interface::Print("Initialising protocol...\n"); @@ -488,6 +467,8 @@ BridgeManager::BridgeManager(bool verbose, int communicationDelay) fileTransferSequenceMaxLength = kFileTransferSequenceMaxLengthDefault; fileTransferPacketSize = kFileTransferPacketSizeDefault; fileTransferSequenceTimeout = kFileTransferSequenceTimeoutDefault; + + usbLogLevel = UsbLogLevel::Default; } BridgeManager::~BridgeManager() @@ -507,14 +488,39 @@ BridgeManager::~BridgeManager() bool BridgeManager::DetectDevice(void) { - // Initialise libusb-1.0 + // Initialise libusb int result = libusb_init(&libusbContext); + if (result != LIBUSB_SUCCESS) { Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result); return (false); } + // Setup libusb log level. + switch (usbLogLevel) + { + case UsbLogLevel::None: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_NONE); + break; + + case UsbLogLevel::Error: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_ERROR); + break; + + case UsbLogLevel::Warning: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_WARNING); + break; + + case UsbLogLevel::Info: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_INFO); + break; + + case UsbLogLevel::Debug: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_DEBUG); + break; + } + // Get handle to Galaxy S device struct libusb_device **devices; int deviceCount = libusb_get_device_list(libusbContext, &devices); @@ -542,11 +548,11 @@ bool BridgeManager::DetectDevice(void) return (false); } -int BridgeManager::Initialise() +int BridgeManager::Initialise(bool resume) { Interface::Print("Initialising connection...\n"); - // Initialise libusb-1.0 + // Initialise libusb int result = libusb_init(&libusbContext); if (result != LIBUSB_SUCCESS) @@ -555,6 +561,30 @@ int BridgeManager::Initialise() Interface::Print("Failed to connect to device!"); return (BridgeManager::kInitialiseFailed); } + + // Setup libusb log level. + switch (usbLogLevel) + { + case UsbLogLevel::None: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_NONE); + break; + + case UsbLogLevel::Error: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_ERROR); + break; + + case UsbLogLevel::Warning: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_WARNING); + break; + + case UsbLogLevel::Info: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_INFO); + break; + + case UsbLogLevel::Debug: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_DEBUG); + break; + } result = FindDeviceInterface(); @@ -567,7 +597,7 @@ int BridgeManager::Initialise() if (!SetupDeviceInterface()) return (BridgeManager::kInitialiseFailed); - if (!CheckProtocol()) + if (!resume) { if (!InitialiseProtocol()) return (BridgeManager::kInitialiseFailed); @@ -865,11 +895,9 @@ bool BridgeManager::RequestDeviceType(unsigned int request, int *result) const return (true); } -bool BridgeManager::SendPitFile(FILE *file) const +bool BridgeManager::SendPitData(const PitData *pitData) const { - fseek(file, 0, SEEK_END); - long fileSize = ftell(file); - rewind(file); + unsigned int pitBufferSize = pitData->GetPaddedSize(); // Start file transfer PitFilePacket *pitFilePacket = new PitFilePacket(PitFilePacket::kRequestFlash); @@ -893,7 +921,7 @@ bool BridgeManager::SendPitFile(FILE *file) const } // Transfer file size - FlashPartPitFilePacket *flashPartPitFilePacket = new FlashPartPitFilePacket(fileSize); + FlashPartPitFilePacket *flashPartPitFilePacket = new FlashPartPitFilePacket(pitBufferSize); success = SendPacket(flashPartPitFilePacket); delete flashPartPitFilePacket; @@ -913,11 +941,20 @@ bool BridgeManager::SendPitFile(FILE *file) const return (false); } + // Create packed in-memory PIT file + + unsigned char *pitBuffer = new unsigned char[pitBufferSize]; + memset(pitBuffer, 0, pitBufferSize); + + pitData->Pack(pitBuffer); + // Flash pit file - SendFilePartPacket *sendFilePartPacket = new SendFilePartPacket(file, fileSize); + SendFilePartPacket *sendFilePartPacket = new SendFilePartPacket(pitBuffer, pitBufferSize); success = SendPacket(sendFilePartPacket); delete sendFilePartPacket; + delete [] pitBuffer; + if (!success) { Interface::PrintError("Failed to send file part packet!\n"); @@ -935,7 +972,7 @@ bool BridgeManager::SendPitFile(FILE *file) const } // End pit file transfer - EndPitFileTransferPacket *endPitFileTransferPacket = new EndPitFileTransferPacket(fileSize); + EndPitFileTransferPacket *endPitFileTransferPacket = new EndPitFileTransferPacket(pitBufferSize); success = SendPacket(endPitFileTransferPacket); delete endPitFileTransferPacket; @@ -1320,106 +1357,33 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int return (true); } -bool BridgeManager::ReceiveDump(unsigned int chipType, unsigned int chipId, FILE *file) const +void BridgeManager::SetUsbLogLevel(UsbLogLevel usbLogLevel) { - bool success; - - // Start file transfer - BeginDumpPacket *beginDumpPacket = new BeginDumpPacket(chipType, chipId); - success = SendPacket(beginDumpPacket); - delete beginDumpPacket; + this->usbLogLevel = usbLogLevel; - if (!success) - { - Interface::PrintError("Failed to request dump!\n"); - return (false); - } - - DumpResponse *dumpResponse = new DumpResponse(); - success = ReceivePacket(dumpResponse); - unsigned int dumpSize = dumpResponse->GetDumpSize(); - delete dumpResponse; - - if (!success) - { - Interface::PrintError("Failed to receive dump size!\n"); - return (false); - } - - unsigned int transferCount = dumpSize / ReceiveFilePartPacket::kDataSize; - if (transferCount % ReceiveFilePartPacket::kDataSize != 0) - transferCount++; - - char *buffer = new char[kDumpBufferSize * ReceiveFilePartPacket::kDataSize]; - unsigned int bufferOffset = 0; - - for (unsigned int i = 0; i < transferCount; i++) + if (libusbContext) { - DumpPartFileTransferPacket *dumpPartPacket = new DumpPartFileTransferPacket(i); - success = SendPacket(dumpPartPacket); - delete dumpPartPacket; - - if (!success) - { - Interface::PrintError("Failed to request dump part #%d!\n", i); - delete [] buffer; - return (false); - } - - ReceiveFilePartPacket *receiveFilePartPacket = new ReceiveFilePartPacket(); - success = ReceivePacket(receiveFilePartPacket); - - if (!success) - { - Interface::PrintError("Failed to receive dump part #%d!\n", i); - continue; - delete receiveFilePartPacket; - delete [] buffer; - return (true); - } - - if (bufferOffset + receiveFilePartPacket->GetReceivedSize() > kDumpBufferSize * ReceiveFilePartPacket::kDataSize) + switch (usbLogLevel) { - // Write the buffer to the output file - fwrite(buffer, 1, bufferOffset, file); - bufferOffset = 0; - } - - // Copy the packet data into pitFile. - memcpy(buffer + bufferOffset, receiveFilePartPacket->GetData(), receiveFilePartPacket->GetReceivedSize()); - bufferOffset += receiveFilePartPacket->GetReceivedSize(); - - delete receiveFilePartPacket; - } - - if (bufferOffset != 0) - { - // Write the buffer to the output file - fwrite(buffer, 1, bufferOffset, file); - } - - delete [] buffer; + case UsbLogLevel::None: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_NONE); + break; - // End file transfer - FileTransferPacket *fileTransferPacket = new FileTransferPacket(FileTransferPacket::kRequestEnd); - success = SendPacket(fileTransferPacket); - delete fileTransferPacket; + case UsbLogLevel::Error: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_ERROR); + break; - if (!success) - { - Interface::PrintError("Failed to send request to end dump transfer!\n"); - return (false); - } + case UsbLogLevel::Warning: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_WARNING); + break; - ResponsePacket *responsePacket = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer); - success = ReceivePacket(responsePacket); - delete responsePacket; + case UsbLogLevel::Info: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_INFO); + break; - if (!success) - { - Interface::PrintError("Failed to receive end dump transfer verification!\n"); - return (false); + case UsbLogLevel::Debug: + libusb_set_debug(libusbContext, LIBUSB_LOG_LEVEL_DEBUG); + break; + } } - - return (true); } diff --git a/heimdall/source/BridgeManager.h b/heimdall/source/BridgeManager.h index 2978340..4402710 100644 --- a/heimdall/source/BridgeManager.h +++ b/heimdall/source/BridgeManager.h @@ -21,6 +21,9 @@ #ifndef BRIDGEMANAGER_H #define BRIDGEMANAGER_H +// libpit +#include "libpit.h" + // Heimdall #include "Heimdall.h" @@ -81,6 +84,17 @@ namespace Heimdall kPidGalaxyCamera = 0x6860 // Is this necessary? }; + enum class UsbLogLevel + { + None = 0, + Error, + Warning, + Info, + Debug, + + Default = Error + }; + private: static const DeviceIdentifier supportedDevices[kSupportedDeviceCount]; @@ -109,13 +123,14 @@ namespace Heimdall unsigned int fileTransferPacketSize; unsigned int fileTransferSequenceTimeout; + UsbLogLevel usbLogLevel; + int FindDeviceInterface(void); bool ClaimDeviceInterface(void); bool SetupDeviceInterface(void); void ReleaseDeviceInterface(void); - bool CheckProtocol(void) const; - bool InitialiseProtocol(void) const; + bool InitialiseProtocol(void); public: @@ -123,7 +138,7 @@ namespace Heimdall ~BridgeManager(); bool DetectDevice(void); - int Initialise(void); + int Initialise(bool resume); bool BeginSession(void); bool EndSession(bool reboot) const; @@ -133,12 +148,18 @@ namespace Heimdall bool RequestDeviceType(unsigned int request, int *result) const; - bool SendPitFile(FILE *file) const; + bool SendPitData(const libpit::PitData *pitData) const; int ReceivePitFile(unsigned char **pitBuffer) const; int DownloadPitFile(unsigned char **pitBuffer) const; // Thin wrapper around ReceivePitFile() with additional logging. bool SendFile(FILE *file, unsigned int destination, unsigned int deviceType, unsigned int fileIdentifier = 0xFFFFFFFF) const; - bool ReceiveDump(unsigned int chipType, unsigned int chipId, FILE *file) const; + + void SetUsbLogLevel(UsbLogLevel usbLogLevel); + + UsbLogLevel GetUsbLogLevel(void) const + { + return usbLogLevel; + } bool IsVerbose(void) const { diff --git a/heimdall/source/ClosePcScreenAction.cpp b/heimdall/source/ClosePcScreenAction.cpp index a7de9d9..1c53ffe 100644 --- a/heimdall/source/ClosePcScreenAction.cpp +++ b/heimdall/source/ClosePcScreenAction.cpp @@ -25,11 +25,13 @@ #include "Heimdall.h" #include "Interface.h" +using namespace std; using namespace Heimdall; const char *ClosePcScreenAction::usage = "Action: close-pc-screen\n\ Arguments: [--verbose] [--no-reboot] [--stdout-errors] [--delay ]\n\ -Description: Attempts to get rid off the \"connect phone to PC\" screen.\n"; + [--usb-log-level ]\n\ +Description: Attempts to get rid off the \"connect phone to PC\" screen.\n"; // TODO: usb-log-level int ClosePcScreenAction::Execute(int argc, char **argv) { @@ -37,9 +39,11 @@ int ClosePcScreenAction::Execute(int argc, char **argv) map argumentTypes; argumentTypes["no-reboot"] = kArgumentTypeFlag; + argumentTypes["resume"] = kArgumentTypeFlag; argumentTypes["delay"] = kArgumentTypeUnsignedInteger; argumentTypes["verbose"] = kArgumentTypeFlag; argumentTypes["stdout-errors"] = kArgumentTypeFlag; + argumentTypes["usb-log-level"] = kArgumentTypeString; Arguments arguments(argumentTypes); @@ -50,8 +54,44 @@ int ClosePcScreenAction::Execute(int argc, char **argv) } const UnsignedIntegerArgument *communicationDelayArgument = static_cast(arguments.GetArgument("delay")); + const StringArgument *usbLogLevelArgument = static_cast(arguments.GetArgument("usb-log-level")); + + BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default; + + if (usbLogLevelArgument) + { + const string& usbLogLevelString = usbLogLevelArgument->GetValue(); + + if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::None; + } + else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Error; + } + else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Warning; + } + else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Info; + } + else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Debug; + } + else + { + Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str()); + Interface::Print(ClosePcScreenAction::usage); + return (0); + } + } bool reboot = arguments.GetArgument("no-reboot") == nullptr; + bool resume = arguments.GetArgument("resume") != nullptr; bool verbose = arguments.GetArgument("verbose") != nullptr; if (arguments.GetArgument("stdout-errors") != nullptr) @@ -70,8 +110,9 @@ int ClosePcScreenAction::Execute(int argc, char **argv) communicationDelay = communicationDelayArgument->GetValue(); BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + bridgeManager->SetUsbLogLevel(usbLogLevel); - if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) { delete bridgeManager; return (1); diff --git a/heimdall/source/DetectAction.cpp b/heimdall/source/DetectAction.cpp index 319433f..c5b4eb6 100644 --- a/heimdall/source/DetectAction.cpp +++ b/heimdall/source/DetectAction.cpp @@ -25,10 +25,12 @@ #include "Heimdall.h" #include "Interface.h" +using namespace std; using namespace Heimdall; const char *DetectAction::usage = "Action: detect\n\ Arguments: [--verbose] [--stdout-errors]\n\ + [--usb-log-level ]\n\ Description: Indicates whether or not a download mode device can be detected.\n"; int DetectAction::Execute(int argc, char **argv) @@ -38,6 +40,7 @@ int DetectAction::Execute(int argc, char **argv) map argumentTypes; argumentTypes["verbose"] = kArgumentTypeFlag; argumentTypes["stdout-errors"] = kArgumentTypeFlag; + argumentTypes["usb-log-level"] = kArgumentTypeString; Arguments arguments(argumentTypes); @@ -52,9 +55,46 @@ int DetectAction::Execute(int argc, char **argv) if (arguments.GetArgument("stdout-errors") != nullptr) Interface::SetStdoutErrors(true); + const StringArgument *usbLogLevelArgument = static_cast(arguments.GetArgument("usb-log-level")); + + BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default; + + if (usbLogLevelArgument) + { + const string& usbLogLevelString = usbLogLevelArgument->GetValue(); + + if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::None; + } + else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Error; + } + else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Warning; + } + else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Info; + } + else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Debug; + } + else + { + Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str()); + Interface::Print(DetectAction::usage); + return (0); + } + } + // Download PIT file from device. BridgeManager *bridgeManager = new BridgeManager(verbose); + bridgeManager->SetUsbLogLevel(usbLogLevel); bool detected = bridgeManager->DetectDevice(); diff --git a/heimdall/source/DownloadPitAction.cpp b/heimdall/source/DownloadPitAction.cpp index b4b81a9..744ba56 100644 --- a/heimdall/source/DownloadPitAction.cpp +++ b/heimdall/source/DownloadPitAction.cpp @@ -28,11 +28,12 @@ #include "Heimdall.h" #include "Interface.h" +using namespace std; using namespace Heimdall; const char *DownloadPitAction::usage = "Action: download-pit\n\ Arguments: --output [--verbose] [--no-reboot] [--stdout-errors]\n\ - [--delay ]\n\ + [--delay ] [--usb-log-level ]\n\ Description: Downloads the connected device's PIT file to the specified\n\ output file.\n"; @@ -43,9 +44,11 @@ int DownloadPitAction::Execute(int argc, char **argv) map argumentTypes; argumentTypes["output"] = kArgumentTypeString; argumentTypes["no-reboot"] = kArgumentTypeFlag; + argumentTypes["resume"] = kArgumentTypeFlag; argumentTypes["delay"] = kArgumentTypeUnsignedInteger; argumentTypes["verbose"] = kArgumentTypeFlag; argumentTypes["stdout-errors"] = kArgumentTypeFlag; + argumentTypes["usb-log-level"] = kArgumentTypeString; Arguments arguments(argumentTypes); @@ -67,11 +70,48 @@ int DownloadPitAction::Execute(int argc, char **argv) const UnsignedIntegerArgument *communicationDelayArgument = static_cast(arguments.GetArgument("delay")); bool reboot = arguments.GetArgument("no-reboot") == nullptr; + bool resume = arguments.GetArgument("resume") != nullptr; bool verbose = arguments.GetArgument("verbose") != nullptr; if (arguments.GetArgument("stdout-errors") != nullptr) Interface::SetStdoutErrors(true); + const StringArgument *usbLogLevelArgument = static_cast(arguments.GetArgument("usb-log-level")); + + BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default; + + if (usbLogLevelArgument) + { + const string& usbLogLevelString = usbLogLevelArgument->GetValue(); + + if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::None; + } + else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Error; + } + else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Warning; + } + else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Info; + } + else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Debug; + } + else + { + Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str()); + Interface::Print(DownloadPitAction::usage); + return (0); + } + } + // Info Interface::PrintReleaseInfo(); @@ -96,8 +136,9 @@ int DownloadPitAction::Execute(int argc, char **argv) communicationDelay = communicationDelayArgument->GetValue(); BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + bridgeManager->SetUsbLogLevel(usbLogLevel); - if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) { fclose(outputPitFile); delete bridgeManager; diff --git a/heimdall/source/DumpAction.cpp b/heimdall/source/DumpAction.cpp deleted file mode 100644 index 38ccbf9..0000000 --- a/heimdall/source/DumpAction.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright (c) 2010-2012 Benjamin Dobell, Glass Echidna - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE.*/ - -// C Standard Library -#include - -// Heimdall -#include "Arguments.h" -#include "BridgeManager.h" -#include "DumpAction.h" -#include "Heimdall.h" -#include "Interface.h" - -using namespace Heimdall; - -const char *DumpAction::usage = "Action: dump\n\ -Arguments: --chip-type --chip-id --output \n\ - [--verbose] [--no-reboot] [--stdout-errors] [--delay ]\n\ -Description: Attempts to dump data from the phone corresponding to the\n\ - specified chip type and chip ID.\n\ -NOTE: Galaxy S phones don't appear to properly support this functionality.\n"; - -int DumpAction::Execute(int argc, char **argv) -{ - // Handle arguments - - map argumentTypes; - - argumentTypes["chip-type"] = kArgumentTypeString; - argumentTypes["chip-id"] = kArgumentTypeUnsignedInteger; - argumentTypes["output"] = kArgumentTypeString; - - argumentTypes["no-reboot"] = kArgumentTypeFlag; - argumentTypes["delay"] = kArgumentTypeUnsignedInteger; - argumentTypes["verbose"] = kArgumentTypeFlag; - argumentTypes["stdout-errors"] = kArgumentTypeFlag; - - Arguments arguments(argumentTypes); - - if (!arguments.ParseArguments(argc, argv, 2)) - { - Interface::Print(DumpAction::usage); - return (0); - } - - const StringArgument *chipTypeArgument = static_cast(arguments.GetArgument("chip-type")); - const UnsignedIntegerArgument *chipIdArgument = static_cast(arguments.GetArgument("chip-id")); - const StringArgument *outputArgument = static_cast(arguments.GetArgument("output")); - - if (!outputArgument) - { - Interface::Print("Output file was not specified.\n\n"); - Interface::Print(DumpAction::usage); - return (false); - } - - if (!chipTypeArgument) - { - Interface::Print("You must specify a chip type.\n\n"); - Interface::Print(DumpAction::usage); - return (false); - } - - if (!(chipTypeArgument->GetValue() == "RAM" || chipTypeArgument->GetValue() == "ram" || chipTypeArgument->GetValue() == "NAND" - || chipTypeArgument->GetValue() == "nand")) - { - Interface::Print("Unknown chip type: %s.\n\n", chipTypeArgument->GetValue().c_str()); - Interface::Print(DumpAction::usage); - return (false); - } - - if (!chipIdArgument) - { - Interface::Print("You must specify a chip ID.\n\n"); - Interface::Print(DumpAction::usage); - return (false); - } - - const UnsignedIntegerArgument *communicationDelayArgument = static_cast(arguments.GetArgument("delay")); - - bool reboot = arguments.GetArgument("no-reboot") == nullptr; - bool verbose = arguments.GetArgument("verbose") != nullptr; - - if (arguments.GetArgument("stdout-errors") != nullptr) - Interface::SetStdoutErrors(true); - - // Open output file - - const char *outputFilename = outputArgument->GetValue().c_str(); - FILE *dumpFile = fopen(outputFilename, "wb"); - - if (!dumpFile) - { - Interface::PrintError("Failed to open file \"%s\"\n", outputFilename); - return (1); - } - - // Info - - Interface::PrintReleaseInfo(); - Sleep(1000); - - // Dump - - int communicationDelay = BridgeManager::kCommunicationDelayDefault; - - if (communicationDelayArgument) - communicationDelay = communicationDelayArgument->GetValue(); - - BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); - - if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) - { - fclose(dumpFile); - delete bridgeManager; - return (1); - } - - int chipType = 0; - - if (chipTypeArgument->GetValue() == "NAND" || chipTypeArgument->GetValue() == "nand") - chipType = 1; - - bool success = bridgeManager->ReceiveDump(chipType, chipIdArgument->GetValue(), dumpFile); - fclose(dumpFile); - - if (!bridgeManager->EndSession(reboot)) - success = false; - - delete bridgeManager; - - if (success) - { - Interface::Print("Attempt complete\n"); - return (0); - } - else - { - return (1); - } -} diff --git a/heimdall/source/DumpAction.h b/heimdall/source/DumpAction.h deleted file mode 100644 index eb97bca..0000000 --- a/heimdall/source/DumpAction.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (c) 2010-2012 Benjamin Dobell, Glass Echidna - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE.*/ - -#ifndef DUMPACTION_H -#define DUMPACTION_H - -namespace Heimdall -{ - namespace DumpAction - { - extern const char *usage; - - int Execute(int argc, char **argv); - }; -} - -#endif diff --git a/heimdall/source/FlashAction.cpp b/heimdall/source/FlashAction.cpp index fad4df7..b5f69f2 100644 --- a/heimdall/source/FlashAction.cpp +++ b/heimdall/source/FlashAction.cpp @@ -33,36 +33,37 @@ #include "TotalBytesPacket.h" #include "Utility.h" +using namespace std; +using namespace libpit; using namespace Heimdall; const char *FlashAction::usage = "Action: flash\n\ Arguments:\n\ - --repartition --pit [--factoryfs ]\n\ - [--cache ] [--dbdata ] [--primary-boot ]\n\ - [--secondary-boot ] [--param ] [--kernel ]\n\ - [--modem ] [--radio ] [--normal-boot ]\n\ - [--system ] [--user-data ] [--fota ]\n\ - [--hidden ] [--movinand ] [--data ]\n\ - [--ums ] [--emmc ]\n\ - [-- ]\n\ - [-- ]\n\ + --repartition --pit \n\ + --|-- [...]\n\ [--verbose] [--no-reboot] [--stdout-errors] [--delay ]\n\ + [--usb-log-level ]\n\ or:\n\ - [--factoryfs ] [--cache ] [--dbdata ]\n\ - [--primary-boot ] [--secondary-boot ]\n\ - [--secondary-boot-backup ] [--param ]\n\ - [--kernel ] [--recovery ] [--efs ]\n\ - [--modem ] [--radio ] [--normal-boot ]\n\ - [--system ] [--user-data ] [--fota ]\n\ - [--hidden ] [--movinand ] [--data ]\n\ - [--ums ] [--emmc ] [--pit ]\n\ - [-- ]\n\ - [-- ]\n\ + --|-- [...]\n\ + [--pit ]\n\ [--verbose] [--no-reboot] [--stdout-errors] [--delay ]\n\ -Description: Flashes firmware files to your phone. Partition identifiers are\n\ - integer values, they can be obtained by executing the print-pit action.\n\ + [--usb-log-level ]\n\ +Description: Flashes one or more firmware files to your phone. Partition names\n\ + (or identifiers) can be obtained by executing the print-pit action.\n\ WARNING: If you're repartitioning it's strongly recommended you specify\n\ - all files at your disposal, including bootloaders.\n"; + all files at your disposal.\n"; + +struct PartitionFile +{ + const char *argumentName; + FILE *file; + + PartitionFile(const char *argumentName, FILE *file) + { + this->argumentName = argumentName; + this->file = file; + } +}; struct PartitionFlashInfo { @@ -76,85 +77,37 @@ struct PartitionFlashInfo } }; -static void buildArgumentPartitionNamesMap(map< string, vector >& argumentPartitionNamesMap, map& shortArgumentAliases) +static bool openFiles(Arguments& arguments, vector& partitionFiles, FILE *& pitFile) { - argumentPartitionNamesMap["pit"].push_back("PIT"); - argumentPartitionNamesMap["factoryfs"].push_back("FACTORYFS"); - argumentPartitionNamesMap["cache"].push_back("CACHE"); - argumentPartitionNamesMap["dbdata"].push_back("DBDATAFS"); - - argumentPartitionNamesMap["primary-boot"].push_back("IBL+PBL"); - argumentPartitionNamesMap["primary-boot"].push_back("BOOT"); - - argumentPartitionNamesMap["secondary-boot"].push_back("SBL"); - argumentPartitionNamesMap["secondary-boot"].push_back("SBL1"); - - argumentPartitionNamesMap["secondary-boot-backup"].push_back("SBL2"); - argumentPartitionNamesMap["param"].push_back("PARAM"); - argumentPartitionNamesMap["kernel"].push_back("KERNEL"); - argumentPartitionNamesMap["recovery"].push_back("RECOVERY"); - argumentPartitionNamesMap["efs"].push_back("EFS"); - argumentPartitionNamesMap["modem"].push_back("MODEM"); - argumentPartitionNamesMap["radio"].push_back("RADIO"); - argumentPartitionNamesMap["normal-boot"].push_back("NORMALBOOT"); - argumentPartitionNamesMap["system"].push_back("SYSTEM"); - argumentPartitionNamesMap["user-data"].push_back("USERDATA"); - argumentPartitionNamesMap["fota"].push_back("FOTA"); - argumentPartitionNamesMap["hidden"].push_back("HIDDEN"); - argumentPartitionNamesMap["movinand"].push_back("MOVINAND"); - argumentPartitionNamesMap["data"].push_back("DATAFS"); - argumentPartitionNamesMap["ums"].push_back("UMS.EN"); - argumentPartitionNamesMap["emmc"].push_back("GANG"); + // Open PIT file - shortArgumentAliases["pit"] = "pit"; - shortArgumentAliases["fs"] = "factoryfs"; - shortArgumentAliases["cache"] = "cache"; - shortArgumentAliases["db"] = "dbdata"; - shortArgumentAliases["boot"] = "primary-boot"; - shortArgumentAliases["sbl"] = "secondary-boot"; - shortArgumentAliases["sbl2"] = "secondary-boot-backup"; - shortArgumentAliases["param"] = "param"; - shortArgumentAliases["z"] = "kernel"; - shortArgumentAliases["rec"] = "recovery"; - shortArgumentAliases["efs"] = "efs"; - shortArgumentAliases["m"] = "modem"; - shortArgumentAliases["rdio"] = "radio"; - shortArgumentAliases["norm"] = "normal-boot"; - shortArgumentAliases["sys"] = "system"; - shortArgumentAliases["udata"] = "user-data"; - shortArgumentAliases["fota"] = "fota"; - shortArgumentAliases["hide"] = "hidden"; - shortArgumentAliases["nand"] = "movinand"; - shortArgumentAliases["data"] = "data"; - shortArgumentAliases["ums"] = "ums"; - shortArgumentAliases["emmc"] = "emmc"; -} + const StringArgument *pitArgument = static_cast(arguments.GetArgument("pit")); -static bool openFiles(Arguments& arguments, const map< string, vector >& argumentPartitionNamesMap, - map& argumentFileMap) -{ - for (map::const_iterator it = arguments.GetArguments().begin(); it != arguments.GetArguments().end(); it++) + if (pitArgument) { - bool isPartitionArgument = false; - const string& argumentName = it->first; + pitFile = fopen(pitArgument->GetValue().c_str(), "rb"); - if (arguments.GetArgumentTypes().find(argumentName) == arguments.GetArgumentTypes().end()) - { - // The only way an argument could exist without being in the argument types map is if it's a wild-card. - // The "%d" wild-card refers to a partition by identifier, where as the "%s" wild-card refers to a - // partition by name. - isPartitionArgument = true; - } - else + if (!pitFile) { - // The argument wasn't a wild-card, check if it's a known partition name. - if (argumentPartitionNamesMap.find(argumentName) != argumentPartitionNamesMap.end()) - isPartitionArgument = true; + Interface::PrintError("Failed to open file \"%s\"\n", pitArgument->GetValue().c_str()); + return (false); } + } + + // Open partition files - if (isPartitionArgument) + for (vector::const_iterator it = arguments.GetArguments().begin(); it != arguments.GetArguments().end(); it++) + { + bool isPartitionArgument = false; + const string& argumentName = (*it)->GetName(); + + // The only way an argument could exist without being in the argument types map is if it's a wild-card. + // The "%d" wild-card refers to a partition by identifier, where as the "%s" wild-card refers to a + // partition by name. + + if (arguments.GetArgumentTypes().find(argumentName) == arguments.GetArgumentTypes().end()) { - const StringArgument *stringArgument = static_cast(it->second); + const StringArgument *stringArgument = static_cast(*it); FILE *file = fopen(stringArgument->GetValue().c_str(), "rb"); if (!file) @@ -163,32 +116,47 @@ static bool openFiles(Arguments& arguments, const map< string, vector >& return (false); } - argumentFileMap[it->first] = file; + partitionFiles.push_back(PartitionFile(argumentName.c_str(), file)); } } return (true); } -static void closeFiles(map argumentfileMap) +static void closeFiles(vector& partitionFiles, FILE *& pitFile) { - for (map::iterator it = argumentfileMap.begin(); it != argumentfileMap.end(); it++) - fclose(it->second); + // Close PIT file - argumentfileMap.clear(); + if (pitFile) + { + fclose(pitFile); + pitFile = nullptr; + } + + // Close partition files + + for (vector::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++) + fclose(it->file); + + partitionFiles.clear(); } -static bool sendTotalTransferSize(BridgeManager *bridgeManager, const map& argumentFileMap, bool repartition) +static bool sendTotalTransferSize(BridgeManager *bridgeManager, const vector& partitionFiles, FILE *pitFile, bool repartition) { int totalBytes = 0; - for (map::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) + + for (vector::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++) { - if (repartition || it->first != "pit") - { - fseek(it->second, 0, SEEK_END); - totalBytes += ftell(it->second); - rewind(it->second); - } + fseek(it->file, 0, SEEK_END); + totalBytes += ftell(it->file); + rewind(it->file); + } + + if (repartition) + { + fseek(pitFile, 0, SEEK_END); + totalBytes += ftell(pitFile); + rewind(pitFile); } bool success; @@ -223,108 +191,67 @@ static bool sendTotalTransferSize(BridgeManager *bridgeManager, const map& argumentFileMap, const map< string, vector >& argumentPartitionNamesMap, - const PitData *pitData, vector& partitionFlashInfos) +static bool setupPartitionFlashInfo(const vector& partitionFiles, const PitData *pitData, vector& partitionFlashInfos) { - for (map::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) + for (vector::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++) { - const string& argumentName = it->first; - FILE *partitionFile = it->second; - const PitEntry *pitEntry = nullptr; // Was the argument a partition identifier? unsigned int partitionIdentifier; - if (Utility::ParseUnsignedInt(partitionIdentifier, argumentName.c_str()) == kNumberParsingStatusSuccess) + if (Utility::ParseUnsignedInt(partitionIdentifier, it->argumentName) == kNumberParsingStatusSuccess) { pitEntry = pitData->FindEntry(partitionIdentifier); if (!pitEntry) { - Interface::PrintError("No partition with identifier \"%s\" exists in the specified PIT.\n", argumentName.c_str()); + Interface::PrintError("No partition with identifier \"%s\" exists in the specified PIT.\n", it->argumentName); return (false); } } else { - // The argument wasn't a partition identifier. Was it a known human-readable partition name? - map< string, vector >::const_iterator argumentPartitionNamesIt = argumentPartitionNamesMap.find(argumentName); + // The argument must be an partition name e.g. "ZIMAGE" + pitEntry = pitData->FindEntry(it->argumentName); - if (argumentPartitionNamesIt != argumentPartitionNamesMap.end()) - { - const vector& partitionNames = argumentPartitionNamesIt->second; - - // Check for the partition in the PIT file using all known names. - for (vector::const_iterator nameIt = partitionNames.begin(); nameIt != partitionNames.end(); nameIt++) - { - pitEntry = pitData->FindEntry(nameIt->c_str()); - - if (pitEntry) - break; - } - - if (!pitEntry) - { - Interface::PrintError("Partition name for \"%s\" could not be located\n", argumentName.c_str()); - return (false); - } - } - else + if (!pitEntry) { - // The argument must be an actual partition name. e.g. "ZIMAGE", instead of human-readable "kernel". - pitEntry = pitData->FindEntry(argumentName.c_str()); - - if (!pitEntry) - { - Interface::PrintError("Partition \"%s\" does not exist in the specified PIT.\n", argumentName.c_str()); - return (false); - } + Interface::PrintError("Partition \"%s\" does not exist in the specified PIT.\n", it->argumentName); + return (false); } } - partitionFlashInfos.push_back(PartitionFlashInfo(pitEntry, partitionFile)); + partitionFlashInfos.push_back(PartitionFlashInfo(pitEntry, it->file)); } return (true); } -static bool isKnownPartition(const map >& argumentPartitionNamesMap, const string& argumentName, const string& partitionName) +static bool flashPitData(BridgeManager *bridgeManager, const PitData *pitData) { - const vector& partitionNames = argumentPartitionNamesMap.find(argumentName)->second; + Interface::Print("Uploading PIT\n"); - for (vector::const_iterator it = partitionNames.begin(); it != partitionNames.end(); it++) + if (bridgeManager->SendPitData(pitData)) { - if (partitionName == *it) - return (true); + Interface::Print("PIT upload successful\n\n"); + return (true); + } + else + { + Interface::PrintError("PIT upload failed!\n\n"); + return (false); } - - return (false); -} - -static bool isKnownBootPartition(const map >& argumentPartitionNamesMap, const char *partitionName) -{ - return (isKnownPartition(argumentPartitionNamesMap, "primary-boot", partitionName) - || isKnownPartition(argumentPartitionNamesMap, "secondary-boot", partitionName) - || isKnownPartition(argumentPartitionNamesMap, "secondary-boot-backup", partitionName) - || isKnownPartition(argumentPartitionNamesMap, "param", partitionName) - || isKnownPartition(argumentPartitionNamesMap, "normal-boot", partitionName) - || strcmp(partitionName, "SBL3") == 0 - || strcmp(partitionName, "ABOOT") == 0 - || strcmp(partitionName, "RPM") == 0 - || strcmp(partitionName, "TZ") == 0); } -static bool flashFile(BridgeManager *bridgeManager, const map< string, vector >& argumentPartitionNamesMap, - const PartitionFlashInfo& partitionFlashInfo) +static bool flashFile(BridgeManager *bridgeManager, const PartitionFlashInfo& partitionFlashInfo) { - // PIT files need to be handled differently, try determine if the partition we're flashing to is a PIT partition. - - if (isKnownPartition(argumentPartitionNamesMap, "pit", partitionFlashInfo.pitEntry->GetPartitionName())) - { + if (partitionFlashInfo.pitEntry->GetBinaryType() == PitEntry::kBinaryTypeCommunicationProcessor) // Modem + { Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName()); - if (bridgeManager->SendPitFile(partitionFlashInfo.file)) + if (bridgeManager->SendFile(partitionFlashInfo.file, EndModemFileTransferPacket::kDestinationModem, + partitionFlashInfo.pitEntry->GetDeviceType())) // <-- Odin method { Interface::Print("%s upload successful\n\n", partitionFlashInfo.pitEntry->GetPartitionName()); return (true); @@ -335,128 +262,71 @@ static bool flashFile(BridgeManager *bridgeManager, const map< string, vectorGetBinaryType() == PitEntry::kBinaryTypeApplicationProcessor { - if (partitionFlashInfo.pitEntry->GetBinaryType() == PitEntry::kBinaryTypeCommunicationProcessor) // Modem - { - Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName()); + Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName()); - if (bridgeManager->SendFile(partitionFlashInfo.file, EndModemFileTransferPacket::kDestinationModem, - partitionFlashInfo.pitEntry->GetDeviceType())) // <-- Odin method - { - Interface::Print("%s upload successful\n\n", partitionFlashInfo.pitEntry->GetPartitionName()); - return (true); - } - else - { - Interface::PrintError("%s upload failed!\n\n", partitionFlashInfo.pitEntry->GetPartitionName()); - return (false); - } + if (bridgeManager->SendFile(partitionFlashInfo.file, EndPhoneFileTransferPacket::kDestinationPhone, + partitionFlashInfo.pitEntry->GetDeviceType(), partitionFlashInfo.pitEntry->GetIdentifier())) + { + Interface::Print("%s upload successful\n\n", partitionFlashInfo.pitEntry->GetPartitionName()); + return (true); } - else // partitionFlashInfo.pitEntry->GetBinaryType() == PitEntry::kBinaryTypeApplicationProcessor + else { - Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName()); - - if (bridgeManager->SendFile(partitionFlashInfo.file, EndPhoneFileTransferPacket::kDestinationPhone, - partitionFlashInfo.pitEntry->GetDeviceType(), partitionFlashInfo.pitEntry->GetIdentifier())) - { - Interface::Print("%s upload successful\n\n", partitionFlashInfo.pitEntry->GetPartitionName()); - return (true); - } - else - { - Interface::PrintError("%s upload failed!\n\n", partitionFlashInfo.pitEntry->GetPartitionName()); - return (false); - } + Interface::PrintError("%s upload failed!\n\n", partitionFlashInfo.pitEntry->GetPartitionName()); + return (false); } } - - return (true); } -static bool flashPartitions(const map& argumentFileMap, const map< string, vector >& argumentPartitionNamesMap, - const PitData *pitData, BridgeManager *bridgeManager, bool repartition) +static bool flashPartitions(BridgeManager *bridgeManager, const vector& partitionFiles, const PitData *pitData, bool repartition) { vector partitionFlashInfos; // Map the files being flashed to partitions stored in the PIT file. - if (!setupPartitionFlashInfo(argumentFileMap, argumentPartitionNamesMap, pitData, partitionFlashInfos)) + if (!setupPartitionFlashInfo(partitionFiles, pitData, partitionFlashInfos)) return (false); - // If we're repartitioning then we need to flash the PIT file first. + // If we're repartitioning then we need to flash the PIT file first (if it is listed in the PIT file). if (repartition) { - vector::const_iterator it; - - for (it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++) - { - if (isKnownPartition(argumentPartitionNamesMap, "pit", it->pitEntry->GetPartitionName())) - { - if (!flashFile(bridgeManager, argumentPartitionNamesMap, *it)) - return (false); - - break; - } - } - - if (it == partitionFlashInfos.end()) - { - Interface::PrintError("Could not identify the PIT partition within the specified PIT file.\n\n"); + if (!flashPitData(bridgeManager, pitData)) return (false); - } } - // Flash partitions not involved in the boot process second. + // Flash partitions in the same order that arguments were specified in. for (vector::const_iterator it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++) { - if (!isKnownPartition(argumentPartitionNamesMap, "pit", it->pitEntry->GetPartitionName()) - && !isKnownBootPartition(argumentPartitionNamesMap, it->pitEntry->GetPartitionName())) - { - if (!flashFile(bridgeManager, argumentPartitionNamesMap, *it)) - return (false); - } - } - - // Flash boot partitions last. - for (vector::const_iterator it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++) - { - if (isKnownBootPartition(argumentPartitionNamesMap, it->pitEntry->GetPartitionName())) - { - if (!flashFile(bridgeManager, argumentPartitionNamesMap, *it)) - return (false); - } + if (!flashFile(bridgeManager, *it)) + return (false); } - return (true); } -static PitData *getPitData(const map& argumentFileMap, BridgeManager *bridgeManager, bool repartition) +static PitData *getPitData(BridgeManager *bridgeManager, FILE *pitFile, bool repartition) { PitData *pitData; PitData *localPitData = nullptr; // If a PIT file was passed as an argument then we must unpack it. - map::const_iterator localPitFileIt = argumentFileMap.find("pit"); - - if (localPitFileIt != argumentFileMap.end()) + if (pitFile) { - FILE *localPitFile = localPitFileIt->second; - // Load the local pit file into memory. - fseek(localPitFile, 0, SEEK_END); - long localPitFileSize = ftell(localPitFile); - rewind(localPitFile); + + fseek(pitFile, 0, SEEK_END); + long localPitFileSize = ftell(pitFile); + rewind(pitFile); unsigned char *pitFileBuffer = new unsigned char[localPitFileSize]; memset(pitFileBuffer, 0, localPitFileSize); - // dataRead is discarded, it's here to remove warnings. - int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile); + int dataRead = fread(pitFileBuffer, 1, localPitFileSize, pitFile); if (dataRead > 0) { - rewind(localPitFile); + rewind(pitFile); localPitData = new PitData(); localPitData->Unpack(pitFileBuffer); @@ -513,21 +383,19 @@ int FlashAction::Execute(int argc, char **argv) // Setup argument types map argumentTypes; + map shortArgumentAliases; argumentTypes["repartition"] = kArgumentTypeFlag; argumentTypes["no-reboot"] = kArgumentTypeFlag; + argumentTypes["resume"] = kArgumentTypeFlag; argumentTypes["delay"] = kArgumentTypeUnsignedInteger; argumentTypes["verbose"] = kArgumentTypeFlag; argumentTypes["stdout-errors"] = kArgumentTypeFlag; + argumentTypes["usb-log-level"] = kArgumentTypeString; - map< string, vector > argumentPartitionNamesMap; - map shortArgumentAliases; - - buildArgumentPartitionNamesMap(argumentPartitionNamesMap, shortArgumentAliases); - - for (map< string, vector >::const_iterator it = argumentPartitionNamesMap.begin(); it != argumentPartitionNamesMap.end(); it++) - argumentTypes[it->first] = kArgumentTypeString; + argumentTypes["pit"] = kArgumentTypeString; + shortArgumentAliases["pit"] = "pit"; // Add wild-cards "%d" and "%s", for partition identifiers and partition names respectively. argumentTypes["%d"] = kArgumentTypeString; @@ -552,11 +420,48 @@ int FlashAction::Execute(int argc, char **argv) const UnsignedIntegerArgument *communicationDelayArgument = static_cast(arguments.GetArgument("delay")); bool reboot = arguments.GetArgument("no-reboot") == nullptr; + bool resume = arguments.GetArgument("resume") != nullptr; bool verbose = arguments.GetArgument("verbose") != nullptr; if (arguments.GetArgument("stdout-errors") != nullptr) Interface::SetStdoutErrors(true); + const StringArgument *usbLogLevelArgument = static_cast(arguments.GetArgument("usb-log-level")); + + BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default; + + if (usbLogLevelArgument) + { + const string& usbLogLevelString = usbLogLevelArgument->GetValue(); + + if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::None; + } + else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Error; + } + else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Warning; + } + else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Info; + } + else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Debug; + } + else + { + Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str()); + Interface::Print(FlashAction::usage); + return (0); + } + } + const StringArgument *pitArgument = static_cast(arguments.GetArgument("pit")); bool repartition = arguments.GetArgument("repartition") != nullptr; @@ -569,16 +474,17 @@ int FlashAction::Execute(int argc, char **argv) } // Open files + + FILE *pitFile = nullptr; + vector partitionFiles; - map argumentFileMap; - - if (!openFiles(arguments, argumentPartitionNamesMap, argumentFileMap)) + if (!openFiles(arguments, partitionFiles, pitFile)) { - closeFiles(argumentFileMap); + closeFiles(partitionFiles, pitFile); return (1); } - if (argumentFileMap.size() == 0) + if (partitionFiles.size() == 0) { Interface::Print(FlashAction::usage); return (0); @@ -597,35 +503,36 @@ int FlashAction::Execute(int argc, char **argv) communicationDelay = communicationDelayArgument->GetValue(); BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + bridgeManager->SetUsbLogLevel(usbLogLevel); - if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) { - closeFiles(argumentFileMap); + closeFiles(partitionFiles, pitFile); delete bridgeManager; return (1); } - bool success = sendTotalTransferSize(bridgeManager, argumentFileMap, repartition); + bool success = sendTotalTransferSize(bridgeManager, partitionFiles, pitFile, repartition); if (success) { - PitData *pitData = getPitData(argumentFileMap, bridgeManager, repartition); + PitData *pitData = getPitData(bridgeManager, pitFile, repartition); if (pitData) - success = flashPartitions(argumentFileMap, argumentPartitionNamesMap, pitData, bridgeManager, repartition); + success = flashPartitions(bridgeManager, partitionFiles, pitData, repartition); else success = false; delete pitData; } - - closeFiles(argumentFileMap); if (!bridgeManager->EndSession(reboot)) success = false; delete bridgeManager; + + closeFiles(partitionFiles, pitFile); return (success ? 0 : 1); } diff --git a/heimdall/source/Interface.cpp b/heimdall/source/Interface.cpp index ec66480..0d9d7d9 100644 --- a/heimdall/source/Interface.cpp +++ b/heimdall/source/Interface.cpp @@ -27,7 +27,6 @@ #include "ClosePcScreenAction.h" #include "DetectAction.h" #include "DownloadPitAction.h" -#include "DumpAction.h" #include "FlashAction.h" #include "HelpAction.h" #include "InfoAction.h" @@ -43,7 +42,7 @@ using namespace Heimdall; map actionMap; bool stdoutErrors = false; -const char *version = "v1.4 RC2"; +const char *version = "v1.4 RC3"; const char *actionUsage = "Usage: heimdall \n"; const char *releaseInfo = "Heimdall %s\n\n\ @@ -64,7 +63,6 @@ void populateActionMap(void) actionMap["close-pc-screen"] = Interface::ActionInfo(&ClosePcScreenAction::Execute, ClosePcScreenAction::usage); actionMap["detect"] = Interface::ActionInfo(&DetectAction::Execute, DetectAction::usage); actionMap["download-pit"] = Interface::ActionInfo(&DownloadPitAction::Execute, DownloadPitAction::usage); - actionMap["dump"] = Interface::ActionInfo(&DumpAction::Execute, DumpAction::usage); actionMap["flash"] = Interface::ActionInfo(&FlashAction::Execute, FlashAction::usage); actionMap["help"] = Interface::ActionInfo(&HelpAction::Execute, HelpAction::usage); actionMap["info"] = Interface::ActionInfo(&InfoAction::Execute, InfoAction::usage); diff --git a/heimdall/source/Interface.h b/heimdall/source/Interface.h index ab4b538..441932a 100644 --- a/heimdall/source/Interface.h +++ b/heimdall/source/Interface.h @@ -31,9 +31,6 @@ // Heimdall #include "Heimdall.h" -using namespace std; -using namespace libpit; - namespace Heimdall { namespace Interface @@ -59,7 +56,7 @@ namespace Heimdall } ActionInfo; - const map& GetActionMap(void); + const std::map& GetActionMap(void); void Print(const char *format, ...); void PrintWarning(const char *format, ...); @@ -74,7 +71,7 @@ namespace Heimdall void PrintDeviceDetectionFailed(void); - void PrintPit(const PitData *pitData); + void PrintPit(const libpit::PitData *pitData); void SetStdoutErrors(bool enabled); }; diff --git a/heimdall/source/PrintPitAction.cpp b/heimdall/source/PrintPitAction.cpp index c520d1c..cdf5b4e 100644 --- a/heimdall/source/PrintPitAction.cpp +++ b/heimdall/source/PrintPitAction.cpp @@ -28,11 +28,13 @@ #include "Interface.h" #include "PrintPitAction.h" +using namespace std; +using namespace libpit; using namespace Heimdall; const char *PrintPitAction::usage = "Action: print-pit\n\ Arguments: [--file ] [--verbose] [--no-reboot] [--stdout-errors]\n\ - [--delay ]\n\ + [--delay ] [--usb-log-level ]\n\ Description: Prints the contents of a PIT file in a human readable format. If\n\ a filename is not provided then Heimdall retrieves the PIT file from the \n\ connected device.\n"; @@ -44,9 +46,11 @@ int PrintPitAction::Execute(int argc, char **argv) map argumentTypes; argumentTypes["file"] = kArgumentTypeString; argumentTypes["no-reboot"] = kArgumentTypeFlag; + argumentTypes["resume"] = kArgumentTypeFlag; argumentTypes["delay"] = kArgumentTypeUnsignedInteger; argumentTypes["verbose"] = kArgumentTypeFlag; argumentTypes["stdout-errors"] = kArgumentTypeFlag; + argumentTypes["usb-log-level"] = kArgumentTypeString; Arguments arguments(argumentTypes); @@ -60,11 +64,48 @@ int PrintPitAction::Execute(int argc, char **argv) const UnsignedIntegerArgument *communicationDelayArgument = static_cast(arguments.GetArgument("delay")); bool reboot = arguments.GetArgument("no-reboot") == nullptr; + bool resume = arguments.GetArgument("resume") != nullptr; bool verbose = arguments.GetArgument("verbose") != nullptr; if (arguments.GetArgument("stdout-errors") != nullptr) Interface::SetStdoutErrors(true); + const StringArgument *usbLogLevelArgument = static_cast(arguments.GetArgument("usb-log-level")); + + BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default; + + if (usbLogLevelArgument) + { + const string& usbLogLevelString = usbLogLevelArgument->GetValue(); + + if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::None; + } + else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Error; + } + else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Warning; + } + else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Info; + } + else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0) + { + usbLogLevel = BridgeManager::UsbLogLevel::Debug; + } + else + { + Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str()); + Interface::Print(PrintPitAction::usage); + return (0); + } + } + // Open file (if specified). FILE *localPitFile = nullptr; @@ -120,8 +161,9 @@ int PrintPitAction::Execute(int argc, char **argv) communicationDelay = communicationDelayArgument->GetValue(); BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + bridgeManager->SetUsbLogLevel(usbLogLevel); - if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) { delete bridgeManager; return (1); diff --git a/heimdall/source/SendFilePartPacket.h b/heimdall/source/SendFilePartPacket.h index 066aacb..092694a 100644 --- a/heimdall/source/SendFilePartPacket.h +++ b/heimdall/source/SendFilePartPacket.h @@ -51,6 +51,11 @@ namespace Heimdall int bytesRead = fread(data, 1, bytesToRead, file); } + SendFilePartPacket(unsigned char *buffer, int size) : OutboundPacket(size) + { + memcpy(data, buffer, size); + } + void Pack(void) { } -- cgit v1.2.3