summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2022-01-28 05:55:03 +0300
committerBjorn Andersson <bjorn.andersson@linaro.org>2022-02-04 00:32:30 +0300
commit8bd42e2341a7857010001f08ee1729ced3b0e394 (patch)
treec36cc5648563696f284218ae55cde7a3ae8c23e2 /drivers/soc
parent26c1f17013a8292fa2bd59917bace883e1fe6afa (diff)
downloadlinux-8bd42e2341a7857010001f08ee1729ced3b0e394.tar.xz
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: Bjorn Andersson <bjorn.andersson@linaro.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Link: https://lore.kernel.org/r/20220128025513.97188-4-bjorn.andersson@linaro.org
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/qcom/mdt_loader.c29
1 files changed, 21 insertions, 8 deletions
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index c9e5bdfac371..4372d8e38b29 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -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",