mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-25 17:38:22 +08:00
0f2ede398d
references #197
660 lines
32 KiB
C++
Executable File
660 lines
32 KiB
C++
Executable File
/* meparser.cpp
|
|
|
|
Copyright (c) 2019, Nikolaj Schlej. All rights reserved.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <map>
|
|
|
|
#include "ffs.h"
|
|
#include "me.h"
|
|
#include "meparser.h"
|
|
#include "parsingdata.h"
|
|
#include "utility.h"
|
|
|
|
#ifdef U_ENABLE_ME_PARSING_SUPPORT
|
|
|
|
struct FPT_PARTITION_INFO {
|
|
FPT_HEADER_ENTRY ptEntry;
|
|
UINT8 type;
|
|
UModelIndex index;
|
|
friend bool operator< (const FPT_PARTITION_INFO & lhs, const FPT_PARTITION_INFO & rhs){ return lhs.ptEntry.Offset < rhs.ptEntry.Offset; }
|
|
};
|
|
|
|
struct IFWI_PARTITION_INFO {
|
|
IFWI_HEADER_ENTRY ptEntry;
|
|
UINT8 type;
|
|
UINT8 subtype;
|
|
friend bool operator< (const IFWI_PARTITION_INFO & lhs, const IFWI_PARTITION_INFO & rhs){ return lhs.ptEntry.Offset < rhs.ptEntry.Offset; }
|
|
};
|
|
|
|
USTATUS MeParser::parseMeRegionBody(const UModelIndex & index)
|
|
{
|
|
// Sanity check
|
|
if (!index.isValid())
|
|
return U_INVALID_PARAMETER;
|
|
|
|
// Obtain ME region
|
|
UByteArray meRegion = model->body(index);
|
|
|
|
// Check region size
|
|
if ((UINT32)meRegion.size() < ME_ROM_BYPASS_VECTOR_SIZE + sizeof(UINT32)) {
|
|
msg(usprintf("%s: ME region too small to fit ROM bypass vector", __FUNCTION__), index);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
// Check ME signature to determine it's version
|
|
// ME v11 and older layout
|
|
if (meRegion.left(sizeof(UINT32)) == FPT_HEADER_SIGNATURE || meRegion.mid(ME_ROM_BYPASS_VECTOR_SIZE, sizeof(UINT32)) == FPT_HEADER_SIGNATURE) {
|
|
UModelIndex ptIndex;
|
|
return parseFptRegion(meRegion, index, ptIndex);
|
|
}
|
|
|
|
// IFWI 1.6
|
|
// Check region size
|
|
if ((UINT32)meRegion.size() < sizeof(IFWI_16_LAYOUT_HEADER)) {
|
|
msg(usprintf("%s: ME region too small to fit IFWI 1.6 layout header", __FUNCTION__), index);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
const IFWI_16_LAYOUT_HEADER* ifwi16Header = (const IFWI_16_LAYOUT_HEADER*)meRegion.constData();
|
|
// Check region size
|
|
if ((UINT32)meRegion.size() < ifwi16Header->DataPartition.Offset + sizeof(UINT32)) {
|
|
msg(usprintf("%s: ME region too small to fit IFWI 1.6 data partition", __FUNCTION__), index);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
// Data partition always points to FPT header
|
|
if (meRegion.mid(ifwi16Header->DataPartition.Offset, sizeof(UINT32)) == FPT_HEADER_SIGNATURE) {
|
|
UModelIndex ptIndex;
|
|
return parseIfwi16Region(meRegion, index, ptIndex);
|
|
}
|
|
|
|
// IFWI 1.7
|
|
if ((UINT32)meRegion.size() < sizeof(IFWI_17_LAYOUT_HEADER)) {
|
|
msg(usprintf("%s: ME region too small to fit IFWI 1.7 layout header", __FUNCTION__), index);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
const IFWI_17_LAYOUT_HEADER* ifwi17Header = (const IFWI_17_LAYOUT_HEADER*)meRegion.constData();
|
|
// Check region size
|
|
if ((UINT32)meRegion.size() < ifwi17Header->DataPartition.Offset + sizeof(UINT32)) {
|
|
msg(usprintf("%s: ME region too small to fit IFWI 1.7 data partition", __FUNCTION__), index);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
// Data partition always points to FPT header
|
|
if (meRegion.mid(ifwi17Header->DataPartition.Offset, sizeof(UINT32)) == FPT_HEADER_SIGNATURE) {
|
|
UModelIndex ptIndex;
|
|
return parseIfwi17Region(meRegion, index, ptIndex);
|
|
}
|
|
|
|
// Something else entirely
|
|
msg(usprintf("%s: unknown ME region format", __FUNCTION__), index);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
USTATUS MeParser::parseFptRegion(const UByteArray & region, const UModelIndex & parent, UModelIndex & index)
|
|
{
|
|
// Check region size
|
|
if ((UINT32)region.size() < sizeof(FPT_HEADER)) {
|
|
msg(usprintf("%s: region too small to fit FPT header", __FUNCTION__), parent);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
// Populate partition table header
|
|
const FPT_HEADER* ptHeader = (const FPT_HEADER*)region.constData();
|
|
UINT32 romBypassVectorSize = 0;
|
|
if (region.left(sizeof(UINT32)) != FPT_HEADER_SIGNATURE) {
|
|
// Adjust the header to skip ROM bypass vector
|
|
romBypassVectorSize = ME_ROM_BYPASS_VECTOR_SIZE;
|
|
ptHeader = (const FPT_HEADER*)(region.constData() + romBypassVectorSize);
|
|
}
|
|
|
|
// Check region size again
|
|
UINT32 ptBodySize = ptHeader->NumEntries * sizeof(FPT_HEADER_ENTRY);
|
|
UINT32 ptSize = romBypassVectorSize + sizeof(FPT_HEADER) + ptBodySize;
|
|
if ((UINT32)region.size() < ptSize) {
|
|
msg(usprintf("%s: ME region too small to fit partition table", __FUNCTION__), parent);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
// Recalculate checksum
|
|
UByteArray tempHeader = UByteArray((const char*)ptHeader, sizeof(FPT_HEADER));
|
|
FPT_HEADER* tempPtHeader = (FPT_HEADER*)tempHeader.data();
|
|
tempPtHeader->Checksum = 0;
|
|
UINT8 calculated = calculateChecksum8((const UINT8*)tempPtHeader, sizeof(FPT_HEADER));
|
|
bool msgInvalidPtHeaderChecksum = (calculated != ptHeader->Checksum);
|
|
|
|
// Get info
|
|
UByteArray header = region.left(romBypassVectorSize + sizeof(FPT_HEADER));
|
|
UByteArray body = region.mid(header.size(), ptBodySize);
|
|
|
|
UString name = UString("FPT partition table");
|
|
UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nNumber of entries: %u\nHeader version: %02Xh\nEntry version: %02Xh\n"
|
|
"Header length: %02Xh\nTicks to add: %04Xh\nTokens to add: %04Xh\nUMA size: %Xh\nFlash layout: %Xh\nFITC version: %u.%u.%u.%u\nChecksum: %02Xh, ",
|
|
ptSize, ptSize,
|
|
header.size(), header.size(),
|
|
ptBodySize, ptBodySize,
|
|
ptHeader->NumEntries,
|
|
ptHeader->HeaderVersion,
|
|
ptHeader->EntryVersion,
|
|
ptHeader->HeaderLength,
|
|
ptHeader->TicksToAdd,
|
|
ptHeader->TokensToAdd,
|
|
ptHeader->UmaSize,
|
|
ptHeader->FlashLayout,
|
|
ptHeader->FitcMajor, ptHeader->FitcMinor, ptHeader->FitcHotfix, ptHeader->FitcBuild,
|
|
ptHeader->Checksum) + (ptHeader->Checksum == calculated ? UString("valid") : usprintf("invalid, should be %02Xh", calculated));
|
|
|
|
// Add tree item
|
|
index = model->addItem(0, Types::FptStore, 0, name, UString(), info, header, body, UByteArray(), Fixed, parent);
|
|
|
|
// Show messages
|
|
if (msgInvalidPtHeaderChecksum) {
|
|
msg(usprintf("%s: FPT partition table header checksum is invalid", __FUNCTION__), index);
|
|
}
|
|
|
|
// Add partition table entries
|
|
std::vector<FPT_PARTITION_INFO> partitions;
|
|
UINT32 offset = header.size();
|
|
const FPT_HEADER_ENTRY* firstPtEntry = (const FPT_HEADER_ENTRY*)(region.constData() + offset);
|
|
for (UINT8 i = 0; i < ptHeader->NumEntries; i++) {
|
|
// Populate entry header
|
|
const FPT_HEADER_ENTRY* ptEntry = firstPtEntry + i;
|
|
|
|
// Get info
|
|
name = usprintf("%c%c%c%c", ptEntry->Name[0], ptEntry->Name[1], ptEntry->Name[2], ptEntry->Name[3]);
|
|
info = usprintf("Full size: %Xh (%u)\nPartition offset: %Xh\nPartition length: %Xh\nPartition type: %02Xh",
|
|
sizeof(FPT_HEADER_ENTRY), sizeof(FPT_HEADER_ENTRY),
|
|
ptEntry->Offset,
|
|
ptEntry->Size,
|
|
ptEntry->Type);
|
|
|
|
// Add tree item
|
|
const UINT8 type = (ptEntry->Offset != 0 && ptEntry->Offset != 0xFFFFFFFF && ptEntry->Size != 0 && ptEntry->EntryValid != 0xFF) ? Subtypes::ValidFptEntry : Subtypes::InvalidFptEntry;
|
|
UModelIndex entryIndex = model->addItem(offset, Types::FptEntry, type, name, UString(), info, UByteArray(), UByteArray((const char*)ptEntry, sizeof(FPT_HEADER_ENTRY)), UByteArray(), Fixed, index);
|
|
|
|
// Adjust offset
|
|
offset += sizeof(FPT_HEADER_ENTRY);
|
|
|
|
// Add valid partitions
|
|
if (type == Subtypes::ValidFptEntry) { // Skip absent and invalid partitions
|
|
// Add to partitions vector
|
|
FPT_PARTITION_INFO partition;
|
|
partition.type = Types::FptPartition;
|
|
partition.ptEntry = *ptEntry;
|
|
partition.index = entryIndex;
|
|
partitions.push_back(partition);
|
|
}
|
|
}
|
|
|
|
make_partition_table_consistent:
|
|
// Sort partitions by offset
|
|
std::sort(partitions.begin(), partitions.end());
|
|
|
|
// Check for intersections and paddings between partitions
|
|
FPT_PARTITION_INFO padding;
|
|
|
|
// Check intersection with the partition table header
|
|
if (partitions.front().ptEntry.Offset < ptSize) {
|
|
msg(usprintf("%s: ME partition has intersection with ME partition table, skipped", __FUNCTION__),
|
|
partitions.front().index);
|
|
partitions.erase(partitions.begin());
|
|
goto make_partition_table_consistent;
|
|
}
|
|
// Check for padding between partition table and the first partition
|
|
else if (partitions.front().ptEntry.Offset > ptSize) {
|
|
padding.ptEntry.Offset = ptSize;
|
|
padding.ptEntry.Size = partitions.front().ptEntry.Offset - ptSize;
|
|
padding.type = Types::Padding;
|
|
partitions.insert(partitions.begin(), padding);
|
|
}
|
|
// Check for intersections/paddings between partitions
|
|
for (size_t i = 1; i < partitions.size(); i++) {
|
|
UINT32 previousPartitionEnd = partitions[i - 1].ptEntry.Offset + partitions[i - 1].ptEntry.Size;
|
|
|
|
// Check that current region is fully present in the image
|
|
if ((UINT32)partitions[i].ptEntry.Offset + (UINT32)partitions[i].ptEntry.Size > (UINT32)region.size()) {
|
|
if ((UINT32)partitions[i].ptEntry.Offset >= (UINT32)region.size()) {
|
|
msg(usprintf("%s: FPT partition is located outside of the opened image, skipped", __FUNCTION__), partitions[i].index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
else {
|
|
msg(usprintf("%s: FPT partition can't fit into the region, truncated", __FUNCTION__), partitions[i].index);
|
|
partitions[i].ptEntry.Size = (UINT32)region.size() - (UINT32)partitions[i].ptEntry.Offset;
|
|
}
|
|
}
|
|
|
|
// Check for intersection with previous partition
|
|
if (partitions[i].ptEntry.Offset < previousPartitionEnd) {
|
|
// Check if current partition is located inside previous one
|
|
if (partitions[i].ptEntry.Offset + partitions[i].ptEntry.Size <= previousPartitionEnd) {
|
|
msg(usprintf("%s: FPT partition is located inside another FPT partition, skipped", __FUNCTION__),
|
|
partitions[i].index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
else {
|
|
msg(usprintf("%s: FPT partition intersects with previous one, skipped", __FUNCTION__),
|
|
partitions[i].index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
}
|
|
|
|
// Check for padding between current and previous partitions
|
|
else if (partitions[i].ptEntry.Offset > previousPartitionEnd) {
|
|
padding.ptEntry.Offset = previousPartitionEnd;
|
|
padding.ptEntry.Size = partitions[i].ptEntry.Offset - previousPartitionEnd;
|
|
padding.type = Types::Padding;
|
|
std::vector<FPT_PARTITION_INFO>::iterator iter = partitions.begin();
|
|
std::advance(iter, i);
|
|
partitions.insert(iter, padding);
|
|
}
|
|
}
|
|
// Check for padding after the last region
|
|
if ((UINT32)partitions.back().ptEntry.Offset + (UINT32)partitions.back().ptEntry.Size < (UINT32)region.size()) {
|
|
padding.ptEntry.Offset = partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size;
|
|
padding.ptEntry.Size = region.size() - padding.ptEntry.Offset;
|
|
padding.type = Types::Padding;
|
|
partitions.push_back(padding);
|
|
}
|
|
|
|
// Partition map is consistent
|
|
for (size_t i = 0; i < partitions.size(); i++) {
|
|
UByteArray partition = region.mid(partitions[i].ptEntry.Offset, partitions[i].ptEntry.Size);
|
|
if (partitions[i].type == Types::FptPartition) {
|
|
UModelIndex partitionIndex;
|
|
// Get info
|
|
name = usprintf("%c%c%c%c", partitions[i].ptEntry.Name[0], partitions[i].ptEntry.Name[1], partitions[i].ptEntry.Name[2], partitions[i].ptEntry.Name[3]);
|
|
info = usprintf("Full size: %Xh (%u)\nPartition type: %02Xh\n",
|
|
partition.size(), partition.size(),
|
|
partitions[i].ptEntry.Type);
|
|
|
|
// Add tree item
|
|
UINT8 type = Subtypes::CodeFptPartition + partitions[i].ptEntry.Type;
|
|
partitionIndex = model->addItem(partitions[i].ptEntry.Offset, Types::FptPartition, type, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
|
if (type == Subtypes::CodeFptPartition && partition.size() >= (int) sizeof(UINT32) && readUnaligned((const UINT32*)partition.constData()) == CPD_SIGNATURE) {
|
|
// Parse code partition contents
|
|
UModelIndex cpdIndex;
|
|
ffsParser->parseCpdRegion(partition, partitions[i].ptEntry.Offset, partitionIndex, cpdIndex);
|
|
}
|
|
}
|
|
else if (partitions[i].type == Types::Padding) {
|
|
// Get info
|
|
name = UString("Padding");
|
|
info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size());
|
|
|
|
// Add tree item
|
|
model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
|
}
|
|
}
|
|
|
|
return U_SUCCESS;
|
|
}
|
|
|
|
USTATUS MeParser::parseIfwi16Region(const UByteArray & region, const UModelIndex & parent, UModelIndex & index)
|
|
{
|
|
// Check region size again
|
|
if ((UINT32)region.size() < sizeof(IFWI_16_LAYOUT_HEADER)) {
|
|
msg(usprintf("%s: ME region too small to fit IFWI 1.6 layout header", __FUNCTION__), parent);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
const IFWI_16_LAYOUT_HEADER* ifwiHeader = (const IFWI_16_LAYOUT_HEADER*)region.constData();
|
|
|
|
// Add header
|
|
UINT32 ptSize = sizeof(IFWI_16_LAYOUT_HEADER);
|
|
UByteArray header = region.left(ptSize);
|
|
|
|
UString name = UString("IFWI 1.6 header");
|
|
UString info = usprintf("Full size: %Xh (%u)\n"
|
|
"Data partition offset: %Xh\nData partition size: %Xh\n"
|
|
"Boot1 partition offset: %Xh\nBoot1 partition size: %Xh\n"
|
|
"Boot2 partition offset: %Xh\nBoot2 partition size: %Xh\n"
|
|
"Boot3 partition offset: %Xh\nBoot3 partition size: %Xh\n"
|
|
"Boot4 partition offset: %Xh\nBoot4 partition size: %Xh\n"
|
|
"Boot5 partition offset: %Xh\nBoot5 partition size: %Xh\n"
|
|
"Checksum: %Xh",
|
|
header.size(), header.size(),
|
|
ifwiHeader->DataPartition.Offset, ifwiHeader->DataPartition.Size,
|
|
ifwiHeader->BootPartition[0].Offset, ifwiHeader->BootPartition[0].Size,
|
|
ifwiHeader->BootPartition[1].Offset, ifwiHeader->BootPartition[1].Size,
|
|
ifwiHeader->BootPartition[2].Offset, ifwiHeader->BootPartition[2].Size,
|
|
ifwiHeader->BootPartition[3].Offset, ifwiHeader->BootPartition[3].Size,
|
|
ifwiHeader->BootPartition[4].Offset, ifwiHeader->BootPartition[4].Size,
|
|
ifwiHeader->Checksum);
|
|
// Add tree item
|
|
index = model->addItem(0, Types::IfwiHeader, 0, name, UString(), info, UByteArray(), header, UByteArray(), Fixed, parent);
|
|
|
|
std::vector<IFWI_PARTITION_INFO> partitions;
|
|
// Add data partition
|
|
{
|
|
IFWI_PARTITION_INFO partition;
|
|
partition.type = Types::IfwiPartition;
|
|
partition.subtype = Subtypes::DataIfwiPartition;
|
|
partition.ptEntry = ifwiHeader->DataPartition;
|
|
partitions.push_back(partition);
|
|
}
|
|
// Add boot partitions
|
|
for (UINT8 i = 0 ; i < 4; i++) {
|
|
if (ifwiHeader->BootPartition[i].Offset != 0 && ifwiHeader->BootPartition[i].Offset != 0xFFFFFFFF) {
|
|
IFWI_PARTITION_INFO partition;
|
|
partition.type = Types::IfwiPartition;
|
|
partition.subtype = Subtypes::BootIfwiPartition;
|
|
partition.ptEntry = ifwiHeader->BootPartition[i];
|
|
partitions.push_back(partition);
|
|
}
|
|
}
|
|
|
|
make_partition_table_consistent:
|
|
// Sort partitions by offset
|
|
std::sort(partitions.begin(), partitions.end());
|
|
|
|
// Check for intersections and paddings between partitions
|
|
IFWI_PARTITION_INFO padding;
|
|
|
|
// Check intersection with the partition table header
|
|
if (partitions.front().ptEntry.Offset < ptSize) {
|
|
msg(usprintf("%s: IFWI partition has intersection with IFWI layout header, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin());
|
|
goto make_partition_table_consistent;
|
|
}
|
|
// Check for padding between partition table and the first partition
|
|
else if (partitions.front().ptEntry.Offset > ptSize) {
|
|
padding.ptEntry.Offset = ptSize;
|
|
padding.ptEntry.Size = partitions.front().ptEntry.Offset - ptSize;
|
|
padding.type = Types::Padding;
|
|
partitions.insert(partitions.begin(), padding);
|
|
}
|
|
// Check for intersections/paddings between partitions
|
|
for (size_t i = 1; i < partitions.size(); i++) {
|
|
UINT32 previousPartitionEnd = partitions[i - 1].ptEntry.Offset + partitions[i - 1].ptEntry.Size;
|
|
|
|
// Check that current region is fully present in the image
|
|
if ((UINT32)partitions[i].ptEntry.Offset + (UINT32)partitions[i].ptEntry.Size > (UINT32)region.size()) {
|
|
if ((UINT32)partitions[i].ptEntry.Offset >= (UINT32)region.size()) {
|
|
msg(usprintf("%s: IFWI partition is located outside of the opened image, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
else {
|
|
msg(usprintf("%s: IFWI partition can't fit into the region, truncated", __FUNCTION__), index);
|
|
partitions[i].ptEntry.Size = (UINT32)region.size() - (UINT32)partitions[i].ptEntry.Offset;
|
|
}
|
|
}
|
|
|
|
// Check for intersection with previous partition
|
|
if (partitions[i].ptEntry.Offset < previousPartitionEnd) {
|
|
// Check if current partition is located inside previous one
|
|
if (partitions[i].ptEntry.Offset + partitions[i].ptEntry.Size <= previousPartitionEnd) {
|
|
msg(usprintf("%s: IFWI partition is located inside another IFWI partition, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
else {
|
|
msg(usprintf("%s: IFWI partition intersects with previous one, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
}
|
|
|
|
// Check for padding between current and previous partitions
|
|
else if (partitions[i].ptEntry.Offset > previousPartitionEnd) {
|
|
padding.ptEntry.Offset = previousPartitionEnd;
|
|
padding.ptEntry.Size = partitions[i].ptEntry.Offset - previousPartitionEnd;
|
|
padding.type = Types::Padding;
|
|
std::vector<IFWI_PARTITION_INFO>::iterator iter = partitions.begin();
|
|
std::advance(iter, i);
|
|
partitions.insert(iter, padding);
|
|
}
|
|
}
|
|
// Check for padding after the last region
|
|
if ((UINT32)partitions.back().ptEntry.Offset + (UINT32)partitions.back().ptEntry.Size < (UINT32)region.size()) {
|
|
padding.ptEntry.Offset = partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size;
|
|
padding.ptEntry.Size = region.size() - padding.ptEntry.Offset;
|
|
padding.type = Types::Padding;
|
|
partitions.push_back(padding);
|
|
}
|
|
|
|
// Partition map is consistent
|
|
for (size_t i = 0; i < partitions.size(); i++) {
|
|
UByteArray partition = region.mid(partitions[i].ptEntry.Offset, partitions[i].ptEntry.Size);
|
|
if (partitions[i].type == Types::IfwiPartition) {
|
|
UModelIndex partitionIndex;
|
|
if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
|
|
name = "Data partition";
|
|
}
|
|
else if (partitions[i].subtype == Subtypes::BootIfwiPartition) {
|
|
name = "Boot partition";
|
|
}
|
|
|
|
// Get info
|
|
info = usprintf("Full size: %Xh (%u)\n",
|
|
partition.size(), partition.size());
|
|
|
|
// Add tree item
|
|
partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
|
|
|
// Parse partition further
|
|
if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
|
|
UModelIndex dataPartitionFptRegionIndex;
|
|
parseFptRegion(partition, partitionIndex, dataPartitionFptRegionIndex);
|
|
}
|
|
else if (partitions[i].subtype == Subtypes::BootIfwiPartition) {
|
|
// Parse code partition contents
|
|
UModelIndex bootPartitionBpdtRegionIndex;
|
|
ffsParser->parseBpdtRegion(partition, 0, 0, partitionIndex, bootPartitionBpdtRegionIndex);
|
|
}
|
|
}
|
|
else if (partitions[i].type == Types::Padding) {
|
|
// Get info
|
|
name = UString("Padding");
|
|
info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size());
|
|
|
|
// Add tree item
|
|
model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
|
}
|
|
}
|
|
|
|
return U_SUCCESS;
|
|
}
|
|
|
|
USTATUS MeParser::parseIfwi17Region(const UByteArray & region, const UModelIndex & parent, UModelIndex & index)
|
|
{
|
|
// Check region size again
|
|
if ((UINT32)region.size() < sizeof(IFWI_17_LAYOUT_HEADER)) {
|
|
msg(usprintf("%s: ME region too small to fit IFWI 1.7 layout header", __FUNCTION__), parent);
|
|
return U_INVALID_ME_PARTITION_TABLE;
|
|
}
|
|
|
|
const IFWI_17_LAYOUT_HEADER* ifwiHeader = (const IFWI_17_LAYOUT_HEADER*)region.constData();
|
|
// TODO: add check for HeaderSize to be 0x40
|
|
|
|
// Add header
|
|
UINT32 ptSize = sizeof(IFWI_17_LAYOUT_HEADER);
|
|
UByteArray header = region.left(ptSize);
|
|
|
|
UString name = UString("IFWI 1.7 header");
|
|
UString info = usprintf("Full size: %Xh (%u)\n"
|
|
"Flags: %02Xh\n"
|
|
"Reserved: %02Xh\n"
|
|
"Checksum: %Xh\n"
|
|
"Data partition offset: %Xh\nData partition size: %Xh\n"
|
|
"Boot1 partition offset: %Xh\nBoot1 partition size: %Xh\n"
|
|
"Boot2 partition offset: %Xh\nBoot2 partition size: %Xh\n"
|
|
"Boot3 partition offset: %Xh\nBoot3 partition size: %Xh\n"
|
|
"Boot4 partition offset: %Xh\nBoot4 partition size: %Xh\n"
|
|
"Boot5 partition offset: %Xh\nBoot5 partition size: %Xh\n"
|
|
"Temp page offset: %Xh\nTemp page size: %Xh\n",
|
|
header.size(), header.size(),
|
|
ifwiHeader->Flags,
|
|
ifwiHeader->Reserved,
|
|
ifwiHeader->Checksum,
|
|
ifwiHeader->DataPartition.Offset, ifwiHeader->DataPartition.Size,
|
|
ifwiHeader->BootPartition[0].Offset, ifwiHeader->BootPartition[0].Size,
|
|
ifwiHeader->BootPartition[1].Offset, ifwiHeader->BootPartition[1].Size,
|
|
ifwiHeader->BootPartition[2].Offset, ifwiHeader->BootPartition[2].Size,
|
|
ifwiHeader->BootPartition[3].Offset, ifwiHeader->BootPartition[3].Size,
|
|
ifwiHeader->BootPartition[4].Offset, ifwiHeader->BootPartition[4].Size,
|
|
ifwiHeader->TempPage.Offset, ifwiHeader->TempPage.Size);
|
|
// Add tree item
|
|
index = model->addItem(0, Types::IfwiHeader, 0, name, UString(), info, UByteArray(), header, UByteArray(), Fixed, parent);
|
|
|
|
std::vector<IFWI_PARTITION_INFO> partitions;
|
|
// Add data partition
|
|
{
|
|
IFWI_PARTITION_INFO partition;
|
|
partition.type = Types::IfwiPartition;
|
|
partition.subtype = Subtypes::DataIfwiPartition;
|
|
partition.ptEntry = ifwiHeader->DataPartition;
|
|
partitions.push_back(partition);
|
|
}
|
|
// Add boot partitions
|
|
for (UINT8 i = 0 ; i < 4; i++) {
|
|
if (ifwiHeader->BootPartition[i].Offset != 0 && ifwiHeader->BootPartition[i].Offset != 0xFFFFFFFF) {
|
|
IFWI_PARTITION_INFO partition;
|
|
partition.type = Types::IfwiPartition;
|
|
partition.subtype = Subtypes::BootIfwiPartition;
|
|
partition.ptEntry = ifwiHeader->BootPartition[i];
|
|
partitions.push_back(partition);
|
|
}
|
|
}
|
|
// Add temp page
|
|
if (ifwiHeader->TempPage.Offset != 0 && ifwiHeader->TempPage.Offset != 0xFFFFFFFF) {
|
|
IFWI_PARTITION_INFO partition;
|
|
partition.type = Types::IfwiPartition;
|
|
partition.subtype = Subtypes::DataPadding;
|
|
partition.ptEntry = ifwiHeader->TempPage;
|
|
partitions.push_back(partition);
|
|
}
|
|
|
|
make_partition_table_consistent:
|
|
// Sort partitions by offset
|
|
std::sort(partitions.begin(), partitions.end());
|
|
|
|
// Check for intersections and paddings between partitions
|
|
IFWI_PARTITION_INFO padding;
|
|
|
|
// Check intersection with the partition table header
|
|
if (partitions.front().ptEntry.Offset < ptSize) {
|
|
msg(usprintf("%s: IFWI partition has intersection with IFWI layout header, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin());
|
|
goto make_partition_table_consistent;
|
|
}
|
|
// Check for padding between partition table and the first partition
|
|
else if (partitions.front().ptEntry.Offset > ptSize) {
|
|
padding.ptEntry.Offset = ptSize;
|
|
padding.ptEntry.Size = partitions.front().ptEntry.Offset - ptSize;
|
|
padding.type = Types::Padding;
|
|
partitions.insert(partitions.begin(), padding);
|
|
}
|
|
// Check for intersections/paddings between partitions
|
|
for (size_t i = 1; i < partitions.size(); i++) {
|
|
UINT32 previousPartitionEnd = partitions[i - 1].ptEntry.Offset + partitions[i - 1].ptEntry.Size;
|
|
|
|
// Check that current region is fully present in the image
|
|
if ((UINT32)partitions[i].ptEntry.Offset + (UINT32)partitions[i].ptEntry.Size > (UINT32)region.size()) {
|
|
if ((UINT32)partitions[i].ptEntry.Offset >= (UINT32)region.size()) {
|
|
msg(usprintf("%s: IFWI partition is located outside of the opened image, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
else {
|
|
msg(usprintf("%s: IFWI partition can't fit into the region, truncated", __FUNCTION__), index);
|
|
partitions[i].ptEntry.Size = (UINT32)region.size() - (UINT32)partitions[i].ptEntry.Offset;
|
|
}
|
|
}
|
|
|
|
// Check for intersection with previous partition
|
|
if (partitions[i].ptEntry.Offset < previousPartitionEnd) {
|
|
// Check if current partition is located inside previous one
|
|
if (partitions[i].ptEntry.Offset + partitions[i].ptEntry.Size <= previousPartitionEnd) {
|
|
msg(usprintf("%s: IFWI partition is located inside another IFWI partition, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
else {
|
|
msg(usprintf("%s: IFWI partition intersects with previous one, skipped", __FUNCTION__), index);
|
|
partitions.erase(partitions.begin() + i);
|
|
goto make_partition_table_consistent;
|
|
}
|
|
}
|
|
|
|
// Check for padding between current and previous partitions
|
|
else if (partitions[i].ptEntry.Offset > previousPartitionEnd) {
|
|
padding.ptEntry.Offset = previousPartitionEnd;
|
|
padding.ptEntry.Size = partitions[i].ptEntry.Offset - previousPartitionEnd;
|
|
padding.type = Types::Padding;
|
|
std::vector<IFWI_PARTITION_INFO>::iterator iter = partitions.begin();
|
|
std::advance(iter, i);
|
|
partitions.insert(iter, padding);
|
|
}
|
|
}
|
|
// Check for padding after the last region
|
|
if ((UINT32)partitions.back().ptEntry.Offset + (UINT32)partitions.back().ptEntry.Size < (UINT32)region.size()) {
|
|
padding.ptEntry.Offset = partitions.back().ptEntry.Offset + partitions.back().ptEntry.Size;
|
|
padding.ptEntry.Size = region.size() - padding.ptEntry.Offset;
|
|
padding.type = Types::Padding;
|
|
partitions.push_back(padding);
|
|
}
|
|
|
|
// Partition map is consistent
|
|
for (size_t i = 0; i < partitions.size(); i++) {
|
|
UByteArray partition = region.mid(partitions[i].ptEntry.Offset, partitions[i].ptEntry.Size);
|
|
if (partitions[i].type == Types::IfwiPartition) {
|
|
UModelIndex partitionIndex;
|
|
if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
|
|
name = "Data partition";
|
|
|
|
}
|
|
else if (partitions[i].subtype == Subtypes::BootIfwiPartition){
|
|
name = "Boot partition";
|
|
}
|
|
else {
|
|
name = "Temp page";
|
|
}
|
|
|
|
// Get info
|
|
info = usprintf("Full size: %Xh (%u)\n",
|
|
partition.size(), partition.size());
|
|
|
|
// Add tree item
|
|
partitionIndex = model->addItem(partitions[i].ptEntry.Offset, partitions[i].type, partitions[i].subtype, name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
|
|
|
// Parse partition further
|
|
if (partitions[i].subtype == Subtypes::DataIfwiPartition) {
|
|
UModelIndex dataPartitionFptRegionIndex;
|
|
parseFptRegion(partition, partitionIndex, dataPartitionFptRegionIndex);
|
|
}
|
|
else if (partitions[i].subtype == Subtypes::BootIfwiPartition) {
|
|
// Parse code partition contents
|
|
UModelIndex bootPartitionBpdtRegionIndex;
|
|
ffsParser->parseBpdtRegion(partition, 0, 0, partitionIndex, bootPartitionBpdtRegionIndex);
|
|
}
|
|
}
|
|
else if (partitions[i].type == Types::Padding) {
|
|
// Get info
|
|
name = UString("Padding");
|
|
info = usprintf("Full size: %Xh (%u)", partition.size(), partition.size());
|
|
|
|
// Add tree item
|
|
model->addItem(partitions[i].ptEntry.Offset, Types::Padding, getPaddingType(partition), name, UString(), info, UByteArray(), partition, UByteArray(), Fixed, parent);
|
|
}
|
|
}
|
|
|
|
return U_SUCCESS;
|
|
}
|
|
|
|
#endif // U_ENABLE_ME_PARSING_SUPPORT
|
|
|