Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 207 additions & 1 deletion lib/moduleEncoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,210 @@ async function addModuleExtensions({ module, exts = [], replaceWithSameType = fa
return buffer;
}

/**
* Remove extensions of a particular type.
*
* @param {Buffer} module Module to update
* @param {Array} exts List of extensions to add
* @param {Boolean} replaceWithSameType Append extensions as-is or replace existing extensions of the same type
* @returns {Promise<Buffer>}
*/
async function removeModuleExtensions({ module, exts = [] } = {}) {
if (exts.length === 0) {
throw new RangeError('Empty extension list');
}

const parser = new HalModuleParser();
const { prefixInfo: prefix } = await parser.parsePrefix({ fileBuffer: module });
const { suffixInfo: suffix } = await parser.parseSuffix({ fileBuffer: module });
prefix.moduleStartAddy = sanitizeAddress(prefix.moduleStartAddy);
prefix.moduleEndAddy = sanitizeAddress(prefix.moduleEndAddy);
const flags = prefix.moduleFlags;
if (flags & ModuleFlags.COMPRESSED) {
throw new RangeError(`Can't add extensions to a compressed module`);
}
if (flags & ModuleFlags.COMBINED) {
throw new RangeError(`Can\'t add extensions to a combined module`);
}
const suffixSize = suffix.suffixSize;
if (suffixSize < MIN_MODULE_SUFFIX_SIZE || suffixSize > MAX_MODULE_SUFFIX_SIZE) {
throw new RangeError('Invalid suffix size');
}
let dataSize = prefix.moduleEndAddy - prefix.moduleStartAddy + 4 /* CRC-32 */;
const prefixOffs = prefix.prefixOffset || 0;
if (module.length < prefixOffs + MODULE_PREFIX_SIZE + suffixSize + 4 || module.length !== dataSize) {
throw new RangeError('Invalid size of the module data');
}

const moduleInfo = firmwareModuleInfoForPlatformAndFunction(prefix.platformID, prefix.moduleFunction, prefix.moduleIndex);
let extensionsInPrefix = false;
if ((prefix.moduleFlags & ModuleInfo.Flags.PREFIX_EXTENSIONS) || (moduleInfo && moduleInfo.growsLeft)) {
extensionsInPrefix = true;
}

let extensions = [];
if (extensionsInPrefix) {
extensions = prefix.extensions;
} else {
extensions = suffix.extensions;
}
if (!extensions) {
extensions = [];
}

extensions = extensions.filter((val) => {
for (let ext of exts) {
if (val.type === ext) {
return false;
}
}
return true;
});

let buffer = null;

if (extensionsInPrefix) {;
prefix.extensions = extensions;
} else {
suffix.extensions = extensions;
}

// Always add END extension: it is mandatory to be present in module prefix extensions
// and due to the fact that product data for some of the platforms may not use an extension and just be
// raw data, to indicate end we will also use END extension here.
if (extensions.length > 0 && extensions[extensions.length - 1].type !== ModuleInfo.ModuleInfoExtension.END &&
extensions[extensions.length - 1].type !== ModuleInfo.ModuleInfoExtension.PRODUCT_DATA) {
extensions.push({
type: ModuleInfo.ModuleInfoExtension.END
});
}

if (extensionsInPrefix && extensions.length > 0) {
if (prefixOffs > 0) {
throw new RangeError('Extensions in prefix are not supported for modules with non-zero prefix offset');
}
prefix.moduleFlags |= ModuleInfo.Flags.PREFIX_EXTENSIONS;
prefix.extensions = extensions;
const originalPrefixSize = prefix.prefixSize;
delete extensions[extensions.length - 1].data;
delete extensions[extensions.length - 1].length;
prefix.prefixSize = calculateModulePrefixSize(prefix);

let newSize = module.length + (prefix.prefixSize - originalPrefixSize);
let newStartAddr = prefix.moduleEndAddy - (newSize - 4);
let alignment = 0;
if (newStartAddr % DEFAULT_START_ALIGNMENT !== 0) {
alignment = (newStartAddr % DEFAULT_START_ALIGNMENT);
newSize += alignment;
}

extensions[extensions.length - 1].padding = alignment;

prefix.prefixSize += alignment;

console.log(prefix);

buffer = Buffer.alloc(newSize);
module.copy(buffer, prefix.prefixSize, originalPrefixSize /* source offset */);
prefix.moduleStartAddy = prefix.moduleEndAddy - (buffer.length - 4);

if (suffix.extensions) {
for (let ext of suffix.extensions) {
if (ext.type === ModuleInfo.ModuleInfoExtension.DYNAMIC_LOCATION) {
// This has to be updated for certain platforms if start address is moved
delete ext.data;
ext.moduleStartAddress = prefix.moduleStartAddy;
}
}
}
} else if (extensions.length > 0) {
// In suffix
suffix.extensions = extensions;
const originalSuffixSize = suffix.suffixSize;
suffix.suffixSize = calculateModuleSuffixSize(suffix);

buffer = Buffer.alloc(module.length + (suffix.suffixSize - originalSuffixSize));
module.copy(buffer, 0, 0, module.length - originalSuffixSize - 4 /* CRC-32 */);
prefix.moduleEndAddy = prefix.moduleStartAddy + buffer.length - 4;
}

if (moduleInfo && moduleInfo.maxSize) {
if (buffer.length > moduleInfo.maxSize) {
throw new PlatformLimitError({}, 'Resulting module exceeds platform size limits');
}
}

updateModulePrefix(buffer, prefix);
updateModuleSuffix(buffer, suffix);
updateModuleSha256(buffer);
updateModuleCrc32(buffer);

return buffer;
}

/**
* list extensions of a particular type.
*
* @param {Buffer} module Module to update
* @param {Array} exts List of extensions to add
* @returns {Promise<[]>}
*/
async function listModuleExtensions({ module, exts = [] } = {}) {
if (exts.length === 0) {
throw new RangeError('Empty extension list');
}

const parser = new HalModuleParser();
const { prefixInfo: prefix } = await parser.parsePrefix({ fileBuffer: module });
const { suffixInfo: suffix } = await parser.parseSuffix({ fileBuffer: module });
prefix.moduleStartAddy = sanitizeAddress(prefix.moduleStartAddy);
prefix.moduleEndAddy = sanitizeAddress(prefix.moduleEndAddy);
const flags = prefix.moduleFlags;
if (flags & ModuleFlags.COMPRESSED) {
throw new RangeError(`Can't add extensions to a compressed module`);
}
if (flags & ModuleFlags.COMBINED) {
throw new RangeError(`Can\'t add extensions to a combined module`);
}
const suffixSize = suffix.suffixSize;
if (suffixSize < MIN_MODULE_SUFFIX_SIZE || suffixSize > MAX_MODULE_SUFFIX_SIZE) {
throw new RangeError('Invalid suffix size');
}
let dataSize = prefix.moduleEndAddy - prefix.moduleStartAddy + 4 /* CRC-32 */;
const prefixOffs = prefix.prefixOffset || 0;
if (module.length < prefixOffs + MODULE_PREFIX_SIZE + suffixSize + 4 || module.length !== dataSize) {
throw new RangeError('Invalid size of the module data');
}

const moduleInfo = firmwareModuleInfoForPlatformAndFunction(prefix.platformID, prefix.moduleFunction, prefix.moduleIndex);
let extensionsInPrefix = false;
if ((prefix.moduleFlags & ModuleInfo.Flags.PREFIX_EXTENSIONS) || (moduleInfo && moduleInfo.growsLeft)) {
extensionsInPrefix = true;
}

let extensions = [];
if (extensionsInPrefix) {
extensions = prefix.extensions;
} else {
extensions = suffix.extensions;
}
if (!extensions) {
extensions = [];
}

extensions = extensions.filter((val) => {
for (let ext of exts) {
if (val.type === ext) {
return true;
}
}
return false;
});

return extensions;
}


/**
* Update module info to include a set of asset dependencies
*
Expand Down Expand Up @@ -1448,5 +1652,7 @@ module.exports = {
AssetLimitError,
PlatformLimitError,
createProtectedModule,
addModuleExtensions
addModuleExtensions,
removeModuleExtensions,
listModuleExtensions
};