Compare commits

...

5 Commits

Author SHA1 Message Date
Henrik Grimler d252c72d34
REVERTME: print size of files and partition sizes in PIT
For debugging purposes.
2021-12-13 09:54:13 +01:00
Henrik Grimler 8d5a79a90c
FlashAction: add option --skip-size-check
Can be used to skip the check that verifies that all files fit in the
partitions. The option need to be set if we are to be able to flash
stock android to some devices, for example klimtlte (sboot.bin is
larger than the BOOTLOADER partition on this device).
2021-12-13 09:54:10 +01:00
Henrik Grimler ee3b0a8fba
Make sure file fit partition before flashing
Partition size is calculated as block count times a block size of 512
for DeviceType 2 and 4096 for DeviceType 8.

Flashing stock android on some devices fail due to some partitions
being too small for the corresponding file.  This is the case on
klimtlte, where sboot.bin does not fit into the BOOTLOADER
partition.

The BOOTLOADER partition on klimtlte has the following properties:

  --- Entry #0 ---
  Binary Type: 0 (AP)
  Device Type: 2 (MMC)
  Identifier: 80
  Attributes: 2 (STL Read-Only)
  Update Attributes: 1 (FOTA)
  Partition Block Size/Offset: 0
  Partition Block Count: 2046
  Partition Name: BOOTLOADER
  Flash Filename: sboot.bin

while the BOOT partition has:

  --- Entry #11 ---
  Binary Type: 0 (AP)
  Device Type: 2 (MMC)
  Identifier: 9
  Attributes: 5 (Read/Write)
  Update Attributes: 1 (FOTA)
  Partition Block Size/Offset: 114688
  Partition Block Count: 16384
  Partition Name: BOOT
  Flash Filename: boot.img

The Attributes entry is the only that differs apart from size and
names.  Maybe the file and partition size check should only be done
for partitions with Attributes: 5 (Read/Write).

Tests done:

* Flash stock android (A500FXXS1CSB2) to a5lte, works fine
* Flash stock android (G930FXXU8ETI2) to herolte (with block
  size 4096), works fine
* Flash stock android (T705XXU1CPL1) to klimtlte, fails due to
  BOOTLOADER partition being smaller than sboot.bin, the file has a
  size of 1148160, and the partition 2046*512=1047552
2021-12-13 09:54:08 +01:00
Henrik Grimler f8001bce66
libpit: describe more parts of pit header
The unknown string is "COM_TAR2" in all devices I have access to.
The CPU/bootloader string looks something like:

* LSI7420 - Seen in Exynos 7420, 8890, 8895 devices (and probably others)
* LSI5410 - Seen in Exynos 5420, 5433 devices (and probably others)
* LSI7880 - Seen in a5y17lte (exynos 7880) and probably others
* Mx - Seen in Galaxy S3 (device codename is m0/m3)
* MSM8916 - Seen in MSM8916 devices
* MSM8960 - Seen in jflte (and probably in others, jflte has a APQ8064AB CPU)
2021-12-13 09:47:30 +01:00
Henrik Grimler b2eaf46662
libpit: add DeviceType = 8 entry for MMC with blksize 4096
Newer devices have an emmc with 4096 block size instead of 512.  These
seem to have DeviceType=8 instead of DeviceType=2.
2021-12-11 16:14:08 +01:00
4 changed files with 80 additions and 102 deletions

View File

@ -48,10 +48,11 @@ Arguments:\n\
--repartition --pit <filename> [--<partition name> <filename> ...]\n\ --repartition --pit <filename> [--<partition name> <filename> ...]\n\
[--<partition identifier> <filename> ...] [--verbose] [--no-reboot]\n\ [--<partition identifier> <filename> ...] [--verbose] [--no-reboot]\n\
[--resume] [--stdout-errors] [--usb-log-level <none/error/warning/debug>]\n\ [--resume] [--stdout-errors] [--usb-log-level <none/error/warning/debug>]\n\
[--tflash]\n\ [--tflash] [--skip-size-check]\n\
Description: Flashes one or more firmware files to your phone. Partition names\n\ Description: Flashes one or more firmware files to your phone. Partition names\n\
(or identifiers) can be obtained by executing the print-pit action.\n\ (or identifiers) can be obtained by executing the print-pit action.\n\
T-Flash mode allows to flash the inserted SD-card instead of the internal MMC.\n\ T-Flash mode allows to flash the inserted SD-card instead of the internal MMC.\n\
Use --skip-size-check to not verify that files fit in the specified partition.\n\
Note: --no-reboot causes the device to remain in download mode after the action\n\ Note: --no-reboot causes the device to remain in download mode after the action\n\
is completed. If you wish to perform another action whilst remaining in\n\ is completed. If you wish to perform another action whilst remaining in\n\
download mode, then the following action must specify the --resume flag.\n\ download mode, then the following action must specify the --resume flag.\n\
@ -62,11 +63,13 @@ struct PartitionFile
{ {
const char *argumentName; const char *argumentName;
FILE *file; FILE *file;
unsigned long fileSize;
PartitionFile(const char *argumentName, FILE *file) PartitionFile(const char *argumentName, FILE *file, unsigned long fileSize)
{ {
this->argumentName = argumentName; this->argumentName = argumentName;
this->file = file; this->file = file;
this->fileSize = fileSize;
} }
}; };
@ -113,6 +116,9 @@ static bool openFiles(Arguments& arguments, vector<PartitionFile>& partitionFile
{ {
const StringArgument *stringArgument = static_cast<const StringArgument *>(*it); const StringArgument *stringArgument = static_cast<const StringArgument *>(*it);
FILE *file = FileOpen(stringArgument->GetValue().c_str(), "rb"); FILE *file = FileOpen(stringArgument->GetValue().c_str(), "rb");
FileSeek(file, 0, SEEK_END);
unsigned long fileSize = (unsigned long)FileTell(file);
FileRewind(file);
if (!file) if (!file)
{ {
@ -120,7 +126,7 @@ static bool openFiles(Arguments& arguments, vector<PartitionFile>& partitionFile
return (false); return (false);
} }
partitionFiles.push_back(PartitionFile(argumentName.c_str(), file)); partitionFiles.push_back(PartitionFile(argumentName.c_str(), file, fileSize));
} }
} }
@ -151,9 +157,7 @@ static bool sendTotalTransferSize(BridgeManager *bridgeManager, const vector<Par
for (vector<PartitionFile>::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++) for (vector<PartitionFile>::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++)
{ {
FileSeek(it->file, 0, SEEK_END); totalBytes += it->fileSize;
totalBytes += (unsigned long)FileTell(it->file);
FileRewind(it->file);
} }
if (repartition) if (repartition)
@ -284,7 +288,7 @@ static bool flashFile(BridgeManager *bridgeManager, const PartitionFlashInfo& pa
} }
} }
static bool flashPartitions(BridgeManager *bridgeManager, const vector<PartitionFile>& partitionFiles, const PitData *pitData, bool repartition) static bool flashPartitions(BridgeManager *bridgeManager, const vector<PartitionFile>& partitionFiles, const PitData *pitData, bool repartition, bool skip_size_check)
{ {
vector<PartitionFlashInfo> partitionFlashInfos; vector<PartitionFlashInfo> partitionFlashInfos;
@ -292,6 +296,29 @@ static bool flashPartitions(BridgeManager *bridgeManager, const vector<Partition
if (!setupPartitionFlashInfo(partitionFiles, pitData, partitionFlashInfos)) if (!setupPartitionFlashInfo(partitionFiles, pitData, partitionFlashInfos))
return (false); return (false);
/* Verify that the files we want to flash fit in partitions */
if (!skip_size_check)
{
for (vector<PartitionFile>::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++)
{
const PitEntry *part = pitData->FindEntry(it->argumentName);
if (part->GetDeviceType() != PitEntry::kDeviceTypeMMC &&
part->GetDeviceType() != PitEntry::kDeviceTypeMMC4096)
continue;
unsigned long partitionSize = part->GetBlockCount();
unsigned int blockSize = 512;
if (part->GetDeviceType() == PitEntry::kDeviceTypeMMC4096)
blockSize = 4096;
printf("Partition %s: size %lu, size in PIT: %lu\n", it->argumentName, it->fileSize, partitionSize*blockSize);
if (partitionSize > 0 && it->fileSize > partitionSize*blockSize)
{
Interface::PrintError("%s partition is too small for specified file\n",
it->argumentName);
return (false);
}
}
}
// If we're repartitioning then we need to flash the PIT file first (if it is listed in the PIT file). // If we're repartitioning then we need to flash the PIT file first (if it is listed in the PIT file).
if (repartition) if (repartition)
{ {
@ -431,6 +458,7 @@ int FlashAction::Execute(int argc, char **argv)
argumentTypes["stdout-errors"] = kArgumentTypeFlag; argumentTypes["stdout-errors"] = kArgumentTypeFlag;
argumentTypes["usb-log-level"] = kArgumentTypeString; argumentTypes["usb-log-level"] = kArgumentTypeString;
argumentTypes["tflash"] = kArgumentTypeFlag; argumentTypes["tflash"] = kArgumentTypeFlag;
argumentTypes["skip-size-check"] = kArgumentTypeFlag;
argumentTypes["pit"] = kArgumentTypeString; argumentTypes["pit"] = kArgumentTypeString;
shortArgumentAliases["pit"] = "pit"; shortArgumentAliases["pit"] = "pit";
@ -459,6 +487,7 @@ int FlashAction::Execute(int argc, char **argv)
bool resume = arguments.GetArgument("resume") != nullptr; bool resume = arguments.GetArgument("resume") != nullptr;
bool verbose = arguments.GetArgument("verbose") != nullptr; bool verbose = arguments.GetArgument("verbose") != nullptr;
bool tflash = arguments.GetArgument("tflash") != nullptr; bool tflash = arguments.GetArgument("tflash") != nullptr;
bool skip_size_check = arguments.GetArgument("skip-size-check") != nullptr;
if (arguments.GetArgument("stdout-errors") != nullptr) if (arguments.GetArgument("stdout-errors") != nullptr)
Interface::SetStdoutErrors(true); Interface::SetStdoutErrors(true);
@ -560,7 +589,9 @@ int FlashAction::Execute(int argc, char **argv)
PitData *pitData = getPitData(bridgeManager, pitFile, repartition); PitData *pitData = getPitData(bridgeManager, pitFile, repartition);
if (pitData) if (pitData)
success = flashPartitions(bridgeManager, partitionFiles, pitData, repartition); success = flashPartitions(bridgeManager, partitionFiles,
pitData, repartition,
skip_size_check);
else else
success = false; success = false;

View File

@ -207,16 +207,11 @@ void Interface::PrintDeviceDetectionFailed(void)
void Interface::PrintPit(const PitData *pitData) void Interface::PrintPit(const PitData *pitData)
{ {
Interface::Print("--- PIT Header ---\n");
Interface::Print("Entry Count: %d\n", pitData->GetEntryCount()); Interface::Print("Entry Count: %d\n", pitData->GetEntryCount());
Interface::Print("Unknown string: %s\n", pitData->GetComTar2());
Interface::Print("Unknown 1: %d\n", pitData->GetUnknown1()); Interface::Print("CPU/bootloader tag: %s\n", pitData->GetCpuBlId());
Interface::Print("Unknown 2: %d\n", pitData->GetUnknown2()); Interface::Print("Unknown: 0x%04x\n", pitData->GetUnknown());
Interface::Print("Unknown 3: %d\n", pitData->GetUnknown3());
Interface::Print("Unknown 4: %d\n", pitData->GetUnknown4());
Interface::Print("Unknown 5: %d\n", pitData->GetUnknown5());
Interface::Print("Unknown 6: %d\n", pitData->GetUnknown6());
Interface::Print("Unknown 7: %d\n", pitData->GetUnknown7());
Interface::Print("Unknown 8: %d\n", pitData->GetUnknown8());
for (unsigned int i = 0; i < pitData->GetEntryCount(); i++) for (unsigned int i = 0; i < pitData->GetEntryCount(); i++)
{ {
@ -262,6 +257,10 @@ void Interface::PrintPit(const PitData *pitData)
Interface::Print("All (?)"); Interface::Print("All (?)");
break; break;
case PitEntry::kDeviceTypeMMC4096:
Interface::Print("MMC 4096");
break;
default: default:
Interface::Print("Unknown"); Interface::Print("Unknown");
break; break;

View File

@ -66,17 +66,10 @@ PitData::PitData()
{ {
entryCount = 0; entryCount = 0;
unknown1 = 0; com_tar2[0] = '\0';
unknown2 = 0; cpu_bl_id[0] = '\0';
unknown3 = 0; unknown = 0;
unknown4 = 0;
unknown5 = 0;
unknown6 = 0;
unknown7 = 0;
unknown8 = 0;
} }
PitData::~PitData() PitData::~PitData()
@ -98,17 +91,14 @@ bool PitData::Unpack(const unsigned char *data)
entries.resize(entryCount); entries.resize(entryCount);
unknown1 = PitData::UnpackInteger(data, 8); if (!memcpy(com_tar2, &data[8], 8))
unknown2 = PitData::UnpackInteger(data, 12); return (false);
com_tar2[8]='\0';
if (!memcpy(cpu_bl_id, &data[16], 8))
return (false);
cpu_bl_id[8]='\0';
unknown3 = PitData::UnpackShort(data, 16); unknown = PitData::UnpackShort(data, 24);
unknown4 = PitData::UnpackShort(data, 18);
unknown5 = PitData::UnpackShort(data, 20);
unknown6 = PitData::UnpackShort(data, 22);
unknown7 = PitData::UnpackShort(data, 24);
unknown8 = PitData::UnpackShort(data, 26);
unsigned int integerValue; unsigned int integerValue;
unsigned int entryOffset; unsigned int entryOffset;
@ -160,17 +150,10 @@ void PitData::Pack(unsigned char *data) const
PitData::PackInteger(data, 4, entryCount); PitData::PackInteger(data, 4, entryCount);
PitData::PackInteger(data, 8, unknown1); memcpy(&data[8], com_tar2, 8);
PitData::PackInteger(data, 12, unknown2); memcpy(&data[16], cpu_bl_id, 8);
PitData::PackShort(data, 16, unknown3); PitData::PackShort(data, 24, unknown);
PitData::PackShort(data, 18, unknown4);
PitData::PackShort(data, 20, unknown5);
PitData::PackShort(data, 22, unknown6);
PitData::PackShort(data, 24, unknown7);
PitData::PackShort(data, 26, unknown8);
int entryOffset; int entryOffset;
@ -201,9 +184,10 @@ void PitData::Pack(unsigned char *data) const
bool PitData::Matches(const PitData *otherPitData) const bool PitData::Matches(const PitData *otherPitData) const
{ {
if (entryCount == otherPitData->entryCount && unknown1 == otherPitData->unknown1 && unknown2 == otherPitData->unknown2 if (entryCount == otherPitData->entryCount &&
&& unknown3 == otherPitData->unknown3 && unknown4 == otherPitData->unknown4 && unknown5 == otherPitData->unknown5 (strncmp(com_tar2, otherPitData->com_tar2, 8) == 0) &&
&& unknown6 == otherPitData->unknown6 && unknown7 == otherPitData->unknown7 && unknown8 == otherPitData->unknown8) (strncmp(cpu_bl_id, otherPitData->cpu_bl_id, 8) == 0) &&
unknown == otherPitData->unknown)
{ {
for (unsigned int i = 0; i < entryCount; i++) for (unsigned int i = 0; i < entryCount; i++)
{ {
@ -223,17 +207,11 @@ void PitData::Clear(void)
{ {
entryCount = 0; entryCount = 0;
unknown1 = 0; com_tar2[0] = '\0';
unknown2 = 0;
unknown3 = 0; cpu_bl_id[0] = '\0';
unknown4 = 0;
unknown5 = 0; unknown = 0;
unknown6 = 0;
unknown7 = 0;
unknown8 = 0;
for (unsigned int i = 0; i < entries.size(); i++) for (unsigned int i = 0; i < entries.size(); i++)
delete entries[i]; delete entries[i];

View File

@ -61,14 +61,15 @@ namespace libpit
kDeviceTypeOneNand = 0, kDeviceTypeOneNand = 0,
kDeviceTypeFile, // FAT kDeviceTypeFile, // FAT
kDeviceTypeMMC, kDeviceTypeMMC,
kDeviceTypeAll // ? kDeviceTypeAll, // ?
kDeviceTypeMMC4096 = 8 // block size 4096
}; };
enum enum
{ {
kAttributeWrite = 1, kAttributeWrite = 1,
kAttributeSTL = 1 << 1/*, kAttributeSTL = 1 << 1
kAttributeBML = 1 << 2*/ // ??? /* kAttributeBML = 1 << 2 */ // ???
}; };
enum enum
@ -261,17 +262,11 @@ namespace libpit
private: private:
unsigned int entryCount; // 0x04 unsigned int entryCount; // 0x04
unsigned int unknown1; // 0x08 char com_tar2[8+1]; // 0x08
unsigned int unknown2; // 0x0C
unsigned short unknown3; // 0x10 char cpu_bl_id[8+1]; // 0x10
unsigned short unknown4; // 0x12
unsigned short unknown5; // 0x14 unsigned short unknown; // 0x18
unsigned short unknown6; // 0x16
unsigned short unknown7; // 0x18
unsigned short unknown8; // 0x1A
// Entries start at 0x1C // Entries start at 0x1C
std::vector<PitEntry *> entries; std::vector<PitEntry *> entries;
@ -370,44 +365,19 @@ namespace libpit
return paddedSize; return paddedSize;
} }
unsigned int GetUnknown1(void) const const char * GetComTar2(void) const
{ {
return unknown1; return com_tar2;
} }
unsigned int GetUnknown2(void) const const char * GetCpuBlId(void) const
{ {
return unknown2; return cpu_bl_id;
} }
unsigned short GetUnknown3(void) const unsigned int GetUnknown(void) const
{ {
return unknown3; return unknown;
}
unsigned short GetUnknown4(void) const
{
return unknown4;
}
unsigned short GetUnknown5(void) const
{
return unknown5;
}
unsigned short GetUnknown6(void) const
{
return unknown6;
}
unsigned short GetUnknown7(void) const
{
return unknown7;
}
unsigned short GetUnknown8(void) const
{
return unknown8;
} }
}; };
} }