Commit 8bd42e23 authored by Bjorn Andersson's avatar Bjorn Andersson

soc: qcom: mdt_loader: Allow hash segment to be split out

It's been observed that some firmware found in a Qualcomm SM8450 device
has the hash table in a separate .bNN file. Use the newly extracted
helper function to load this segment from the separate file, if it's
determined that the hashes are not part of the already loaded firmware.

In order to do this, the function needs access to the firmware basename
and to provide more useful error messages a struct device to associate
the errors with.
Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Reviewed-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20220128025513.97188-4-bjorn.andersson@linaro.org
parent 26c1f170
......@@ -928,7 +928,8 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
}
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
const char *fw_name)
{
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
dma_addr_t phys;
......@@ -939,7 +940,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
void *ptr;
int ret;
metadata = qcom_mdt_read_metadata(fw, &size);
metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev);
if (IS_ERR(metadata))
return PTR_ERR(metadata);
......@@ -1289,7 +1290,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
/* Initialize the RMB validator */
writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
ret = q6v5_mpss_init_image(qproc, fw);
ret = q6v5_mpss_init_image(qproc, fw, qproc->hexagon_mdt_image);
if (ret)
goto release_firmware;
......
......@@ -121,13 +121,15 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
*
* Return: pointer to data, or ERR_PTR()
*/
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
const char *fw_name, struct device *dev)
{
const struct elf32_phdr *phdrs;
const struct elf32_hdr *ehdr;
size_t hash_offset;
size_t hash_size;
size_t ehdr_size;
ssize_t ret;
void *data;
ehdr = (struct elf32_hdr *)fw->data;
......@@ -149,14 +151,25 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
if (!data)
return ERR_PTR(-ENOMEM);
/* Is the header and hash already packed */
if (ehdr_size + hash_size == fw->size)
/* Copy ELF header */
memcpy(data, fw->data, ehdr_size);
if (ehdr_size + hash_size == fw->size) {
/* Firmware is split and hash is packed following the ELF header */
hash_offset = phdrs[0].p_filesz;
else
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
} else if (phdrs[1].p_offset + hash_size <= fw->size) {
/* Hash is in its own segment, but within the loaded file */
hash_offset = phdrs[1].p_offset;
memcpy(data, fw->data, ehdr_size);
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
} else {
/* Hash is in its own segment, beyond the loaded file */
ret = mdt_load_split_segment(data + ehdr_size, phdrs, 1, fw_name, dev);
if (ret) {
kfree(data);
return ERR_PTR(ret);
}
}
*data_len = ehdr_size + hash_size;
......@@ -190,7 +203,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
phdrs = (struct elf32_phdr *)(ehdr + 1);
if (pas_init) {
metadata = qcom_mdt_read_metadata(fw, &metadata_len);
metadata = qcom_mdt_read_metadata(fw, &metadata_len, fw_name, dev);
if (IS_ERR(metadata)) {
ret = PTR_ERR(metadata);
dev_err(dev, "error %d reading firmware %s metadata\n",
......
......@@ -23,7 +23,8 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base);
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len);
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
const char *fw_name, struct device *dev);
#else /* !IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */
......@@ -51,7 +52,8 @@ static inline int qcom_mdt_load_no_init(struct device *dev,
}
static inline void *qcom_mdt_read_metadata(const struct firmware *fw,
size_t *data_len)
size_t *data_len, const char *fw_name,
struct device *dev)
{
return ERR_PTR(-ENODEV);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment