diff options
author | Benjamin Dobell <benjamin.dobell+git@glassechidna.com.au> | 2012-10-01 04:43:05 +0200 |
---|---|---|
committer | Benjamin Dobell <benjamin.dobell+git@glassechidna.com.au> | 2012-10-01 17:41:25 +0200 |
commit | 6cd6b35c737e0e4042a8fd79af1decc9f10ed84b (patch) | |
tree | 89625119662474ef30c84f410c056343d412121b /heimdall/source | |
parent | Updated version to 1.3.2 and copyright notices to 2012. (diff) | |
download | Heimdall-6cd6b35c737e0e4042a8fd79af1decc9f10ed84b.tar Heimdall-6cd6b35c737e0e4042a8fd79af1decc9f10ed84b.tar.gz Heimdall-6cd6b35c737e0e4042a8fd79af1decc9f10ed84b.tar.bz2 Heimdall-6cd6b35c737e0e4042a8fd79af1decc9f10ed84b.tar.lz Heimdall-6cd6b35c737e0e4042a8fd79af1decc9f10ed84b.tar.xz Heimdall-6cd6b35c737e0e4042a8fd79af1decc9f10ed84b.tar.zst Heimdall-6cd6b35c737e0e4042a8fd79af1decc9f10ed84b.zip |
Diffstat (limited to 'heimdall/source')
39 files changed, 3193 insertions, 1711 deletions
diff --git a/heimdall/source/Arguments.cpp b/heimdall/source/Arguments.cpp new file mode 100644 index 0000000..321c12f --- /dev/null +++ b/heimdall/source/Arguments.cpp @@ -0,0 +1,212 @@ +/* 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.*/ + +// Heimdall +#include "Arguments.h" +#include "Heimdall.h" +#include "Interface.h" +#include "Utility.h" + +using namespace Heimdall; + +FlagArgument *FlagArgument::ParseArgument(int argc, char **argv, int& argi) +{ + return new FlagArgument(); +} + + + +StringArgument *StringArgument::ParseArgument(int argc, char **argv, int& argi) +{ + if (++argi < argc) + { + return (new StringArgument(argv[argi])); + } + else + { + Interface::Print("Missing parameter for argument: %s\n\n", argv[argi - 1]); + return (nullptr); + } +} + + + +UnsignedIntegerArgument *UnsignedIntegerArgument::ParseArgument(int argc, char **argv, int& argi) +{ + UnsignedIntegerArgument *unsignedIntegerArgument = nullptr; + + if (++argi < argc) + { + unsigned int value; + + if (Utility::ParseUnsignedInt(value, argv[argi]) == kNumberParsingStatusSuccess) + unsignedIntegerArgument = new UnsignedIntegerArgument(value); + else + Interface::Print("%s must be a positive integer.", argv[argi - 1]); + } + else + { + Interface::Print("Missing parameter for argument: %s\n\n", argv[argi - 1]); + } + + return (unsignedIntegerArgument); +} + + + +Arguments::Arguments(const map<string, ArgumentType>& argumentTypes, const map<string, string>& shortArgumentAliases, + const map<string, string> argumentAliases) : + argumentTypes(argumentTypes), + shortArgumentAliases(shortArgumentAliases), + argumentAliases(argumentAliases) +{ +} + +Arguments::~Arguments() +{ + for (map<string, Argument *>::const_iterator it = arguments.begin(); it != arguments.end(); it++) + delete it->second; +} + +bool Arguments::ParseArguments(int argc, char **argv, int argi) +{ + for (; argi < argc; ++argi) + { + string argumentName = argv[argi]; + string nonwildcardArgumentName; + + if (argumentName.find_first_of("--") == 0) + { + // Regular argument + argumentName = argumentName.substr(2); + nonwildcardArgumentName = argumentName; + } + else if (argumentName.find_first_of("-") == 0) + { + // Short argument alias + string shortArgumentAlias = argumentName.substr(1); + map<string, string>::const_iterator shortAliasIt = shortArgumentAliases.find(shortArgumentAlias); + + if (shortAliasIt != shortArgumentAliases.end()) + { + argumentName = shortAliasIt->second; + nonwildcardArgumentName = argumentName; + } + else + { + Interface::Print("Unknown argument: %s\n\n", argv[argi]); + return (false); + } + } + else + { + Interface::Print("Invalid argument: %s\n\n", argv[argi]); + return (false); + } + + map<string, ArgumentType>::const_iterator argumentTypeIt = argumentTypes.find(argumentName); + + if (argumentTypeIt == argumentTypes.end()) + { + // No argument with that name, maybe it's an alias... + map<string, string>::const_iterator aliasIt = argumentAliases.find(argumentName); + + if (aliasIt != argumentAliases.end()) + { + argumentName = aliasIt->second; + nonwildcardArgumentName = argumentName; + + argumentTypeIt = argumentTypes.find(argumentName); + } + } + + // Handle wilcards + + unsigned int unsignedIntName; + + if (argumentTypeIt == argumentTypes.end()) + { + // Look for the unsigned integer wildcard "%d". + if (Utility::ParseUnsignedInt(unsignedIntName, argumentName.c_str()) == kNumberParsingStatusSuccess) + { + argumentTypeIt = argumentTypes.find("%d"); + argumentName = "%d"; + } + + // Look for the string wildcard "%s" + if (argumentTypeIt == argumentTypes.end()) + { + argumentTypeIt = argumentTypes.find("%s"); + argumentName = "%s"; + } + } + + Argument *argument = nullptr; + + if (argumentTypeIt != argumentTypes.end()) + { + switch (argumentTypeIt->second) + { + case kArgumentTypeFlag: + argument = FlagArgument::ParseArgument(argc, argv, argi); + break; + + case kArgumentTypeString: + argument = StringArgument::ParseArgument(argc, argv, argi); + break; + + case kArgumentTypeUnsignedInteger: + argument = UnsignedIntegerArgument::ParseArgument(argc, argv, argi); + break; + + default: + Interface::Print("Unknown argument type: %s\n\n", argv[argi]); + break; + } + } + else + { + 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<map<string, Argument *>::iterator, bool> insertResult = arguments.insert(pair<string, Argument *>(argumentName, argument)); + + if (!insertResult.second) + { + Interface::Print("Duplicate argument: %s (%s)\n\n", argv[argi], insertResult.first->first.c_str()); + delete argument; + + return (false); + } + } + else + { + return (false); + } + } + + return (true); +} diff --git a/heimdall/source/Arguments.h b/heimdall/source/Arguments.h new file mode 100644 index 0000000..7294e70 --- /dev/null +++ b/heimdall/source/Arguments.h @@ -0,0 +1,160 @@ +/* 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 ARGUMENTS_H +#define ARGUMENTS_H + +// C/C++ Standard Library +#include <map> +#include <string> + +// Heimdall +#include "Heimdall.h" + +using namespace std; + +namespace Heimdall +{ + typedef enum + { + kArgumentTypeFlag = 0, + kArgumentTypeString, + kArgumentTypeUnsignedInteger + + } ArgumentType; + + class Argument + { + private: + + ArgumentType argumentType; + + protected: + + Argument(ArgumentType argumentType) + { + this->argumentType = argumentType; + } + + public: + + virtual ~Argument() + { + } + + ArgumentType GetArgumentType(void) const + { + return argumentType; + } + }; + + class FlagArgument : public Argument + { + private: + + FlagArgument() : Argument(kArgumentTypeFlag) + { + } + + public: + + static FlagArgument *ParseArgument(int argc, char **argv, int& argi); + }; + + class StringArgument : public Argument + { + private: + + string value; + + StringArgument(const string& value) : Argument(kArgumentTypeString) + { + this->value = value; + } + + public: + + static StringArgument *ParseArgument(int argc, char **argv, int& argi); + + const string& GetValue(void) const + { + return (value); + } + }; + + class UnsignedIntegerArgument : public Argument + { + private: + + unsigned int value; + + UnsignedIntegerArgument(unsigned int value) : Argument(kArgumentTypeUnsignedInteger) + { + this->value = value; + } + + public: + + static UnsignedIntegerArgument *ParseArgument(int argc, char **argv, int& argi); + + unsigned int GetValue(void) const + { + return (value); + } + }; + + class Arguments + { + private: + + const map<string, ArgumentType> argumentTypes; + const map<string, string> shortArgumentAliases; + const map<string, string> argumentAliases; + + map<string, Argument *> arguments; + + public: + + Arguments(const map<string, ArgumentType>& argumentTypes, const map<string, string>& shortArgumentAliases = map<string, string>(), + const map<string, string> argumentAliases = map<string, string>()); + ~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 + { + map<string, Argument *>::const_iterator it = arguments.find(argumentName); + return (it != arguments.end() ? it->second : nullptr); + } + + const map<string, ArgumentType>& GetArgumentTypes(void) const + { + return (argumentTypes); + } + + const map<string, Argument *>& GetArguments(void) const + { + return (arguments); + } + }; +} + +#endif diff --git a/heimdall/source/BeginSessionPacket.h b/heimdall/source/BeginSessionPacket.h new file mode 100644 index 0000000..d0f9c05 --- /dev/null +++ b/heimdall/source/BeginSessionPacket.h @@ -0,0 +1,39 @@ +/* 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 BEGINSESSIONPACKET_H +#define BEGINSESSIONPACKET_H + +// Heimdall +#include "SessionSetupPacket.h" + +namespace Heimdall +{ + class BeginSessionPacket : public SessionSetupPacket + { + public: + + BeginSessionPacket() : SessionSetupPacket(SessionSetupPacket::kBeginSession) + { + } + }; +} + +#endif diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp index 0019021..fa83b1c 100644 --- a/heimdall/source/BridgeManager.cpp +++ b/heimdall/source/BridgeManager.cpp @@ -26,9 +26,9 @@ // Heimdall #include "BeginDumpPacket.h" +#include "BeginSessionPacket.h" #include "BridgeManager.h" -#include "SetupSessionPacket.h" -#include "SetupSessionResponse.h" +#include "DeviceTypePacket.h" #include "DumpPartFileTransferPacket.h" #include "DumpPartPitFilePacket.h" #include "DumpResponse.h" @@ -36,6 +36,7 @@ #include "EndPhoneFileTransferPacket.h" #include "EndPitFileTransferPacket.h" #include "EndSessionPacket.h" +#include "FilePartSizePacket.h" #include "FileTransferPacket.h" #include "FlashPartFileTransferPacket.h" #include "FlashPartPitFilePacket.h" @@ -48,11 +49,13 @@ #include "ResponsePacket.h" #include "SendFilePartPacket.h" #include "SendFilePartResponse.h" +#include "SessionSetupPacket.h" +#include "SessionSetupResponse.h" // Future versions of libusb will use usb_interface instead of interface. #define usb_interface interface -#define CLASS_CDC 0x0A +#define USB_CLASS_CDC_DATA 0x0A using namespace Heimdall; @@ -64,259 +67,26 @@ const DeviceIdentifier BridgeManager::supportedDevices[BridgeManager::kSupported enum { - kMaxSequenceLength = 800 + kDumpBufferSize = 4096 }; -bool BridgeManager::CheckProtocol(void) const -{ - Interface::Print("Checking if protocol is initialised...\n"); - - SetupSessionPacket deviceInfoPacket(SetupSessionPacket::kDeviceInfo); - - if (!SendPacket(&deviceInfoPacket, 100, false)) - { - Interface::Print("Protocol is not initialised.\n"); - return (false); - } - - SetupSessionResponse deviceInfoResponse; - - if (!ReceivePacket(&deviceInfoResponse, 100, false)) - { - Interface::Print("Protocol is not initialised.\n"); - return (false); - } - - Interface::Print("Protocol is initialised.\n"); - return (true); -} - -bool BridgeManager::InitialiseProtocol(void) const -{ - Interface::Print("Initialising protocol...\n"); - - unsigned char *dataBuffer = new unsigned char[7]; - - int result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000); - - if (result < 0) - { - Interface::PrintError("Failed to initialise protocol!\n"); - - delete [] dataBuffer; - return (false); - } - - memset(dataBuffer, 0, 7); - dataBuffer[1] = 0xC2; - dataBuffer[2] = 0x01; - dataBuffer[6] = 0x07; - - result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000); - if (result < 0) - { - Interface::PrintError("Failed to initialise protocol!\n"); - - delete [] dataBuffer; - return (false); - } - - result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000); - if (result < 0) - { - Interface::PrintError("Failed to initialise protocol!\n"); - - delete [] dataBuffer; - return (false); - } - - result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000); - if (result < 0) - { - Interface::PrintError("Failed to initialise protocol!\n"); - - delete [] dataBuffer; - return (false); - } - - memset(dataBuffer, 0, 7); - dataBuffer[1] = 0xC2; - dataBuffer[2] = 0x01; - dataBuffer[6] = 0x08; - - result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000); - if (result < 0) - { - Interface::PrintError("Failed to initialise protocol!\n"); - - delete [] dataBuffer; - return (false); - } - - result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000); - if (result < 0) - { - Interface::PrintError("Failed to initialise protocol!\n"); - - delete [] dataBuffer; - return (false); - } - - Interface::Print("Handshaking with Loke...\n"); - - int dataTransferred; - - // Send "ODIN" - strcpy((char *)dataBuffer, "ODIN"); - - result = libusb_bulk_transfer(deviceHandle, outEndpoint, dataBuffer, 4, &dataTransferred, 1000); - if (result < 0) - { - if (verbose) - Interface::PrintError("Failed to send data: \"%s\"\n", dataBuffer); - else - Interface::PrintError("Failed to send data!"); - - delete [] dataBuffer; - return (false); - } - - if (dataTransferred != 4) - { - if (verbose) - Interface::PrintError("Failed to complete sending of data: \"%s\"\n", dataBuffer); - else - Interface::PrintError("Failed to complete sending of data!"); - - delete [] dataBuffer; - return (false); - } - - // Expect "LOKE" - memset(dataBuffer, 0, 7); - - result = libusb_bulk_transfer(deviceHandle, inEndpoint, dataBuffer, 7, &dataTransferred, 1000); - if (result < 0) - { - Interface::PrintError("Failed to receive response!\n"); - - delete [] dataBuffer; - return (false);; - } - - if (dataTransferred != 4 || memcmp(dataBuffer, "LOKE", 4) != 0) - { - Interface::PrintError("Unexpected communication!\n"); - - if (verbose) - Interface::PrintError("Expected: \"%s\"\nReceived: \"%s\"\n", "LOKE", dataBuffer); - - Interface::PrintError("Handshake failed!\n"); - - delete [] dataBuffer; - return (false); - } - - return (true); -} - -BridgeManager::BridgeManager(bool verbose, int communicationDelay) -{ - this->verbose = verbose; - this->communicationDelay = communicationDelay; - - libusbContext = nullptr; - deviceHandle = nullptr; - heimdallDevice = nullptr; - inEndpoint = -1; - outEndpoint = -1; - interfaceIndex = -1; - -#ifdef OS_LINUX - - detachedDriver = false; - -#endif -} - -BridgeManager::~BridgeManager() +enum { - if (interfaceIndex >= 0) - libusb_release_interface(deviceHandle, interfaceIndex); - -#ifdef OS_LINUX - - if (detachedDriver) - { - Interface::Print("Re-attaching kernel driver...\n"); - libusb_attach_kernel_driver(deviceHandle, interfaceIndex); - } - -#endif - - if (deviceHandle) - libusb_close(deviceHandle); - - if (heimdallDevice) - libusb_unref_device(heimdallDevice); - - if (libusbContext) - libusb_exit(libusbContext); -} + kFileTransferSequenceMaxLengthDefault = 800, + kFileTransferPacketSizeDefault = 131072, + kFileTransferSequenceTimeoutDefault = 30000 // 30 seconds +}; -bool BridgeManager::DetectDevice(void) +enum { - // Initialise libusb-1.0 - int result = libusb_init(&libusbContext); - if (result != LIBUSB_SUCCESS) - { - Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result); - return (false); - } - - // Get handle to Galaxy S device - struct libusb_device **devices; - int deviceCount = libusb_get_device_list(libusbContext, &devices); - - for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) - { - libusb_device_descriptor descriptor; - libusb_get_device_descriptor(devices[deviceIndex], &descriptor); - - for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++) - { - if (descriptor.idVendor == supportedDevices[i].vendorId && descriptor.idProduct == supportedDevices[i].productId) - { - libusb_free_device_list(devices, deviceCount); - - Interface::Print("Device detected\n"); - return (true); - } - } - } - - libusb_free_device_list(devices, deviceCount); - - Interface::PrintDeviceDetectionFailed(); - return (false); -} + kHandshakeMaxAttempts = 5, + kReceivePacketMaxAttempts = 5 +}; -int BridgeManager::Initialise(void) +int BridgeManager::FindDeviceInterface(void) { - Interface::Print("Initialising connection...\n"); - - // Initialise libusb-1.0 - int result = libusb_init(&libusbContext); - if (result != LIBUSB_SUCCESS) - { - Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result); - Interface::Print("Failed to connect to device!"); - return (BridgeManager::kInitialiseFailed); - } - Interface::Print("Detecting device...\n"); - // Get handle to Galaxy S device struct libusb_device **devices; int deviceCount = libusb_get_device_list(libusbContext, &devices); @@ -347,7 +117,7 @@ int BridgeManager::Initialise(void) return (BridgeManager::kInitialiseDeviceNotDetected); } - result = libusb_open(heimdallDevice, &deviceHandle); + int result = libusb_open(heimdallDevice, &deviceHandle); if (result != LIBUSB_SUCCESS) { Interface::PrintError("Failed to access device. libusb error: %d\n", result); @@ -403,8 +173,8 @@ int BridgeManager::Initialise(void) return (BridgeManager::kInitialiseFailed); } - int interfaceIndex = -1; - int altSettingIndex; + interfaceIndex = -1; + altSettingIndex = -1; for (int i = 0; i < configDescriptor->bNumInterfaces; i++) { @@ -440,9 +210,11 @@ int BridgeManager::Initialise(void) outEndpointAddress = endpoint->bEndpointAddress; } - if (interfaceIndex < 0 && configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints == 2 - && configDescriptor->usb_interface[i].altsetting[j].bInterfaceClass == CLASS_CDC - && inEndpointAddress != -1 && outEndpointAddress != -1) + if (interfaceIndex < 0 + && configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints == 2 + && configDescriptor->usb_interface[i].altsetting[j].bInterfaceClass == USB_CLASS_CDC_DATA + && inEndpointAddress != -1 + && outEndpointAddress != -1) { interfaceIndex = i; altSettingIndex = j; @@ -459,9 +231,15 @@ int BridgeManager::Initialise(void) Interface::PrintError("Failed to find correct interface configuration\n"); return (BridgeManager::kInitialiseFailed); } - + + return (BridgeManager::kInitialiseSucceeded); +} + +bool BridgeManager::ClaimDeviceInterface(void) +{ Interface::Print("Claiming interface...\n"); - result = libusb_claim_interface(deviceHandle, interfaceIndex); + + int result = libusb_claim_interface(deviceHandle, interfaceIndex); #ifdef OS_LINUX @@ -479,19 +257,314 @@ int BridgeManager::Initialise(void) if (result != LIBUSB_SUCCESS) { Interface::PrintError("Claiming interface failed!\n"); - return (BridgeManager::kInitialiseFailed); + return (false); } + interfaceClaimed = true; + + return (true); +} + +bool BridgeManager::SetupDeviceInterface(void) +{ Interface::Print("Setting up interface...\n"); - result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex); + + int result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex); if (result != LIBUSB_SUCCESS) { Interface::PrintError("Setting up interface failed!\n"); - return (BridgeManager::kInitialiseFailed); + return (false); + } + + Interface::Print("\n"); + return (true); +} + +void BridgeManager::ReleaseDeviceInterface(void) +{ + Interface::Print("Releasing device interface...\n"); + + libusb_release_interface(deviceHandle, interfaceIndex); + +#ifdef OS_LINUX + + if (detachedDriver) + { + Interface::Print("Re-attaching kernel driver...\n"); + libusb_attach_kernel_driver(deviceHandle, interfaceIndex); } +#endif + + interfaceClaimed = false; 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 +{ + Interface::Print("Initialising protocol...\n"); + + unsigned char dataBuffer[7]; + + int result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000); + + if (result < 0 && verbose) + Interface::PrintWarning("Control transfer #1 failed. Result: %d\n", result); + + memset(dataBuffer, 0, 7); + dataBuffer[1] = 0xC2; + dataBuffer[2] = 0x01; + dataBuffer[6] = 0x07; + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000); + + if (result < 0 && verbose) + Interface::PrintWarning("Control transfer #2 failed. Result: %d\n", result); + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000); + + if (result < 0 && verbose) + Interface::PrintWarning("Control transfer #3 failed. Result: %d\n", result); + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000); + + if (result < 0 && verbose) + Interface::PrintWarning("Control transfer #4 failed. Result: %d\n", result); + + memset(dataBuffer, 0, 7); + dataBuffer[1] = 0xC2; + dataBuffer[2] = 0x01; + dataBuffer[6] = 0x08; + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000); + + if (result < 0 && verbose) + Interface::PrintWarning("Control transfer #5 failed. Result: %d\n", result); + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000); + + if (result < 0 && verbose) + Interface::PrintWarning("Control transfer #6 failed. Result: %d\n", result); + + unsigned int attempt = 0; + + // max(250, communicationDelay) + int retryDelay = (communicationDelay > 250) ? communicationDelay : 250; + + for (; attempt < kHandshakeMaxAttempts; attempt++) + { + if (attempt > 0) + { + if (verbose) + Interface::PrintErrorSameLine(" Retrying...\n"); + + // Wait longer each retry + Sleep(retryDelay * (attempt + 1)); + } + + int dataTransferred = 0; + + // Send "ODIN" + memcpy(dataBuffer, "ODIN", 4); + memset(dataBuffer + 4, 0, 1); + + result = libusb_bulk_transfer(deviceHandle, outEndpoint, dataBuffer, 4, &dataTransferred, 1000); + if (result < 0) + { + if (verbose) + Interface::PrintError("Failed to send data: \"%s\"\n", dataBuffer); + else + Interface::PrintError("Failed to send data!"); + + return (false); + } + + if (dataTransferred != 4) + { + if (verbose) + Interface::PrintError("Failed to complete sending of data: \"%s\"\n", dataBuffer); + else + Interface::PrintError("Failed to complete sending of data!"); + + return (false); + } + + // Expect "LOKE" + memset(dataBuffer, 0, 7); + + int retry = 0; + dataTransferred = 0; + + result = libusb_bulk_transfer(deviceHandle, inEndpoint, dataBuffer, 7, &dataTransferred, 1000); + + if (result < 0) + { + if (verbose) + Interface::PrintError("Failed to receive handshake response."); + } + else + { + if (dataTransferred == 4 && memcmp(dataBuffer, "LOKE", 4) == 0) + { + // Successfully received "LOKE" + break; + } + else + { + if (verbose) + Interface::PrintError("Expected: \"%s\"\nReceived: \"%s\"\n", "LOKE", dataBuffer); + + Interface::PrintError("Unexpected handshake response!"); + } + } + } + + if (attempt == kHandshakeMaxAttempts) + { + if (verbose) + Interface::PrintErrorSameLine("\n"); + + Interface::PrintError("Protocol initialisation failed!\n\n"); + return (false); + } + else + { + Interface::Print("Protocol initialisation successful.\n\n"); + return (true); + } +} + +BridgeManager::BridgeManager(bool verbose, int communicationDelay) +{ + this->verbose = verbose; + this->communicationDelay = communicationDelay; + + libusbContext = nullptr; + deviceHandle = nullptr; + heimdallDevice = nullptr; + + inEndpoint = -1; + outEndpoint = -1; + interfaceIndex = -1; + altSettingIndex = -1; + + interfaceClaimed = false; + +#ifdef OS_LINUX + + detachedDriver = false; + +#endif + + fileTransferSequenceMaxLength = kFileTransferSequenceMaxLengthDefault; + fileTransferPacketSize = kFileTransferPacketSizeDefault; + fileTransferSequenceTimeout = kFileTransferSequenceTimeoutDefault; +} + +BridgeManager::~BridgeManager() +{ + if (interfaceClaimed) + ReleaseDeviceInterface(); + + if (deviceHandle) + libusb_close(deviceHandle); + + if (heimdallDevice) + libusb_unref_device(heimdallDevice); + + if (libusbContext) + libusb_exit(libusbContext); +} + +bool BridgeManager::DetectDevice(void) +{ + // Initialise libusb-1.0 + int result = libusb_init(&libusbContext); + if (result != LIBUSB_SUCCESS) + { + Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result); + return (false); + } + + // Get handle to Galaxy S device + struct libusb_device **devices; + int deviceCount = libusb_get_device_list(libusbContext, &devices); + + for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) + { + libusb_device_descriptor descriptor; + libusb_get_device_descriptor(devices[deviceIndex], &descriptor); + + for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++) + { + if (descriptor.idVendor == supportedDevices[i].vendorId && descriptor.idProduct == supportedDevices[i].productId) + { + libusb_free_device_list(devices, deviceCount); + + Interface::Print("Device detected\n"); + return (true); + } + } + } + + libusb_free_device_list(devices, deviceCount); + + Interface::PrintDeviceDetectionFailed(); + return (false); +} + +int BridgeManager::Initialise() +{ + Interface::Print("Initialising connection...\n"); + + // Initialise libusb-1.0 + int result = libusb_init(&libusbContext); + + if (result != LIBUSB_SUCCESS) + { + Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result); + Interface::Print("Failed to connect to device!"); + return (BridgeManager::kInitialiseFailed); + } + + result = FindDeviceInterface(); + + if (result != BridgeManager::kInitialiseSucceeded) + return (result); + + if (!ClaimDeviceInterface()) + return (BridgeManager::kInitialiseFailed); + + if (!SetupDeviceInterface()) + return (BridgeManager::kInitialiseFailed); if (!CheckProtocol()) { @@ -499,16 +572,14 @@ int BridgeManager::Initialise(void) return (BridgeManager::kInitialiseFailed); } - Interface::Print("\n"); - return (BridgeManager::kInitialiseSucceeded); } -bool BridgeManager::BeginSession(void) const +bool BridgeManager::BeginSession(void) { Interface::Print("Beginning session...\n"); - SetupSessionPacket beginSessionPacket(SetupSessionPacket::kBeginSession); + BeginSessionPacket beginSessionPacket; if (!SendPacket(&beginSessionPacket)) { @@ -516,22 +587,18 @@ bool BridgeManager::BeginSession(void) const return (false); } - SetupSessionResponse setupSessionResponse; - if (!ReceivePacket(&setupSessionResponse)) + SessionSetupResponse beginSessionResponse; + if (!ReceivePacket(&beginSessionResponse)) return (false); - unsigned int result = setupSessionResponse.GetUnknown(); + unsigned int result = beginSessionResponse.GetResult(); - // 131072 for Galaxy S II, 0 for other devices. - if (result != 0 && result != 131072) - { - Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", result); - return (false); - } + if (result != 0) // Assume 0 means don't care, otherwise use the response as the fileTransferPacketSize. + fileTransferPacketSize = result; // -------------------- KIES DOESN'T DO THIS -------------------- - SetupSessionPacket deviceTypePacket(SetupSessionPacket::kDeviceInfo); + DeviceTypePacket deviceTypePacket; if (!SendPacket(&deviceTypePacket)) { @@ -539,23 +606,67 @@ bool BridgeManager::BeginSession(void) const return (false); } - if (!ReceivePacket(&setupSessionResponse)) + SessionSetupResponse deviceTypeResponse; + + if (!ReceivePacket(&deviceTypeResponse)) return (false); - unsigned int deviceType = setupSessionResponse.GetUnknown(); + unsigned int deviceType = deviceTypeResponse.GetResult(); - // TODO: Work out what this value is... it has been either 180 or 0 for Galaxy S phones, 3 on the Galaxy Tab, 190 for SHW-M110S. - if (deviceType != 180 && deviceType != 0 && deviceType != 3 && deviceType != 190) - { - Interface::PrintError("Unexpected device info response!\nExpected: 180, 0 or 3\nReceived:%d\n", deviceType); - return (false); - } - else + switch (deviceType) { - Interface::Print("Session begun with device of type: %d\n\n", result); - } + // NOTE: If you add a new device type don't forget to update the error message below! - return (true); + case 0: // Galaxy S etc. + case 3: // Galaxy Tab + case 30: // Galaxy S 2 Skyrocket + case 180: // Galaxy S etc. + case 190: // M110S Galaxy S + + if (verbose) + Interface::Print("Session begun with device of type: %d.\n\n", deviceType); + else + Interface::Print("Session begun.\n\n", deviceType); + + if (deviceType == 30) + { + Interface::Print("In certain situations this device may take up to 2 minutes to respond.\nPlease be patient!\n\n", deviceType); + Sleep(2000); // Give the user time to read the message. + + // The SGH-I727 is very unstable/unreliable using the default settings. Flashing + // seems to be much more reliable using the following setup. + + fileTransferSequenceMaxLength = 30; + fileTransferSequenceTimeout = 120000; // 2 minutes! + fileTransferPacketSize = 1048576; // 1 MiB + + FilePartSizePacket filePartSizePacket(fileTransferPacketSize); // 1 MiB + + if (!SendPacket(&filePartSizePacket)) + { + Interface::PrintError("Failed to send file part size packet!\n"); + return (false); + } + + SessionSetupResponse filePartSizeResponse; + + if (!ReceivePacket(&filePartSizeResponse)) + return (false); + + if (filePartSizeResponse.GetResult() != 0) + { + Interface::PrintError("Unexpected file part size response!\nExpected: 0\nReceived: %d\n", filePartSizeResponse.GetResult()); + return (false); + } + } + + return (true); + + default: + + Interface::PrintError("Unexpected device info response!\nExpected: 0, 3, 30, 180 or 190\nReceived:%d\n", deviceType); + return (false); + } } bool BridgeManager::EndSession(bool reboot) const @@ -662,58 +773,79 @@ bool BridgeManager::SendPacket(OutboundPacket *packet, int timeout, bool retry) return (true); } -bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout, bool retry) const +bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout, bool retry, unsigned char *buffer, unsigned int bufferSize) const { - int dataTransferred; - int result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(), - &dataTransferred, timeout); + bool bufferProvided = buffer != nullptr && bufferSize >= packet->GetSize(); - if (result < 0 && retry) + if (!bufferProvided) { - // max(250, communicationDelay) - int retryDelay = (communicationDelay > 250) ? communicationDelay : 250; + buffer = packet->GetData(); + bufferSize = packet->GetSize(); + } - if (verbose) - Interface::PrintError("libusb error %d whilst receiving packet.", result); + int dataTransferred; + int result; - // Retry - for (int i = 0; i < 5; i++) + unsigned int attempt = 0; + unsigned int maxAttempts = (retry) ? kReceivePacketMaxAttempts : 1; + + // max(250, communicationDelay) + int retryDelay = (communicationDelay > 250) ? communicationDelay : 250; + + for (; attempt < maxAttempts; attempt++) + { + if (attempt > 0) { if (verbose) Interface::PrintErrorSameLine(" Retrying...\n"); - + // Wait longer each retry - Sleep(retryDelay * (i + 1)); - - result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(), - &dataTransferred, timeout); + Sleep(retryDelay * (attempt + 1)); + } - if (result >= 0) - break; + result = libusb_bulk_transfer(deviceHandle, inEndpoint, buffer, bufferSize, &dataTransferred, timeout); - if (verbose) - Interface::PrintError("libusb error %d whilst receiving packet.", result); - } + if (result >= 0) + break; if (verbose) - Interface::PrintErrorSameLine("\n"); + Interface::PrintError("libusb error %d whilst receiving packet.", result); } + if (verbose && attempt > 0) + Interface::PrintErrorSameLine("\n"); + + if (attempt == maxAttempts) + return (false); + if (communicationDelay != 0) Sleep(communicationDelay); - if (result < 0 || (dataTransferred != packet->GetSize() && !packet->IsSizeVariable())) + if (dataTransferred != packet->GetSize() && !packet->IsSizeVariable()) + { + if (verbose) + Interface::PrintError("Incorrect packet size received - expected size = %d, received size = %d.\n", packet->GetSize(), dataTransferred); + return (false); + } + + if (bufferProvided) + memcpy(packet->GetData(), buffer, dataTransferred); packet->SetReceivedSize(dataTransferred); - return (packet->Unpack()); + bool unpacked = packet->Unpack(); + + if (!unpacked && verbose) + Interface::PrintError("Failed to unpack received packet.\n"); + + return (unpacked); } -bool BridgeManager::RequestDeviceInfo(unsigned int request, int *result) const +bool BridgeManager::RequestDeviceType(unsigned int request, int *result) const { - SetupSessionPacket beginSessionPacket(request); - bool success = SendPacket(&beginSessionPacket); + DeviceTypePacket deviceTypePacket; + bool success = SendPacket(&deviceTypePacket); if (!success) { @@ -725,11 +857,12 @@ bool BridgeManager::RequestDeviceInfo(unsigned int request, int *result) const return (false); } - SetupSessionResponse deviceInfoResponse; - if (!ReceivePacket(&deviceInfoResponse)) + SessionSetupResponse deviceTypeResponse; + + if (!ReceivePacket(&deviceTypeResponse)) return (false); - *result = deviceInfoResponse.GetUnknown(); + *result = deviceTypeResponse.GetResult(); return (true); } @@ -921,7 +1054,23 @@ int BridgeManager::ReceivePitFile(unsigned char **pitBuffer) const return (fileSize); } -bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int chipIdentifier, unsigned int fileIdentifier) const +int BridgeManager::DownloadPitFile(unsigned char **pitBuffer) const +{ + Interface::Print("Downloading device's PIT file...\n"); + + int devicePitFileSize = ReceivePitFile(pitBuffer); + + if (!*pitBuffer) + { + Interface::PrintError("Failed to download PIT file!\n"); + return (0); + } + + Interface::Print("PIT file download successful.\n\n"); + return (devicePitFileSize); +} + +bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int deviceType, unsigned int fileIdentifier) const { if (destination != EndFileTransferPacket::kDestinationModem && destination != EndFileTransferPacket::kDestinationPhone) { @@ -959,16 +1108,16 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int return (false); } - unsigned int sequenceCount = fileSize / (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize); - unsigned int lastSequenceSize = kMaxSequenceLength; - unsigned int partialPacketByteCount = fileSize % SendFilePartPacket::kDefaultPacketSize; + unsigned int sequenceCount = fileSize / (fileTransferSequenceMaxLength * fileTransferPacketSize); + unsigned int lastSequenceSize = fileTransferSequenceMaxLength; + unsigned int partialPacketByteCount = fileSize % fileTransferPacketSize; - if (fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize) != 0) + if (fileSize % (fileTransferSequenceMaxLength * fileTransferPacketSize) != 0) { sequenceCount++; - int lastSequenceBytes = fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize); - lastSequenceSize = lastSequenceBytes / SendFilePartPacket::kDefaultPacketSize; + int lastSequenceBytes = fileSize % (fileTransferSequenceMaxLength * fileTransferPacketSize); + lastSequenceSize = lastSequenceBytes / fileTransferPacketSize; if (partialPacketByteCount != 0) lastSequenceSize++; @@ -981,12 +1130,16 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int for (unsigned int sequenceIndex = 0; sequenceIndex < sequenceCount; sequenceIndex++) { - // Min(lastSequenceSize, 131072) - bool isLastSequence = sequenceIndex == sequenceCount - 1; - unsigned int sequenceSize = (isLastSequence) ? lastSequenceSize : kMaxSequenceLength; - unsigned int sequenceByteCount = ((isLastSequence) ? lastSequenceSize : kMaxSequenceLength) * SendFilePartPacket::kDefaultPacketSize + partialPacketByteCount; + bool isLastSequence = (sequenceIndex == sequenceCount - 1); + unsigned int sequenceSize = (isLastSequence) ? lastSequenceSize : fileTransferSequenceMaxLength; + unsigned int sequenceByteCount; + + if (isLastSequence) + sequenceByteCount = ((partialPacketByteCount) ? lastSequenceSize - 1 : lastSequenceSize) * fileTransferPacketSize + partialPacketByteCount; + else + sequenceByteCount = fileTransferSequenceMaxLength * fileTransferPacketSize; - FlashPartFileTransferPacket *beginFileTransferPacket = new FlashPartFileTransferPacket(0, 2 * sequenceSize); + FlashPartFileTransferPacket *beginFileTransferPacket = new FlashPartFileTransferPacket(sequenceByteCount); success = SendPacket(beginFileTransferPacket); delete beginFileTransferPacket; @@ -1014,7 +1167,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int for (unsigned int filePartIndex = 0; filePartIndex < sequenceSize; filePartIndex++) { // Send - sendFilePartPacket = new SendFilePartPacket(file); + sendFilePartPacket = new SendFilePartPacket(file, fileTransferPacketSize); success = SendPacket(sendFilePartPacket); delete sendFilePartPacket; @@ -1050,7 +1203,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int Interface::PrintError("Retrying..."); // Send - sendFilePartPacket = new SendFilePartPacket(file); + sendFilePartPacket = new SendFilePartPacket(file, fileTransferPacketSize); success = SendPacket(sendFilePartPacket); delete sendFilePartPacket; @@ -1097,7 +1250,8 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int return (false); } - bytesTransferred += SendFilePartPacket::kDefaultPacketSize; + bytesTransferred += fileTransferPacketSize; + if (bytesTransferred > fileSize) bytesTransferred = fileSize; @@ -1123,8 +1277,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int if (destination == EndFileTransferPacket::kDestinationPhone) { - EndPhoneFileTransferPacket *endPhoneFileTransferPacket = new EndPhoneFileTransferPacket(sequenceByteCount, 0, chipIdentifier, - fileIdentifier, isLastSequence); + EndPhoneFileTransferPacket *endPhoneFileTransferPacket = new EndPhoneFileTransferPacket(sequenceByteCount, 0, deviceType, fileIdentifier, isLastSequence); success = SendPacket(endPhoneFileTransferPacket, 3000); delete endPhoneFileTransferPacket; @@ -1138,7 +1291,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int } else // destination == EndFileTransferPacket::kDestinationModem { - EndModemFileTransferPacket *endModemFileTransferPacket = new EndModemFileTransferPacket(sequenceByteCount, 0, chipIdentifier, isLastSequence); + EndModemFileTransferPacket *endModemFileTransferPacket = new EndModemFileTransferPacket(sequenceByteCount, 0, deviceType, isLastSequence); success = SendPacket(endModemFileTransferPacket, 3000); delete endModemFileTransferPacket; @@ -1152,7 +1305,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int } fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer); - success = ReceivePacket(fileTransferResponse, 30000); + success = ReceivePacket(fileTransferResponse, fileTransferSequenceTimeout); delete fileTransferResponse; if (!success) diff --git a/heimdall/source/BridgeManager.h b/heimdall/source/BridgeManager.h index f131bda..1c3a435 100644 --- a/heimdall/source/BridgeManager.h +++ b/heimdall/source/BridgeManager.h @@ -41,8 +41,8 @@ namespace Heimdall const int productId;
DeviceIdentifier(int vid, int pid) :
- vendorId(vid),
- productId(pid)
+ vendorId(vid),
+ productId(pid)
{
}
};
@@ -53,10 +53,12 @@ namespace Heimdall enum
{
- kSupportedDeviceCount = 3,
+ kSupportedDeviceCount = 3,
+ };
- kCommunicationDelayDefault = 0,
- kDumpBufferSize = 4096
+ enum
+ {
+ kCommunicationDelayDefault = 0
};
enum
@@ -83,15 +85,18 @@ namespace Heimdall static const DeviceIdentifier supportedDevices[kSupportedDeviceCount];
bool verbose;
+ int communicationDelay;
libusb_context *libusbContext;
libusb_device_handle *deviceHandle;
libusb_device *heimdallDevice;
+
int interfaceIndex;
+ int altSettingIndex;
int inEndpoint;
int outEndpoint;
- int communicationDelay;
+ bool interfaceClaimed;
#ifdef OS_LINUX
@@ -99,29 +104,39 @@ namespace Heimdall #endif
+ unsigned int fileTransferSequenceMaxLength;
+ unsigned int fileTransferPacketSize;
+ unsigned int fileTransferSequenceTimeout;
+
+ int FindDeviceInterface(void);
+ bool ClaimDeviceInterface(void);
+ bool SetupDeviceInterface(void);
+ void ReleaseDeviceInterface(void);
+
bool CheckProtocol(void) const;
bool InitialiseProtocol(void) const;
public:
- BridgeManager(bool verbose, int communicationDelay);
+ BridgeManager(bool verbose, int communicationDelay = BridgeManager::kCommunicationDelayDefault);
~BridgeManager();
bool DetectDevice(void);
int Initialise(void);
- bool BeginSession(void) const;
+ bool BeginSession(void);
bool EndSession(bool reboot) const;
bool SendPacket(OutboundPacket *packet, int timeout = 3000, bool retry = true) const;
- bool ReceivePacket(InboundPacket *packet, int timeout = 3000, bool retry = true) const;
+ bool ReceivePacket(InboundPacket *packet, int timeout = 3000, bool retry = true, unsigned char *buffer = nullptr, unsigned int bufferSize = -1) const;
- bool RequestDeviceInfo(unsigned int request, int *result) const;
+ bool RequestDeviceType(unsigned int request, int *result) const;
bool SendPitFile(FILE *file) 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 chipIdentifier, unsigned int fileIdentifier = 0xFFFFFFFF) const;
+ 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;
bool IsVerbose(void) const
diff --git a/heimdall/source/ClosePcScreenAction.cpp b/heimdall/source/ClosePcScreenAction.cpp new file mode 100644 index 0000000..a7de9d9 --- /dev/null +++ b/heimdall/source/ClosePcScreenAction.cpp @@ -0,0 +1,94 @@ +/* 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.*/ + +// Heimdall +#include "Arguments.h" +#include "BridgeManager.h" +#include "ClosePcScreenAction.h" +#include "Heimdall.h" +#include "Interface.h" + +using namespace Heimdall; + +const char *ClosePcScreenAction::usage = "Action: close-pc-screen\n\ +Arguments: [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\ +Description: Attempts to get rid off the \"connect phone to PC\" screen.\n"; + +int ClosePcScreenAction::Execute(int argc, char **argv) +{ + // Handle arguments + + map<string, ArgumentType> argumentTypes; + 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(ClosePcScreenAction::usage); + return (0); + } + + const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(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); + + // Info + + Interface::PrintReleaseInfo(); + Sleep(1000); + + // Download PIT file from device. + + int communicationDelay = BridgeManager::kCommunicationDelayDefault; + + if (communicationDelayArgument) + communicationDelay = communicationDelayArgument->GetValue(); + + BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + + if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + { + delete bridgeManager; + return (1); + } + + Interface::Print("Attempting to close connect to pc screen...\n"); + + bool success = bridgeManager->EndSession(reboot); + delete bridgeManager; + + if (success) + { + Interface::Print("Attempt complete\n"); + return (0); + } + else + { + return (1); + } +} diff --git a/heimdall/source/ClosePcScreenAction.h b/heimdall/source/ClosePcScreenAction.h new file mode 100644 index 0000000..e4470a2 --- /dev/null +++ b/heimdall/source/ClosePcScreenAction.h @@ -0,0 +1,34 @@ +/* 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 CLOSEPCSCREENACTION_H +#define CLOSEPCSCREENACTION_H + +namespace Heimdall +{ + namespace ClosePcScreenAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/ControlPacket.h b/heimdall/source/ControlPacket.h index eb12b09..7f46d7d 100644 --- a/heimdall/source/ControlPacket.h +++ b/heimdall/source/ControlPacket.h @@ -32,10 +32,10 @@ namespace Heimdall enum
{
- kControlTypeSetupSession = 0x64,
- kControlTypePitFile = 0x65,
- kControlTypeFileTransfer = 0x66,
- kControlTypeEndSession = 0x67
+ kControlTypeSession = 0x64,
+ kControlTypePitFile = 0x65,
+ kControlTypeFileTransfer = 0x66,
+ kControlTypeEndSession = 0x67
};
protected:
diff --git a/heimdall/source/DetectAction.cpp b/heimdall/source/DetectAction.cpp new file mode 100644 index 0000000..319433f --- /dev/null +++ b/heimdall/source/DetectAction.cpp @@ -0,0 +1,64 @@ +/* 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.*/ + +// Heimdall +#include "Arguments.h" +#include "BridgeManager.h" +#include "DetectAction.h" +#include "Heimdall.h" +#include "Interface.h" + +using namespace Heimdall; + +const char *DetectAction::usage = "Action: detect\n\ +Arguments: [--verbose] [--stdout-errors]\n\ +Description: Indicates whether or not a download mode device can be detected.\n"; + +int DetectAction::Execute(int argc, char **argv) +{ + // Handle arguments + + map<string, ArgumentType> argumentTypes; + argumentTypes["verbose"] = kArgumentTypeFlag; + argumentTypes["stdout-errors"] = kArgumentTypeFlag; + + Arguments arguments(argumentTypes); + + if (!arguments.ParseArguments(argc, argv, 2)) + { + Interface::Print(DetectAction::usage); + return (0); + } + + bool verbose = arguments.GetArgument("verbose") != nullptr; + + if (arguments.GetArgument("stdout-errors") != nullptr) + Interface::SetStdoutErrors(true); + + // Download PIT file from device. + + BridgeManager *bridgeManager = new BridgeManager(verbose); + + bool detected = bridgeManager->DetectDevice(); + + delete bridgeManager; + + return ((detected) ? 0 : 1); +} diff --git a/heimdall/source/DetectAction.h b/heimdall/source/DetectAction.h new file mode 100644 index 0000000..374306b --- /dev/null +++ b/heimdall/source/DetectAction.h @@ -0,0 +1,34 @@ +/* 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 DETECTACTION_H +#define DETECTACTION_H + +namespace Heimdall +{ + namespace DetectAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/DeviceTypePacket.h b/heimdall/source/DeviceTypePacket.h new file mode 100644 index 0000000..72dbfc6 --- /dev/null +++ b/heimdall/source/DeviceTypePacket.h @@ -0,0 +1,39 @@ +/* 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 DEVICETYPEPACKET_H +#define DEVICETYPEPACKET_H + +// Heimdall +#include "SessionSetupPacket.h" + +namespace Heimdall +{ + class DeviceTypePacket : public SessionSetupPacket + { + public: + + DeviceTypePacket() : SessionSetupPacket(SessionSetupPacket::kDeviceType) + { + } + }; +} + +#endif diff --git a/heimdall/source/DownloadPitAction.cpp b/heimdall/source/DownloadPitAction.cpp new file mode 100644 index 0000000..b4b81a9 --- /dev/null +++ b/heimdall/source/DownloadPitAction.cpp @@ -0,0 +1,135 @@ +/* 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 <stdio.h> + +// Heimdall +#include "Arguments.h" +#include "BridgeManager.h" +#include "DownloadPitAction.h" +#include "Heimdall.h" +#include "Interface.h" + +using namespace Heimdall; + +const char *DownloadPitAction::usage = "Action: download-pit\n\ +Arguments: --output <filename> [--verbose] [--no-reboot] [--stdout-errors]\n\ + [--delay <ms>]\n\ +Description: Downloads the connected device's PIT file to the specified\n\ + output file.\n"; + +int DownloadPitAction::Execute(int argc, char **argv) +{ + // Handle arguments + + map<string, ArgumentType> argumentTypes; + 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(DownloadPitAction::usage); + return (0); + } + + const StringArgument *outputArgument = static_cast<const StringArgument *>(arguments.GetArgument("output")); + + if (!outputArgument) + { + Interface::Print("Output file was not specified.\n\n"); + Interface::Print(DownloadPitAction::usage); + return (0); + } + + const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(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); + + // Info + + Interface::PrintReleaseInfo(); + Sleep(1000); + + // Open output file + + const char *outputFilename = outputArgument->GetValue().c_str(); + FILE *outputPitFile = fopen(outputFilename, "wb"); + + if (!outputPitFile) + { + Interface::PrintError("Failed to open output file \"%s\"\n", outputFilename); + return (1); + } + + // Download PIT file from device. + + int communicationDelay = BridgeManager::kCommunicationDelayDefault; + + if (communicationDelayArgument) + communicationDelay = communicationDelayArgument->GetValue(); + + BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + + if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + { + fclose(outputPitFile); + delete bridgeManager; + + return (1); + } + + unsigned char *pitBuffer; + int fileSize = bridgeManager->DownloadPitFile(&pitBuffer); + + bool success = true; + + if (fileSize > 0) + { + if (fwrite(pitBuffer, 1, fileSize, outputPitFile) != fileSize) + { + Interface::PrintError("Failed to write PIT data to output file.\n"); + success = false; + } + } + else + { + success = false; + } + + if (!bridgeManager->EndSession(reboot)) + success = false; + + delete bridgeManager; + + fclose(outputPitFile); + delete [] pitBuffer; + + return (success ? 0 : 1); +} diff --git a/heimdall/source/DownloadPitAction.h b/heimdall/source/DownloadPitAction.h new file mode 100644 index 0000000..7ccc0bd --- /dev/null +++ b/heimdall/source/DownloadPitAction.h @@ -0,0 +1,34 @@ +/* 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 DOWNLOADPITACTION_H +#define DOWNLOADPITACTION_H + +namespace Heimdall +{ + namespace DownloadPitAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/DumpAction.cpp b/heimdall/source/DumpAction.cpp new file mode 100644 index 0000000..38ccbf9 --- /dev/null +++ b/heimdall/source/DumpAction.cpp @@ -0,0 +1,158 @@ +/* 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 <stdio.h> + +// 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 <NAND | RAM> --chip-id <integer> --output <filename>\n\ + [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\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<string, ArgumentType> 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<const StringArgument *>(arguments.GetArgument("chip-type")); + const UnsignedIntegerArgument *chipIdArgument = static_cast<const UnsignedIntegerArgument *>(arguments.GetArgument("chip-id")); + const StringArgument *outputArgument = static_cast<const StringArgument *>(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<const UnsignedIntegerArgument *>(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 new file mode 100644 index 0000000..eb97bca --- /dev/null +++ b/heimdall/source/DumpAction.h @@ -0,0 +1,34 @@ +/* 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/FilePartSizePacket.h b/heimdall/source/FilePartSizePacket.h new file mode 100644 index 0000000..561ec5b --- /dev/null +++ b/heimdall/source/FilePartSizePacket.h @@ -0,0 +1,56 @@ +/* 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 FILEPARTSIZEPACKET_H +#define FILEPARTSIZEPACKET_H + +// Heimdall +#include "SessionSetupPacket.h" + +namespace Heimdall +{ + class FilePartSizePacket : public SessionSetupPacket + { + private: + + unsigned int filePartSize; + + public: + + FilePartSizePacket(unsigned int filePartSize) : SessionSetupPacket(SessionSetupPacket::kFilePartSize) + { + this->filePartSize = filePartSize; + } + + unsigned int GetFilePartSize(void) const + { + return filePartSize; + } + + void Pack(void) + { + SessionSetupPacket::Pack(); + + PackInteger(SessionSetupPacket::kDataSize, filePartSize); + } + }; +} + +#endif diff --git a/heimdall/source/FlashAction.cpp b/heimdall/source/FlashAction.cpp new file mode 100644 index 0000000..d79235e --- /dev/null +++ b/heimdall/source/FlashAction.cpp @@ -0,0 +1,620 @@ +/* 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 <stdio.h> + +// Heimdall +#include "Arguments.h" +#include "BridgeManager.h" +#include "EndModemFileTransferPacket.h" +#include "EndPhoneFileTransferPacket.h" +#include "FlashAction.h" +#include "Heimdall.h" +#include "Interface.h" +#include "SessionSetupResponse.h" +#include "TotalBytesPacket.h" +#include "Utility.h" + +using namespace Heimdall; + +const char *FlashAction::usage = "Action: flash\n\ +Arguments:\n\ + --repartition --pit <filename> [--factoryfs <filename>]\n\ + [--cache <filename>] [--dbdata <filename>] [--primary-boot <filename>]\n\ + [--secondary-boot <filename>] [--param <filename>] [--kernel <filename>]\n\ + [--modem <filename>] [--radio <filename>] [--normal-boot <filename>]\n\ + [--system <filename>] [--user-data <filename>] [--fota <filename>]\n\ + [--hidden <filename>] [--movinand <filename>] [--data <filename>]\n\ + [--ums <filename>] [--emmc <filename>]\n\ + [--<partition identifier> <filename>]\n\ + [--<partition name> <filename>]\n\ + [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\ + or:\n\ + [--factoryfs <filename>] [--cache <filename>] [--dbdata <filename>]\n\ + [--primary-boot <filename>] [--secondary-boot <filename>]\n\ + [--secondary-boot-backup <filename>] [--param <filename>]\n\ + [--kernel <filename>] [--recovery <filename>] [--efs <filename>]\n\ + [--modem <filename>] [--radio <filename>] [--normal-boot <filename>]\n\ + [--system <filename>] [--user-data <filename>] [--fota <filename>]\n\ + [--hidden <filename>] [--movinand <filename>] [--data <filename>]\n\ + [--ums <filename>] [--emmc <filename>] [--pit <filename>]\n\ + [--<partition identifier> <filename>]\n\ + [--<partition name> <filename>]\n\ + [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\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\ +WARNING: If you're repartitioning it's strongly recommended you specify\n\ + all files at your disposal, including bootloaders.\n"; + +struct PartitionFlashInfo +{ + const PitEntry *pitEntry; + FILE *file; + + PartitionFlashInfo(const PitEntry *pitEntry, FILE *file) + { + this->pitEntry = pitEntry; + this->file = file; + } +}; + +static void buildArgumentPartitionNamesMap(map< string, vector<string> >& argumentPartitionNamesMap, map<string, string>& shortArgumentAliases) +{ + 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"); + + 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"; +} + +static bool openFiles(Arguments& arguments, const map< string, vector<string> >& argumentPartitionNamesMap, + map<string, FILE *>& argumentFileMap) +{ + for (map<string, Argument *>::const_iterator it = arguments.GetArguments().begin(); it != arguments.GetArguments().end(); it++) + { + bool isPartitionArgument = false; + const string& argumentName = it->first; + + 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 + { + // The argument wasn't a wild-card, check if it's a known partition name. + if (argumentPartitionNamesMap.find(argumentName) != argumentPartitionNamesMap.end()) + isPartitionArgument = true; + } + + if (isPartitionArgument) + { + const StringArgument *stringArgument = static_cast<StringArgument *>(it->second); + FILE *file = fopen(stringArgument->GetValue().c_str(), "rb"); + + if (!file) + { + Interface::PrintError("Failed to open file \"%s\"\n", stringArgument->GetValue().c_str()); + return (false); + } + + argumentFileMap[it->first] = file; + } + } + + return (true); +} + +static void closeFiles(map<string, FILE *> argumentfileMap) +{ + for (map<string, FILE *>::iterator it = argumentfileMap.begin(); it != argumentfileMap.end(); it++) + fclose(it->second); + + argumentfileMap.clear(); +} + +static bool sendTotalTransferSize(BridgeManager *bridgeManager, const map<string, FILE *>& argumentFileMap, bool repartition) +{ + int totalBytes = 0; + for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) + { + if (repartition || it->first != "pit") + { + fseek(it->second, 0, SEEK_END); + totalBytes += ftell(it->second); + rewind(it->second); + } + } + + bool success; + + TotalBytesPacket *totalBytesPacket = new TotalBytesPacket(totalBytes); + success = bridgeManager->SendPacket(totalBytesPacket); + delete totalBytesPacket; + + if (!success) + { + Interface::PrintError("Failed to send total bytes device info packet!\n"); + return (false); + } + + SessionSetupResponse *totalBytesResponse = new SessionSetupResponse(); + success = bridgeManager->ReceivePacket(totalBytesResponse); + int totalBytesResult = totalBytesResponse->GetResult(); + delete totalBytesResponse; + + if (!success) + { + Interface::PrintError("Failed to receive device info response!\n"); + return (false); + } + + if (totalBytesResult != 0) + { + Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", totalBytesResponse); + return (false); + } + + return (true); +} + +static bool setupPartitionFlashInfo(const map<string, FILE *>& argumentFileMap, const map< string, vector<string> >& argumentPartitionNamesMap, + const PitData *pitData, vector<PartitionFlashInfo>& partitionFlashInfos) +{ + for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.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) + { + pitEntry = pitData->FindEntry(partitionIdentifier); + + if (!pitEntry) + { + Interface::PrintError("No partition with identifier \"%s\" exists in the specified PIT.\n", argumentName.c_str()); + return (false); + } + } + else + { + // The argument wasn't a partition identifier. Was it a known human-readable partition name? + map< string, vector<string> >::const_iterator argumentPartitionNamesIt = argumentPartitionNamesMap.find(argumentName); + + if (argumentPartitionNamesIt != argumentPartitionNamesMap.end()) + { + const vector<string>& partitionNames = argumentPartitionNamesIt->second; + + // Check for the partition in the PIT file using all known names. + for (vector<string>::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 + { + // 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); + } + } + } + + partitionFlashInfos.push_back(PartitionFlashInfo(pitEntry, partitionFile)); + } + + return (true); +} + +static bool isKnownPartition(const map<string, vector<string> >& argumentPartitionNamesMap, const string& argumentName, const string& partitionName) +{ + const vector<string>& partitionNames = argumentPartitionNamesMap.find(argumentName)->second; + + for (vector<string>::const_iterator it = partitionNames.begin(); it != partitionNames.end(); it++) + { + if (partitionName == *it) + return (true); + } + + return (false); +} + +static bool isKnownBootPartition(const map<string, vector<string> >& 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<string> >& argumentPartitionNamesMap, + 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())) + { + Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName()); + + if (bridgeManager->SendPitFile(partitionFlashInfo.file)) + { + 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); + } + } + else + { + if (partitionFlashInfo.pitEntry->GetBinaryType() == PitEntry::kBinaryTypeCommunicationProcessor) // Modem + { + 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); + } + } + else // partitionFlashInfo.pitEntry->GetBinaryType() == PitEntry::kBinaryTypeApplicationProcessor + { + 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); + } + } + } + + return (true); +} + +static bool flashPartitions(const map<string, FILE *>& argumentFileMap, const map< string, vector<string> >& argumentPartitionNamesMap, + const PitData *pitData, BridgeManager *bridgeManager, bool repartition) +{ + vector<PartitionFlashInfo> partitionFlashInfos; + + // Map the files being flashed to partitions stored in the PIT file. + if (!setupPartitionFlashInfo(argumentFileMap, argumentPartitionNamesMap, pitData, partitionFlashInfos)) + return (false); + + // If we're repartitioning then we need to flash the PIT file first. + if (repartition) + { + vector<PartitionFlashInfo>::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"); + return (false); + } + } + + // Flash partitions not involved in the boot process second. + for (vector<PartitionFlashInfo>::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<PartitionFlashInfo>::const_iterator it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++) + { + if (isKnownBootPartition(argumentPartitionNamesMap, it->pitEntry->GetPartitionName())) + { + if (!flashFile(bridgeManager, argumentPartitionNamesMap, *it)) + return (false); + } + } + + return (true); +} + +static PitData *getPitData(const map<string, FILE *>& argumentFileMap, BridgeManager *bridgeManager, bool repartition) +{ + PitData *pitData; + PitData *localPitData = nullptr; + + // If a PIT file was passed as an argument then we must unpack it. + + map<string, FILE *>::const_iterator localPitFileIt = argumentFileMap.find("pit"); + + if (localPitFileIt != argumentFileMap.end()) + { + FILE *localPitFile = localPitFileIt->second; + + // Load the local pit file into memory. + unsigned char *pitFileBuffer = new unsigned char[4096]; + memset(pitFileBuffer, 0, 4096); + + fseek(localPitFile, 0, SEEK_END); + long localPitFileSize = ftell(localPitFile); + rewind(localPitFile); + + // dataRead is discarded, it's here to remove warnings. + int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile); + rewind(localPitFile); + + localPitData = new PitData(); + localPitData->Unpack(pitFileBuffer); + + delete [] pitFileBuffer; + } + + if (repartition) + { + // Use the local PIT file data. + pitData = localPitData; + } + else + { + // If we're not repartitioning then we need to retrieve the device's PIT file and unpack it. + unsigned char *pitFileBuffer; + + if (bridgeManager->DownloadPitFile(&pitFileBuffer) == 0) + return (nullptr); + + pitData = new PitData(); + pitData->Unpack(pitFileBuffer); + + delete [] pitFileBuffer; + + if (localPitData != nullptr) + { + // The user has specified a PIT without repartitioning, we should verify the local and device PIT data match! + bool pitsMatch = pitData->Matches(localPitData); + delete localPitData; + + if (!pitsMatch) + { + Interface::Print("Local and device PIT files don't match and repartition wasn't specified!\n"); + Interface::PrintError("Flash aborted!\n"); + return (nullptr); + } + } + } + + return (pitData); +} + +int FlashAction::Execute(int argc, char **argv) +{ + // Setup argument types + + map<string, ArgumentType> argumentTypes; + + argumentTypes["repartition"] = kArgumentTypeString; + + argumentTypes["no-reboot"] = kArgumentTypeFlag; + argumentTypes["delay"] = kArgumentTypeUnsignedInteger; + argumentTypes["verbose"] = kArgumentTypeFlag; + argumentTypes["stdout-errors"] = kArgumentTypeFlag; + + map< string, vector<string> > argumentPartitionNamesMap; + map<string, string> shortArgumentAliases; + + buildArgumentPartitionNamesMap(argumentPartitionNamesMap, shortArgumentAliases); + + for (map< string, vector<string> >::const_iterator it = argumentPartitionNamesMap.begin(); it != argumentPartitionNamesMap.end(); it++) + argumentTypes[it->first] = kArgumentTypeString; + + // Add wild-cards "%d" and "%s", for partition identifiers and partition names respectively. + argumentTypes["%d"] = kArgumentTypeString; + shortArgumentAliases["%d"] = "%d"; + + argumentTypes["%s"] = kArgumentTypeString; + shortArgumentAliases["%s"] = "%s"; + + map<string, string> argumentAliases; + argumentAliases["PIT"] = "pit"; // Map upper-case PIT argument (i.e. partition name) to known lower-case pit argument. + + // Handle arguments + + Arguments arguments(argumentTypes, shortArgumentAliases, argumentAliases); + + if (!arguments.ParseArguments(argc, argv, 2)) + { + Interface::Print(FlashAction::usage); + return (0); + } + + const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(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); + + const StringArgument *pitArgument = static_cast<const StringArgument *>(arguments.GetArgument("pit")); + + bool repartition = arguments.GetArgument("repartition") != nullptr; + + if (repartition && !pitArgument) + { + Interface::Print("If you wish to repartition then a PIT file must be specified.\n\n"); + Interface::Print(FlashAction::usage); + return (0); + } + + // Open files + + map<string, FILE *> argumentFileMap; + + if (!openFiles(arguments, argumentPartitionNamesMap, argumentFileMap)) + { + closeFiles(argumentFileMap); + return (1); + } + + if (argumentFileMap.size() == 0) + { + Interface::Print(FlashAction::usage); + return (0); + } + + // Info + + Interface::PrintReleaseInfo(); + Sleep(1000); + + // Perform flash + + int communicationDelay = BridgeManager::kCommunicationDelayDefault; + + if (communicationDelayArgument) + communicationDelay = communicationDelayArgument->GetValue(); + + BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + + if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + { + closeFiles(argumentFileMap); + delete bridgeManager; + + return (1); + } + + bool success = sendTotalTransferSize(bridgeManager, argumentFileMap, repartition); + + if (success) + { + PitData *pitData = getPitData(argumentFileMap, bridgeManager, repartition); + + if (pitData) + success = flashPartitions(argumentFileMap, argumentPartitionNamesMap, pitData, bridgeManager, repartition); + else + success = false; + + delete pitData; + } + + closeFiles(argumentFileMap); + + if (!bridgeManager->EndSession(reboot)) + success = false; + + delete bridgeManager; + + return (success ? 0 : 1); +} diff --git a/heimdall/source/FlashAction.h b/heimdall/source/FlashAction.h new file mode 100644 index 0000000..b4e1b6b --- /dev/null +++ b/heimdall/source/FlashAction.h @@ -0,0 +1,34 @@ +/* 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 FLASHACTION_H +#define FLASHACTION_H + +namespace Heimdall +{ + namespace FlashAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/FlashPartFileTransferPacket.h b/heimdall/source/FlashPartFileTransferPacket.h index a444211..dcf3422 100644 --- a/heimdall/source/FlashPartFileTransferPacket.h +++ b/heimdall/source/FlashPartFileTransferPacket.h @@ -30,34 +30,26 @@ namespace Heimdall {
private:
- unsigned short unknown;
- unsigned int transferCount;
+ unsigned int sequenceByteCount;
public:
- FlashPartFileTransferPacket(unsigned short unknown, unsigned int transferCount)
+ FlashPartFileTransferPacket(unsigned int sequenceByteCount)
: FileTransferPacket(FileTransferPacket::kRequestPart)
{
- this->unknown = unknown;
- this->transferCount = transferCount;
+ this->sequenceByteCount = sequenceByteCount;
}
- unsigned short GetUnknown(void) const
+ unsigned int GetSequenceByteCount(void) const
{
- return (unknown);
- }
-
- unsigned int GetTransferCount(void) const
- {
- return (transferCount);
+ return (sequenceByteCount);
}
void Pack(void)
{
FileTransferPacket::Pack();
- PackShort(FileTransferPacket::kDataSize, unknown);
- PackInteger(FileTransferPacket::kDataSize + 2, transferCount);
+ PackInteger(FileTransferPacket::kDataSize, sequenceByteCount);
}
};
}
diff --git a/heimdall/source/Heimdall.h b/heimdall/source/Heimdall.h index eb3c96c..1cb2eaa 100644 --- a/heimdall/source/Heimdall.h +++ b/heimdall/source/Heimdall.h @@ -23,6 +23,7 @@ #ifdef OS_WINDOWS
#include <Windows.h>
+#undef GetBinaryType
#else
#include "../config.h"
diff --git a/heimdall/source/HelpAction.cpp b/heimdall/source/HelpAction.cpp new file mode 100644 index 0000000..f041a81 --- /dev/null +++ b/heimdall/source/HelpAction.cpp @@ -0,0 +1,35 @@ +/* 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.*/ + +// Heimdall +#include "Heimdall.h" +#include "HelpAction.h" +#include "Interface.h" + +using namespace Heimdall; + +const char *HelpAction::usage = "Action: help\n\ +Description: Displays this dialogue.\n"; + +int HelpAction::Execute(int argc, char **argv) +{ + Interface::PrintUsage(); + return (0); +} diff --git a/heimdall/source/HelpAction.h b/heimdall/source/HelpAction.h new file mode 100644 index 0000000..7fb3e82 --- /dev/null +++ b/heimdall/source/HelpAction.h @@ -0,0 +1,34 @@ +/* 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 HELPACTION_H +#define HELPACTION_H + +namespace Heimdall +{ + namespace HelpAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/InfoAction.cpp b/heimdall/source/InfoAction.cpp new file mode 100644 index 0000000..740f4e2 --- /dev/null +++ b/heimdall/source/InfoAction.cpp @@ -0,0 +1,35 @@ +/* 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.*/ + +// Heimdall +#include "Heimdall.h" +#include "InfoAction.h" +#include "Interface.h" + +using namespace Heimdall; + +const char *InfoAction::usage = "Action: info\n\ +Description: Displays information about Heimdall.\n"; + +int InfoAction::Execute(int argc, char **argv) +{ + Interface::PrintFullInfo(); + return (0); +} diff --git a/heimdall/source/InfoAction.h b/heimdall/source/InfoAction.h new file mode 100644 index 0000000..8829d4a --- /dev/null +++ b/heimdall/source/InfoAction.h @@ -0,0 +1,34 @@ +/* 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 INFOACTION_H +#define INFOACTION_H + +namespace Heimdall +{ + namespace InfoAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/Interface.cpp b/heimdall/source/Interface.cpp index 4d42ad0..67f1bee 100644 --- a/heimdall/source/Interface.cpp +++ b/heimdall/source/Interface.cpp @@ -24,342 +24,108 @@ #include <stdio.h> // Heimdall +#include "ClosePcScreenAction.h" +#include "DetectAction.h" +#include "DownloadPitAction.h" +#include "DumpAction.h" +#include "FlashAction.h" +#include "HelpAction.h" +#include "InfoAction.h" #include "Heimdall.h" #include "Interface.h" +#include "PrintPitAction.h" +#include "VersionAction.h" using namespace std; using namespace libpit; using namespace Heimdall; -bool Interface::stdoutErrors = false; +map<string, Interface::ActionInfo> actionMap; +bool stdoutErrors = false; + +const char *version = "v1.4 RC1"; +const char *actionUsage = "Usage: heimdall <action> <action arguments>\n"; -const char *Interface::version = "v1.3.2"; - -const char *Interface::usage = "Usage: heimdall <action> <action arguments> <common arguments>\n\ -\n\ -Common Arguments:\n\ - [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\ -\n\ -\n\ -Action: flash\n\ -Arguments:\n\ - --repartition --pit <filename> [--factoryfs <filename>]\n\ - [--cache <filename>] [--dbdata <filename>] [--primary-boot <filename>]\n\ - [--secondary-boot <filename>] [--param <filename>] [--kernel <filename>]\n\ - [--modem <filename>] [--normal-boot <filename>] [--system <filename>]\n\ - [--user-data <filename>] [--fota <filename>] [--hidden <filename>]\n\ - [--movinand <filename>] [--data <filename>] [--ums <filename>]\n\ - [--emmc <filename>] [--<partition identifier> <filename>]\n\ - or:\n\ - [--factoryfs <filename>] [--cache <filename>] [--dbdata <filename>]\n\ - [--primary-boot <filename>] [--secondary-boot <filename>]\n\ - [--secondary-boot-backup <filename>] [--param <filename>]\n\ - [--kernel <filename>] [--recovery <filename>] [--efs <filename>]\n\ - [--modem <filename>] [--normal-boot <filename>] [--system <filename>]\n\ - [--user-data <filename>] [--fota <filename>] [--hidden <filename>]\n\ - [--movinand <filename>] [--data <filename>] [--ums <filename>]\n\ - [--emmc <filename>] [--<partition identifier> <filename>]\n\ -Description: Flashes firmware files to your phone.\n\ -WARNING: If you're repartitioning it's strongly recommended you specify\n\ - all files at your disposal, including bootloaders.\n\ -\n\ -Action: close-pc-screen\n\ -Description: Attempts to get rid off the \"connect phone to PC\" screen.\n\ -\n\ -Action: download-pit\n\ -Arguments: --output <filename>\n\ -Description: Downloads the connected device's PIT file to the specified\n\ - output file.\n\ -\n\ -Action: detect\n\ -Description: Indicates whether or not a download mode device can be detected.\n\ -\n\ -Action: dump\n\ -Arguments: --chip-type <NAND | RAM> --chip-id <integer> --output <filename>\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\ -\n\ -Action: print-pit\n\ -Description: Dumps the PIT file from the connected device and prints it in\n\ - a human readable format.\n\ -\n\ -Action: version\n\ -Description: Displays the version number of this binary.\n\ -\n\ -Action: help\n\ -Description: Displays this dialogue.\n"; - -const char *Interface::releaseInfo = "Heimdall %s, Copyright (c) 2010-2012, Benjamin Dobell, Glass Echidna\n\ -http://www.glassechidna.com.au\n\n\ +const char *releaseInfo = "Heimdall %s\n\n\ +Copyright (c) 2010-2012, Benjamin Dobell, Glass Echidna\n\ +http://www.glassechidna.com.au/\n\n\ This software is provided free of charge. Copying and redistribution is\nencouraged.\n\n\ If you appreciate this software and you would like to support future\ndevelopment please consider donating:\n\ http://www.glassechidna.com.au/donate/\n\n"; -const char *Interface::extraInfo = "Heimdall utilises libusb-1.0 for all USB communication:\n\ +static const char *extraInfo = "Heimdall utilises libusb-1.0 for all USB communication:\n\ http://www.libusb.org/\n\ \n\ libusb-1.0 is licensed under the LGPL-2.1:\n\ http://www.gnu.org/licenses/licenses.html#LGPL\n\n"; -// Flash arguments -string Interface::flashValueArguments[kFlashValueArgCount] = { - "-pit", "-factoryfs", "-cache", "-dbdata", "-primary-boot", "-secondary-boot", "-secondary-boot-backup", "-param", "-kernel", "-recovery", "-efs", "-modem", - "-normal-boot", "-system", "-user-data", "-fota", "-hidden", "-movinand", "-data", "-ums", "-emmc", "-%d" -}; - -string Interface::flashValueShortArguments[kFlashValueArgCount] = { - "pit", "fs", "cache", "db", "boot", "sbl", "sbl2", "param", "z", "rec", "efs", "m", - "norm", "sys", "udata", "fota", "hide", "nand", "data", "ums", "emmc", "%d" -}; - -string Interface::flashValuelessArguments[kFlashValuelessArgCount] = { - "-repartition" -}; - -string Interface::flashValuelessShortArguments[kFlashValuelessArgCount] = { - "r" -}; - -// Download PIT arguments -string Interface::downloadPitValueArguments[kDownloadPitValueArgCount] = { - "-output" -}; - -string Interface::downloadPitValueShortArguments[kDownloadPitValueArgCount] = { - "o" -}; - -// Dump arguments -string Interface::dumpValueArguments[kDumpValueArgCount] = { - "-chip-type", "-chip-id", "-output" -}; - -string Interface::dumpValueShortArguments[kDumpValueArgCount] = { - "type", "id", "out" -}; - -// Common arguments -string Interface::commonValueArguments[kCommonValueArgCount] = { - "-delay" -}; - -string Interface::commonValueShortArguments[kCommonValueArgCount] = { - "d" -}; - -string Interface::commonValuelessArguments[kCommonValuelessArgCount] = { - "-verbose", "-no-reboot", "-stdout-errors" -}; - -string Interface::commonValuelessShortArguments[kCommonValuelessArgCount] = { - "v", "nobt", "err" -}; - -Action Interface::actions[Interface::kActionCount] = { - // kActionFlash - Action("flash", flashValueArguments, flashValueShortArguments, kFlashValueArgCount, - flashValuelessArguments, flashValuelessShortArguments, kFlashValuelessArgCount), - - // kActionClosePcScreen - Action("close-pc-screen", nullptr, nullptr, kClosePcScreenValueArgCount, - nullptr, nullptr, kClosePcScreenValuelessArgCount), - - // kActionDump - Action("dump", dumpValueArguments, dumpValueShortArguments, kDumpValueArgCount, - nullptr, nullptr, kDumpValuelessArgCount), - - // kActionPrintPit - Action("print-pit", nullptr, nullptr, kPrintPitValueArgCount, - nullptr, nullptr, kPrintPitValuelessArgCount), - - // kActionVersion - Action("version", nullptr, nullptr, kVersionValueArgCount, - nullptr, nullptr, kVersionValuelessArgCount), - - // kActionHelp - Action("help", nullptr, nullptr, kHelpValueArgCount, - nullptr, nullptr, kHelpValuelessArgCount), - - // kActionDetect - Action("detect", nullptr, nullptr, kDetectValueArgCount, - nullptr, nullptr, kDetectValuelessArgCount), - - // kActionDownloadPit - Action("download-pit", downloadPitValueArguments, downloadPitValueShortArguments, kDownloadPitValueArgCount, - nullptr, nullptr, kDownloadPitValuelessArgCount), - - // kActionInfo - Action("info", nullptr, nullptr, kInfoValueArgCount, - nullptr, nullptr, kInfoValuelessArgCount) -}; - -bool Interface::GetArguments(int argc, char **argv, map<string, string>& argumentMap, int *actionIndex) +void populateActionMap(void) { - if (argc < 2) - { - Print(usage, version); - return (false); - } - - const char *actionName = argv[1]; - *actionIndex = -1; - - for (int i = 0; i < kActionCount; i++) - { - if (actions[i].name == actionName) - { - *actionIndex = i; - break; - } - } - - if (*actionIndex < 0) - { - Print("Unknown action \"%s\"\n\n", actionName); - Print(usage, version); - return (false); - } - - const Action& action = actions[*actionIndex]; - - for (int argIndex = 2; argIndex < argc; argIndex++) - { - if (*(argv[argIndex]) != '-') - { - Print(usage, version); - return (false); - } - - string argumentName = (char *)(argv[argIndex] + 1); - - // Check if the argument is a valid valueless argument - bool valid = false; - - for (unsigned int i = 0; i < action.valuelessArgumentCount; i++) - { - if (argumentName == action.valuelessArguments[i] || argumentName == action.valuelessShortArguments[i]) - { - argumentName = action.valuelessArguments[i]; - valid = true; - break; - } - } - - if (!valid) - { - // Check if it's a common valueless argument - for (unsigned int i = 0; i < kCommonValuelessArgCount; i++) - { - if (argumentName == commonValuelessArguments[i] || argumentName == commonValuelessShortArguments[i]) - { - argumentName = commonValuelessArguments[i]; - valid = true; - break; - } - } - } + 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); + actionMap["print-pit"] = Interface::ActionInfo(&PrintPitAction::Execute, PrintPitAction::usage); + actionMap["version"] = Interface::ActionInfo(&VersionAction::Execute, VersionAction::usage); +} - if (valid) - { - // The argument is valueless - argumentMap.insert(pair<string, string>(argumentName, "")); - continue; - } +const map<string, Interface::ActionInfo>& Interface::GetActionMap(void) +{ + if (actionMap.size() == 0) + populateActionMap(); - // Check if the argument is a valid value argument - for (unsigned int i = 0; i < action.valueArgumentCount; i++) - { - // Support for --<integer> and -<integer> parameters. - if (argumentName.length() > 1 && action.valueArguments[i] == "-%d") - { - if (atoi(argumentName.substr(1).c_str()) > 0 || argumentName == "-0") - { - valid = true; - break; - } - } - else if (action.valueArguments[i] == "%d") - { - if (atoi(argumentName.c_str()) > 0 || argumentName == "0") - { - argumentName = "-" + argumentName; - valid = true; - break; - } - } + return actionMap; +} - if (argumentName == action.valueArguments[i] || argumentName == action.valueShortArguments[i]) - { - argumentName = action.valueArguments[i]; - valid = true; - break; - } - } +void Interface::Print(const char *format, ...) +{ + va_list args; + va_start(args, format); - if (!valid) - { - // Check if it's a common value argument - for (unsigned int i = 0; i < kCommonValueArgCount; i++) - { - // Support for --<integer> and -<integer> parameters. - if (argumentName.length() > 1 && commonValueArguments[i] == "-%d") - { - if (atoi(argumentName.substr(1).c_str()) > 0 || argumentName == "-0") - { - valid = true; - break; - } - } - else if (commonValueArguments[i] == "%d") - { - if (atoi(argumentName.c_str()) > 0 || argumentName == "0") - { - argumentName = "-" + argumentName; - valid = true; - break; - } - } - - if (argumentName == commonValueArguments[i] || argumentName == commonValueShortArguments[i]) - { - argumentName = commonValueArguments[i]; - valid = true; - break; - } - } - } + vfprintf(stdout, format, args); + fflush(stdout); - if (!valid) - { - PrintError("\"%s\" is not a valid argument\n", argumentName.c_str()); - return (false); - } + va_end(args); + +} - argIndex++; +void Interface::PrintWarning(const char *format, ...) +{ + va_list args; + va_start(args, format); - if (argIndex >= argc) - { - PrintError("\"%s\" is missing a value\n", argumentName.c_str()); - return (false); - } + fprintf(stderr, "WARNING: "); + vfprintf(stderr, format, args); + fflush(stderr); - argumentMap.insert(pair<string, string>(argumentName, argv[argIndex])); + if (stdoutErrors) + { + fprintf(stdout, "WARNING: "); + vfprintf(stdout, format, args); + fflush(stdout); } - return (true); + va_end(args); } -void Interface::Print(const char *format, ...) +void Interface::PrintWarningSameLine(const char *format, ...) { va_list args; va_start(args, format); - vfprintf(stdout, format, args); - fflush(stdout); + vfprintf(stderr, format, args); + fflush(stderr); + + if (stdoutErrors) + { + vfprintf(stdout, format, args); + fflush(stdout); + } va_end(args); - } void Interface::PrintError(const char *format, ...) @@ -400,28 +166,33 @@ void Interface::PrintErrorSameLine(const char *format, ...) void Interface::PrintVersion(void) { - Print("%s\n", version); + Interface::Print("%s\n", version); } void Interface::PrintUsage(void) { - Print(usage); + const map<string, ActionInfo>& actionMap = Interface::GetActionMap(); + + Interface::Print(actionUsage); + + for (map<string, ActionInfo>::const_iterator it = actionMap.begin(); it != actionMap.end(); it++) + Interface::Print("\n%s", it->second.usage); } void Interface::PrintReleaseInfo(void) { - Print(releaseInfo, version); + Interface::Print(releaseInfo, version); } void Interface::PrintFullInfo(void) { - Print(releaseInfo, version); - Print(extraInfo); + Interface::Print(releaseInfo, version); + Interface::Print(extraInfo); } void Interface::PrintDeviceDetectionFailed(void) { - Print("Failed to detect compatible download-mode device.\n"); + Interface::PrintError("Failed to detect compatible download-mode device.\n"); } void Interface::PrintPit(const PitData *pitData) @@ -442,34 +213,107 @@ void Interface::PrintPit(const PitData *pitData) const PitEntry *entry = pitData->GetEntry(i); Interface::Print("\n\n--- Entry #%d ---\n", i); - Interface::Print("Unused: %s\n", (entry->GetUnused()) ? "Yes" : "No"); + Interface::Print("Binary Type: %d (", entry->GetBinaryType()); - const char *chipIdentifierText = "Unknown"; + switch (entry->GetBinaryType()) + { + case PitEntry::kBinaryTypeApplicationProcessor: + Interface::Print("AP"); + break; - Interface::Print("Chip Identifier: %d (%s)\n", entry->GetChipIdentifier()); + case PitEntry::kBinaryTypeCommunicationProcessor: + Interface::Print("CP"); + break; - Interface::Print("Partition Identifier: %d\n", entry->GetPartitionIdentifier()); + default: + Interface::Print("Unknown"); + break; + } - Interface::Print("Partition Flags: %d (", entry->GetPartitionFlags()); + Interface::Print(")\n"); - if (entry->GetPartitionFlags() & PitEntry::kPartitionFlagWrite) - Interface::Print("R/W"); + Interface::Print("Device Type: %d (", entry->GetDeviceType()); + + switch (entry->GetDeviceType()) + { + case PitEntry::kDeviceTypeOneNand: + Interface::Print("OneNAND"); + break; + + case PitEntry::kDeviceTypeFile: + Interface::Print("File/FAT"); + break; + + case PitEntry::kDeviceTypeMMC: + Interface::Print("MMC"); + break; + + case PitEntry::kDeviceTypeAll: + Interface::Print("All (?)"); + break; + + default: + Interface::Print("Unknown"); + break; + } + + Interface::Print(")\n"); + + Interface::Print("Identifier: %d\n", entry->GetIdentifier()); + + Interface::Print("Attributes: %d (", entry->GetAttributes()); + + if (entry->GetAttributes() & PitEntry::kAttributeSTL) + Interface::Print("STL "); + + if (entry->GetAttributes() & PitEntry::kAttributeWrite) + Interface::Print("Read/Write"); else - Interface::Print("R"); + Interface::Print("Read-Only"); Interface::Print(")\n"); - Interface::Print("Unknown 1: %d\n", entry->GetUnknown1()); + Interface::Print("Update Attributes: %d", entry->GetUpdateAttributes()); + + if (entry->GetUpdateAttributes()) + { + Interface::Print(" ("); + + if (entry->GetUpdateAttributes() & PitEntry::kUpdateAttributeFota) + { + if (entry->GetUpdateAttributes() & PitEntry::kUpdateAttributeSecure) + Interface::Print("FOTA, Secure"); + else + Interface::Print("FOTA"); + } + else + { + if (entry->GetUpdateAttributes() & PitEntry::kUpdateAttributeSecure) + Interface::Print("Secure"); + } + + Interface::Print(")\n"); + } + else + { + Interface::Print("\n"); + } - Interface::Print("Partition Block Size: %d\n", entry->GetPartitionBlockSize()); - Interface::Print("Partition Block Count: %d\n", entry->GetPartitionBlockCount()); + Interface::Print("Partition Block Size: %d\n", entry->GetBlockSize()); + Interface::Print("Partition Block Count: %d\n", entry->GetBlockCount()); - Interface::Print("Unknown 2: %d\n", entry->GetUnknown2()); - Interface::Print("Unknown 3: %d\n", entry->GetUnknown3()); + Interface::Print("File Offset (Obsolete): %d\n", entry->GetFileOffset()); + Interface::Print("File Size (Obsolete): %d\n", entry->GetFileSize()); Interface::Print("Partition Name: %s\n", entry->GetPartitionName()); - Interface::Print("Filename: %s\n", entry->GetFilename()); + Interface::Print("Flash Filename: %s\n", entry->GetFlashFilename()); + Interface::Print("FOTA Filename: %s\n", entry->GetFotaFilename()); } Interface::Print("\n"); } + +void Interface::SetStdoutErrors(bool enabled) +{ + stdoutErrors = enabled; +} diff --git a/heimdall/source/Interface.h b/heimdall/source/Interface.h index ddb7f55..ab4b538 100644 --- a/heimdall/source/Interface.h +++ b/heimdall/source/Interface.h @@ -28,276 +28,55 @@ // libpit #include "libpit.h" +// Heimdall +#include "Heimdall.h" + using namespace std; using namespace libpit; namespace Heimdall { - struct Action + namespace Interface { - public: - - string name; - - string *valueArguments; - string *valueShortArguments; - unsigned int valueArgumentCount; + typedef int (*ActionExecuteFunction)(int, char **); - string *valuelessArguments; - string *valuelessShortArguments; - unsigned int valuelessArgumentCount; + typedef struct ActionInfo + { + ActionExecuteFunction executeFunction; + const char *usage; - Action(const char *name, string *valueArguments, string *valueShortArguments, unsigned int valueArgumentCount, - string *valuelessArguments, string *valuelessShortArguments, unsigned int valuelessArgumentCount) + ActionInfo() { - this->name = name; - - this->valueArguments = valueArguments; - this->valueShortArguments = valueShortArguments; - this->valueArgumentCount = valueArgumentCount; - - this->valuelessArguments = valuelessArguments; - this->valuelessShortArguments = valuelessShortArguments; - this->valuelessArgumentCount = valuelessArgumentCount; + executeFunction = nullptr; + usage = nullptr; } - }; - - class Interface - { - public: - - // Actions - enum - { - kActionFlash = 0, - kActionClosePcScreen, - kActionDump, - kActionPrintPit, - kActionVersion, - kActionHelp, - kActionDetect, - kActionDownloadPit, - kActionInfo, - kActionCount - }; - // Flash value arguments - enum + ActionInfo(ActionExecuteFunction executeFunction, const char *usage) { - kFlashValueArgPit, - kFlashValueArgFactoryFs, - kFlashValueArgCache, - kFlashValueArgDatabaseData, - kFlashValueArgPrimaryBootloader, - kFlashValueArgSecondaryBootloader, - kFlashValueArgSecondaryBootloaderBackup, - kFlashValueArgParam, - kFlashValueArgKernel, - kFlashValueArgRecovery, - kFlashValueArgEfs, - kFlashValueArgModem, - - kFlashValueArgNormalBoot, - kFlashValueArgSystem, - kFlashValueArgUserData, - kFlashValueArgFota, - kFlashValueArgHidden, - kFlashValueArgMovinand, - kFlashValueArgData, - kFlashValueArgUms, - kFlashValueArgEmmc, - - kFlashValueArgPartitionIndex, - - kFlashValueArgCount - }; - - // Flash valueless arguments - enum - { - kFlashValuelessArgRepartition = 0, - - kFlashValuelessArgCount - }; - - // Close PC Screen value arguments - enum - { - kClosePcScreenValueArgCount = 0 - }; - - // Close PC Screen valueless arguments - enum - { - kClosePcScreenValuelessArgCount = 0 - }; - - // Dump value arguments - enum - { - kDumpValueArgChipType = 0, - kDumpValueArgChipId, - kDumpValueArgOutput, - - kDumpValueArgCount - }; - - // Dump valueless arguments - enum - { - kDumpValuelessArgCount = 0 - }; - - // Print PIT value arguments - enum - { - kPrintPitValueArgCount = 0 - }; - - // Print PIT valueless arguments - enum - { - kPrintPitValuelessArgCount = 0 - }; - - // Version value arguments - enum - { - kVersionValueArgCount = 0 - }; - - // Version valueless arguments - enum - { - kVersionValuelessArgCount = 0 - }; - - // Help value arguments - enum - { - kHelpValueArgCount = 0 - }; - - // Help valueless arguments - enum - { - kHelpValuelessArgCount = 0 - }; - - // Info value arguments - enum - { - kInfoValueArgCount = 0 - }; - - // Info valueless arguments - enum - { - kInfoValuelessArgCount = 0 - }; - - // Detect value arguments - enum - { - kDetectValueArgCount = 0 - }; - - // Detect valueless arguments - enum - { - kDetectValuelessArgCount = 0 - }; - - // Download PIT value arguments - enum - { - kDownloadPitValueArgOutput = 0, - kDownloadPitValueArgCount - }; - - // Download PIT valueless arguments - enum - { - kDownloadPitValuelessArgCount = 0 - }; - - // Common value arguments - enum - { - kCommonValueArgDelay = 0, - - kCommonValueArgCount - }; - - // Comon valueless arguments - enum - { - kCommonValuelessArgVerbose = 0, - kCommonValuelessArgNoReboot, - kCommonValuelessArgStdoutErrors, - - kCommonValuelessArgCount - }; - - private: - - static bool stdoutErrors; - - static const char *version; - static const char *usage; - static const char *releaseInfo; - static const char *extraInfo; - - // Flash arguments - static string flashValueArguments[kFlashValueArgCount]; - static string flashValueShortArguments[kFlashValueArgCount]; - - static string flashValuelessArguments[kFlashValuelessArgCount]; - static string flashValuelessShortArguments[kFlashValuelessArgCount]; - - // Download PIT arguments - static string downloadPitValueArguments[kDownloadPitValueArgCount]; - static string downloadPitValueShortArguments[kDownloadPitValueArgCount]; - - // Dump arguments - static string dumpValueArguments[kDumpValueArgCount]; - static string dumpValueShortArguments[kDumpValueArgCount]; - - public: - - // Common arguments - static string commonValueArguments[kCommonValueArgCount]; - static string commonValueShortArguments[kCommonValueArgCount]; - - static string commonValuelessArguments[kCommonValuelessArgCount]; - static string commonValuelessShortArguments[kCommonValuelessArgCount]; - - static Action actions[kActionCount]; + this->executeFunction = executeFunction; + this->usage = usage; + } - static bool GetArguments(int argc, char **argv, map<string, string>& argumentMap, int *actionIndex); + } ActionInfo; - static void Print(const char *format, ...); - static void PrintError(const char *format, ...); - static void PrintErrorSameLine(const char *format, ...); + const map<string, ActionInfo>& GetActionMap(void); - static void PrintVersion(void); - static void PrintUsage(void); - static void PrintReleaseInfo(void); - static void PrintFullInfo(void); + void Print(const char *format, ...); + void PrintWarning(const char *format, ...); + void PrintWarningSameLine(const char *format, ...); + void PrintError(const char *format, ...); + void PrintErrorSameLine(const char *format, ...); - static void PrintDeviceDetectionFailed(void); + void PrintVersion(void); + void PrintUsage(void); + void PrintReleaseInfo(void); + void PrintFullInfo(void); - static void PrintPit(const PitData *pitData); + void PrintDeviceDetectionFailed(void); - static string& GetPitArgument(void) - { - return (flashValueArguments[kFlashValueArgPit]); - } + void PrintPit(const PitData *pitData); - static void SetStdoutErrors(bool enabled) - { - stdoutErrors = enabled; - } + void SetStdoutErrors(bool enabled); }; } diff --git a/heimdall/source/Packet.h b/heimdall/source/Packet.h index 41ce081..9f47e33 100644 --- a/heimdall/source/Packet.h +++ b/heimdall/source/Packet.h @@ -50,7 +50,7 @@ namespace Heimdall delete [] data;
}
- int GetSize(void) const
+ unsigned int GetSize(void) const
{
return (size);
}
diff --git a/heimdall/source/PrintPitAction.cpp b/heimdall/source/PrintPitAction.cpp new file mode 100644 index 0000000..c520d1c --- /dev/null +++ b/heimdall/source/PrintPitAction.cpp @@ -0,0 +1,159 @@ +/* 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 <stdio.h> + +// Heimdall +#include "Arguments.h" +#include "BridgeManager.h" +#include "Heimdall.h" +#include "Interface.h" +#include "PrintPitAction.h" + +using namespace Heimdall; + +const char *PrintPitAction::usage = "Action: print-pit\n\ +Arguments: [--file <filename>] [--verbose] [--no-reboot] [--stdout-errors]\n\ + [--delay <ms>]\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"; + +int PrintPitAction::Execute(int argc, char **argv) +{ + // Handle arguments + + map<string, ArgumentType> argumentTypes; + argumentTypes["file"] = 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(PrintPitAction::usage); + return (0); + } + + const StringArgument *fileArgument = static_cast<const StringArgument *>(arguments.GetArgument("file")); + const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(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 file (if specified). + + FILE *localPitFile = nullptr; + + if (fileArgument) + { + const char *filename = fileArgument->GetValue().c_str(); + + localPitFile = fopen(filename, "rb"); + + if (!localPitFile) + { + Interface::PrintError("Failed to open file \"%s\"\n", filename); + return (1); + } + } + + // Info + + Interface::PrintReleaseInfo(); + Sleep(1000); + + if (localPitFile) + { + // Print PIT from file; there's no need for a BridgeManager. + + fseek(localPitFile, 0, SEEK_END); + long localPitFileSize = ftell(localPitFile); + rewind(localPitFile); + + // Load the local pit file into memory. + unsigned char *pitFileBuffer = new unsigned char[localPitFileSize]; + size_t dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile); // dataRead is discarded, it's here to remove warnings. + fclose(localPitFile); + + PitData *pitData = new PitData(); + pitData->Unpack(pitFileBuffer); + + delete [] pitFileBuffer; + + Interface::PrintPit(pitData); + delete pitData; + + return (0); + } + else + { + // Print PIT from a device. + + int communicationDelay = BridgeManager::kCommunicationDelayDefault; + + if (communicationDelayArgument) + communicationDelay = communicationDelayArgument->GetValue(); + + BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + + if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession()) + { + delete bridgeManager; + return (1); + } + + unsigned char *devicePit; + bool success = bridgeManager->DownloadPitFile(&devicePit) != 0; + + if (success) + { + PitData *pitData = new PitData(); + + if (pitData->Unpack(devicePit)) + { + Interface::PrintPit(pitData); + } + else + { + Interface::PrintError("Failed to unpack device's PIT file!\n"); + success = false; + } + + delete pitData; + } + + delete [] devicePit; + + if (!bridgeManager->EndSession(reboot)) + success = false; + + delete bridgeManager; + + return (success ? 0 : 1); + } +} diff --git a/heimdall/source/PrintPitAction.h b/heimdall/source/PrintPitAction.h new file mode 100644 index 0000000..5bbfd3d --- /dev/null +++ b/heimdall/source/PrintPitAction.h @@ -0,0 +1,34 @@ +/* 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 PRINTPITACTION_H +#define PRINTPITACTION_H + +namespace Heimdall +{ + namespace PrintPitAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/ResponsePacket.h b/heimdall/source/ResponsePacket.h index e8678cf..9c5c2cc 100644 --- a/heimdall/source/ResponsePacket.h +++ b/heimdall/source/ResponsePacket.h @@ -32,11 +32,11 @@ namespace Heimdall enum
{
- kResponseTypeSendFilePart = 0x00,
- kResponseTypeBeginSession = 0x64,
- kResponseTypePitFile = 0x65,
- kResponseTypeFileTransfer = 0x66,
- kResponseTypeEndSession = 0x67
+ kResponseTypeSendFilePart = 0x00,
+ kResponseTypeSessionSetup = 0x64,
+ kResponseTypePitFile = 0x65,
+ kResponseTypeFileTransfer = 0x66,
+ kResponseTypeEndSession = 0x67
};
private:
diff --git a/heimdall/source/SendFilePartPacket.h b/heimdall/source/SendFilePartPacket.h index 8f6e27f..066aacb 100644 --- a/heimdall/source/SendFilePartPacket.h +++ b/heimdall/source/SendFilePartPacket.h @@ -34,12 +34,7 @@ namespace Heimdall {
public:
- enum
- {
- kDefaultPacketSize = 131072
- };
-
- SendFilePartPacket(FILE *file, int size = SendFilePartPacket::kDefaultPacketSize) : OutboundPacket(size)
+ SendFilePartPacket(FILE *file, int size) : OutboundPacket(size)
{
memset(data, 0, size);
diff --git a/heimdall/source/SessionSetupPacket.h b/heimdall/source/SessionSetupPacket.h new file mode 100644 index 0000000..9a91684 --- /dev/null +++ b/heimdall/source/SessionSetupPacket.h @@ -0,0 +1,74 @@ +/* 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 SESSIONSETUPPACKET_H +#define SESSIONSETUPPACKET_H + +// Heimdall +#include "ControlPacket.h" + +namespace Heimdall +{ + class SessionSetupPacket : public ControlPacket + { + public: + + enum + { + kBeginSession = 0, + kDeviceType = 1, // ? + kTotalBytes = 2, + //kEnableSomeSortOfFlag = 3, + kFilePartSize = 5 + }; + + private: + + unsigned int request; + + protected: + + enum + { + kDataSize = ControlPacket::kDataSize + 4 + }; + + public: + + SessionSetupPacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeSession) + { + this->request = request; + } + + unsigned int GetRequest(void) const + { + return (request); + } + + void Pack(void) + { + ControlPacket::Pack(); + + PackInteger(ControlPacket::kDataSize, request); + } + }; +} + +#endif diff --git a/heimdall/source/SessionSetupResponse.h b/heimdall/source/SessionSetupResponse.h new file mode 100644 index 0000000..f7c1175 --- /dev/null +++ b/heimdall/source/SessionSetupResponse.h @@ -0,0 +1,58 @@ +/* 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 SESSIONSETUPRESPONSE_H +#define SESSIONSETUPRESPONSE_H + +// Heimdall +#include "ResponsePacket.h" + +namespace Heimdall +{ + class SessionSetupResponse : public ResponsePacket + { + private: + + unsigned int result; + + public: + + SessionSetupResponse() : ResponsePacket(ResponsePacket::kResponseTypeSessionSetup) + { + } + + unsigned int GetResult(void) const + { + return (result); + } + + bool Unpack(void) + { + if (!ResponsePacket::Unpack()) + return (false); + + result = UnpackInteger(ResponsePacket::kDataSize); + + return (true); + } + }; +} + +#endif diff --git a/heimdall/source/TotalBytesPacket.h b/heimdall/source/TotalBytesPacket.h new file mode 100644 index 0000000..60190ec --- /dev/null +++ b/heimdall/source/TotalBytesPacket.h @@ -0,0 +1,56 @@ +/* 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 TOTALBYTESSPACKET_H +#define TOTALBYTESPACKET_H + +// Heimdall +#include "SessionSetupPacket.h" + +namespace Heimdall +{ + class TotalBytesPacket : public SessionSetupPacket + { + private: + + unsigned int totalBytes; + + public: + + TotalBytesPacket(unsigned int totalBytes) : SessionSetupPacket(SessionSetupPacket::kTotalBytes) + { + this->totalBytes = totalBytes; + } + + unsigned int GetTotalBytes(void) const + { + return (totalBytes); + } + + void Pack(void) + { + SessionSetupPacket::Pack(); + + PackInteger(SessionSetupPacket::kDataSize, totalBytes); + } + }; +} + +#endif diff --git a/heimdall/source/Utility.cpp b/heimdall/source/Utility.cpp new file mode 100644 index 0000000..1dba264 --- /dev/null +++ b/heimdall/source/Utility.cpp @@ -0,0 +1,82 @@ +/* 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/C++ Standard Library +#include <cerrno> +#include <limits.h> +#include <stdlib.h> + +// Heimdall +#include "Heimdall.h" +#include "Utility.h" + +using namespace Heimdall; + +NumberParsingStatus Utility::ParseInt(int &intValue, const char *string, int base) +{ + errno = 0; + + char *end; + long longValue = strtol(string, &end, base); + + if (*string == '\0' || *end != '\0') + { + return (kNumberParsingStatusInconvertible); + } + else if (errno == ERANGE) + { + intValue = (longValue == LONG_MAX) ? INT_MAX : INT_MIN; + return (kNumberParsingStatusRangeError); + } + else if (longValue > INT_MAX) + { + intValue = INT_MAX; + return (kNumberParsingStatusRangeError); + } + else if (longValue < INT_MIN) + { + intValue = INT_MIN; + return (kNumberParsingStatusRangeError); + } + + intValue = longValue; + return (kNumberParsingStatusSuccess); +} + +NumberParsingStatus Utility::ParseUnsignedInt(unsigned int &uintValue, const char *string, int base) +{ + errno = 0; + + char *end; + unsigned long ulongValue = strtoul(string, &end, base); + + if (*string == '\0' || *end != '\0') + { + return kNumberParsingStatusInconvertible; + } + else if (errno == ERANGE || ulongValue > INT_MAX) + { + uintValue = UINT_MAX; + return (kNumberParsingStatusRangeError); + } + + uintValue = ulongValue; + return (kNumberParsingStatusSuccess); +} diff --git a/heimdall/source/Utility.h b/heimdall/source/Utility.h new file mode 100644 index 0000000..4d3f3e4 --- /dev/null +++ b/heimdall/source/Utility.h @@ -0,0 +1,40 @@ +/* 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 UTILITY_H +#define UTILITY_H + +namespace Heimdall +{ + typedef enum + { + kNumberParsingStatusSuccess = 0, + kNumberParsingStatusRangeError, + kNumberParsingStatusInconvertible + } NumberParsingStatus; + + namespace Utility + { + NumberParsingStatus ParseInt(int &intValue, const char *string, int base = 0); + NumberParsingStatus ParseUnsignedInt(unsigned int &uintValue, const char *string, int base = 0); + } +} + +#endif diff --git a/heimdall/source/VersionAction.cpp b/heimdall/source/VersionAction.cpp new file mode 100644 index 0000000..d76c1da --- /dev/null +++ b/heimdall/source/VersionAction.cpp @@ -0,0 +1,35 @@ +/* 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.*/ + +// Heimdall +#include "Heimdall.h" +#include "Interface.h" +#include "VersionAction.h" + +using namespace Heimdall; + +const char *VersionAction::usage = "Action: version\n\ +Description: Displays the version number of this binary.\n"; + +int VersionAction::Execute(int argc, char **argv) +{ + Interface::PrintVersion(); + return (0); +} diff --git a/heimdall/source/VersionAction.h b/heimdall/source/VersionAction.h new file mode 100644 index 0000000..fa9035c --- /dev/null +++ b/heimdall/source/VersionAction.h @@ -0,0 +1,34 @@ +/* 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 VERSIONACTION_H +#define VERSIONACTION_H + +namespace Heimdall +{ + namespace VersionAction + { + extern const char *usage; + + int Execute(int argc, char **argv); + }; +} + +#endif diff --git a/heimdall/source/main.cpp b/heimdall/source/main.cpp index db7de1c..41d7a3c 100644 --- a/heimdall/source/main.cpp +++ b/heimdall/source/main.cpp @@ -28,782 +28,28 @@ #include "libpit.h" // Heimdall -#include "BridgeManager.h" -#include "SetupSessionPacket.h" -#include "SetupSessionResponse.h" -#include "EndModemFileTransferPacket.h" -#include "EndPhoneFileTransferPacket.h" +#include "Heimdall.h" +#include "HelpAction.h" #include "Interface.h" using namespace std; using namespace Heimdall; -// Known partitions -enum -{ - kKnownPartitionPit = 0, - kKnownPartitionFactoryFs, - kKnownPartitionCache, - kKnownPartitionDatabaseData, - kKnownPartitionPrimaryBootloader, - kKnownPartitionSecondaryBootloader, - kKnownPartitionSecondaryBootloaderBackup, - kKnownPartitionParam, - kKnownPartitionKernel, - kKnownPartitionRecovery, - kKnownPartitionEfs, - kKnownPartitionModem, - - kKnownPartitionNormalBoot, - kKnownPartitionSystem, - kKnownPartitionUserData, - kKnownPartitionFota, - kKnownPartitionHidden, - kKnownPartitionMovinand, - kKnownPartitionData, - kKnownPartitionUms, - kKnownPartitionEmmc, - - kKnownPartitionCount -}; - -vector<const char *> knownPartitionNames[kKnownPartitionCount]; - -struct PartitionInfo -{ - unsigned int chipIdentifier; - string partitionName; - FILE *file; - - PartitionInfo(unsigned int chipIdentifier, const char *partitionName, FILE *file) - { - this->chipIdentifier = chipIdentifier; - this->partitionName = partitionName; - this->file = file; - } -}; - -void initialiseKnownPartitionNames(void) -{ - knownPartitionNames[kKnownPartitionPit].push_back("PIT"); - knownPartitionNames[kKnownPartitionFactoryFs].push_back("FACTORYFS"); - knownPartitionNames[kKnownPartitionCache].push_back("CACHE"); - knownPartitionNames[kKnownPartitionDatabaseData].push_back("DBDATAFS"); - - knownPartitionNames[kKnownPartitionPrimaryBootloader].push_back("IBL+PBL"); - knownPartitionNames[kKnownPartitionPrimaryBootloader].push_back("BOOT"); - - knownPartitionNames[kKnownPartitionSecondaryBootloader].push_back("SBL"); - knownPartitionNames[kKnownPartitionSecondaryBootloader].push_back("SBL1"); - - knownPartitionNames[kKnownPartitionSecondaryBootloaderBackup].push_back("SBL2"); - knownPartitionNames[kKnownPartitionParam].push_back("PARAM"); - knownPartitionNames[kKnownPartitionKernel].push_back("KERNEL"); - knownPartitionNames[kKnownPartitionRecovery].push_back("RECOVERY"); - knownPartitionNames[kKnownPartitionEfs].push_back("EFS"); - knownPartitionNames[kKnownPartitionModem].push_back("MODEM"); - - knownPartitionNames[kKnownPartitionNormalBoot].push_back("NORMALBOOT"); - knownPartitionNames[kKnownPartitionSystem].push_back("SYSTEM"); - knownPartitionNames[kKnownPartitionUserData].push_back("USERDATA"); - knownPartitionNames[kKnownPartitionFota].push_back("FOTA"); - knownPartitionNames[kKnownPartitionHidden].push_back("HIDDEN"); - knownPartitionNames[kKnownPartitionMovinand].push_back("MOVINAND"); - knownPartitionNames[kKnownPartitionData].push_back("DATAFS"); - knownPartitionNames[kKnownPartitionUms].push_back("UMS.EN"); - knownPartitionNames[kKnownPartitionEmmc].push_back("GANG"); -} - -bool isKnownPartition(const char *partitionName, unsigned int knownPartitionIndex) -{ - for (unsigned int i = 0; i < knownPartitionNames[knownPartitionIndex].size(); i++) - { - if (strcmp(partitionName, knownPartitionNames[knownPartitionIndex][i]) == 0) - return (true); - } - - return (false); -} - -bool isKnownBootPartition(const char *partitionName) -{ - return (isKnownPartition(partitionName, kKnownPartitionPrimaryBootloader) || - isKnownPartition(partitionName, kKnownPartitionSecondaryBootloader) || - isKnownPartition(partitionName, kKnownPartitionSecondaryBootloaderBackup) || - isKnownPartition(partitionName, kKnownPartitionParam) || - isKnownPartition(partitionName, kKnownPartitionNormalBoot)); -} - -bool openFiles(const map<string, string>& argumentMap, map<string, FILE *>& argumentFileMap) -{ - map<string, string>::const_iterator it = argumentMap.begin(); - - for (it = argumentMap.begin(); it != argumentMap.end(); it++) - { - bool isFileArgument = false; - - int partitionIndex = atoi(it->first.substr(it->first.find_first_not_of('-')).c_str()); - - // Was the argument a partition index? - if (partitionIndex > 0 || it->first.compare("-0") == 0) - { - isFileArgument = true; - } - else - { - // The argument wasn't a partition index, check if it's a known partition name. - for (int knownPartition = 0; knownPartition < kKnownPartitionCount; knownPartition++) - { - if (it->first == Interface::actions[Interface::kActionFlash].valueArguments[knownPartition]) - { - isFileArgument = true; - break; - } - } - } - - if (!isFileArgument) - continue; - - pair<string, FILE *> argumentFilePair; - argumentFilePair.first = it->first; - argumentFilePair.second = fopen(it->second.c_str(), "rb"); - - if (!argumentFilePair.second) - { - Interface::PrintError("Failed to open file \"%s\"\n", it->second.c_str()); - return (false); - } - - argumentFileMap.insert(argumentFilePair); - } - - return (true); -} - -bool mapFilesToPartitions(const map<string, FILE *>& argumentFileMap, const PitData *pitData, map<unsigned int, PartitionInfo>& partitionInfoMap) -{ - map<string, FILE *>::const_iterator it = argumentFileMap.begin(); - - for (it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) - { - int partitionIndex = atoi(it->first.substr(it->first.find_first_not_of('-')).c_str()); - - const PitEntry *pitEntry = nullptr; - - // Was the argument a partition index? - if (partitionIndex > 0 || it->first.compare("-0") == 0) - { - pitEntry = pitData->FindEntry(partitionIndex); - } - else - { - // The argument wasn't a partition index, so it must be a known partition name. - int knownPartition; - - for (knownPartition = 0; knownPartition < kKnownPartitionCount; knownPartition++) - { - if (it->first == Interface::actions[Interface::kActionFlash].valueArguments[knownPartition]) - break; - } - - // Check for the partition in the PIT file using all known names. - for (unsigned int i = 0; i < knownPartitionNames[knownPartition].size(); i++) - { - pitEntry = pitData->FindEntry(knownPartitionNames[knownPartition][i]); - - if (pitEntry) - break; - } - - if (!pitEntry && knownPartition == kKnownPartitionPit) - { - // NOTE: We're assuming a PIT file always has chipIdentifier zero. - PartitionInfo partitionInfo(0, knownPartitionNames[kKnownPartitionPit][0], it->second); - partitionInfoMap.insert(pair<unsigned int, PartitionInfo>(0xFFFFFFFF, partitionInfo)); - - return (true); - } - } - - if (!pitEntry) - { - Interface::PrintError("Partition corresponding to %s argument could not be located\n", it->first.c_str()); - return (false); - } - - PartitionInfo partitionInfo(pitEntry->GetChipIdentifier(), pitEntry->GetPartitionName(), it->second); - partitionInfoMap.insert(pair<unsigned int, PartitionInfo>(pitEntry->GetPartitionIdentifier(), partitionInfo)); - } - - return (true); -} - -void closeFiles(map<string, FILE *> argumentfileMap) -{ - for (map<string, FILE *>::iterator it = argumentfileMap.begin(); it != argumentfileMap.end(); it++) - fclose(it->second); - - argumentfileMap.clear(); -} - -int downloadPitFile(BridgeManager *bridgeManager, unsigned char **pitBuffer) -{ - Interface::Print("Downloading device's PIT file...\n"); - - int devicePitFileSize = bridgeManager->ReceivePitFile(pitBuffer); - - if (!*pitBuffer) - { - Interface::PrintError("Failed to download PIT file!\n"); - - return (-1); - } - - Interface::Print("PIT file download sucessful\n\n"); - return (devicePitFileSize); -} - -bool flashFile(BridgeManager *bridgeManager, unsigned int chipIdentifier, unsigned int partitionIndex, const char *partitionName, FILE *file) -{ - // PIT files need to be handled differently, try determine if the partition we're flashing to is a PIT partition. - bool isPit = false; - - for (unsigned int i = 0; i < knownPartitionNames[kKnownPartitionPit].size(); i++) - { - if (strcmp(partitionName, knownPartitionNames[kKnownPartitionPit][i]) == 0) - { - isPit = true; - break; - } - } - - if (isPit) - { - Interface::Print("Uploading %s\n", partitionName); - - if (bridgeManager->SendPitFile(file)) - { - Interface::Print("%s upload successful\n", partitionName); - return (true); - } - else - { - Interface::Print("%s upload failed!\n", partitionName); - return (false); - } - } - else - { - // Modems need to be handled differently, try determine if the partition we're flashing to is a modem partition. - bool isModem = false; - - for (unsigned int i = 0; i < knownPartitionNames[kKnownPartitionModem].size(); i++) - { - if (strcmp(partitionName, knownPartitionNames[kKnownPartitionModem][i]) == 0) - { - isModem = true; - break; - } - } - - if (isModem) - { - Interface::Print("Uploading %s\n", partitionName); - - //if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, // <-- Kies method. WARNING: Doesn't work on Galaxy Tab! - // EndPhoneFileTransferPacket::kFileModem)) - if (bridgeManager->SendFile(file, EndModemFileTransferPacket::kDestinationModem, chipIdentifier)) // <-- Odin method - { - Interface::Print("%s upload successful\n", partitionName); - return (true); - } - else - { - Interface::Print("%s upload failed!\n", partitionName); - return (false); - } - } - else - { - // We're uploading to a phone partition - Interface::Print("Uploading %s\n", partitionName); - - if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, chipIdentifier, partitionIndex)) - { - Interface::Print("%s upload successful\n", partitionName); - return (true); - } - else - { - Interface::Print("%s upload failed!\n", partitionName); - return (false); - } - } - } - - return (true); -} - -bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFileMap, bool repartition) -{ - bool success; - - // ------------- SEND TOTAL BYTES TO BE TRANSFERRED ------------- - - int totalBytes = 0; - for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) - { - if (repartition || it->first != Interface::GetPitArgument()) - { - fseek(it->second, 0, SEEK_END); - totalBytes += ftell(it->second); - rewind(it->second); - } - } - - SetupSessionPacket *deviceInfoPacket = new SetupSessionPacket(SetupSessionPacket::kTotalBytes, totalBytes); - success = bridgeManager->SendPacket(deviceInfoPacket); - delete deviceInfoPacket; - - if (!success) - { - Interface::PrintError("Failed to send total bytes device info packet!\n"); - return (false); - } - - SetupSessionResponse *deviceInfoResponse = new SetupSessionResponse(); - success = bridgeManager->ReceivePacket(deviceInfoResponse); - int deviceInfoResult = deviceInfoResponse->GetUnknown(); - delete deviceInfoResponse; - - if (!success) - { - Interface::PrintError("Failed to receive device info response!\n"); - return (false); - } - - if (deviceInfoResult != 0) - { - Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", deviceInfoResult); - return (false); - } - - // ----------------------------------------------------- - - PitData *pitData; - PitData *localPitData = nullptr; - - FILE *localPitFile = nullptr; - - // If a PIT file was passed as an argument then we must unpack it. - map<string, FILE *>::iterator it = argumentFileMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]); - - if (it != argumentFileMap.end()) - { - localPitFile = it->second; - - // Load the local pit file into memory. - unsigned char *pitFileBuffer = new unsigned char[4096]; - memset(pitFileBuffer, 0, 4096); - - fseek(localPitFile, 0, SEEK_END); - long localPitFileSize = ftell(localPitFile); - rewind(localPitFile); - - // dataRead is discarded, it's here to remove warnings. - int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile); - rewind(localPitFile); - - localPitData = new PitData(); - localPitData->Unpack(pitFileBuffer); - - delete [] pitFileBuffer; - } - - if (repartition) - { - // Use the local PIT file data. - pitData = localPitData; - } - else - { - // If we're not repartitioning then we need to retrieve the device's PIT file and unpack it. - unsigned char *pitFileBuffer; - downloadPitFile(bridgeManager, &pitFileBuffer); - - pitData = new PitData(); - pitData->Unpack(pitFileBuffer); - - delete [] pitFileBuffer; - - if (localPitData != nullptr) - { - // The user has specified a PIT without repartitioning, we should verify the local and device PIT data match! - bool pitsMatch = pitData->Matches(localPitData); - delete localPitData; - - if (!pitsMatch) - { - Interface::Print("Local and device PIT files don't match and repartition wasn't specified!\n"); - Interface::PrintError("Flash aborted!\n"); - - delete pitData; - return (false); - } - } - } - - map<unsigned int, PartitionInfo> partitionInfoMap; - - // Map the files being flashed to partitions stored in the PIT file. - if (!mapFilesToPartitions(argumentFileMap, pitData, partitionInfoMap)) - { - delete pitData; - return (false); - } - - delete pitData; - - // If we're repartitioning then we need to flash the PIT file first. - if (repartition) - { - for (map<unsigned int, PartitionInfo>::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++) - { - if (it->second.file == localPitFile) - { - PartitionInfo *partitionInfo = &(it->second); - - if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file)) - return (false); - - break; - } - } - } - - // Flash partitions not involved in the boot process second. - for (map<unsigned int, PartitionInfo>::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++) - { - if (!isKnownPartition(it->second.partitionName.c_str(), kKnownPartitionPit) && !isKnownBootPartition(it->second.partitionName.c_str())) - { - PartitionInfo *partitionInfo = &(it->second); - - if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file)) - return (false); - } - } - - // Flash boot partitions last. - for (map<unsigned int, PartitionInfo>::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++) - { - if (isKnownBootPartition(it->second.partitionName.c_str())) - { - PartitionInfo *partitionInfo = &(it->second); - - if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file)) - return (false); - } - } - - return (true); -} - int main(int argc, char **argv) { - map<string, string> argumentMap; - int actionIndex; - - if (!Interface::GetArguments(argc, argv, argumentMap, &actionIndex)) + if (argc < 2) { - Sleep(250); + Interface::PrintUsage(); return (0); } - initialiseKnownPartitionNames(); - - switch (actionIndex) - { - case Interface::kActionFlash: - if (argumentMap.find(Interface::actions[Interface::kActionFlash].valuelessArguments[Interface::kFlashValuelessArgRepartition]) != argumentMap.end() - && argumentMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]) == argumentMap.end()) - { - Interface::Print("If you wish to repartition then a PIT file must be specified.\n\n"); - Interface::PrintUsage(); - return (0); - } - - break; - - case Interface::kActionDownloadPit: - if (argumentMap.find(Interface::actions[Interface::kActionDownloadPit].valueArguments[Interface::kDownloadPitValueArgOutput]) == argumentMap.end()) - { - Interface::Print("Output file was not specified.\n\n"); - Interface::PrintUsage(); - return (0); - } - - break; - - case Interface::kActionDump: - { - if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgOutput]) == argumentMap.end()) - { - Interface::Print("Output file was not specified.\n\n"); - Interface::PrintUsage(); - return (0); - } - - if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType]) == argumentMap.end()) - { - Interface::Print("You must specify a chip type.\n\n"); - Interface::PrintUsage(); - return (0); - } - - string chipType = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType])->second; - if (!(chipType == "RAM" || chipType == "ram" || chipType == "NAND" || chipType == "nand")) - { - Interface::Print("Unknown chip type: %s.\n\n", chipType.c_str()); - Interface::PrintUsage(); - return (0); - } - - if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId]) == argumentMap.end()) - { - Interface::Print("You must specify a Chip ID.\n\n"); - Interface::PrintUsage(); - return (0); - } - - int chipId = atoi(argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId])->second.c_str()); - if (chipId < 0) - { - Interface::Print("Chip ID must be a non-negative integer.\n"); - Interface::PrintUsage(); - return (0); - } - - break; - } - - case Interface::kActionVersion: - Interface::PrintVersion(); - return (0); - - case Interface::kActionHelp: - Interface::PrintUsage(); - return (0); - - case Interface::kActionInfo: - Interface::PrintFullInfo(); - return (0); - } - - bool verbose = argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgVerbose]) != argumentMap.end(); - bool reboot = argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgNoReboot]) == argumentMap.end(); - - Interface::SetStdoutErrors(argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgStdoutErrors]) != argumentMap.end()); - - int communicationDelay = BridgeManager::kCommunicationDelayDefault; + int result = 0; + map<string, Interface::ActionInfo>::const_iterator actionIt = Interface::GetActionMap().find(argv[1]); - if (argumentMap.find(Interface::commonValueArguments[Interface::kCommonValueArgDelay]) != argumentMap.end()) - communicationDelay = atoi(argumentMap.find(Interface::commonValueArguments[Interface::kCommonValueArgDelay])->second.c_str()); - - BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); - - if (actionIndex == Interface::kActionDetect) - { - bool detected = bridgeManager->DetectDevice(); - delete bridgeManager; - - return ((detected) ? 0 : 1); - } - - Interface::PrintReleaseInfo(); - Sleep(1000); - - int initialiseResult = bridgeManager->Initialise(); - - if (initialiseResult != 0) - { - delete bridgeManager; - return ((initialiseResult == BridgeManager::kInitialiseDeviceNotDetected) ? 1 : 0); - } - - bool success; - - switch (actionIndex) - { - case Interface::kActionFlash: - { - map<string, FILE *> argumentFileMap; - - // We open the files before doing anything else to ensure they exist. - if (!openFiles(argumentMap, argumentFileMap)) - { - closeFiles(argumentFileMap); - delete bridgeManager; - - return (0); - } - - if (!bridgeManager->BeginSession()) - { - closeFiles(argumentFileMap); - delete bridgeManager; - - return (-1); - } - - bool repartition = argumentMap.find(Interface::actions[Interface::kActionFlash].valuelessArguments[Interface::kFlashValuelessArgRepartition]) != argumentMap.end(); - success = attemptFlash(bridgeManager, argumentFileMap, repartition); - - success = bridgeManager->EndSession(reboot) && success; - - closeFiles(argumentFileMap); - - break; - } - - case Interface::kActionClosePcScreen: - { - if (!bridgeManager->BeginSession()) - { - delete bridgeManager; - return (-1); - } - - Interface::Print("Attempting to close connect to pc screen...\n"); - - success = bridgeManager->EndSession(reboot); - - if (success) - Interface::Print("Attempt complete\n"); - - break; - } - - case Interface::kActionDownloadPit: - { - map<string, string>::const_iterator it = argumentMap.find(Interface::actions[Interface::kActionDownloadPit].valueArguments[Interface::kDownloadPitValueArgOutput]); - FILE *outputPitFile = fopen(it->second.c_str(), "wb"); - - if (!outputPitFile) - { - delete bridgeManager; - return (0); - } - - if (!bridgeManager->BeginSession()) - { - delete bridgeManager; - fclose(outputPitFile); - return (-1); - } - - unsigned char *pitBuffer; - int fileSize = downloadPitFile(bridgeManager, &pitBuffer); - - if (fileSize > 0) - { - success = fwrite(pitBuffer, 1, fileSize, outputPitFile) == fileSize; - fclose(outputPitFile); - - if (!success) - Interface::PrintError("Failed to write PIT data to output file.\n"); - - success = bridgeManager->EndSession(reboot) && success; - } - else - { - fclose(outputPitFile); - success = false; - bridgeManager->EndSession(reboot); - } - - delete [] pitBuffer; - - break; - } - - case Interface::kActionDump: - { - const char *outputFilename = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgOutput])->second.c_str(); - FILE *dumpFile = fopen(outputFilename, "wb"); - if (!dumpFile) - { - Interface::PrintError("Failed to open file \"%s\"\n", outputFilename); - - delete bridgeManager; - return (-1); - } - - int chipType = 0; - string chipTypeName = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType])->second; - if (chipTypeName == "NAND" || chipTypeName == "nand") - chipType = 1; - - int chipId = atoi(argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId])->second.c_str()); - - if (!bridgeManager->BeginSession()) - { - fclose(dumpFile); - - delete bridgeManager; - return (-1); - } - - success = bridgeManager->ReceiveDump(chipType, chipId, dumpFile); - - fclose(dumpFile); - - success = bridgeManager->EndSession(reboot) && success; - - break; - } - - case Interface::kActionPrintPit: - { - if (!bridgeManager->BeginSession()) - { - delete bridgeManager; - return (-1); - } - - unsigned char *devicePit; - - if (downloadPitFile(bridgeManager, &devicePit) < -1) - { - bridgeManager->EndSession(reboot); - - delete bridgeManager; - return (-1); - } - - PitData *pitData = new PitData(); - - if (pitData->Unpack(devicePit)) - { - Interface::PrintPit(pitData); - success = true; - } - else - { - Interface::PrintError("Failed to unpack device's PIT file!\n"); - success = false; - } - - delete [] devicePit; - delete pitData; - - success = bridgeManager->EndSession(reboot) && success; - - break; - } - } - - delete bridgeManager; - - return ((success) ? 0 : -1); + if (actionIt != Interface::GetActionMap().end()) + result = actionIt->second.executeFunction(argc, argv); + else + result = HelpAction::Execute(argc, argv); + + return (result); } |