From 6cd6b35c737e0e4042a8fd79af1decc9f10ed84b Mon Sep 17 00:00:00 2001 From: Benjamin Dobell Date: Mon, 1 Oct 2012 12:43:05 +1000 Subject: Heimdall 1.4 RC1: - Massive refactoring. - Support for Qualcomm based devices. - Print PIT from file. - Use partition names as arguments e.g. --HIDDEN, --KERNEL, --MOVINAND etc. - Heimdall Frontend UI improvements. - And much more... --- heimdall/source/main.cpp | 778 +---------------------------------------------- 1 file changed, 12 insertions(+), 766 deletions(-) (limited to 'heimdall/source/main.cpp') diff --git a/heimdall/source/main.cpp b/heimdall/source/main.cpp index db7de1c..41d7a3c 100644 --- a/heimdall/source/main.cpp +++ b/heimdall/source/main.cpp @@ -28,782 +28,28 @@ #include "libpit.h" // Heimdall -#include "BridgeManager.h" -#include "SetupSessionPacket.h" -#include "SetupSessionResponse.h" -#include "EndModemFileTransferPacket.h" -#include "EndPhoneFileTransferPacket.h" +#include "Heimdall.h" +#include "HelpAction.h" #include "Interface.h" using namespace std; using namespace Heimdall; -// Known partitions -enum -{ - kKnownPartitionPit = 0, - kKnownPartitionFactoryFs, - kKnownPartitionCache, - kKnownPartitionDatabaseData, - kKnownPartitionPrimaryBootloader, - kKnownPartitionSecondaryBootloader, - kKnownPartitionSecondaryBootloaderBackup, - kKnownPartitionParam, - kKnownPartitionKernel, - kKnownPartitionRecovery, - kKnownPartitionEfs, - kKnownPartitionModem, - - kKnownPartitionNormalBoot, - kKnownPartitionSystem, - kKnownPartitionUserData, - kKnownPartitionFota, - kKnownPartitionHidden, - kKnownPartitionMovinand, - kKnownPartitionData, - kKnownPartitionUms, - kKnownPartitionEmmc, - - kKnownPartitionCount -}; - -vector knownPartitionNames[kKnownPartitionCount]; - -struct PartitionInfo -{ - unsigned int chipIdentifier; - string partitionName; - FILE *file; - - PartitionInfo(unsigned int chipIdentifier, const char *partitionName, FILE *file) - { - this->chipIdentifier = chipIdentifier; - this->partitionName = partitionName; - this->file = file; - } -}; - -void initialiseKnownPartitionNames(void) -{ - knownPartitionNames[kKnownPartitionPit].push_back("PIT"); - knownPartitionNames[kKnownPartitionFactoryFs].push_back("FACTORYFS"); - knownPartitionNames[kKnownPartitionCache].push_back("CACHE"); - knownPartitionNames[kKnownPartitionDatabaseData].push_back("DBDATAFS"); - - knownPartitionNames[kKnownPartitionPrimaryBootloader].push_back("IBL+PBL"); - knownPartitionNames[kKnownPartitionPrimaryBootloader].push_back("BOOT"); - - knownPartitionNames[kKnownPartitionSecondaryBootloader].push_back("SBL"); - knownPartitionNames[kKnownPartitionSecondaryBootloader].push_back("SBL1"); - - knownPartitionNames[kKnownPartitionSecondaryBootloaderBackup].push_back("SBL2"); - knownPartitionNames[kKnownPartitionParam].push_back("PARAM"); - knownPartitionNames[kKnownPartitionKernel].push_back("KERNEL"); - knownPartitionNames[kKnownPartitionRecovery].push_back("RECOVERY"); - knownPartitionNames[kKnownPartitionEfs].push_back("EFS"); - knownPartitionNames[kKnownPartitionModem].push_back("MODEM"); - - knownPartitionNames[kKnownPartitionNormalBoot].push_back("NORMALBOOT"); - knownPartitionNames[kKnownPartitionSystem].push_back("SYSTEM"); - knownPartitionNames[kKnownPartitionUserData].push_back("USERDATA"); - knownPartitionNames[kKnownPartitionFota].push_back("FOTA"); - knownPartitionNames[kKnownPartitionHidden].push_back("HIDDEN"); - knownPartitionNames[kKnownPartitionMovinand].push_back("MOVINAND"); - knownPartitionNames[kKnownPartitionData].push_back("DATAFS"); - knownPartitionNames[kKnownPartitionUms].push_back("UMS.EN"); - knownPartitionNames[kKnownPartitionEmmc].push_back("GANG"); -} - -bool isKnownPartition(const char *partitionName, unsigned int knownPartitionIndex) -{ - for (unsigned int i = 0; i < knownPartitionNames[knownPartitionIndex].size(); i++) - { - if (strcmp(partitionName, knownPartitionNames[knownPartitionIndex][i]) == 0) - return (true); - } - - return (false); -} - -bool isKnownBootPartition(const char *partitionName) -{ - return (isKnownPartition(partitionName, kKnownPartitionPrimaryBootloader) || - isKnownPartition(partitionName, kKnownPartitionSecondaryBootloader) || - isKnownPartition(partitionName, kKnownPartitionSecondaryBootloaderBackup) || - isKnownPartition(partitionName, kKnownPartitionParam) || - isKnownPartition(partitionName, kKnownPartitionNormalBoot)); -} - -bool openFiles(const map& argumentMap, map& argumentFileMap) -{ - map::const_iterator it = argumentMap.begin(); - - for (it = argumentMap.begin(); it != argumentMap.end(); it++) - { - bool isFileArgument = false; - - int partitionIndex = atoi(it->first.substr(it->first.find_first_not_of('-')).c_str()); - - // Was the argument a partition index? - if (partitionIndex > 0 || it->first.compare("-0") == 0) - { - isFileArgument = true; - } - else - { - // The argument wasn't a partition index, check if it's a known partition name. - for (int knownPartition = 0; knownPartition < kKnownPartitionCount; knownPartition++) - { - if (it->first == Interface::actions[Interface::kActionFlash].valueArguments[knownPartition]) - { - isFileArgument = true; - break; - } - } - } - - if (!isFileArgument) - continue; - - pair argumentFilePair; - argumentFilePair.first = it->first; - argumentFilePair.second = fopen(it->second.c_str(), "rb"); - - if (!argumentFilePair.second) - { - Interface::PrintError("Failed to open file \"%s\"\n", it->second.c_str()); - return (false); - } - - argumentFileMap.insert(argumentFilePair); - } - - return (true); -} - -bool mapFilesToPartitions(const map& argumentFileMap, const PitData *pitData, map& partitionInfoMap) -{ - map::const_iterator it = argumentFileMap.begin(); - - for (it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) - { - int partitionIndex = atoi(it->first.substr(it->first.find_first_not_of('-')).c_str()); - - const PitEntry *pitEntry = nullptr; - - // Was the argument a partition index? - if (partitionIndex > 0 || it->first.compare("-0") == 0) - { - pitEntry = pitData->FindEntry(partitionIndex); - } - else - { - // The argument wasn't a partition index, so it must be a known partition name. - int knownPartition; - - for (knownPartition = 0; knownPartition < kKnownPartitionCount; knownPartition++) - { - if (it->first == Interface::actions[Interface::kActionFlash].valueArguments[knownPartition]) - break; - } - - // Check for the partition in the PIT file using all known names. - for (unsigned int i = 0; i < knownPartitionNames[knownPartition].size(); i++) - { - pitEntry = pitData->FindEntry(knownPartitionNames[knownPartition][i]); - - if (pitEntry) - break; - } - - if (!pitEntry && knownPartition == kKnownPartitionPit) - { - // NOTE: We're assuming a PIT file always has chipIdentifier zero. - PartitionInfo partitionInfo(0, knownPartitionNames[kKnownPartitionPit][0], it->second); - partitionInfoMap.insert(pair(0xFFFFFFFF, partitionInfo)); - - return (true); - } - } - - if (!pitEntry) - { - Interface::PrintError("Partition corresponding to %s argument could not be located\n", it->first.c_str()); - return (false); - } - - PartitionInfo partitionInfo(pitEntry->GetChipIdentifier(), pitEntry->GetPartitionName(), it->second); - partitionInfoMap.insert(pair(pitEntry->GetPartitionIdentifier(), partitionInfo)); - } - - return (true); -} - -void closeFiles(map argumentfileMap) -{ - for (map::iterator it = argumentfileMap.begin(); it != argumentfileMap.end(); it++) - fclose(it->second); - - argumentfileMap.clear(); -} - -int downloadPitFile(BridgeManager *bridgeManager, unsigned char **pitBuffer) -{ - Interface::Print("Downloading device's PIT file...\n"); - - int devicePitFileSize = bridgeManager->ReceivePitFile(pitBuffer); - - if (!*pitBuffer) - { - Interface::PrintError("Failed to download PIT file!\n"); - - return (-1); - } - - Interface::Print("PIT file download sucessful\n\n"); - return (devicePitFileSize); -} - -bool flashFile(BridgeManager *bridgeManager, unsigned int chipIdentifier, unsigned int partitionIndex, const char *partitionName, FILE *file) -{ - // PIT files need to be handled differently, try determine if the partition we're flashing to is a PIT partition. - bool isPit = false; - - for (unsigned int i = 0; i < knownPartitionNames[kKnownPartitionPit].size(); i++) - { - if (strcmp(partitionName, knownPartitionNames[kKnownPartitionPit][i]) == 0) - { - isPit = true; - break; - } - } - - if (isPit) - { - Interface::Print("Uploading %s\n", partitionName); - - if (bridgeManager->SendPitFile(file)) - { - Interface::Print("%s upload successful\n", partitionName); - return (true); - } - else - { - Interface::Print("%s upload failed!\n", partitionName); - return (false); - } - } - else - { - // Modems need to be handled differently, try determine if the partition we're flashing to is a modem partition. - bool isModem = false; - - for (unsigned int i = 0; i < knownPartitionNames[kKnownPartitionModem].size(); i++) - { - if (strcmp(partitionName, knownPartitionNames[kKnownPartitionModem][i]) == 0) - { - isModem = true; - break; - } - } - - if (isModem) - { - Interface::Print("Uploading %s\n", partitionName); - - //if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, // <-- Kies method. WARNING: Doesn't work on Galaxy Tab! - // EndPhoneFileTransferPacket::kFileModem)) - if (bridgeManager->SendFile(file, EndModemFileTransferPacket::kDestinationModem, chipIdentifier)) // <-- Odin method - { - Interface::Print("%s upload successful\n", partitionName); - return (true); - } - else - { - Interface::Print("%s upload failed!\n", partitionName); - return (false); - } - } - else - { - // We're uploading to a phone partition - Interface::Print("Uploading %s\n", partitionName); - - if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, chipIdentifier, partitionIndex)) - { - Interface::Print("%s upload successful\n", partitionName); - return (true); - } - else - { - Interface::Print("%s upload failed!\n", partitionName); - return (false); - } - } - } - - return (true); -} - -bool attemptFlash(BridgeManager *bridgeManager, map argumentFileMap, bool repartition) -{ - bool success; - - // ------------- SEND TOTAL BYTES TO BE TRANSFERRED ------------- - - int totalBytes = 0; - for (map::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++) - { - if (repartition || it->first != Interface::GetPitArgument()) - { - fseek(it->second, 0, SEEK_END); - totalBytes += ftell(it->second); - rewind(it->second); - } - } - - SetupSessionPacket *deviceInfoPacket = new SetupSessionPacket(SetupSessionPacket::kTotalBytes, totalBytes); - success = bridgeManager->SendPacket(deviceInfoPacket); - delete deviceInfoPacket; - - if (!success) - { - Interface::PrintError("Failed to send total bytes device info packet!\n"); - return (false); - } - - SetupSessionResponse *deviceInfoResponse = new SetupSessionResponse(); - success = bridgeManager->ReceivePacket(deviceInfoResponse); - int deviceInfoResult = deviceInfoResponse->GetUnknown(); - delete deviceInfoResponse; - - if (!success) - { - Interface::PrintError("Failed to receive device info response!\n"); - return (false); - } - - if (deviceInfoResult != 0) - { - Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", deviceInfoResult); - return (false); - } - - // ----------------------------------------------------- - - PitData *pitData; - PitData *localPitData = nullptr; - - FILE *localPitFile = nullptr; - - // If a PIT file was passed as an argument then we must unpack it. - map::iterator it = argumentFileMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]); - - if (it != argumentFileMap.end()) - { - localPitFile = it->second; - - // Load the local pit file into memory. - unsigned char *pitFileBuffer = new unsigned char[4096]; - memset(pitFileBuffer, 0, 4096); - - fseek(localPitFile, 0, SEEK_END); - long localPitFileSize = ftell(localPitFile); - rewind(localPitFile); - - // dataRead is discarded, it's here to remove warnings. - int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile); - rewind(localPitFile); - - localPitData = new PitData(); - localPitData->Unpack(pitFileBuffer); - - delete [] pitFileBuffer; - } - - if (repartition) - { - // Use the local PIT file data. - pitData = localPitData; - } - else - { - // If we're not repartitioning then we need to retrieve the device's PIT file and unpack it. - unsigned char *pitFileBuffer; - downloadPitFile(bridgeManager, &pitFileBuffer); - - pitData = new PitData(); - pitData->Unpack(pitFileBuffer); - - delete [] pitFileBuffer; - - if (localPitData != nullptr) - { - // The user has specified a PIT without repartitioning, we should verify the local and device PIT data match! - bool pitsMatch = pitData->Matches(localPitData); - delete localPitData; - - if (!pitsMatch) - { - Interface::Print("Local and device PIT files don't match and repartition wasn't specified!\n"); - Interface::PrintError("Flash aborted!\n"); - - delete pitData; - return (false); - } - } - } - - map partitionInfoMap; - - // Map the files being flashed to partitions stored in the PIT file. - if (!mapFilesToPartitions(argumentFileMap, pitData, partitionInfoMap)) - { - delete pitData; - return (false); - } - - delete pitData; - - // If we're repartitioning then we need to flash the PIT file first. - if (repartition) - { - for (map::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++) - { - if (it->second.file == localPitFile) - { - PartitionInfo *partitionInfo = &(it->second); - - if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file)) - return (false); - - break; - } - } - } - - // Flash partitions not involved in the boot process second. - for (map::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++) - { - if (!isKnownPartition(it->second.partitionName.c_str(), kKnownPartitionPit) && !isKnownBootPartition(it->second.partitionName.c_str())) - { - PartitionInfo *partitionInfo = &(it->second); - - if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file)) - return (false); - } - } - - // Flash boot partitions last. - for (map::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++) - { - if (isKnownBootPartition(it->second.partitionName.c_str())) - { - PartitionInfo *partitionInfo = &(it->second); - - if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file)) - return (false); - } - } - - return (true); -} - int main(int argc, char **argv) { - map argumentMap; - int actionIndex; - - if (!Interface::GetArguments(argc, argv, argumentMap, &actionIndex)) + if (argc < 2) { - Sleep(250); + Interface::PrintUsage(); return (0); } - initialiseKnownPartitionNames(); - - switch (actionIndex) - { - case Interface::kActionFlash: - if (argumentMap.find(Interface::actions[Interface::kActionFlash].valuelessArguments[Interface::kFlashValuelessArgRepartition]) != argumentMap.end() - && argumentMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]) == argumentMap.end()) - { - Interface::Print("If you wish to repartition then a PIT file must be specified.\n\n"); - Interface::PrintUsage(); - return (0); - } - - break; - - case Interface::kActionDownloadPit: - if (argumentMap.find(Interface::actions[Interface::kActionDownloadPit].valueArguments[Interface::kDownloadPitValueArgOutput]) == argumentMap.end()) - { - Interface::Print("Output file was not specified.\n\n"); - Interface::PrintUsage(); - return (0); - } - - break; - - case Interface::kActionDump: - { - if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgOutput]) == argumentMap.end()) - { - Interface::Print("Output file was not specified.\n\n"); - Interface::PrintUsage(); - return (0); - } - - if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType]) == argumentMap.end()) - { - Interface::Print("You must specify a chip type.\n\n"); - Interface::PrintUsage(); - return (0); - } - - string chipType = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType])->second; - if (!(chipType == "RAM" || chipType == "ram" || chipType == "NAND" || chipType == "nand")) - { - Interface::Print("Unknown chip type: %s.\n\n", chipType.c_str()); - Interface::PrintUsage(); - return (0); - } - - if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId]) == argumentMap.end()) - { - Interface::Print("You must specify a Chip ID.\n\n"); - Interface::PrintUsage(); - return (0); - } - - int chipId = atoi(argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId])->second.c_str()); - if (chipId < 0) - { - Interface::Print("Chip ID must be a non-negative integer.\n"); - Interface::PrintUsage(); - return (0); - } - - break; - } - - case Interface::kActionVersion: - Interface::PrintVersion(); - return (0); - - case Interface::kActionHelp: - Interface::PrintUsage(); - return (0); - - case Interface::kActionInfo: - Interface::PrintFullInfo(); - return (0); - } - - bool verbose = argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgVerbose]) != argumentMap.end(); - bool reboot = argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgNoReboot]) == argumentMap.end(); - - Interface::SetStdoutErrors(argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgStdoutErrors]) != argumentMap.end()); - - int communicationDelay = BridgeManager::kCommunicationDelayDefault; + int result = 0; + map::const_iterator actionIt = Interface::GetActionMap().find(argv[1]); - if (argumentMap.find(Interface::commonValueArguments[Interface::kCommonValueArgDelay]) != argumentMap.end()) - communicationDelay = atoi(argumentMap.find(Interface::commonValueArguments[Interface::kCommonValueArgDelay])->second.c_str()); - - BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay); - - if (actionIndex == Interface::kActionDetect) - { - bool detected = bridgeManager->DetectDevice(); - delete bridgeManager; - - return ((detected) ? 0 : 1); - } - - Interface::PrintReleaseInfo(); - Sleep(1000); - - int initialiseResult = bridgeManager->Initialise(); - - if (initialiseResult != 0) - { - delete bridgeManager; - return ((initialiseResult == BridgeManager::kInitialiseDeviceNotDetected) ? 1 : 0); - } - - bool success; - - switch (actionIndex) - { - case Interface::kActionFlash: - { - map argumentFileMap; - - // We open the files before doing anything else to ensure they exist. - if (!openFiles(argumentMap, argumentFileMap)) - { - closeFiles(argumentFileMap); - delete bridgeManager; - - return (0); - } - - if (!bridgeManager->BeginSession()) - { - closeFiles(argumentFileMap); - delete bridgeManager; - - return (-1); - } - - bool repartition = argumentMap.find(Interface::actions[Interface::kActionFlash].valuelessArguments[Interface::kFlashValuelessArgRepartition]) != argumentMap.end(); - success = attemptFlash(bridgeManager, argumentFileMap, repartition); - - success = bridgeManager->EndSession(reboot) && success; - - closeFiles(argumentFileMap); - - break; - } - - case Interface::kActionClosePcScreen: - { - if (!bridgeManager->BeginSession()) - { - delete bridgeManager; - return (-1); - } - - Interface::Print("Attempting to close connect to pc screen...\n"); - - success = bridgeManager->EndSession(reboot); - - if (success) - Interface::Print("Attempt complete\n"); - - break; - } - - case Interface::kActionDownloadPit: - { - map::const_iterator it = argumentMap.find(Interface::actions[Interface::kActionDownloadPit].valueArguments[Interface::kDownloadPitValueArgOutput]); - FILE *outputPitFile = fopen(it->second.c_str(), "wb"); - - if (!outputPitFile) - { - delete bridgeManager; - return (0); - } - - if (!bridgeManager->BeginSession()) - { - delete bridgeManager; - fclose(outputPitFile); - return (-1); - } - - unsigned char *pitBuffer; - int fileSize = downloadPitFile(bridgeManager, &pitBuffer); - - if (fileSize > 0) - { - success = fwrite(pitBuffer, 1, fileSize, outputPitFile) == fileSize; - fclose(outputPitFile); - - if (!success) - Interface::PrintError("Failed to write PIT data to output file.\n"); - - success = bridgeManager->EndSession(reboot) && success; - } - else - { - fclose(outputPitFile); - success = false; - bridgeManager->EndSession(reboot); - } - - delete [] pitBuffer; - - break; - } - - case Interface::kActionDump: - { - const char *outputFilename = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgOutput])->second.c_str(); - FILE *dumpFile = fopen(outputFilename, "wb"); - if (!dumpFile) - { - Interface::PrintError("Failed to open file \"%s\"\n", outputFilename); - - delete bridgeManager; - return (-1); - } - - int chipType = 0; - string chipTypeName = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType])->second; - if (chipTypeName == "NAND" || chipTypeName == "nand") - chipType = 1; - - int chipId = atoi(argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId])->second.c_str()); - - if (!bridgeManager->BeginSession()) - { - fclose(dumpFile); - - delete bridgeManager; - return (-1); - } - - success = bridgeManager->ReceiveDump(chipType, chipId, dumpFile); - - fclose(dumpFile); - - success = bridgeManager->EndSession(reboot) && success; - - break; - } - - case Interface::kActionPrintPit: - { - if (!bridgeManager->BeginSession()) - { - delete bridgeManager; - return (-1); - } - - unsigned char *devicePit; - - if (downloadPitFile(bridgeManager, &devicePit) < -1) - { - bridgeManager->EndSession(reboot); - - delete bridgeManager; - return (-1); - } - - PitData *pitData = new PitData(); - - if (pitData->Unpack(devicePit)) - { - Interface::PrintPit(pitData); - success = true; - } - else - { - Interface::PrintError("Failed to unpack device's PIT file!\n"); - success = false; - } - - delete [] devicePit; - delete pitData; - - success = bridgeManager->EndSession(reboot) && success; - - break; - } - } - - delete bridgeManager; - - return ((success) ? 0 : -1); + if (actionIt != Interface::GetActionMap().end()) + result = actionIt->second.executeFunction(argc, argv); + else + result = HelpAction::Execute(argc, argv); + + return (result); } -- cgit v1.2.3