int main(int argc, char **argv) { map<string, string> argumentMap; int actionIndex; if (!InterfaceManager::GetArguments(argc, argv, argumentMap, &actionIndex)) { Sleep(250); return (0); } initialiseKnownPartitionNames(); 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()) { InterfaceManager::Print("If you wish to repartition then a PIT file must be specified.\n"); return (0); } if (argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit]) != argumentMap.end() && argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) == argumentMap.end()) { InterfaceManager::Print("A PIT file should only be used when repartitioning.\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 v1.2.0, Copyright (c) 2010-2011, 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(); bool noReboot = argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgNoReboot]) != 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: { map<string, FILE *> argumentFileMap; // We open the files before doing anything else to ensure they exist. if (!openFiles(argumentMap, argumentFileMap)) { closeFiles(argumentFileMap); delete bridgeManager; return (0); } if (!bridgeManager->BeginSession()) { closeFiles(argumentFileMap); delete bridgeManager; return (-1); } bool repartition = argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) != argumentMap.end(); success = attemptFlash(bridgeManager, argumentFileMap, repartition); if (noReboot) success = bridgeManager->EndSession() && success; else success = bridgeManager->EndSession() && bridgeManager->RebootDevice() && success; closeFiles(argumentFileMap); break; } case InterfaceManager::kActionClosePcScreen: { if (!bridgeManager->BeginSession()) { delete bridgeManager; return (-1); } InterfaceManager::Print("Attempting to close connect to pc screen...\n"); if (noReboot) success = bridgeManager->EndSession(); else 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 (noReboot) success = bridgeManager->EndSession() && success; else success = bridgeManager->EndSession() && bridgeManager->RebootDevice() && success; break; } case InterfaceManager::kActionPrintPit: { if (!bridgeManager->BeginSession()) { delete bridgeManager; return (-1); } unsigned char *devicePit; if (downloadPitFile(bridgeManager, &devicePit) < -1) { if (!bridgeManager->EndSession()) return (-1); if (!noReboot) bridgeManager->RebootDevice(); delete bridgeManager; return (-1); } PitData *pitData = new PitData(); if (pitData->Unpack(devicePit)) { pitData->Print(); success = true; } else { InterfaceManager::PrintError("Failed to unpack device's PIT file!\n"); success = false; } delete pitData; if (noReboot) success = bridgeManager->EndSession() && success; else success = bridgeManager->EndSession() && bridgeManager->RebootDevice() && success; break; } } delete bridgeManager; return ((success) ? 0 : -1); }
static PitData *getPitData(BridgeManager *bridgeManager, FILE *pitFile, bool repartition) { PitData *pitData; PitData *localPitData = nullptr; // If a PIT file was passed as an argument then we must unpack it. if (pitFile) { // Load the local pit file into memory. FileSeek(pitFile, 0, SEEK_END); unsigned int localPitFileSize = (unsigned int)FileTell(pitFile); FileRewind(pitFile); unsigned char *pitFileBuffer = new unsigned char[localPitFileSize]; memset(pitFileBuffer, 0, localPitFileSize); int dataRead = fread(pitFileBuffer, 1, localPitFileSize, pitFile); if (dataRead > 0) { FileRewind(pitFile); localPitData = new PitData(); localPitData->Unpack(pitFileBuffer); delete [] pitFileBuffer; } else { Interface::PrintError("Failed to read PIT file.\n"); delete [] pitFileBuffer; return (nullptr); } } if (repartition) { // Use the local PIT file data. pitData = localPitData; } else { // If we're not repartitioning then we need to retrieve the device's PIT file and unpack it. unsigned char *pitFileBuffer; if (bridgeManager->DownloadPitFile(&pitFileBuffer) == 0) return (nullptr); pitData = new PitData(); pitData->Unpack(pitFileBuffer); delete [] pitFileBuffer; if (localPitData != nullptr) { // The user has specified a PIT without repartitioning, we should verify the local and device PIT data match! bool pitsMatch = pitData->Matches(localPitData); delete localPitData; if (!pitsMatch) { Interface::Print("Local and device PIT files don't match and repartition wasn't specified!\n"); Interface::PrintError("Flash aborted!\n"); return (nullptr); } } } return (pitData); }
bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFileMap, 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); } // 131072 for Galaxy S II, 0 for other devices. if (unknown != 0 && unknown != 131072) { InterfaceManager::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%i\n", unknown); 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, 3 on the Galaxy Tab, 190 for SHW-M110S. if (unknown != 180 && unknown != 0 && unknown != 3 && unknown != 190) { InterfaceManager::PrintError("Unexpected device info response!\nExpected: 180, 0 or 3\nReceived:%i\n", unknown); return (false); } // -------------------------------------------------------------- int totalBytes = 0; for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) { fseek(it->second, 0, SEEK_END); totalBytes += ftell(it->second); rewind(it->second); } 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); return (false); } // ----------------------------------------------------- PitData *pitData; FILE *localPitFile = nullptr; if (repartition) { // If we're repartitioning then we need to unpack the information from the specified PIT file. map<string, FILE *>::iterator it = argumentFileMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit]); // This shouldn't ever happen due to early checks, but we'll check again just in case... if (it == argumentFileMap.end()) { InterfaceManager::PrintError("Attempt was made to repartition without specifying a PIT file!\n"); return (false); } localPitFile = it->second; // Load the local pit file into memory. unsigned char *pitFileBuffer = new unsigned char[4096]; memset(pitFileBuffer, 0, 4096); fseek(localPitFile, 0, SEEK_END); long localPitFileSize = ftell(localPitFile); rewind(localPitFile); // dataRead is discarded, it's here to remove warnings. int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile); rewind(localPitFile); pitData = new PitData(); pitData->Unpack(pitFileBuffer); delete [] pitFileBuffer; } else { // If we're not repartitioning then we need to retrieve the device's PIT file and unpack it. unsigned char *pitFileBuffer; downloadPitFile(bridgeManager, &pitFileBuffer); pitData = new PitData(); pitData->Unpack(pitFileBuffer); delete [] pitFileBuffer; } map<unsigned int, PartitionNameFilePair> partitionFileMap; // Map the files being flashed to partitions stored in PIT file. mapFilesToPartitions(argumentFileMap, pitData, partitionFileMap); delete pitData; // If we're repartitioning then we need to flash the PIT file first. if (repartition) { for (map<unsigned int, PartitionNameFilePair>::iterator it = partitionFileMap.begin(); it != partitionFileMap.end(); it++) { if (it->second.file == localPitFile) { if (!flashFile(bridgeManager, it->first, it->second.partitionName.c_str(), it->second.file)) return (false); } } } // Flash all other files for (map<unsigned int, PartitionNameFilePair>::iterator it = partitionFileMap.begin(); it != partitionFileMap.end(); it++) { if (it->second.file != localPitFile) { if (!flashFile(bridgeManager, it->first, it->second.partitionName.c_str(), it->second.file)) return (false); } } return (true); }