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
12 changed files with 85 additions and 91 deletions

View File

@ -1,9 +1,5 @@
# Heimdall # Heimdall
[![builds.sr.ht status](https://builds.sr.ht/~grimler/Heimdall/commits/ubuntu.yml.svg)](https://builds.sr.ht/~grimler/Heimdall/commits/ubuntu.yml?)
[![builds.sr.ht status](https://builds.sr.ht/~grimler/Heimdall/commits/archlinux.yml.svg)](https://builds.sr.ht/~grimler/Heimdall/commits/archlinux.yml?)
[![builds.sr.ht status](https://builds.sr.ht/~grimler/Heimdall/commits/alpine.yml.svg)](https://builds.sr.ht/~grimler/Heimdall/commits/alpine.yml?)
Heimdall is a cross-platform open-source tool suite used to flash Heimdall is a cross-platform open-source tool suite used to flash
firmware (aka ROMs) onto Samsung mobile devices. firmware (aka ROMs) onto Samsung mobile devices.
@ -24,7 +20,7 @@ Heimdall communicate via the custom Samsung-developed protocol
typically referred to as the 'Odin 3 protocol'. typically referred to as the 'Odin 3 protocol'.
USB communication in Heimdall is handled by the popular open-source USB communication in Heimdall is handled by the popular open-source
USB library, [libusb](https://libusb.info). USB library, [libusb](http://libusb.info).
## Free & Open Source ## Free & Open Source
@ -44,17 +40,12 @@ refer to the appropriate platform specific README:
#### Linux #### Linux
- Linux/README ([online](Linux/README)) - Linux/README ([online](https://raw.githubusercontent.com/Benjamin-Dobell/Heimdall/master/Linux/README))
#### OS X #### OS X
- OSX/README.txt ([online](OSX/README.txt)) - OSX/README.txt ([online](https://raw.githubusercontent.com/Benjamin-Dobell/Heimdall/master/OSX/README.txt))
#### Windows #### Windows
- Win32/README.txt ([online](Win32/README.txt)) - Win32/README.txt ([online](https://raw.githubusercontent.com/Benjamin-Dobell/Heimdall/master/Win32/README.txt))
### Odin protocol and PIT format
For more details on the Odin protocol, and the PIT files, see the
external project [samsung-loki/samsung-docs](https://samsung-loki.github.io/samsung-docs/).

BIN
Win32/Drivers/zadig.exe Normal file

Binary file not shown.

View File

@ -20,7 +20,7 @@ Driver Installation Instructions:
1. Put your device into download mode and plug it in. 1. Put your device into download mode and plug it in.
2. Download zadig from https://zadig.akeo.ie/downloads/, and run zadig.exe. 2. Run zadig.exe included in the Drivers subdirectory.
3. From the menu chose Options -> List All Devices. 3. From the menu chose Options -> List All Devices.

View File

@ -114,7 +114,7 @@
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:400; font-style:normal;"> </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Heimdall Frontend</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Heimdall Frontend</span></p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Version 2.0.2</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Version 1.4.2</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright © 2010-2017 Benjamin Dobell, Glass Echidna</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright © 2010-2017 Benjamin Dobell, Glass Echidna</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Heimdall (command line)</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Heimdall (command line)</span></p>

View File

@ -20,7 +20,6 @@
// C Standard Library // C Standard Library
#include <cstdio> #include <cstdio>
#include <fstream>
// libusb // libusb
#include <libusb.h> #include <libusb.h>
@ -81,17 +80,16 @@ int BridgeManager::FindDeviceInterface(void)
Interface::Print("Detecting device...\n"); Interface::Print("Detecting device...\n");
struct libusb_device **devices; struct libusb_device **devices;
unsigned int deviceCount = libusb_get_device_list(libusbContext, &devices); int deviceCount = libusb_get_device_list(libusbContext, &devices);
for (unsigned int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
{ {
libusb_device_descriptor descriptor; libusb_device_descriptor descriptor;
libusb_get_device_descriptor(devices[deviceIndex], &descriptor); libusb_get_device_descriptor(devices[deviceIndex], &descriptor);
for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++) for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++)
{ {
if (descriptor.idVendor == supportedDevices[i].vendorId && if (descriptor.idVendor == supportedDevices[i].vendorId && descriptor.idProduct == supportedDevices[i].productId)
descriptor.idProduct == supportedDevices[i].productId)
{ {
heimdallDevice = devices[deviceIndex]; heimdallDevice = devices[deviceIndex];
libusb_ref_device(heimdallDevice); libusb_ref_device(heimdallDevice);
@ -312,20 +310,14 @@ bool BridgeManager::InitialiseProtocol(void)
memcpy(dataBuffer, "ODIN", 4); memcpy(dataBuffer, "ODIN", 4);
memset(dataBuffer + 4, 0, 1); memset(dataBuffer + 4, 0, 1);
#ifdef OS_LINUX
if (IsUbuntu())
{
Interface::Print("Resetting device...\n");
if (libusb_reset_device(deviceHandle)) if (libusb_reset_device(deviceHandle))
{ {
Interface::PrintError("Failed to reset device!\n"); Interface::PrintError("Failed to reset device!");
} }
}
#endif
if (!SendBulkTransfer(dataBuffer, 4, 1000)) if (!SendBulkTransfer(dataBuffer, 4, 1000))
{ {
Interface::PrintError("Failed to send handshake!\n"); Interface::PrintError("Failed to send handshake!");
} }
// Expect "LOKE" // Expect "LOKE"
@ -415,8 +407,29 @@ bool BridgeManager::DetectDevice(void)
return (false); return (false);
} }
// Set libusb log level. // Setup libusb log level.
SetUsbLogLevel(usbLogLevel); switch (usbLogLevel)
{
case UsbLogLevel::None:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
break;
case UsbLogLevel::Error:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_ERROR);
break;
case UsbLogLevel::Warning:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_WARNING);
break;
case UsbLogLevel::Info:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
break;
case UsbLogLevel::Debug:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG);
break;
}
// Get handle to Galaxy S device // Get handle to Galaxy S device
struct libusb_device **devices; struct libusb_device **devices;
@ -429,8 +442,7 @@ bool BridgeManager::DetectDevice(void)
for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++) for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++)
{ {
if (descriptor.idVendor == supportedDevices[i].vendorId && if (descriptor.idVendor == supportedDevices[i].vendorId && descriptor.idProduct == supportedDevices[i].productId)
descriptor.idProduct == supportedDevices[i].productId)
{ {
libusb_free_device_list(devices, deviceCount); libusb_free_device_list(devices, deviceCount);
@ -456,12 +468,33 @@ int BridgeManager::Initialise(bool resume)
if (result != LIBUSB_SUCCESS) if (result != LIBUSB_SUCCESS)
{ {
Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result); Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result);
Interface::Print("Failed to connect to device!\n"); Interface::Print("Failed to connect to device!");
return (BridgeManager::kInitialiseFailed); return (BridgeManager::kInitialiseFailed);
} }
// Setup libusb log level. // Setup libusb log level.
SetUsbLogLevel(usbLogLevel); switch (usbLogLevel)
{
case UsbLogLevel::None:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
break;
case UsbLogLevel::Error:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_ERROR);
break;
case UsbLogLevel::Warning:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_WARNING);
break;
case UsbLogLevel::Info:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
break;
case UsbLogLevel::Debug:
libusb_set_option(libusbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG);
break;
}
result = FindDeviceInterface(); result = FindDeviceInterface();
@ -716,7 +749,7 @@ bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout, int emptyT
if (receivedSize < 0) if (receivedSize < 0)
return (false); return (false);
if (static_cast<unsigned int>(receivedSize) != packet->GetSize() && !packet->IsSizeVariable()) if (receivedSize != packet->GetSize() && !packet->IsSizeVariable())
{ {
if (verbose) if (verbose)
Interface::PrintError("Incorrect packet size received - expected size = %d, received size = %d.\n", packet->GetSize(), receivedSize); Interface::PrintError("Incorrect packet size received - expected size = %d, received size = %d.\n", packet->GetSize(), receivedSize);
@ -1244,32 +1277,3 @@ void BridgeManager::SetUsbLogLevel(UsbLogLevel usbLogLevel)
} }
} }
} }
#ifdef OS_LINUX
bool BridgeManager::IsUbuntu()
{
std::ifstream os_release("/etc/os-release");
std::string line, entry, os;
int pos;
while (std::getline(os_release, line))
{
pos = line.find("=");
entry = line.substr(0, pos);
if (entry == "ID")
{
os = line.substr(pos+1);
if (verbose)
{
Interface::Print("Linux distro ID: %s\n",
os.c_str());
}
if (os == "ubuntu")
{
return true;
}
break;
}
}
return false;
}
#endif

View File

@ -166,9 +166,7 @@ namespace Heimdall
bool SendFile(FILE *file, unsigned int destination, unsigned int deviceType, unsigned int fileIdentifier = 0xFFFFFFFF) const; bool SendFile(FILE *file, unsigned int destination, unsigned int deviceType, unsigned int fileIdentifier = 0xFFFFFFFF) const;
void SetUsbLogLevel(UsbLogLevel usbLogLevel); void SetUsbLogLevel(UsbLogLevel usbLogLevel);
#ifdef OS_LINUX
bool IsUbuntu(void);
#endif
UsbLogLevel GetUsbLogLevel(void) const UsbLogLevel GetUsbLogLevel(void) const
{ {
return usbLogLevel; return usbLogLevel;

View File

@ -148,7 +148,7 @@ int DownloadPitAction::Execute(int argc, char **argv)
if (fileSize > 0) if (fileSize > 0)
{ {
if (fwrite(pitBuffer, 1, fileSize, outputPitFile) != static_cast<size_t>(fileSize)) if (fwrite(pitBuffer, 1, fileSize, outputPitFile) != fileSize)
{ {
Interface::PrintError("Failed to write PIT data to output file.\n"); Interface::PrintError("Failed to write PIT data to output file.\n");
success = false; success = false;

View File

@ -116,16 +116,16 @@ 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)
{ {
Interface::PrintError("Failed to open file \"%s\"\n", stringArgument->GetValue().c_str()); Interface::PrintError("Failed to open file \"%s\"\n", stringArgument->GetValue().c_str());
return (false); return (false);
} }
FileSeek(file, 0, SEEK_END);
unsigned long fileSize = (unsigned long)FileTell(file);
FileRewind(file);
partitionFiles.push_back(PartitionFile(argumentName.c_str(), file, fileSize)); partitionFiles.push_back(PartitionFile(argumentName.c_str(), file, fileSize));
} }
} }
@ -303,15 +303,16 @@ static bool flashPartitions(BridgeManager *bridgeManager, const vector<Partition
{ {
const PitEntry *part = pitData->FindEntry(it->argumentName); const PitEntry *part = pitData->FindEntry(it->argumentName);
if (part->GetDeviceType() != PitEntry::kDeviceTypeMMC && if (part->GetDeviceType() != PitEntry::kDeviceTypeMMC &&
part->GetDeviceType() != PitEntry::kDeviceTypeUFS) part->GetDeviceType() != PitEntry::kDeviceTypeMMC4096)
continue; continue;
unsigned long partitionSize = part->GetBlockCount(); unsigned long partitionSize = part->GetBlockCount();
unsigned int blockSize = 512; unsigned int blockSize = 512;
if (part->GetDeviceType() == PitEntry::kDeviceTypeUFS) if (part->GetDeviceType() == PitEntry::kDeviceTypeMMC4096)
blockSize = 4096; 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) if (partitionSize > 0 && it->fileSize > partitionSize*blockSize)
{ {
Interface::PrintError("%s partition is too small for given file. Use --skip-size-check to flash anyways.\n", Interface::PrintError("%s partition is too small for specified file\n",
it->argumentName); it->argumentName);
return (false); return (false);
} }

View File

@ -42,7 +42,7 @@ using namespace Heimdall;
map<string, Interface::ActionInfo> actionMap; map<string, Interface::ActionInfo> actionMap;
bool stdoutErrors = false; bool stdoutErrors = false;
const char *version = "v2.0.2"; const char *version = "v1.4.2";
const char *actionUsage = "Usage: heimdall <action> <action arguments>\n"; const char *actionUsage = "Usage: heimdall <action> <action arguments>\n";
const char *releaseInfo = "Heimdall %s\n\n\ const char *releaseInfo = "Heimdall %s\n\n\
@ -211,7 +211,7 @@ void Interface::PrintPit(const PitData *pitData)
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 string: %s\n", pitData->GetComTar2());
Interface::Print("CPU/bootloader tag: %s\n", pitData->GetCpuBlId()); Interface::Print("CPU/bootloader tag: %s\n", pitData->GetCpuBlId());
Interface::Print("Logic unit count: %d\n", pitData->GetLUCount()); Interface::Print("Unknown: 0x%04x\n", pitData->GetUnknown());
for (unsigned int i = 0; i < pitData->GetEntryCount(); i++) for (unsigned int i = 0; i < pitData->GetEntryCount(); i++)
{ {
@ -257,8 +257,8 @@ void Interface::PrintPit(const PitData *pitData)
Interface::Print("All (?)"); Interface::Print("All (?)");
break; break;
case PitEntry::kDeviceTypeUFS: case PitEntry::kDeviceTypeMMC4096:
Interface::Print("UFS"); Interface::Print("MMC 4096");
break; break;
default: default:

View File

@ -45,7 +45,7 @@ namespace Heimdall
memset(data, 0, size); memset(data, 0, size);
} }
virtual ~Packet() ~Packet()
{ {
delete [] data; delete [] data;
} }

View File

@ -69,7 +69,7 @@ PitData::PitData()
com_tar2[0] = '\0'; com_tar2[0] = '\0';
cpu_bl_id[0] = '\0'; cpu_bl_id[0] = '\0';
luCount = 0; unknown = 0;
} }
PitData::~PitData() PitData::~PitData()
@ -98,7 +98,7 @@ bool PitData::Unpack(const unsigned char *data)
return (false); return (false);
cpu_bl_id[8]='\0'; cpu_bl_id[8]='\0';
luCount = PitData::UnpackShort(data, 24); unknown = PitData::UnpackShort(data, 24);
unsigned int integerValue; unsigned int integerValue;
unsigned int entryOffset; unsigned int entryOffset;
@ -153,7 +153,7 @@ void PitData::Pack(unsigned char *data) const
memcpy(&data[8], com_tar2, 8); memcpy(&data[8], com_tar2, 8);
memcpy(&data[16], cpu_bl_id, 8); memcpy(&data[16], cpu_bl_id, 8);
PitData::PackShort(data, 24, luCount); PitData::PackShort(data, 24, unknown);
int entryOffset; int entryOffset;
@ -187,7 +187,7 @@ bool PitData::Matches(const PitData *otherPitData) const
if (entryCount == otherPitData->entryCount && if (entryCount == otherPitData->entryCount &&
(strncmp(com_tar2, otherPitData->com_tar2, 8) == 0) && (strncmp(com_tar2, otherPitData->com_tar2, 8) == 0) &&
(strncmp(cpu_bl_id, otherPitData->cpu_bl_id, 8) == 0) && (strncmp(cpu_bl_id, otherPitData->cpu_bl_id, 8) == 0) &&
luCount == otherPitData->luCount) unknown == otherPitData->unknown)
{ {
for (unsigned int i = 0; i < entryCount; i++) for (unsigned int i = 0; i < entryCount; i++)
{ {
@ -211,7 +211,7 @@ void PitData::Clear(void)
cpu_bl_id[0] = '\0'; cpu_bl_id[0] = '\0';
luCount = 0; unknown = 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

@ -62,7 +62,7 @@ namespace libpit
kDeviceTypeFile, // FAT kDeviceTypeFile, // FAT
kDeviceTypeMMC, kDeviceTypeMMC,
kDeviceTypeAll, // ? kDeviceTypeAll, // ?
kDeviceTypeUFS = 8 kDeviceTypeMMC4096 = 8 // block size 4096
}; };
enum enum
@ -266,7 +266,7 @@ namespace libpit
char cpu_bl_id[8+1]; // 0x10 char cpu_bl_id[8+1]; // 0x10
unsigned short luCount; // 0x18 unsigned short unknown; // 0x18
// Entries start at 0x1C // Entries start at 0x1C
std::vector<PitEntry *> entries; std::vector<PitEntry *> entries;
@ -375,9 +375,9 @@ namespace libpit
return cpu_bl_id; return cpu_bl_id;
} }
unsigned int GetLUCount(void) const unsigned int GetUnknown(void) const
{ {
return luCount; return unknown;
} }
}; };
} }