mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-11-04 12:59:07 +01:00
Add bootloader extension
This commit is contained in:
committed by
Kyle Schwarz
parent
4db27aa187
commit
6ac041cadc
@@ -0,0 +1,249 @@
|
||||
#include "icsneo/device/extensions/bootloader/parser/fwbin.h"
|
||||
#include "icsneo/device/extensions/bootloader/platform/logging.h"
|
||||
#include "icsneo/device/extensions/bootloader/parser/ief.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
/**
|
||||
* fw.bin file format (all integers little-endian):
|
||||
*
|
||||
* uint8_t versionLength
|
||||
* char version[versionLength] Vehicle Spy 3 version, "major.minor.release.build"
|
||||
* uint8_t hashLength
|
||||
* char hash[hashLength] Build hash, unused
|
||||
* Then tags until the end of the file:
|
||||
* uint32_t nameHash HashDjb2() of the tag name, e.g. "fire2_core"
|
||||
* uint8_t type TagData::Type
|
||||
* uint32_t length
|
||||
* uint8_t data[length]
|
||||
*
|
||||
* Exactly one Signature tag is required, it uses the reserved name hash 0.
|
||||
*/
|
||||
|
||||
uint32_t FWBin::HashDjb2(const std::string& tag) {
|
||||
uint32_t retv = 5381;
|
||||
for(char c : tag)
|
||||
retv = ((retv << 5) + retv) + c;
|
||||
return retv;
|
||||
}
|
||||
|
||||
bool FWBin::load(const std::string& path) {
|
||||
file.open(path, std::ios::binary);
|
||||
if(!file.is_open() || file.fail() || file.eof()) {
|
||||
Log::Error(__func__, "Could not open file at " + path);
|
||||
return false;
|
||||
}
|
||||
// Read out the version string, it is a single byte length followed by a string
|
||||
uint8_t size;
|
||||
file.read((char*)&size, 1);
|
||||
if(file.fail() || file.eof()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read the version length");
|
||||
return false;
|
||||
}
|
||||
std::string unparsedVersion;
|
||||
unparsedVersion.resize(size);
|
||||
file.read(unparsedVersion.data(), size);
|
||||
if(file.fail() || file.eof()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read the version string");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!version.load(unparsedVersion)) {
|
||||
Log::Error(__func__, "The fw.bin version string is invalid: " + unparsedVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read out the hash string, it is a single byte length followed by a string
|
||||
file.read((char*)&size, 1);
|
||||
if(file.fail() || file.eof()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read the hash length");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The hash string is not used, skip over it
|
||||
file.seekg(size, file.cur);
|
||||
if(file.fail() || file.eof()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read the hash string");
|
||||
return false;
|
||||
}
|
||||
|
||||
while(true) {
|
||||
uint32_t tagHash;
|
||||
file.read((char*)&tagHash, sizeof(uint32_t));
|
||||
if(file.eof()) {
|
||||
break;
|
||||
}
|
||||
if(file.fail()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read a tag name hash");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(tags.count(tagHash)) {
|
||||
// Duplicate tag
|
||||
Log::Error(__func__, "The fw.bin contains a duplicate tag");
|
||||
return false;
|
||||
}
|
||||
TagData& current = tags[tagHash];
|
||||
|
||||
// Read the type field
|
||||
file.read((char*)¤t.type, sizeof(TagData::Type));
|
||||
if(file.fail() || file.eof()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read a tag type");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(current.type) {
|
||||
case TagData::Type::DataBytes:
|
||||
case TagData::Type::DataLength:
|
||||
case TagData::Type::IEFVersion:
|
||||
if(tagHash == SignatureHash) {
|
||||
Log::Error(__func__, "The fw.bin contains a data tag using the reserved signature name hash");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case TagData::Type::Signature:
|
||||
if(tagHash != SignatureHash) {
|
||||
Log::Error(__func__, "The fw.bin contains a signature tag with a non-signature name hash");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default: // Unknown type
|
||||
Log::Error(__func__, "The fw.bin contains a tag of unknown type " + std::to_string(static_cast<int>(current.type)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the length field
|
||||
file.read((char*)¤t.arrayLength, sizeof(uint32_t));
|
||||
if(file.fail() || file.eof()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read a tag length");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note the current position so we can jump back to it and read it later
|
||||
current.arrayPosition = file.tellg();
|
||||
file.seekg(current.arrayLength, file.cur);
|
||||
if(file.fail()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, a tag extends past the end of the file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
file.clear();
|
||||
|
||||
// The signature tag is required to be present, but it is not verified
|
||||
if(tags.count(SignatureHash) == 0) {
|
||||
Log::Error(__func__, "The fw.bin is missing its signature tag");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWBin::readTag(const std::string& tag, std::vector<uint8_t>& out) const {
|
||||
const auto hash = HashDjb2(tag);
|
||||
if(hash == SignatureHash) {
|
||||
Log::Error(__func__, "The signature tag can not be read as data");
|
||||
return false;
|
||||
}
|
||||
const auto it = tags.find(hash);
|
||||
if(it == tags.end()) {
|
||||
Log::Error(__func__, "The fw.bin does not contain the tag " + tag);
|
||||
return false;
|
||||
}
|
||||
return it->second.read(file, out);
|
||||
}
|
||||
|
||||
bool FWBin::TagData::read(std::ifstream& stream, std::vector<uint8_t>& out) const {
|
||||
stream.clear();
|
||||
stream.seekg(arrayPosition, stream.beg);
|
||||
out.resize(arrayLength);
|
||||
stream.read((char*)out.data(), arrayLength);
|
||||
if(stream.fail()) {
|
||||
Log::Error(__func__, "The fw.bin is truncated, could not read tag data");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWBin::getFW(const std::string& iefName, std::vector<uint8_t>& fw) const {
|
||||
return readTag(iefName, fw);
|
||||
}
|
||||
|
||||
FWBin::VersionTags FWBin::GetVersionTags(const std::string& iefName) {
|
||||
static const std::unordered_map<std::string, VersionTags> VersionTable = {
|
||||
{"fire2_core", {"fire2_core_version_major", "fire2_core_version_minor"}},
|
||||
{"fire2_core_sg4", {"fire2_core_sg4_version_major", "fire2_core_sg4_version_minor"}},
|
||||
{"RADA2B_SW_bin", {"RADA2B_SW_Version_Major", "RADA2B_SW_Version_Minor"}},
|
||||
{"RADA2B_REVB_SW_bin", {"RADA2B_SW_Version_Major", "RADA2B_SW_Version_Minor"}},
|
||||
{"RADComet_SW_bin", {"RADComet_SW_Version_Major", "RADComet_SW_Version_Minor"}},
|
||||
{"RADComet3_SW_bin", {"RADComet3_SW_Version_Major", "RADComet3_SW_Version_Minor"}},
|
||||
{"RADGalaxy_SG2_SW_bin", {"RADGalaxy_SG2_SW_Version_Major", "RADGalaxy_SG2_SW_Version_Minor"}},
|
||||
{"RADGalaxy_SG2_FFG_SW_bin", {"RADGalaxy_SG2_FFG_SW_Version_Major", "RADGalaxy_SG2_SW_Version_Minor"}},
|
||||
{"RADGalaxy2_SW_bin_p1", {"RADGalaxy2_SW_Version_Major", "RADGalaxy2_SW_Version_Minor"}},
|
||||
{"RADGalaxy2_SW_bin_p2", {"RADGalaxy2_SW_Version_Major", "RADGalaxy2_SW_Version_Minor"}},
|
||||
{"RADGigastar_SW_bin", {"RADGigastar_SW_Version_Major", "RADGigastar_SW_Version_Minor"}},
|
||||
{"RADGigastar_FFG_SW_bin", {"RADGigastar_SW_Version_Major", "RADGigastar_SW_Version_Minor"}},
|
||||
{"RADGigastar_USBz_SW_bin", {"RADGigastar_USBz_SW_Version_Major", "RADGigastar_USBz_SW_Version_Minor"}},
|
||||
{"RADGigastar_USBz_Z7010_SW_bin", {"RADGigastar_USBz_SW_Version_Major", "RADGigastar_USBz_SW_Version_Minor"}},
|
||||
{"RADGigastar_USBz_Z7007s_SW_bin", {"RADGigastar_USBz_SW_Version_Major", "RADGigastar_USBz_SW_Version_Minor"}},
|
||||
{"RADGigastar2_T1S_LIN_SW_bin", {"RADGigastar2_T1S_LIN_SW_Version_Major", "RADGigastar2_T1S_LIN_SW_Version_Minor"}},
|
||||
{"RADGigastar2_T1S_CAN_SW_bin", {"RADGigastar2_T1S_CAN_SW_Version_Major", "RADGigastar2_T1S_CAN_SW_Version_Minor"}},
|
||||
{"RADMoon2_SW_bin", {"RADMoon2_SW_Version_Major", "RADMoon2_SW_Version_Minor"}},
|
||||
{"RADMoon2_Z7010_SW_bin", {"RADMoon2_SW_Version_Major", "RADMoon2_SW_Version_Minor"}},
|
||||
{"RADMoonT1S_SW_bin", {"RADMoonT1S_SW_Version_Major", "RADMoonT1S_SW_Version_Minor"}},
|
||||
{"vcan44_core_ief", {"vcan44_core_version_major", "vcan44_core_version_minor"}}
|
||||
};
|
||||
auto iter = VersionTable.find(iefName);
|
||||
return iter != VersionTable.end() ? iter->second : VersionTags();
|
||||
}
|
||||
|
||||
std::optional<icsneo::DeviceAppVersion> FWBin::getChipVersion(const std::string& iefName) const {
|
||||
auto versionTags = GetVersionTags(iefName);
|
||||
|
||||
if(versionTags) {
|
||||
std::vector<uint8_t> majData;
|
||||
std::vector<uint8_t> minData;
|
||||
|
||||
if(!readTag(versionTags.majorTag, majData)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(!readTag(versionTags.minorTag, minData)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(majData.size() != 1)
|
||||
return std::nullopt;
|
||||
|
||||
if(minData.size() != 1)
|
||||
return std::nullopt;
|
||||
|
||||
icsneo::DeviceAppVersion chipVersion;
|
||||
chipVersion.major = majData[0];
|
||||
chipVersion.minor = minData[0];
|
||||
return chipVersion;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> buf;
|
||||
|
||||
if(!readTag(iefName, buf)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
IEF ief;
|
||||
|
||||
if(!ief.load(std::move(buf))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
icsneo::DeviceAppVersion chipVersion;
|
||||
chipVersion.major = ief.getVersion().appMajor;
|
||||
chipVersion.minor = ief.getVersion().appMinor;
|
||||
return chipVersion;
|
||||
}
|
||||
|
||||
} // namespace Bootloader
|
||||
|
||||
} // namespace icsneo
|
||||
@@ -0,0 +1,142 @@
|
||||
#include "icsneo/device/extensions/bootloader/parser/fwbundle.h"
|
||||
#include "icsneo/device/extensions/bootloader/parser/fwbin.h"
|
||||
#include "icsneo/device/extensions/bootloader/platform/logging.h"
|
||||
#include "icsneo/core/crc32.h"
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
/**
|
||||
* Firmware bundle file format (all integers little-endian):
|
||||
*
|
||||
* FWBundleHeader
|
||||
* Then chips until the end of the file:
|
||||
* FWBundleChip
|
||||
* uint8_t data[FWBundleChip::length]
|
||||
*
|
||||
* The CRC32 covers the whole file with the crc field set to zero.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
struct FWBundleHeader {
|
||||
char magic[2]; // "FW"
|
||||
uint16_t fmtVersion;
|
||||
uint32_t crc;
|
||||
uint8_t build;
|
||||
uint8_t maintenance;
|
||||
uint8_t minor;
|
||||
uint8_t major;
|
||||
uint8_t type; // Build type, unused
|
||||
};
|
||||
|
||||
struct FWBundleChip {
|
||||
uint32_t hash; // FWBin::HashDjb2() of the chip's IEF name
|
||||
uint8_t build;
|
||||
uint8_t maintenance;
|
||||
uint8_t minor;
|
||||
uint8_t major;
|
||||
uint32_t length;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
bool FWBundle::IsFWBundle(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if(!file.is_open())
|
||||
return false;
|
||||
// Only check the magic, so a truncated bundle is still reported as a bundle error by load()
|
||||
char magic[sizeof(FWBundleHeader::magic)];
|
||||
file.read(magic, sizeof(magic));
|
||||
if(file.fail())
|
||||
return false;
|
||||
return magic[0] == 'F' && magic[1] == 'W';
|
||||
}
|
||||
|
||||
bool FWBundle::load(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if(!file.is_open()) {
|
||||
Log::Error(__func__, "Could not open file at " + path);
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> bytes((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
if(file.bad()) {
|
||||
Log::Error(__func__, "Could not read file at " + path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(bytes.size() < sizeof(FWBundleHeader) || bytes.size() > std::numeric_limits<uint32_t>::max()) {
|
||||
Log::Error(__func__, "The firmware bundle is smaller than its header or larger than 4 GiB");
|
||||
return false;
|
||||
}
|
||||
|
||||
FWBundleHeader header;
|
||||
std::memcpy(&header, bytes.data(), sizeof(header));
|
||||
if(header.magic[0] != 'F' || header.magic[1] != 'W') {
|
||||
Log::Error(__func__, "The file is not a firmware bundle, bad magic");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The CRC is computed with the CRC field zeroed
|
||||
std::memset(bytes.data() + offsetof(FWBundleHeader, crc), 0, sizeof(header.crc));
|
||||
if(icsneo::crc32(0, bytes.data(), static_cast<uint32_t>(bytes.size())) != header.crc) {
|
||||
Log::Error(__func__, "The firmware bundle failed CRC validation");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, ChipBinary> parsed;
|
||||
size_t offset = sizeof(FWBundleHeader);
|
||||
while(offset < bytes.size()) {
|
||||
if(bytes.size() - offset < sizeof(FWBundleChip)) {
|
||||
Log::Error(__func__, "The firmware bundle is truncated, could not read a chip header");
|
||||
return false;
|
||||
}
|
||||
FWBundleChip chip;
|
||||
std::memcpy(&chip, bytes.data() + offset, sizeof(chip));
|
||||
offset += sizeof(FWBundleChip);
|
||||
|
||||
if(bytes.size() - offset < chip.length) {
|
||||
Log::Error(__func__, "The firmware bundle is truncated, a chip binary extends past the end of the file");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& bin = parsed[chip.hash];
|
||||
bin.data.assign(bytes.begin() + offset, bytes.begin() + offset + chip.length);
|
||||
bin.version.major = chip.major;
|
||||
bin.version.minor = chip.minor;
|
||||
bin.version.release = chip.maintenance;
|
||||
bin.version.build = chip.build;
|
||||
offset += chip.length;
|
||||
}
|
||||
|
||||
version.major = header.major;
|
||||
version.minor = header.minor;
|
||||
version.release = header.maintenance;
|
||||
version.build = header.build;
|
||||
binaries = std::move(parsed);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWBundle::getFW(const std::string& iefName, std::vector<uint8_t>& fw) const {
|
||||
const auto it = binaries.find(FWBin::HashDjb2(iefName));
|
||||
if(it == binaries.end()) {
|
||||
Log::Error(__func__, "The chip binary could not be found");
|
||||
return false;
|
||||
}
|
||||
fw = it->second.data;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<icsneo::DeviceAppVersion> FWBundle::getChipVersion(const std::string& iefName) const {
|
||||
const auto it = binaries.find(FWBin::HashDjb2(iefName));
|
||||
if(it == binaries.end())
|
||||
return std::nullopt;
|
||||
return icsneo::DeviceAppVersion(it->second.version.major, it->second.version.minor);
|
||||
}
|
||||
|
||||
} // namespace Bootloader
|
||||
|
||||
} // namespace icsneo
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "icsneo/device/extensions/bootloader/parser/fwloader.h"
|
||||
#include "icsneo/device/extensions/bootloader/parser/fwbin.h"
|
||||
#include "icsneo/device/extensions/bootloader/parser/fwbundle.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
std::unique_ptr<FWRepo> FWLoader::Load(const std::string& path) {
|
||||
if(FWBundle::IsFWBundle(path)) {
|
||||
auto bundle = std::make_unique<FWBundle>();
|
||||
if(!bundle->load(path))
|
||||
return nullptr;
|
||||
return bundle;
|
||||
}
|
||||
|
||||
auto bin = std::make_unique<FWBin>();
|
||||
if(!bin->load(path))
|
||||
return nullptr;
|
||||
return bin;
|
||||
}
|
||||
|
||||
} // namespace Bootloader
|
||||
|
||||
} // namespace icsneo
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "icsneo/device/extensions/bootloader/parser/fwzip.h"
|
||||
#include "icsneo/device/extensions/bootloader/platform/logging.h"
|
||||
|
||||
#include <miniz.h>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
class ZipHandle {
|
||||
public:
|
||||
ZipHandle() {
|
||||
mz_zip_zero_struct(&handle);
|
||||
}
|
||||
~ZipHandle() {
|
||||
mz_zip_reader_end(&handle);
|
||||
}
|
||||
|
||||
operator mz_zip_archive*() {
|
||||
return &handle;
|
||||
}
|
||||
|
||||
private:
|
||||
mz_zip_archive handle;
|
||||
};
|
||||
|
||||
// A zip firmware image holds a single entry, the raw binary to send to the device
|
||||
FWZip::FWZip(std::vector<uint8_t>&& tagData)
|
||||
: handle(std::make_unique<ZipHandle>()), zipData(std::move(tagData)) {
|
||||
|
||||
if(!mz_zip_reader_init_mem(*handle, zipData.data(), zipData.size(), 0)) {
|
||||
Log::Error(__func__, "The firmware zip could not be opened");
|
||||
return;
|
||||
}
|
||||
|
||||
mz_zip_archive_file_stat file;
|
||||
if(!mz_zip_reader_file_stat(*handle, 0, &file)) {
|
||||
Log::Error(__func__, "The firmware zip is empty or its first entry could not be read");
|
||||
} else {
|
||||
uncompressedSize = static_cast<size_t>(file.m_uncomp_size);
|
||||
}
|
||||
}
|
||||
|
||||
FWZip::~FWZip() = default;
|
||||
|
||||
bool FWZip::readAll(uint8_t* out) {
|
||||
if(!uncompressedSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!out) {
|
||||
Log::Error(__func__, "No output buffer for the firmware zip");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!mz_zip_reader_extract_to_mem(*handle, 0, out, *uncompressedSize, 0)) {
|
||||
Log::Error(__func__, "The firmware zip could not be decompressed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWZip::readAll(std::vector<uint8_t>& out) {
|
||||
if(!uncompressedSize) {
|
||||
return false;
|
||||
}
|
||||
out = std::vector<uint8_t>(*uncompressedSize, 0);
|
||||
return readAll(out.data());
|
||||
}
|
||||
|
||||
} // namespace Bootloader
|
||||
|
||||
} // namespace icsneo
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "icsneo/device/extensions/bootloader/parser/ief.h"
|
||||
#include "icsneo/device/extensions/bootloader/platform/logging.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
namespace Bootloader {
|
||||
|
||||
/**
|
||||
* IEF file format (all integers little-endian):
|
||||
*
|
||||
* uint8_t magic 0xAA
|
||||
* Version version
|
||||
* uint8_t configLength
|
||||
* uint8_t config[configLength] Unused
|
||||
* Then sectors until the end of the file:
|
||||
* uint8_t magic 0xAA
|
||||
* uint32_t index Sector index, see the communication for how this maps to an address
|
||||
* uint32_t length
|
||||
* uint8_t data[length]
|
||||
*/
|
||||
bool IEF::load(std::vector<uint8_t>&& bytes) {
|
||||
static constexpr uint8_t Magic = 0xAA;
|
||||
// Magic, version, config byte count
|
||||
static constexpr size_t FixedHeaderSize = 1 + sizeof(Version) + 1;
|
||||
// Magic, index, size
|
||||
static constexpr size_t SectorHeaderSize = 1 + sizeof(uint32_t) + sizeof(uint32_t);
|
||||
|
||||
data = std::move(bytes);
|
||||
sectors.clear();
|
||||
if(data.size() < FixedHeaderSize) {
|
||||
Log::Error(__func__, "IEF too short");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.front() != Magic) {
|
||||
Log::Error(__func__, "Invalid IEF magic");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(&version, data.data() + 1, sizeof(Version));
|
||||
|
||||
const size_t headerSize = FixedHeaderSize + data[FixedHeaderSize - 1];
|
||||
if(data.size() <= headerSize) {
|
||||
Log::Error(__func__, "Invalid IEF config bytes");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t offset = headerSize;
|
||||
while(data.size() - offset >= SectorHeaderSize) {
|
||||
if(data[offset] != Magic) {
|
||||
Log::Error(__func__, "Invalid IEF sector magic");
|
||||
return false;
|
||||
}
|
||||
uint32_t index;
|
||||
uint32_t size;
|
||||
std::memcpy(&index, data.data() + offset + 1, sizeof(index));
|
||||
std::memcpy(&size, data.data() + offset + 1 + sizeof(index), sizeof(size));
|
||||
offset += SectorHeaderSize;
|
||||
if(data.size() - offset < size) {
|
||||
Log::Error(__func__, "Invalid IEF sector");
|
||||
return false;
|
||||
}
|
||||
|
||||
sectors.emplace_back(index, BytesView(data.data() + offset, size));
|
||||
offset += size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Bootloader
|
||||
|
||||
} // namespace icsneo
|
||||
Reference in New Issue
Block a user