From 46f2c1134d276944fb74584a61d90cc363aee7eb Mon Sep 17 00:00:00 2001 From: Benjamin Dobell Date: Sun, 5 Dec 2010 00:25:04 +1100 Subject: Removed the "Heimdall" folder and moved its contents to the root directory. --- heimdall/source/.DS_Store | Bin 0 -> 15364 bytes heimdall/source/._.DS_Store | Bin 0 -> 4096 bytes heimdall/source/._BridgeManager.cpp | Bin 0 -> 4096 bytes heimdall/source/._InterfaceManager.cpp | Bin 0 -> 4096 bytes heimdall/source/._InterfaceManager.h | Bin 0 -> 4096 bytes heimdall/source/.dirstamp | 0 heimdall/source/BeginDumpPacket.h | 72 ++ heimdall/source/BridgeManager.cpp | 1086 +++++++++++++++++++++++++ heimdall/source/BridgeManager.h | 124 +++ heimdall/source/ControlPacket.h | 71 ++ heimdall/source/DeviceInfoPacket.h | 74 ++ heimdall/source/DeviceInfoResponse.h | 58 ++ heimdall/source/DumpPartFileTransferPacket.h | 56 ++ heimdall/source/DumpPartPitFilePacket.h | 56 ++ heimdall/source/DumpResponse.h | 58 ++ heimdall/source/EndFileTransferPacket.h | 120 +++ heimdall/source/EndModemFileTransferPacket.h | 59 ++ heimdall/source/EndPhoneFileTransferPacket.h | 86 ++ heimdall/source/FileTransferPacket.h | 73 ++ heimdall/source/FlashPartFileTransferPacket.h | 65 ++ heimdall/source/FlashPartPitFilePacket.h | 56 ++ heimdall/source/Heimdall.h | 43 + heimdall/source/InboundPacket.h | 77 ++ heimdall/source/InterfaceManager.cpp | 265 ++++++ heimdall/source/InterfaceManager.h | 109 +++ heimdall/source/OutboundPacket.h | 71 ++ heimdall/source/Packet.h | 65 ++ heimdall/source/PitFilePacket.h | 73 ++ heimdall/source/PitFileResponse.h | 58 ++ heimdall/source/RebootDevicePacket.h | 64 ++ heimdall/source/ReceiveFilePartPacket.h | 49 ++ heimdall/source/ResponsePacket.h | 81 ++ heimdall/source/SendFilePartPacket.h | 63 ++ heimdall/source/SendFilePartResponse.h | 58 ++ heimdall/source/main.cpp | 660 +++++++++++++++ 35 files changed, 3850 insertions(+) create mode 100644 heimdall/source/.DS_Store create mode 100644 heimdall/source/._.DS_Store create mode 100644 heimdall/source/._BridgeManager.cpp create mode 100644 heimdall/source/._InterfaceManager.cpp create mode 100644 heimdall/source/._InterfaceManager.h create mode 100644 heimdall/source/.dirstamp create mode 100644 heimdall/source/BeginDumpPacket.h create mode 100644 heimdall/source/BridgeManager.cpp create mode 100644 heimdall/source/BridgeManager.h create mode 100644 heimdall/source/ControlPacket.h create mode 100644 heimdall/source/DeviceInfoPacket.h create mode 100644 heimdall/source/DeviceInfoResponse.h create mode 100644 heimdall/source/DumpPartFileTransferPacket.h create mode 100644 heimdall/source/DumpPartPitFilePacket.h create mode 100644 heimdall/source/DumpResponse.h create mode 100644 heimdall/source/EndFileTransferPacket.h create mode 100644 heimdall/source/EndModemFileTransferPacket.h create mode 100644 heimdall/source/EndPhoneFileTransferPacket.h create mode 100644 heimdall/source/FileTransferPacket.h create mode 100644 heimdall/source/FlashPartFileTransferPacket.h create mode 100644 heimdall/source/FlashPartPitFilePacket.h create mode 100644 heimdall/source/Heimdall.h create mode 100644 heimdall/source/InboundPacket.h create mode 100644 heimdall/source/InterfaceManager.cpp create mode 100644 heimdall/source/InterfaceManager.h create mode 100644 heimdall/source/OutboundPacket.h create mode 100644 heimdall/source/Packet.h create mode 100644 heimdall/source/PitFilePacket.h create mode 100644 heimdall/source/PitFileResponse.h create mode 100644 heimdall/source/RebootDevicePacket.h create mode 100644 heimdall/source/ReceiveFilePartPacket.h create mode 100644 heimdall/source/ResponsePacket.h create mode 100644 heimdall/source/SendFilePartPacket.h create mode 100644 heimdall/source/SendFilePartResponse.h create mode 100644 heimdall/source/main.cpp (limited to 'heimdall/source') diff --git a/heimdall/source/.DS_Store b/heimdall/source/.DS_Store new file mode 100644 index 0000000..b244d9f Binary files /dev/null and b/heimdall/source/.DS_Store differ diff --git a/heimdall/source/._.DS_Store b/heimdall/source/._.DS_Store new file mode 100644 index 0000000..338bd7b Binary files /dev/null and b/heimdall/source/._.DS_Store differ diff --git a/heimdall/source/._BridgeManager.cpp b/heimdall/source/._BridgeManager.cpp new file mode 100644 index 0000000..5b4b4a0 Binary files /dev/null and b/heimdall/source/._BridgeManager.cpp differ diff --git a/heimdall/source/._InterfaceManager.cpp b/heimdall/source/._InterfaceManager.cpp new file mode 100644 index 0000000..a322a67 Binary files /dev/null and b/heimdall/source/._InterfaceManager.cpp differ diff --git a/heimdall/source/._InterfaceManager.h b/heimdall/source/._InterfaceManager.h new file mode 100644 index 0000000..a322a67 Binary files /dev/null and b/heimdall/source/._InterfaceManager.h differ diff --git a/heimdall/source/.dirstamp b/heimdall/source/.dirstamp new file mode 100644 index 0000000..e69de29 diff --git a/heimdall/source/BeginDumpPacket.h b/heimdall/source/BeginDumpPacket.h new file mode 100644 index 0000000..4bd6d88 --- /dev/null +++ b/heimdall/source/BeginDumpPacket.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2010 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 BEGINDUMPPACKET_H +#define BEGINDUMPPACKET_H + +// Heimdall +#include "FileTransferPacket.h" + +namespace Heimdall +{ + class BeginDumpPacket : public FileTransferPacket + { + public: + + enum + { + kChipTypeRam = 0, + kChipTypeNand = 1 + }; + + private: + + unsigned int chipType; + unsigned int chipId; + + public: + + BeginDumpPacket(unsigned int chipType, unsigned int chipId) : FileTransferPacket(FileTransferPacket::kRequestDump) + { + this->chipType = chipType; + this->chipId = chipId; + } + + unsigned int GetChipType(void) const + { + return (chipType); + } + + unsigned int GetChipId(void) const + { + return (chipId); + } + + virtual void Pack(void) + { + FileTransferPacket::Pack(); + + PackInteger(FileTransferPacket::kDataSize, chipType); + PackInteger(FileTransferPacket::kDataSize + 4, chipId); + } + }; +} + +#endif diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp new file mode 100644 index 0000000..0b94dfb --- /dev/null +++ b/heimdall/source/BridgeManager.cpp @@ -0,0 +1,1086 @@ +/* Copyright (c) 2010 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 + +// libusb +#include + +// Heimdall +#include "BeginDumpPacket.h" +#include "BridgeManager.h" +#include "DumpPartFileTransferPacket.h" +#include "DumpPartPitFilePacket.h" +#include "DumpResponse.h" +#include "EndModemFileTransferPacket.h" +#include "EndPhoneFileTransferPacket.h" +#include "FileTransferPacket.h" +#include "FlashPartFileTransferPacket.h" +#include "FlashPartPitFilePacket.h" +#include "InboundPacket.h" +#include "InterfaceManager.h" +#include "OutboundPacket.h" +#include "PitFilePacket.h" +#include "PitFileResponse.h" +#include "ReceiveFilePartPacket.h" +#include "RebootDevicePacket.h" +#include "ResponsePacket.h" +#include "SendFilePartPacket.h" +#include "SendFilePartResponse.h" + +// Future versions of libusb will use usb_interface instead of interface. +#define usb_interface interface + +#define CLASS_CDC 0x0A + +using namespace Heimdall; + +const DeviceIdentifier BridgeManager::supportedDevices[BridgeManager::kSupportedDeviceCount] = { + DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidGalaxySDownloadMode)/*, + DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidGalaxySInternational), + DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidGalaxySNewInternational), + DeviceIdentifier(BridgeManager::kVidSamsung, BridgeManager::kPidVibrantCanadaBell)*/ +}; + +enum +{ + kMaxSequenceLength = 800 +}; + +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() +{ + if (interfaceIndex >= 0) + libusb_release_interface(deviceHandle, interfaceIndex); + +#ifdef OS_LINUX + + if (detachedDriver) + { + InterfaceManager::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); +} + +bool BridgeManager::Initialise(void) +{ + // Initialise libusb-1.0 + int result = libusb_init(&libusbContext); + if (result != LIBUSB_SUCCESS) + { + InterfaceManager::PrintError("Failed to initialise libusb. Error: %i\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) + { + heimdallDevice = devices[deviceIndex]; + libusb_ref_device(heimdallDevice); + break; + } + } + + if (heimdallDevice) + break; + } + + libusb_free_device_list(devices, deviceCount); + + if (!heimdallDevice) + { + InterfaceManager::PrintError("Failed to detect compatible device\n"); + return (false); + } + + result = libusb_open(heimdallDevice, &deviceHandle); + if (result != LIBUSB_SUCCESS) + { + InterfaceManager::PrintError("Failed to access device. Error: %i\n", result); + return (false); + } + + libusb_device_descriptor deviceDescriptor; + result = libusb_get_device_descriptor(heimdallDevice, &deviceDescriptor); + if (result != LIBUSB_SUCCESS) + { + InterfaceManager::PrintError("Failed to retrieve device description\n"); + return (false); + } + + if (verbose) + { + unsigned char stringBuffer[128]; + if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iManufacturer, + stringBuffer, 128) >= 0) + { + InterfaceManager::Print(" Manufacturer: \"%s\"\n", stringBuffer); + } + + if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iProduct, + stringBuffer, 128) >= 0) + { + InterfaceManager::Print(" Product: \"%s\"\n", stringBuffer); + } + + if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iSerialNumber, + stringBuffer, 128) >= 0) + { + InterfaceManager::Print(" Serial No: \"%s\"\n", stringBuffer); + } + + InterfaceManager::Print("\n length: %d\n", deviceDescriptor.bLength); + InterfaceManager::Print(" device class: %d\n", deviceDescriptor.bDeviceClass); + InterfaceManager::Print(" S/N: %d\n", deviceDescriptor.iSerialNumber); + InterfaceManager::Print(" VID:PID: %04X:%04X\n", deviceDescriptor.idVendor, deviceDescriptor.idProduct); + InterfaceManager::Print(" bcdDevice: %04X\n", deviceDescriptor.bcdDevice); + InterfaceManager::Print(" iMan:iProd:iSer: %d:%d:%d\n", deviceDescriptor.iManufacturer, deviceDescriptor.iProduct, + deviceDescriptor.iSerialNumber); + InterfaceManager::Print(" nb confs: %d\n", deviceDescriptor.bNumConfigurations); + } + + libusb_config_descriptor *configDescriptor; + result = libusb_get_config_descriptor(heimdallDevice, 0, &configDescriptor); + if (result != LIBUSB_SUCCESS || !configDescriptor) + { + InterfaceManager::PrintError("Failed to retrieve config descriptor\n"); + return (false); + } + + int interfaceIndex = -1; + int altSettingIndex; + + for (int i = 0; i < configDescriptor->bNumInterfaces; i++) + { + for (int j = 0 ; j < configDescriptor->usb_interface[i].num_altsetting; j++) + { + if (verbose) + { + InterfaceManager::Print("\ninterface[%d].altsetting[%d]: num endpoints = %d\n", + i, j, configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints); + InterfaceManager::Print(" Class.SubClass.Protocol: %02X.%02X.%02X\n", + configDescriptor->usb_interface[i].altsetting[j].bInterfaceClass, + configDescriptor->usb_interface[i].altsetting[j].bInterfaceSubClass, + configDescriptor->usb_interface[i].altsetting[j].bInterfaceProtocol); + } + + int inEndpointAddress = -1; + int outEndpointAddress = -1; + + for (int k = 0; k < configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints; k++) + { + const libusb_endpoint_descriptor *endpoint = + &configDescriptor->usb_interface[i].altsetting[j].endpoint[k]; + + if (verbose) + { + InterfaceManager::Print(" endpoint[%d].address: %02X\n", k, endpoint->bEndpointAddress); + InterfaceManager::Print(" max packet size: %04X\n", endpoint->wMaxPacketSize); + InterfaceManager::Print(" polling interval: %02X\n", endpoint->bInterval); + } + + if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) + inEndpointAddress = endpoint->bEndpointAddress; + else + 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) + { + interfaceIndex = i; + altSettingIndex = j; + inEndpoint = inEndpointAddress; + outEndpoint = outEndpointAddress; + } + } + } + + libusb_free_config_descriptor(configDescriptor); + + if (result != LIBUSB_SUCCESS) + { + InterfaceManager::PrintError("Failed to find correct interface configuration\n"); + return (false); + } + + InterfaceManager::Print("\nClaiming interface..."); + result = libusb_claim_interface(deviceHandle, interfaceIndex); + +#ifdef OS_LINUX + + if (result != LIBUSB_SUCCESS) + { + detachedDriver = true; + InterfaceManager::Print(" Failed. Attempting to detach driver...\n"); + libusb_detach_kernel_driver(deviceHandle, interfaceIndex); + InterfaceManager::Print("Claiming interface again..."); + result = libusb_claim_interface(deviceHandle, interfaceIndex); + } + +#endif + + if (result != LIBUSB_SUCCESS) + { + InterfaceManager::PrintError(" Failed!\n"); + return (false); + } + + InterfaceManager::Print(" Success\n"); + + InterfaceManager::Print("Setting up interface..."); + result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex); + if (result != LIBUSB_SUCCESS) + { + InterfaceManager::PrintError(" Failed!\n"); + return (false); + } + + InterfaceManager::Print(" Success\n"); + + return (true); +} + +bool BridgeManager::BeginSession(void) const +{ + InterfaceManager::Print("Beginning session...\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) + { + InterfaceManager::PrintError("Failed to initialise usb communication!\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) + { + InterfaceManager::PrintError("Failed to initialise usb communication!\n"); + delete [] dataBuffer; + return (false); + } + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000); + if (result < 0) + { + InterfaceManager::PrintError("Failed to initialise usb communication!\n"); + delete [] dataBuffer; + return (false); + } + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000); + if (result < 0) + { + InterfaceManager::PrintError("Failed to initialise usb communication!\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) + { + InterfaceManager::PrintError("Failed to initialise usb communication!\n"); + delete [] dataBuffer; + return (false); + } + + result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000); + if (result < 0) + { + InterfaceManager::PrintError("Failed to initialise usb communication!\n"); + delete [] dataBuffer; + return (false); + } + + InterfaceManager::Print("Handshaking with Loke..."); + + int dataTransferred; + + // Send "ODIN" + strcpy((char *)dataBuffer, "ODIN"); + + result = libusb_bulk_transfer(deviceHandle, outEndpoint, dataBuffer, 4, &dataTransferred, 1000); + if (result < 0) + { + InterfaceManager::PrintError(" Failed!\n"); + + if (verbose) + InterfaceManager::PrintError("ERROR: Failed to send data: \"%s\"\n", dataBuffer); + + delete [] dataBuffer; + return (false); + } + + if (dataTransferred != 4) + { + InterfaceManager::PrintError(" Failed!\n"); + + if (verbose) + InterfaceManager::PrintError("ERROR: Failed to complete sending data: \"%s\"\n", dataBuffer); + + delete [] dataBuffer; + return (false); + } + + // Expect "LOKE" + memset(dataBuffer, 0, 7); + + result = libusb_bulk_transfer(deviceHandle, inEndpoint, dataBuffer, 7, &dataTransferred, 1000); + if (result < 0) + { + InterfaceManager::PrintError(" Failed!\n"); + + if (verbose) + InterfaceManager::PrintError("ERROR: Failed to receive response\n"); + delete [] dataBuffer; + return (false);; + } + + if (dataTransferred != 4 || memcmp(dataBuffer, "LOKE", 4) != 0) + { + InterfaceManager::PrintError(" Failed!\n"); + + if (verbose) + InterfaceManager::PrintError("ERROR: Unexpected communication.\nExpected: \"%s\"\nReceived: \"%s\"\n", "LOKE", dataBuffer); + + delete [] dataBuffer; + return (false); + } + + InterfaceManager::Print(" Success\n\n"); + return (true); +} + +bool BridgeManager::EndSession(void) const +{ + InterfaceManager::Print("Ending session...\n"); + + RebootDevicePacket *rebootDevicePacket = new RebootDevicePacket(RebootDevicePacket::kRequestEndSession); + bool success = SendPacket(rebootDevicePacket); + delete rebootDevicePacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send end session packet!\n"); + return (false); + } + + ResponsePacket *rebootDeviceResponse = new ResponsePacket(ResponsePacket::kResponseTypeRebootDevice); + success = ReceivePacket(rebootDeviceResponse); + delete rebootDeviceResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive session end confirmation!\n"); + return (false); + } + + return (true); +} + +bool BridgeManager::SendPacket(OutboundPacket *packet, int timeout) const +{ + packet->Pack(); + + int dataTransferred; + int result = libusb_bulk_transfer(deviceHandle, outEndpoint, packet->GetData(), packet->GetSize(), + &dataTransferred, timeout); + + if (result < 0) + { + // max(250, communicationDelay) + int retryDelay = (communicationDelay > 250) ? communicationDelay : 250; + + if (verbose) + InterfaceManager::PrintError("Error %i whilst sending packet. ", result); + + // Retry + for (int i = 0; i < 5; i++) + { + if (verbose) + InterfaceManager::PrintError(" Retrying...\n"); + + // Wait longer each retry + Sleep(retryDelay * (i + 1)); + + result = libusb_bulk_transfer(deviceHandle, outEndpoint, packet->GetData(), packet->GetSize(), + &dataTransferred, timeout); + + if (result >= 0) + break; + + if (verbose) + InterfaceManager::PrintError("Error %i whilst sending packet. ", result); + } + + if (verbose) + InterfaceManager::PrintError("\n"); + } + + if (communicationDelay != 0) + Sleep(communicationDelay); + + if (result < 0 || dataTransferred != packet->GetSize()) + return (false); + + return (true); +} + +bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout) const +{ + int dataTransferred; + int result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(), + &dataTransferred, timeout); + + if (result < 0) + { + // max(250, communicationDelay) + int retryDelay = (communicationDelay > 250) ? communicationDelay : 250; + + if (verbose) + InterfaceManager::PrintError("Error %i whilst receiving packet. ", result); + + // Retry + for (int i = 0; i < 5; i++) + { + if (verbose) + InterfaceManager::PrintError(" Retrying\n"); + + // Wait longer each retry + Sleep(retryDelay * (i + 1)); + + result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(), + &dataTransferred, timeout); + + if (result >= 0) + break; + + if (verbose) + InterfaceManager::PrintError("Error %i whilst receiving packet. ", result); + + if (i >= 3) + { + int breakHere = 0; + breakHere++; + } + } + + if (verbose) + InterfaceManager::PrintError("\n"); + } + + if (communicationDelay != 0) + Sleep(communicationDelay); + + if (result < 0 || (dataTransferred != packet->GetSize() && !packet->IsSizeVariable())) + return (false); + + packet->SetReceivedSize(dataTransferred); + + return (packet->Unpack()); +} + +bool BridgeManager::SendPitFile(FILE *file) const +{ + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + rewind(file); + + // Start file transfer + PitFilePacket *pitFilePacket = new PitFilePacket(PitFilePacket::kRequestFlash); + bool success = SendPacket(pitFilePacket); + delete pitFilePacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to request sending of PIT file!\n"); + return (false); + } + + PitFileResponse *pitFileResponse = new PitFileResponse(); + success = ReceivePacket(pitFileResponse); + delete pitFileResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to confirm sending of PIT file!\n"); + return (false); + } + + // Transfer file size + FlashPartPitFilePacket *flashPartPitFilePacket = new FlashPartPitFilePacket(fileSize); + success = SendPacket(flashPartPitFilePacket); + delete flashPartPitFilePacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send PIT file part information!\n"); + return (false); + } + + pitFileResponse = new PitFileResponse(); + success = ReceivePacket(pitFileResponse); + delete pitFileResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to confirm sending of PIT file part information!\n"); + return (false); + } + + // Flash pit file + SendFilePartPacket *sendFilePartPacket = new SendFilePartPacket(file, fileSize); + success = SendPacket(sendFilePartPacket); + delete sendFilePartPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send file part packet!\n"); + return (false); + } + + pitFileResponse = new PitFileResponse(); + success = ReceivePacket(pitFileResponse); + delete pitFileResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive PIT file transfer count!\n"); + return (false); + } + + return (true); +} + +int BridgeManager::ReceivePitFile(unsigned char **pitBuffer) const +{ + *pitBuffer = nullptr; + + bool success; + + // Start file transfer + PitFilePacket *pitFilePacket = new PitFilePacket(PitFilePacket::kRequestDump); + success = SendPacket(pitFilePacket); + delete pitFilePacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to request receival of PIT file!\n"); + return (0); + } + + PitFileResponse *pitFileResponse = new PitFileResponse(); + success = ReceivePacket(pitFileResponse); + int fileSize = pitFileResponse->GetFileSize(); + delete pitFileResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive PIT file size!\n"); + return (0); + } + + int transferCount = fileSize / ReceiveFilePartPacket::kDataSize; + if (fileSize % ReceiveFilePartPacket::kDataSize != 0) + transferCount++; + + unsigned char *buffer = new unsigned char[fileSize]; + int offset = 0; + + // NOTE: The PIT file appears to always be padded out to exactly 4 kilobytes. + for (int i = 0; i < transferCount; i++) + { + DumpPartPitFilePacket *requestPacket = new DumpPartPitFilePacket(i); + success = SendPacket(requestPacket); + delete requestPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to request PIT file part #%i!\n", i); + delete [] buffer; + return (0); + } + + ReceiveFilePartPacket *receiveFilePartPacket = new ReceiveFilePartPacket(); + success = ReceivePacket(receiveFilePartPacket); + + if (!success) + { + InterfaceManager::PrintError("Failed to receive PIT file part #%i!\n", i); + delete receiveFilePartPacket; + delete [] buffer; + return (0); + } + + // Copy the whole packet data into the buffer. + memcpy(buffer + offset, receiveFilePartPacket->GetData(), receiveFilePartPacket->GetReceivedSize()); + offset += receiveFilePartPacket->GetReceivedSize(); + + delete receiveFilePartPacket; + } + + // End file transfer + pitFilePacket = new PitFilePacket(PitFilePacket::kRequestEndTransfer); + success = SendPacket(pitFilePacket); + delete pitFilePacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send request to end PIT file transfer!\n"); + delete [] buffer; + return (0); + } + + pitFileResponse = new PitFileResponse(); + success = ReceivePacket(pitFileResponse); + delete pitFileResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive end PIT file transfer verification!\n"); + delete [] buffer; + return (0); + } + + *pitBuffer = buffer; + return (fileSize); +} + +bool BridgeManager::SendFile(FILE *file, int destination, int fileIdentifier) const +{ + if (destination != EndFileTransferPacket::kDestinationModem && destination != EndFileTransferPacket::kDestinationPhone) + { + InterfaceManager::PrintError("ERROR: Attempted to send file to unknown destination!\n"); + return (false); + } + + if (destination == EndFileTransferPacket::kDestinationModem && fileIdentifier != -1) + { + InterfaceManager::PrintError("ERROR: The modem file does not have an identifier!\n"); + return (false); + } + + FileTransferPacket *flashFileTransferPacket = new FileTransferPacket(FileTransferPacket::kRequestFlash); + bool success = SendPacket(flashFileTransferPacket); + delete flashFileTransferPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to initialise transfer!\n"); + return (false); + } + + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + rewind(file); + + ResponsePacket *fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer); + success = ReceivePacket(fileTransferResponse); + delete fileTransferResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to confirm transfer initialisation!\n"); + return (false); + } + + int sequenceCount = fileSize / (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize); + int lastSequenceSize = kMaxSequenceLength; + int partialPacketLength = fileSize % SendFilePartPacket::kDefaultPacketSize; + if (fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize) != 0) + { + sequenceCount++; + + int lastSequenceBytes = fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize); + lastSequenceSize = lastSequenceBytes / SendFilePartPacket::kDefaultPacketSize; + if (partialPacketLength != 0) + lastSequenceSize++; + } + + long bytesTransferred = 0; + int currentPercent; + int previousPercent = 0; + InterfaceManager::Print("0%%"); + + for (int sequenceIndex = 0; sequenceIndex < sequenceCount; sequenceIndex++) + { + // Min(lastSequenceSize, 131072) + bool isLastSequence = sequenceIndex == sequenceCount - 1; + int sequenceSize = (isLastSequence) ? lastSequenceSize : kMaxSequenceLength; + + FlashPartFileTransferPacket *beginFileTransferPacket = new FlashPartFileTransferPacket(0, 2 * sequenceSize); + success = SendPacket(beginFileTransferPacket); + delete beginFileTransferPacket; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to begin file transfer sequence!\n"); + return (false); + } + + fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer); + bool success = ReceivePacket(fileTransferResponse); + delete fileTransferResponse; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to confirm beginning of file transfer sequence!\n"); + return (false); + } + + SendFilePartPacket *sendFilePartPacket; + SendFilePartResponse *sendFilePartResponse; + + for (int filePartIndex = 0; filePartIndex < sequenceSize; filePartIndex++) + { + // Send + sendFilePartPacket = new SendFilePartPacket(file); + success = SendPacket(sendFilePartPacket); + delete sendFilePartPacket; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to send file part packet!\n"); + return (false); + } + + // Response + sendFilePartResponse = new SendFilePartResponse(); + success = ReceivePacket(sendFilePartResponse); + int receivedPartIndex = sendFilePartResponse->GetPartIndex(); + + if (verbose) + { + const unsigned char *data = sendFilePartResponse->GetData(); + InterfaceManager::Print("File Part #%i... Response: %X %X %X %X %X %X %X %X \n", filePartIndex, + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); + } + + delete sendFilePartResponse; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to receive file part response!\n"); + + for (int retry = 0; retry < 4; retry++) + { + InterfaceManager::PrintError("\nRetrying..."); + + // Send + sendFilePartPacket = new SendFilePartPacket(file); + success = SendPacket(sendFilePartPacket); + delete sendFilePartPacket; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to send file part packet!\n"); + return (false); + } + + // Response + sendFilePartResponse = new SendFilePartResponse(); + success = ReceivePacket(sendFilePartResponse); + int receivedPartIndex = sendFilePartResponse->GetPartIndex(); + + if (verbose) + { + const unsigned char *data = sendFilePartResponse->GetData(); + InterfaceManager::Print("File Part #%i... Response: %X %X %X %X %X %X %X %X \n", filePartIndex, + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); + } + + delete sendFilePartResponse; + + if (receivedPartIndex != filePartIndex) + { + InterfaceManager::PrintError("\nERROR: Expected file part index: %i Received: %i\n", + filePartIndex, receivedPartIndex); + return (false); + } + + if (success) + break; + } + + if (!success) + return (false); + } + + if (receivedPartIndex != filePartIndex) + { + InterfaceManager::PrintError("\nERROR: Expected file part index: %i Received: %i\n", + filePartIndex, receivedPartIndex); + return (false); + } + + bytesTransferred += SendFilePartPacket::kDefaultPacketSize; + if (bytesTransferred > fileSize) + bytesTransferred = fileSize; + + currentPercent = (int)(100.0f * ((float)bytesTransferred / (float)fileSize)); + + if (!verbose) + { + if (currentPercent != previousPercent) + { + if (previousPercent < 10) + InterfaceManager::Print("\b\b%i%%", currentPercent); + else + InterfaceManager::Print("\b\b\b%i%%", currentPercent); + } + } + + previousPercent = currentPercent; + } + + int lastFullPacketIndex = 2 * ((isLastSequence && partialPacketLength != 0) ? sequenceSize - 1 : sequenceSize); + + if (destination == EndFileTransferPacket::kDestinationPhone) + { + EndPhoneFileTransferPacket *endPhoneFileTransferPacket = new EndPhoneFileTransferPacket( + (isLastSequence) ? partialPacketLength : 0, lastFullPacketIndex, 0, 0, fileIdentifier, isLastSequence); + + success = SendPacket(endPhoneFileTransferPacket, 3000); + delete endPhoneFileTransferPacket; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to end phone file transfer sequence!\n"); + return (false); + } + } + else // destination == EndFileTransferPacket::kDestinationModem + { + EndModemFileTransferPacket *endModemFileTransferPacket = new EndModemFileTransferPacket( + (isLastSequence) ? partialPacketLength : 0, lastFullPacketIndex, 0, 0, isLastSequence); + + success = SendPacket(endModemFileTransferPacket, 3000); + delete endModemFileTransferPacket; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to end modem file transfer sequence!\n"); + return (false); + } + } + + fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer); + success = ReceivePacket(fileTransferResponse, 30000); + delete fileTransferResponse; + + if (!success) + { + InterfaceManager::PrintError("\nFailed to confirm end of file transfer sequence!\n"); + return (false); + } + } + + if (!verbose) + InterfaceManager::Print("\n"); + + return (true); +} + +bool BridgeManager::ReceiveDump(int chipType, int chipId, FILE *file) const +{ + bool success; + + // Start file transfer + BeginDumpPacket *beginDumpPacket = new BeginDumpPacket(chipType, chipId); + success = SendPacket(beginDumpPacket); + delete beginDumpPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to request dump!\n"); + return (false); + } + + DumpResponse *dumpResponse = new DumpResponse(); + success = ReceivePacket(dumpResponse); + unsigned int dumpSize = dumpResponse->GetDumpSize(); + delete dumpResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive dump size!\n"); + return (false); + } + + unsigned int transferCount = dumpSize / ReceiveFilePartPacket::kDataSize; + if (transferCount % ReceiveFilePartPacket::kDataSize != 0) + transferCount++; + + char *buffer = new char[kDumpBufferSize * ReceiveFilePartPacket::kDataSize]; + int bufferOffset = 0; + + for (unsigned int i = 0; i < transferCount; i++) + { + DumpPartFileTransferPacket *dumpPartPacket = new DumpPartFileTransferPacket(i); + success = SendPacket(dumpPartPacket); + delete dumpPartPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to request dump part #%i!\n", i); + delete [] buffer; + return (false); + } + + ReceiveFilePartPacket *receiveFilePartPacket = new ReceiveFilePartPacket(); + success = ReceivePacket(receiveFilePartPacket); + + if (!success) + { + InterfaceManager::PrintError("Failed to receive dump part #%i!\n", i); + continue; + delete receiveFilePartPacket; + delete [] buffer; + return (true); + } + + if (bufferOffset + receiveFilePartPacket->GetReceivedSize() > kDumpBufferSize * ReceiveFilePartPacket::kDataSize) + { + // Write the buffer to the output file + fwrite(buffer, 1, bufferOffset, file); + bufferOffset = 0; + } + + // Copy the packet data into pitFile. + memcpy(buffer + bufferOffset, receiveFilePartPacket->GetData(), receiveFilePartPacket->GetReceivedSize()); + bufferOffset += receiveFilePartPacket->GetReceivedSize(); + + delete receiveFilePartPacket; + } + + if (bufferOffset != 0) + { + // Write the buffer to the output file + fwrite(buffer, 1, bufferOffset, file); + } + + delete [] buffer; + + // End file transfer + FileTransferPacket *fileTransferPacket = new FileTransferPacket(FileTransferPacket::kRequestEnd); + success = SendPacket(fileTransferPacket); + delete fileTransferPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send request to end dump transfer!\n"); + return (false); + } + + ResponsePacket *responsePacket = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer); + success = ReceivePacket(responsePacket); + delete responsePacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive end dump transfer verification!\n"); + return (false); + } + + return (true); +} + +bool BridgeManager::RebootDevice(void) const +{ + InterfaceManager::Print("Rebooting device...\n"); + + RebootDevicePacket *rebootDevicePacket = new RebootDevicePacket(RebootDevicePacket::kRequestRebootDevice); + bool success = SendPacket(rebootDevicePacket); + delete rebootDevicePacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send end session packet!\n"); + return (false); + } + + ResponsePacket *rebootDeviceResponse = new ResponsePacket(ResponsePacket::kResponseTypeRebootDevice); + success = ReceivePacket(rebootDeviceResponse); + delete rebootDeviceResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive reboot confirmation!\n"); + return (false); + } + + return (true); +} diff --git a/heimdall/source/BridgeManager.h b/heimdall/source/BridgeManager.h new file mode 100644 index 0000000..40a7ceb --- /dev/null +++ b/heimdall/source/BridgeManager.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2010 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 BRIDGEMANAGER_H +#define BRIDGEMANAGER_H + +// Heimdall +#include "Heimdall.h" + +struct libusb_context; +struct libusb_device; +struct libusb_device_handle; + +namespace Heimdall +{ + class InboundPacket; + class OutboundPacket; + + class DeviceIdentifier + { + public: + + const int vendorId; + const int productId; + + DeviceIdentifier(int vid, int pid) : + vendorId(vid), + productId(pid) + { + } + }; + + class BridgeManager + { + public: + + enum + { + kSupportedDeviceCount = 1, + + kCommunicationDelayDefault = 0, + kDumpBufferSize = 4096 + }; + + enum + { + kVidSamsung = 0x04E8 + }; + + enum + { + kPidGalaxySDownloadMode = 0x6601/*, + kPidGalaxySInternational = 0x681C, + kPidGalaxySNewInternational = 0x681D, + kPidVibrantCanadaBell = 0x6877*/ + }; + + private: + + static const DeviceIdentifier supportedDevices[kSupportedDeviceCount]; + + bool verbose; + + libusb_context *libusbContext; + libusb_device_handle *deviceHandle; + libusb_device *heimdallDevice; + int interfaceIndex; + int inEndpoint; + int outEndpoint; + + int communicationDelay; + +#ifdef OS_LINUX + + bool detachedDriver; + +#endif + + public: + + BridgeManager(bool verbose, int communicationDelay); + ~BridgeManager(); + + bool Initialise(void); + + bool BeginSession(void) const; + bool EndSession(void) const; + + bool SendPacket(OutboundPacket *packet, int timeout = 3000) const; + bool ReceivePacket(InboundPacket *packet, int timeout = 3000) const; + + bool SendPitFile(FILE *file) const; + int ReceivePitFile(unsigned char **pitBuffer) const; + + bool SendFile(FILE *file, int destination, int fileIdentifier = -1) const; + bool ReceiveDump(int chipType, int chipId, FILE *file) const; + + bool RebootDevice(void) const; + + bool IsVerbose(void) const + { + return (verbose); + } + }; +} + +#endif diff --git a/heimdall/source/ControlPacket.h b/heimdall/source/ControlPacket.h new file mode 100644 index 0000000..2379073 --- /dev/null +++ b/heimdall/source/ControlPacket.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2010 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 CONTROLPACKET_H +#define CONTROLPACKET_H + +// Heimdall +#include "OutboundPacket.h" + +namespace Heimdall +{ + class ControlPacket : public OutboundPacket + { + public: + + enum + { + kControlTypeDeviceInfo = 0x64, + kControlTypePitFile = 0x65, + kControlTypeFileTransfer = 0x66, + kControlTypeRebootDevice = 0x67 + }; + + protected: + + enum + { + kDataSize = 4 + }; + + private: + + unsigned int controlType; + + public: + + ControlPacket(unsigned int controlType) : OutboundPacket(1024) + { + this->controlType = controlType; + } + + unsigned int GetControlType(void) const + { + return (controlType); + } + + virtual void Pack(void) + { + PackInteger(0, controlType); + } + }; +} + +#endif diff --git a/heimdall/source/DeviceInfoPacket.h b/heimdall/source/DeviceInfoPacket.h new file mode 100644 index 0000000..153cdc5 --- /dev/null +++ b/heimdall/source/DeviceInfoPacket.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2010 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 DEVICEINFOPACKET_H +#define DEVICEINFOPACKET_H + +// Heimdall +#include "ControlPacket.h" + +namespace Heimdall +{ + class DeviceInfoPacket : public ControlPacket + { + public: + + enum + { + kUnknown1 = 0, // Begin device info? + kUnknown2 = 1, // End device info? + kTotalBytes = 2 // Total no. bytes that will be flashed, seems to be ignored though. + }; + + private: + + unsigned int request; + unsigned int unknown3Parameter; // TODO: Subclass for unknown2. + + public: + + DeviceInfoPacket(unsigned int request, unsigned int unknown3Parameter = 0) + : ControlPacket(ControlPacket::kControlTypeDeviceInfo) + { + this->request = request; + this->unknown3Parameter = unknown3Parameter; + } + + unsigned int GetRequest(void) const + { + return (request); + } + + unsigned int GetUnknown3Parameter(void) const + { + return (unknown3Parameter); + } + + void Pack(void) + { + ControlPacket::Pack(); + + PackInteger(ControlPacket::kDataSize, request); + PackInteger(ControlPacket::kDataSize + 4, unknown3Parameter); + } + }; +} + +#endif diff --git a/heimdall/source/DeviceInfoResponse.h b/heimdall/source/DeviceInfoResponse.h new file mode 100644 index 0000000..3bf2d8f --- /dev/null +++ b/heimdall/source/DeviceInfoResponse.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2010 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 DEVICEINFORESPONSE_H +#define DEVICEINFORESPONSE_H + +// Heimdall +#include "ResponsePacket.h" + +namespace Heimdall +{ + class DeviceInfoResponse : public ResponsePacket + { + private: + + unsigned int unknown; + + public: + + DeviceInfoResponse() : ResponsePacket(ResponsePacket::kResponseTypeDeviceInfo) + { + } + + int GetUnknown(void) const + { + return (unknown); + } + + bool Unpack(void) + { + if (!ResponsePacket::Unpack()) + return (false); + + unknown = UnpackInteger(ResponsePacket::kDataSize); + + return (true); + } + }; +} + +#endif diff --git a/heimdall/source/DumpPartFileTransferPacket.h b/heimdall/source/DumpPartFileTransferPacket.h new file mode 100644 index 0000000..60fb8c5 --- /dev/null +++ b/heimdall/source/DumpPartFileTransferPacket.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2010 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 DUMPPARTFILETRANSFERPACKET_H +#define DUMPPARTFILETRANSFERPACKET_H + +// Heimdall +#include "FileTransferPacket.h" + +namespace Heimdall +{ + class DumpPartFileTransferPacket : public FileTransferPacket + { + private: + + unsigned int partIndex; + + public: + + DumpPartFileTransferPacket(unsigned int partIndex) : FileTransferPacket(FileTransferPacket::kRequestPart) + { + this->partIndex = partIndex; + } + + unsigned int GetPartIndex(void) const + { + return (partIndex); + } + + virtual void Pack(void) + { + FileTransferPacket::Pack(); + + PackInteger(FileTransferPacket::kDataSize, partIndex); + } + }; +} + +#endif diff --git a/heimdall/source/DumpPartPitFilePacket.h b/heimdall/source/DumpPartPitFilePacket.h new file mode 100644 index 0000000..29025c2 --- /dev/null +++ b/heimdall/source/DumpPartPitFilePacket.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2010 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 DUMPPARTPITFILEPACKET_H +#define DUMPPARTPITFILEPACKET_H + +// Heimdall +#include "PitFilePacket.h" + +namespace Heimdall +{ + class DumpPartPitFilePacket : public PitFilePacket + { + private: + + unsigned int partIndex; + + public: + + DumpPartPitFilePacket(unsigned int partIndex) : PitFilePacket(PitFilePacket::kRequestPart) + { + this->partIndex = partIndex; + } + + unsigned int GetPartIndex(void) const + { + return (partIndex); + } + + void Pack(void) + { + PitFilePacket::Pack(); + + PackInteger(PitFilePacket::kDataSize, partIndex); + } + }; +} + +#endif diff --git a/heimdall/source/DumpResponse.h b/heimdall/source/DumpResponse.h new file mode 100644 index 0000000..126982a --- /dev/null +++ b/heimdall/source/DumpResponse.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2010 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 DUMPRESPONSE_H +#define DUMPRESPONSE_H + +// Heimdall +#include "ResponsePacket.h" + +namespace Heimdall +{ + class DumpResponse : public ResponsePacket + { + private: + + unsigned int dumpSize; + + public: + + DumpResponse() : ResponsePacket(kResponseTypeFileTransfer) + { + } + + unsigned int GetDumpSize(void) const + { + return (dumpSize); + } + + bool Unpack(void) + { + if (!ResponsePacket::Unpack()) + return (false); + + dumpSize = UnpackInteger(ResponsePacket::kDataSize); + + return (true); + } + }; +} + +#endif diff --git a/heimdall/source/EndFileTransferPacket.h b/heimdall/source/EndFileTransferPacket.h new file mode 100644 index 0000000..3f3d689 --- /dev/null +++ b/heimdall/source/EndFileTransferPacket.h @@ -0,0 +1,120 @@ +/* Copyright (c) 2010 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 ENDFILETRANSFERPACKET_H +#define ENDFILETRANSFERPACKET_H + +// Heimdall +#include "FileTransferPacket.h" + +namespace Heimdall +{ + class EndFileTransferPacket : public FileTransferPacket + { + public: + + enum + { + kDestinationPhone = 0x00, + kDestinationModem = 0x01 + }; + + protected: + + enum + { + kDataSize = FileTransferPacket::kDataSize + 16 + }; + + private: + + unsigned int destination; // Chip identifier perhaps + unsigned short partialPacketLength; // Length or (length - 65536) if lastFullPacket is odd. + unsigned int lastFullPacketIndex; + unsigned short unknown1; + unsigned int unknown2; + + protected: + + EndFileTransferPacket(unsigned int destination, unsigned int partialPacketLength, unsigned int lastFullPacketIndex, + unsigned short unknown1, unsigned int unknown2) + : FileTransferPacket(FileTransferPacket::kRequestEnd) + { + this->destination = destination; + + if (partialPacketLength > 65535) + { + this->partialPacketLength = (partialPacketLength - 65536); + this->lastFullPacketIndex = lastFullPacketIndex + 1; + } + else + { + this->partialPacketLength = partialPacketLength; + this->lastFullPacketIndex = lastFullPacketIndex; + } + + this->unknown1 = unknown1; + this->unknown2 = unknown2; + } + + public: + + unsigned int GetDestination(void) const + { + return (destination); + } + + unsigned int GetPartialPacketLength(void) const + { + if (lastFullPacketIndex % 2 == 0) + return (partialPacketLength); + else + return (partialPacketLength + 65536); + } + + unsigned int GetLastFullPacketIndex(void) const + { + return (lastFullPacketIndex - lastFullPacketIndex % 2); + } + + unsigned short GetUnknown1(void) const + { + return (unknown1); + } + + unsigned int GetUnknown2(void) const + { + return (unknown2); + } + + virtual void Pack(void) + { + FileTransferPacket::Pack(); + + PackInteger(FileTransferPacket::kDataSize, destination); + PackShort(FileTransferPacket::kDataSize + 4, partialPacketLength); + PackInteger(FileTransferPacket::kDataSize + 6, lastFullPacketIndex); + PackShort(FileTransferPacket::kDataSize + 10, unknown1); + PackInteger(FileTransferPacket::kDataSize + 12, unknown2); + } + }; +} + +#endif diff --git a/heimdall/source/EndModemFileTransferPacket.h b/heimdall/source/EndModemFileTransferPacket.h new file mode 100644 index 0000000..9dc4c78 --- /dev/null +++ b/heimdall/source/EndModemFileTransferPacket.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2010 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 ENDMODEMFILETRANSFERPACKET_H +#define ENDMODEMFILETRANSFERPACKET_H + +// Heimdall +#include "EndFileTransferPacket.h" + +namespace Heimdall +{ + class EndModemFileTransferPacket : public EndFileTransferPacket + { + private: + + unsigned int endOfFile; + + public: + + EndModemFileTransferPacket(unsigned int partialPacketLength, unsigned int lastFullPacketIndex, unsigned short unknown1, + unsigned int unknown2, bool endOfFile) + : EndFileTransferPacket(EndFileTransferPacket::kDestinationModem, partialPacketLength, + lastFullPacketIndex, unknown1, unknown2) + { + this->endOfFile = (endOfFile) ? 1 : 0; + } + + bool IsEndOfFile(void) const + { + return (endOfFile == 1); + } + + void Pack(void) + { + EndFileTransferPacket::Pack(); + + PackInteger(EndFileTransferPacket::kDataSize, endOfFile); + } + }; +} + +#endif diff --git a/heimdall/source/EndPhoneFileTransferPacket.h b/heimdall/source/EndPhoneFileTransferPacket.h new file mode 100644 index 0000000..24650a2 --- /dev/null +++ b/heimdall/source/EndPhoneFileTransferPacket.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2010 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 ENDPHONEFILETRANSFERPACKET_H +#define ENDPHONEFILETRANSFERPACKET_H + +// Heimdall +#include "EndFileTransferPacket.h" + +namespace Heimdall +{ + class EndPhoneFileTransferPacket : public EndFileTransferPacket + { + public: + + enum + { + kFilePrimaryBootloader = 0x00, + kFilePit = 0x01, // New 1.1 - Don't flash the pit this way! + kFileSecondaryBootloader = 0x03, + kFileSecondaryBootloaderBackup = 0x04, // New 1.1 + kFileKernel = 0x06, + kFileRecovery = 0x07, // New 1.1 + kFileEfs = 0x14, // New 1.1 + kFileParamLfs = 0x15, + kFileFactoryFilesystem = 0x16, + kFileDatabaseData = 0x17, + kFileCache = 0x18, + + kFileModem = 0x0B // New 1.1 - Kies flashes the modem this way rather than using the EndModemFileTransferPacket. + }; + + private: + + unsigned int fileIdentifier; + unsigned int endOfFile; + + public: + + EndPhoneFileTransferPacket(unsigned int partialPacketLength, unsigned int lastFullPacketIndex, unsigned short unknown1, + unsigned int unknown2, unsigned int fileIdentifier, bool endOfFile) + : EndFileTransferPacket(EndFileTransferPacket::kDestinationPhone, partialPacketLength, + lastFullPacketIndex, unknown1, unknown2) + { + this->fileIdentifier = fileIdentifier; + this->endOfFile = (endOfFile) ? 1 : 0; + } + + unsigned int GetFileIdentifier(void) + { + return (fileIdentifier); + } + + bool IsEndOfFile(void) const + { + return (endOfFile == 1); + } + + void Pack(void) + { + EndFileTransferPacket::Pack(); + + PackInteger(EndFileTransferPacket::kDataSize, fileIdentifier); + PackInteger(EndFileTransferPacket::kDataSize + 4, endOfFile); + } + }; +} + +#endif diff --git a/heimdall/source/FileTransferPacket.h b/heimdall/source/FileTransferPacket.h new file mode 100644 index 0000000..daa6a75 --- /dev/null +++ b/heimdall/source/FileTransferPacket.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2010 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 FILETRANSFERPACKET_H +#define FILETRANSFERPACKET_H + +// Heimdall +#include "ControlPacket.h" + +namespace Heimdall +{ + class FileTransferPacket : public ControlPacket + { + public: + + enum + { + kRequestFlash = 0x00, + kRequestDump = 0x01, + kRequestPart = 0x02, + kRequestEnd = 0x03 + }; + + protected: + + enum + { + kDataSize = ControlPacket::kDataSize + 4 + }; + + private: + + unsigned int request; + + public: + + FileTransferPacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeFileTransfer) + { + this->request = request; + } + + unsigned int GetRequest(void) const + { + return (request); + } + + virtual void Pack(void) + { + ControlPacket::Pack(); + + PackInteger(ControlPacket::kDataSize, request); + } + }; +} + +#endif diff --git a/heimdall/source/FlashPartFileTransferPacket.h b/heimdall/source/FlashPartFileTransferPacket.h new file mode 100644 index 0000000..6aa57da --- /dev/null +++ b/heimdall/source/FlashPartFileTransferPacket.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2010 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 FLASHPARTFILETRANSFERPACKET_H +#define FLASHPARTFILETRANSFERPACKET_H + +// Heimdall +#include "FileTransferPacket.h" + +namespace Heimdall +{ + class FlashPartFileTransferPacket : public FileTransferPacket + { + private: + + unsigned short unknown; + unsigned int transferCount; + + public: + + FlashPartFileTransferPacket(unsigned short unknown, unsigned int transferCount) + : FileTransferPacket(FileTransferPacket::kRequestPart) + { + this->unknown = unknown; + this->transferCount = transferCount; + } + + unsigned short GetUnknown(void) const + { + return (unknown); + } + + unsigned int GetTransferCount(void) const + { + return (transferCount); + } + + void Pack(void) + { + FileTransferPacket::Pack(); + + PackShort(FileTransferPacket::kDataSize, unknown); + PackInteger(FileTransferPacket::kDataSize + 2, transferCount); + } + }; +} + +#endif diff --git a/heimdall/source/FlashPartPitFilePacket.h b/heimdall/source/FlashPartPitFilePacket.h new file mode 100644 index 0000000..3974c3c --- /dev/null +++ b/heimdall/source/FlashPartPitFilePacket.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2010 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 FLASHPARTPITFILEPACKET_H +#define FLASHPARTPITFILEPACKET_H + +// Heimdall +#include "PitFilePacket.h" + +namespace Heimdall +{ + class FlashPartPitFilePacket : public PitFilePacket + { + private: + + unsigned int partSize; + + public: + + FlashPartPitFilePacket(unsigned int partSize) : PitFilePacket(PitFilePacket::kRequestPart) + { + this->partSize = partSize; + } + + unsigned int GetPartSize(void) const + { + return (partSize); + } + + void Pack(void) + { + PitFilePacket::Pack(); + + PackInteger(PitFilePacket::kDataSize, partSize); + } + }; +} + +#endif diff --git a/heimdall/source/Heimdall.h b/heimdall/source/Heimdall.h new file mode 100644 index 0000000..672cf14 --- /dev/null +++ b/heimdall/source/Heimdall.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2010 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 HEIMDALL_H +#define HEIMDALL_H + +#ifdef OS_WINDOWS +#include +#else + +#include "../config.h" + +#if defined(OS_DARWIN) || defined(OS_LINUX) +#include +#define Sleep(t) usleep(1000*t) +#else +#error operating system not supported +#endif + +#endif + +#ifndef nullptr +#define nullptr 0 +#endif + +#endif diff --git a/heimdall/source/InboundPacket.h b/heimdall/source/InboundPacket.h new file mode 100644 index 0000000..bf393fa --- /dev/null +++ b/heimdall/source/InboundPacket.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2010 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 INBOUNDPACKET_H +#define INBOUNDPACKET_H + +// Heimdall +#include "Packet.h" + +namespace Heimdall +{ + class InboundPacket : public Packet + { + private: + + bool sizeVariable; + unsigned int receivedSize; + + protected: + + int UnpackInteger(int offset) + { +#ifdef PPC + int value = (data[offset] << 24) | (data[offset + 1] << 16) | + (data[offset + 2] << 8) | data[offset + 3]; +#else + // Flip endianness + int value = data[offset] | (data[offset + 1] << 8) | + (data[offset + 2] << 16) | (data[offset + 3] << 24); +#endif + return (value); + } + + public: + + InboundPacket(unsigned int size, bool sizeVariable = false) : Packet(size) + { + this->sizeVariable = sizeVariable; + } + + bool IsSizeVariable(void) const + { + return (sizeVariable); + } + + unsigned int GetReceivedSize(void) const + { + return (receivedSize); + } + + void SetReceivedSize(unsigned int receivedSize) + { + this->receivedSize = receivedSize; + } + + virtual bool Unpack(void) = 0; + }; +} + +#endif diff --git a/heimdall/source/InterfaceManager.cpp b/heimdall/source/InterfaceManager.cpp new file mode 100644 index 0000000..23791bc --- /dev/null +++ b/heimdall/source/InterfaceManager.cpp @@ -0,0 +1,265 @@ +/* Copyright (c) 2010 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 +#include + +// Heimdall +#include "Heimdall.h" +#include "InterfaceManager.h" + +using namespace std; +using namespace Heimdall; + +string InterfaceManager::actionNames[kActionCount] = { "flash", "close-pc-screen", "dump", "help" }; + +string InterfaceManager::flashArgumentNames[kFlashArgCount * 2] = { + // --- Long Names --- + "-repartition", + + "-pit", "-factoryfs", "-cache", "-dbdata", "-primary-boot", "-secondary-boot", "-secondary-boot-backup", "-param", "-kernel", "-recovery", "-efs", "-modem", + + // --- Short Names --- + "r", + + "pit", "fs", "cache", "db", "boot", "sbl", "sbl2", "param", "z", "rec", "efs", "m" +}; + +string InterfaceManager::dumpArgumentNames[kDumpArgCount * 2] = { + // --- Long Names --- + "-chip-type", "-chip-id", "-output", + + // --- Short Names --- + "type", "id", "out" +}; + +string InterfaceManager::commonArgumentNames[kCommonArgCount * 2] = { + // --- Long Names --- + "-verbose", + + "-delay", + + // --- Short Names --- + "v", + + "d" +}; + +// argumentNames[kActionCount][] stores common arguments. +string *InterfaceManager::actionArgumentNames[kActionCount + 1] = { + // kActionFlash + flashArgumentNames, + + // kActionClosePcScreen + nullptr, + + // kActionDump + dumpArgumentNames, + + // kActionHelp + nullptr, + + // Common (kActionCount) + commonArgumentNames +}; + +int InterfaceManager::actionArgumentCounts[kActionCount + 1] = { + kFlashArgCount, 0, kDumpArgCount, 0, kCommonArgCount +}; + +int InterfaceManager::actionValuelessArgumentCounts[kActionCount + 1] = { + kFlashArgPit, 0, kDumpArgChipType, 0, kCommonArgDelay +}; + +const char *InterfaceManager::usage = "Usage: heimdall [--verbose] [--delay ]\n\ +\n\ +action: flash\n\ +arguments:\n\ + --repartition --pit --factoryfs \n\ + --cache --dbdata --primary-boot \n\ + --secondary-boot --param --kernel \n\ + --modem \n\ + or:\n\ + [--pit ] [--factoryfs ] [--cache ]\n\ + [--dbdata ] [--primary-boot ]\n\ + [--secondary-boot ] [--secondary-boot-backup ]\n\ + [--param ] [--kernel ] [--recovery ]\n\ + [--efs ] [--modem ]\n\ +description: Flashes firmware files to your phone.\n\ +\n\ +action: close-pc-screen\n\ +description: Attempts to get rid off the \"connect phone to PC\" screen.\n\ +\n\ +action: dump\n\ +arguments: --chip-type --chip-id --output \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: help\n\ +description: Display this dialogue.\n"; + +bool InterfaceManager::GetArguments(int argc, char **argv, map& argumentMap, int *actionIndex) +{ + if (argc < 2) + { + Print(usage); + return (false); + } + + const char *actionName = argv[1]; + *actionIndex = -1; + + for (int i = 0; i < kActionCount; i++) + { + if (actionNames[i] == actionName) + { + *actionIndex = i; + break; + } + } + + if (*actionIndex < 0) + { + Print("Unknown action \"%s\"\n\n", actionName); + Print(usage); + return (false); + } + + int actionArgumentCount = actionArgumentCounts[*actionIndex]; + int commonArgumentCount = actionArgumentCounts[kActionCount]; + + int actionValuelessArgumentCount = actionValuelessArgumentCounts[*actionIndex]; + int commonValuelessArgumentCount = actionValuelessArgumentCounts[kActionCount]; + + string *argumentNames = actionArgumentNames[*actionIndex]; + string *commonArgumentNames = actionArgumentNames[kActionCount]; + + for (int argIndex = 2; argIndex < argc; argIndex++) + { + if (*(argv[argIndex]) != '-') + { + Print(usage); + return (false); + } + + string argumentName = (char *)(argv[argIndex] + 1); + + // Check if the argument is a valid valueless argument + bool valid = false; + + for (int i = 0; i < actionValuelessArgumentCount; i++) + { + if (argumentName == argumentNames[i] || argumentName == argumentNames[actionArgumentCount + i]) + { + argumentName = argumentNames[i]; + valid = true; + break; + } + } + + if (!valid) + { + // Check if it's a common valueless argument + for (int i = 0; i < commonValuelessArgumentCount; i++) + { + if (argumentName == commonArgumentNames[i] || argumentName == commonArgumentNames[commonArgumentCount + i]) + { + argumentName = commonArgumentNames[i]; + valid = true; + break; + } + } + } + + if (valid) + { + // The argument is valueless + argumentMap.insert(pair(argumentName, "")); + continue; + } + + // Check if the argument is a valid regular argument + for (int i = actionValuelessArgumentCount; i < actionArgumentCount; i++) + { + if (argumentName == argumentNames[i] || argumentName == argumentNames[actionArgumentCount + i]) + { + argumentName = argumentNames[i]; + valid = true; + break; + } + } + + if (!valid) + { + // Check if it's a common regular argument + for (int i = commonValuelessArgumentCount; i < commonArgumentCount; i++) + { + if (argumentName == commonArgumentNames[i] || argumentName == commonArgumentNames[commonArgumentCount + i]) + { + argumentName = commonArgumentNames[i]; + valid = true; + break; + } + } + } + + if (!valid) + { + PrintError("\"%s\" is not a valid argument\n", argumentName.c_str()); + return (false); + } + + argIndex++; + + if (argIndex >= argc) + { + PrintError("\"%s\" is missing a value\n", argumentName.c_str()); + return (false); + } + + argumentMap.insert(pair(argumentName, argv[argIndex])); + } + + return (true); +} + +void InterfaceManager::Print(const char *format, ...) +{ + va_list args; + + va_start(args, format); + vfprintf(stdout, format, args); + va_end(args); + + fflush(stdout); // Make sure output isn't buffered. +} + +void InterfaceManager::PrintError(const char *format, ...) +{ + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + fflush(stderr); // Make sure output isn't buffered. +} diff --git a/heimdall/source/InterfaceManager.h b/heimdall/source/InterfaceManager.h new file mode 100644 index 0000000..734c086 --- /dev/null +++ b/heimdall/source/InterfaceManager.h @@ -0,0 +1,109 @@ +/* Copyright (c) 2010 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 INTERFACEMANAGER_H +#define INTERFACEMANAGER_H + +// C/C++ Standard Library +#include +#include + +using namespace std; + +namespace Heimdall +{ + class InterfaceManager + { + public: + + enum + { + kActionFlash = 0, + kActionClosePcScreen, + kActionDump, + kActionHelp, + kActionCount + }; + + enum + { + // Valueless arguments + kFlashArgRepartition = 0, + + // Regular arguments + kFlashArgPit, + kFlashArgFactoryFs, + kFlashArgCache, + kFlashArgData, + kFlashArgPrimaryBootloader, + kFlashArgSecondaryBootloader, + kFlashArgSecondaryBootloaderBackup, + kFlashArgParam, + kFlashArgKernel, + kFlashArgRecovery, + kFlashArgEfs, + kFlashArgModem, + + kFlashArgCount + }; + + enum + { + // Regular arguments + kDumpArgChipType = 0, + kDumpArgChipId, + kDumpArgOutput, + + kDumpArgCount + }; + + enum + { + // Valueless arguments + kCommonArgVerbose = 0, + + // Regular arguments + kCommonArgDelay, + + kCommonArgCount + }; + + static string actionNames[kActionCount]; + + static string flashArgumentNames[kFlashArgCount * 2]; + static string dumpArgumentNames[kDumpArgCount * 2]; + static string commonArgumentNames[kCommonArgCount * 2]; + + // argumentNames[kActionCount][] defines common arguments. + static string *actionArgumentNames[kActionCount + 1]; + + static int actionArgumentCounts[kActionCount + 1]; + static int actionValuelessArgumentCounts[kActionCount + 1]; + + static const char *usage; + + static bool GetArguments(int argc, char **argv, map& argumentMap, int *actionIndex); + + static void Print(const char *format, ...); + static void PrintError(const char *format, ...); + }; +} + +#endif diff --git a/heimdall/source/OutboundPacket.h b/heimdall/source/OutboundPacket.h new file mode 100644 index 0000000..d433d84 --- /dev/null +++ b/heimdall/source/OutboundPacket.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2010 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 OUTBOUNDPACKET_H +#define OUTBOUNDPACKET_H + +// Heimdall include +#include "Packet.h" + +namespace Heimdall +{ + class OutboundPacket : public Packet + { + protected: + + void PackInteger(unsigned int offset, unsigned int value) + { +#ifdef PPC + data[offset] = (value & 0xFF000000) >> 24; + data[offset + 1] = (value & 0x00FF0000) >> 16; + data[offset + 2] = (value & 0x0000FF00) >> 8; + data[offset + 3] = value & 0x000000FF; +#else + // Flip endianness + data[offset] = value & 0x000000FF; + data[offset + 1] = (value & 0x0000FF00) >> 8; + data[offset + 2] = (value & 0x00FF0000) >> 16; + data[offset + 3] = (value & 0xFF000000) >> 24; +#endif + } + + void PackShort(unsigned int offset, unsigned short value) + { +#ifdef PPC + data[offset] = (value & 0xFF00) >> 8; + data[offset + 1] = value & 0x00FF; +#else + // Flip endianness + data[offset] = value & 0x00FF; + data[offset + 1] = (value & 0xFF00) >> 8; +#endif + } + + public: + + OutboundPacket(unsigned int size) : Packet(size) + { + } + + virtual void Pack(void) = 0; + }; +} + +#endif diff --git a/heimdall/source/Packet.h b/heimdall/source/Packet.h new file mode 100644 index 0000000..33469f1 --- /dev/null +++ b/heimdall/source/Packet.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2010 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 PACKET_H +#define PACKET_H + +// C++ Standard Library +#include + +namespace Heimdall +{ + class Packet + { + private: + + unsigned int size; + + protected: + + unsigned char *data; + + public: + + Packet(unsigned int size) + { + this->size = size; + data = new unsigned char[size]; + memset(data, 0, size); + } + + ~Packet() + { + delete [] data; + } + + int GetSize(void) const + { + return (size); + } + + unsigned char *GetData(void) + { + return (data); + } + }; +} + +#endif diff --git a/heimdall/source/PitFilePacket.h b/heimdall/source/PitFilePacket.h new file mode 100644 index 0000000..d23314e --- /dev/null +++ b/heimdall/source/PitFilePacket.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2010 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 PITFILEPACKET_H +#define PITFILEPACKET_H + +// Heimdall +#include "ControlPacket.h" + +namespace Heimdall +{ + class PitFilePacket : public ControlPacket + { + public: + + enum + { + kRequestFlash = 0x00, + kRequestDump = 0x01, + kRequestPart = 0x02, + kRequestEndTransfer = 0x03 + }; + + protected: + + enum + { + kDataSize = ControlPacket::kDataSize + 4 + }; + + private: + + unsigned int request; + + public: + + PitFilePacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypePitFile) + { + 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/PitFileResponse.h b/heimdall/source/PitFileResponse.h new file mode 100644 index 0000000..bf8f6f6 --- /dev/null +++ b/heimdall/source/PitFileResponse.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2010 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 PITFILERESPONSE_H +#define PITFILERESPONSE_H + +// Heimdall +#include "ResponsePacket.h" + +namespace Heimdall +{ + class PitFileResponse : public ResponsePacket + { + private: + + unsigned int fileSize; + + public: + + PitFileResponse() : ResponsePacket(ResponsePacket::kResponseTypePitFile) + { + } + + unsigned int GetFileSize(void) const + { + return (fileSize); + } + + bool Unpack(void) + { + if (!ResponsePacket::Unpack()) + return (false); + + fileSize = UnpackInteger(ResponsePacket::kDataSize); + + return (true); + } + }; +} + +#endif diff --git a/heimdall/source/RebootDevicePacket.h b/heimdall/source/RebootDevicePacket.h new file mode 100644 index 0000000..f40a227 --- /dev/null +++ b/heimdall/source/RebootDevicePacket.h @@ -0,0 +1,64 @@ +/* Copyright (c) 2010 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 REBOOTDEVICEPACKET_H +#define REBOOTDEVICEPACKET_H + +// Heimdall +#include "ControlPacket.h" + +namespace Heimdall +{ + class RebootDevicePacket : public ControlPacket + { + public: + + enum + { + kRequestEndSession = 0, + kRequestRebootDevice = 1 + }; + + private: + + unsigned int request; + + public: + + RebootDevicePacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeRebootDevice) + { + 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/ReceiveFilePartPacket.h b/heimdall/source/ReceiveFilePartPacket.h new file mode 100644 index 0000000..5671ed4 --- /dev/null +++ b/heimdall/source/ReceiveFilePartPacket.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2010 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 RECEIVEFILEPARTPACKET_H +#define RECEIVEFILEPARTPACKET_H + +// Heimdall +#include "InboundPacket.h" + +namespace Heimdall +{ + class ReceiveFilePartPacket : public InboundPacket + { + public: + + enum + { + kDataSize = 500 + }; + + ReceiveFilePartPacket() : InboundPacket(kDataSize, true) + { + } + + bool Unpack(void) + { + return (true); + } + }; +} + +#endif diff --git a/heimdall/source/ResponsePacket.h b/heimdall/source/ResponsePacket.h new file mode 100644 index 0000000..ce799b5 --- /dev/null +++ b/heimdall/source/ResponsePacket.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2010 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 RESPONSEPACKET_H +#define RESPONSEPACKET_H + +// Heimdall +#include "InboundPacket.h" + +namespace Heimdall +{ + class ResponsePacket : public InboundPacket + { + public: + + enum + { + kResponseTypeSendFilePart = 0x00, + kResponseTypeDeviceInfo = 0x64, + kResponseTypePitFile = 0x65, + kResponseTypeFileTransfer = 0x66, + kResponseTypeRebootDevice = 0x67 + }; + + private: + + unsigned int responseType; + + protected: + + enum + { + kDataSize = 4 + }; + + public: + + ResponsePacket(int responseType) : InboundPacket(8) + { + this->responseType = responseType; + } + + unsigned int GetResponseType(void) const + { + return (responseType); + } + + virtual bool Unpack(void) + { + const unsigned char *data = GetData(); + + unsigned int receivedResponseType = UnpackInteger(0); + if (receivedResponseType != responseType) + { + responseType = receivedResponseType; + return (false); + } + + return (true); + } + }; +} + +#endif diff --git a/heimdall/source/SendFilePartPacket.h b/heimdall/source/SendFilePartPacket.h new file mode 100644 index 0000000..0b41830 --- /dev/null +++ b/heimdall/source/SendFilePartPacket.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2010 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 SENDFILEPARTPACKET_H +#define SENDFILEPARTPACKET_H + +// C Standard Library +#include +#include + +// Heimdall +#include "Packet.h" + +namespace Heimdall +{ + class SendFilePartPacket : public OutboundPacket + { + public: + + enum + { + kDefaultPacketSize = 131072 + }; + + SendFilePartPacket(FILE *file, int size = SendFilePartPacket::kDefaultPacketSize) : OutboundPacket(size) + { + memset(data, 0, size); + + long position = ftell(file); + + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + fseek(file, position, SEEK_SET); + + // min(fileSize, size) + int bytesToRead = (fileSize < size) ? fileSize - position : size; + fread(data, 1, bytesToRead, file); + } + + void Pack(void) + { + } + }; +} + +#endif diff --git a/heimdall/source/SendFilePartResponse.h b/heimdall/source/SendFilePartResponse.h new file mode 100644 index 0000000..ba6eb6b --- /dev/null +++ b/heimdall/source/SendFilePartResponse.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2010 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 SENDFILEPARTRESPONSE_H +#define SENDFILEPARTRESPONSE_H + +// Heimdall +#include "ResponsePacket.h" + +namespace Heimdall +{ + class SendFilePartResponse : public ResponsePacket + { + private: + + unsigned int partIndex; + + public: + + SendFilePartResponse() : ResponsePacket(ResponsePacket::kResponseTypeSendFilePart) + { + } + + unsigned int GetPartIndex(void) const + { + return (partIndex); + } + + bool Unpack(void) + { + if (!ResponsePacket::Unpack()) + return (false); + + partIndex = UnpackInteger(ResponsePacket::kDataSize); + + return (true); + } + }; +} + +#endif diff --git a/heimdall/source/main.cpp b/heimdall/source/main.cpp new file mode 100644 index 0000000..037d097 --- /dev/null +++ b/heimdall/source/main.cpp @@ -0,0 +1,660 @@ +/* Copyright (c) 2010 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 +#include +#include +#include + +// Heimdall +#include "BridgeManager.h" +#include "DeviceInfoPacket.h" +#include "DeviceInfoResponse.h" +#include "EndModemFileTransferPacket.h" +#include "EndPhoneFileTransferPacket.h" +#include "InterfaceManager.h" + +using namespace std; +using namespace Heimdall; + +enum +{ + kFilePit = 0, + kFileFactoryFs, + kFileCache, + kFileData, + kFilePrimaryBootloader, + kFileSecondaryBootloader, + kFileSecondaryBootloaderBackup, + kFileParam, + kFileKernel, + kFileRecovery, + kFileEfs, + kFileModem, + kFileCount +}; + +bool flashFile(BridgeManager *bridgeManager, FILE *file, int fileIndex) +{ + switch (fileIndex) + { + case kFilePit: + + InterfaceManager::Print("Uploading PIT file\n"); + if (bridgeManager->SendPitFile(file)) + { + InterfaceManager::Print("PIT file upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("PIT file upload failed!\n"); + return (false); + } + + case kFileFactoryFs: + + InterfaceManager::Print("Uploading factory filesytem\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileFactoryFilesystem)) + { + InterfaceManager::Print("Factory filesytem upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Factory filesytem upload failed!\n"); + return (false); + } + + case kFileCache: + + InterfaceManager::Print("Uploading cache\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileCache)) + { + InterfaceManager::Print("Cache upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Cache upload failed!\n"); + return (false); + } + + case kFileData: + + InterfaceManager::Print("Uploading data database\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileDatabaseData)) + { + InterfaceManager::Print("Data database upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Data database upload failed!\n"); + return (false); + } + + case kFilePrimaryBootloader: + + InterfaceManager::Print("Uploading primary bootloader\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFilePrimaryBootloader)) + { + InterfaceManager::Print("Primary bootloader upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Primary bootloader upload failed!\n"); + return (false); + } + + case kFileSecondaryBootloader: + + InterfaceManager::Print("Uploading secondary bootloader\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileSecondaryBootloader)) + { + InterfaceManager::Print("Secondary bootloader upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Secondary bootloader upload failed!\n"); + return (false); + } + + case kFileSecondaryBootloaderBackup: + + InterfaceManager::Print("Uploading backup secondary bootloader\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileSecondaryBootloaderBackup)) + { + InterfaceManager::Print("Backup secondary bootloader upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Backup secondary bootloader upload failed!\n"); + return (false); + } + + case kFileParam: + InterfaceManager::Print("Uploading param.lfs\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileParamLfs)) + { + InterfaceManager::Print("param.lfs upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("param.lfs upload failed!\n"); + return (false); + } + + case kFileKernel: + + InterfaceManager::Print("Uploading kernel\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileKernel)) + { + InterfaceManager::Print("Kernel upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Kernel upload failed!\n"); + return (false); + } + + case kFileModem: + + InterfaceManager::Print("Uploading modem\n"); + + /*if (bridgeManager->SendFile(file, EndModemFileTransferPacket::kDestinationModem))*/ // <-- Odin method + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, // <-- Kies method + EndPhoneFileTransferPacket::kFileModem)) + { + InterfaceManager::Print("Modem upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Modem upload failed!\n"); + return (false); + } + + case kFileRecovery: + + InterfaceManager::Print("Uploading recovery\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileRecovery)) + { + InterfaceManager::Print("Recovery upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("Recovery upload failed!\n"); + return (false); + } + + case kFileEfs: + + InterfaceManager::Print("Uploading EFS\n"); + if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, + EndPhoneFileTransferPacket::kFileEfs)) + { + InterfaceManager::Print("EFS upload successful\n"); + return (true); + } + else + { + InterfaceManager::PrintError("EFS upload failed!\n"); + return (false); + } + + default: + + InterfaceManager::PrintError("ERROR: Attempted to flash unknown file!\n"); + return (false); + } +} + +bool attemptFlash(BridgeManager *bridgeManager, FILE **fileArray, bool repartition) +{ + bool success; + + // ---------- GET DEVICE INFORMATION ---------- + + DeviceInfoPacket *deviceInfoPacket = new DeviceInfoPacket(DeviceInfoPacket::kUnknown1); + success = bridgeManager->SendPacket(deviceInfoPacket); + delete deviceInfoPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send device info packet!\nFailed Request: kUnknown1\n"); + return (false); + } + + DeviceInfoResponse *deviceInfoResponse = new DeviceInfoResponse(); + success = bridgeManager->ReceivePacket(deviceInfoResponse); + int unknown = deviceInfoResponse->GetUnknown(); + delete deviceInfoResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive device info response!\n"); + return (false); + } + + if (unknown != 0) + { + InterfaceManager::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%i\n", unknown); + + if (!bridgeManager->EndSession()) + return (false); + bridgeManager->RebootDevice(); + + return (false); + } + + // -------------------- KIES DOESN'T DO THIS -------------------- + deviceInfoPacket = new DeviceInfoPacket(DeviceInfoPacket::kUnknown2); + success = bridgeManager->SendPacket(deviceInfoPacket); + delete deviceInfoPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send device info packet!\nFailed Request: kUnknown2\n"); + return (false); + } + + deviceInfoResponse = new DeviceInfoResponse(); + success = bridgeManager->ReceivePacket(deviceInfoResponse); + unknown = deviceInfoResponse->GetUnknown(); + delete deviceInfoResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive device info response!\n"); + return (false); + } + + // TODO: Work out what this value is... it has been either 180 or 0 for Galaxy S phones, and 3 on the Galaxy Tab. + if (unknown != 180 && unknown != 0 && unknown != 3) + { + InterfaceManager::PrintError("Unexpected device info response!\nExpected: 180, 0 or 3\nReceived:%i\n", unknown); + + if (!bridgeManager->EndSession()) + return (false); + bridgeManager->RebootDevice(); + + return (false); + } + // -------------------------------------------------------------- + + int totalBytes = 0; + for (int i = kFileFactoryFs; i < kFileCount; i++) + { + if (fileArray[i]) + { + fseek(fileArray[i], 0, SEEK_END); + totalBytes += ftell(fileArray[i]); + rewind(fileArray[i]); + } + } + + if (repartition) + { + // When repartitioning we send the PIT file to the device. + fseek(fileArray[kFilePit], 0, SEEK_END); + totalBytes += ftell(fileArray[kFilePit]); + rewind(fileArray[kFilePit]); + } + + deviceInfoPacket = new DeviceInfoPacket(DeviceInfoPacket::kTotalBytes, totalBytes); + success = bridgeManager->SendPacket(deviceInfoPacket); + delete deviceInfoPacket; + + if (!success) + { + InterfaceManager::PrintError("Failed to send total bytes device info packet!\n"); + return (false); + } + + deviceInfoResponse = new DeviceInfoResponse(); + success = bridgeManager->ReceivePacket(deviceInfoResponse); + unknown = deviceInfoResponse->GetUnknown(); + delete deviceInfoResponse; + + if (!success) + { + InterfaceManager::PrintError("Failed to receive device info response!\n"); + return (false); + } + + if (unknown != 0) + { + InterfaceManager::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%i\n", unknown); + + if (!bridgeManager->EndSession()) + return (false); + bridgeManager->RebootDevice(); + + return (false); + } + + // ----------------------------------------------------- + + if (fileArray[kFilePit]) + { + if (repartition) + { + flashFile(bridgeManager, fileArray[kFilePit], kFilePit); + } + else // We're performing a PIT check + { + // Load the local pit file into memory. + char *localPit = new char[4096]; + memset(localPit, 0, 4096); + + fseek(fileArray[kFilePit], 0, SEEK_END); + long localPitFileSize = ftell(fileArray[kFilePit]); + rewind(fileArray[kFilePit]); + + fread(localPit, 1, localPitFileSize, fileArray[kFilePit]); + + InterfaceManager::Print("Downloading device's PIT file...\n"); + + unsigned char *devicePit; + int devicePitFileSize = bridgeManager->ReceivePitFile(&devicePit); + + if (!devicePit) + { + InterfaceManager::PrintError("Failed to download PIT file!\n"); + + if (!bridgeManager->EndSession()) + return (false); + bridgeManager->RebootDevice(); + + return (false); + } + + InterfaceManager::Print("PIT file download sucessful\n\n"); + + bool pitFilesMatch = !memcmp(localPit, devicePit, localPitFileSize); + + delete [] localPit; + delete [] devicePit; + + if (!pitFilesMatch) + { + InterfaceManager::Print("Optional PIT check failed! To disable this check don't use the --pit parameter."); + + if (!bridgeManager->EndSession()) + return (false); + bridgeManager->RebootDevice(); + + return (false); + } + } + } + + // Flash specified files + for (int fileIndex = kFileFactoryFs; fileIndex < kFileCount; fileIndex++) + { + if (fileArray[fileIndex]) + { + if (!flashFile(bridgeManager, fileArray[fileIndex], fileIndex)) + return (false); + } + } + + return (bridgeManager->EndSession() && bridgeManager->RebootDevice()); +} + +bool openFiles(const map& argumentMap, FILE **fileArray) +{ + for (int fileIndex = 0; fileIndex < kFileCount; fileIndex++) + { + // kFlashArgPit + kFile == kFlashArg + map::const_iterator it = argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit + fileIndex]); + if (it == argumentMap.end()) + continue; + + fileArray[fileIndex] = fopen(it->second.c_str(), "rb"); + if (!fileArray[fileIndex]) + { + InterfaceManager::PrintError("Failed to open file \"%s\"\n", it->second.c_str()); + return (false); + } + } + + return (true); +} + +void closeFiles(FILE **fileArray) +{ + for (int fileIndex = 0; fileIndex < kFileCount; fileIndex++) + { + if (fileArray[fileIndex] != nullptr) + fclose(fileArray[fileIndex]); + } +} + +int main(int argc, char **argv) +{ + map argumentMap; + int actionIndex; + + if (!InterfaceManager::GetArguments(argc, argv, argumentMap, &actionIndex)) + { + Sleep(1000); + return (0); + } + + if (actionIndex == InterfaceManager::kActionHelp) + { + InterfaceManager::Print(InterfaceManager::usage); + return (0); + } + else if (actionIndex == InterfaceManager::kActionFlash) + { + if (argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) != argumentMap.end() + && (argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit]) == argumentMap.end() + || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgFactoryFs]) == argumentMap.end() + || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgCache]) == argumentMap.end() + || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgData]) == argumentMap.end() + || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPrimaryBootloader]) == argumentMap.end() + || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgSecondaryBootloader]) == argumentMap.end() + || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgParam]) == argumentMap.end() + || argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgKernel]) == argumentMap.end())) + { + InterfaceManager::Print("If you wish to repartition then factoryfs, cache, dbdata, primary and secondary\nbootloaders, param, kernel and a PIT file must all be specified.\n"); + return (0); + } + } + else if (actionIndex == InterfaceManager::kActionDump) + { + if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgOutput]) == argumentMap.end()) + { + InterfaceManager::Print("Output file not specified.\n\n"); + InterfaceManager::Print(InterfaceManager::usage); + return (0); + } + + if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType]) == argumentMap.end()) + { + InterfaceManager::Print("You must specify a chip type.\n\n"); + InterfaceManager::Print(InterfaceManager::usage); + return (0); + } + + string chipType = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType])->second; + if (!(chipType == "RAM" || chipType == "ram" || chipType == "NAND" || chipType == "nand")) + { + InterfaceManager::Print("Unknown chip type: %s.\n\n", chipType.c_str()); + InterfaceManager::Print(InterfaceManager::usage); + return (0); + } + + if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId]) == argumentMap.end()) + { + InterfaceManager::Print("You must specify a Chip ID.\n\n"); + InterfaceManager::Print(InterfaceManager::usage); + return (0); + } + + int chipId = atoi(argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId])->second.c_str()); + if (chipId < 0) + { + InterfaceManager::Print("Chip ID must be a non-negative integer.\n"); + return (0); + } + } + + InterfaceManager::Print("\nHeimdall, Copyright (c) 2010, Benjamin Dobell, Glass Echidna\n"); + InterfaceManager::Print("http://www.glassechidna.com.au\n\n"); + InterfaceManager::Print("This software is provided free of charge. Copying and redistribution is\nencouraged.\n\n"); + InterfaceManager::Print("If you appreciate this software and you would like to support future\ndevelopment please consider donating:\n"); + InterfaceManager::Print("http://www.glassechidna.com.au/donate/\n\n"); + + Sleep(1000); + + bool verbose = argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgVerbose]) != argumentMap.end(); + + int communicationDelay = BridgeManager::kCommunicationDelayDefault; + if (argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgDelay]) != argumentMap.end()) + communicationDelay = atoi(argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgDelay])->second.c_str()); + + BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); + + if (!bridgeManager->Initialise()) + { + delete bridgeManager; + return (-2); + } + + bool success; + + switch (actionIndex) + { + case InterfaceManager::kActionFlash: + { + FILE **fileArray = new FILE *[kFileCount]; + for (int i = 0; i < kFileCount; i++) + fileArray[i] = nullptr; + + // We open the files before doing anything else to ensure they exist. + if (!openFiles(argumentMap, fileArray)) + { + closeFiles(fileArray); + delete [] fileArray; + + delete bridgeManager; + + return (0); + } + + if (!bridgeManager->BeginSession()) + { + closeFiles(fileArray); + delete [] fileArray; + + delete bridgeManager; + + return (-1); + } + + bool repartition = argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) != argumentMap.end(); + success = attemptFlash(bridgeManager, fileArray, repartition); + + closeFiles(fileArray); + delete [] fileArray; + + break; + } + + case InterfaceManager::kActionClosePcScreen: + { + if (!bridgeManager->BeginSession()) + { + delete bridgeManager; + return (-1); + } + + InterfaceManager::Print("Attempting to close connect to pc screen...\n"); + success = bridgeManager->EndSession() && bridgeManager->RebootDevice(); + + if (success) + InterfaceManager::Print("Attempt complete\n"); + + break; + } + + case InterfaceManager::kActionDump: + { + const char *outputFilename = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgOutput])->second.c_str(); + FILE *dumpFile = fopen(outputFilename, "wb"); + if (!dumpFile) + { + InterfaceManager::PrintError("Failed to open file \"%s\"\n", outputFilename); + + delete bridgeManager; + return (-1); + } + + int chipType = 0; + string chipTypeName = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType])->second; + if (chipTypeName == "NAND" || chipTypeName == "nand") + chipType = 1; + + int chipId = atoi(argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId])->second.c_str()); + + if (!bridgeManager->BeginSession()) + { + fclose(dumpFile); + + delete bridgeManager; + + return (-1); + } + + success = bridgeManager->ReceiveDump(chipType, chipId, dumpFile); + + fclose(dumpFile); + + if (success) + success = bridgeManager->EndSession() && bridgeManager->RebootDevice(); + + break; + } + } + + delete bridgeManager; + + return ((success) ? 0 : -1); +} \ No newline at end of file -- cgit v1.2.3