mdt_loader.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Qualcomm Peripheral Image Loader
  4. *
  5. * Copyright (C) 2016 Linaro Ltd
  6. * Copyright (C) 2015 Sony Mobile Communications Inc
  7. * Copyright (c) 2012-2013, 2021 The Linux Foundation. All rights reserved.
  8. */
  9. #include <linux/device.h>
  10. #include <linux/elf.h>
  11. #include <linux/firmware.h>
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/qcom_scm.h>
  15. #include <linux/sizes.h>
  16. #include <linux/slab.h>
  17. #include <linux/dma-mapping.h>
  18. #include <linux/soc/qcom/mdt_loader.h>
  19. static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
  20. {
  21. if (phdr->p_type != PT_LOAD)
  22. return false;
  23. if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
  24. return false;
  25. if (!phdr->p_memsz)
  26. return false;
  27. return true;
  28. }
  29. static bool qcom_mdt_bins_are_split(const struct firmware *fw)
  30. {
  31. const struct elf32_phdr *phdrs;
  32. const struct elf32_hdr *ehdr;
  33. uint64_t seg_start, seg_end;
  34. int i;
  35. ehdr = (struct elf32_hdr *)fw->data;
  36. phdrs = (struct elf32_phdr *)(ehdr + 1);
  37. for (i = 0; i < ehdr->e_phnum; i++) {
  38. seg_start = phdrs[i].p_offset;
  39. seg_end = phdrs[i].p_offset + phdrs[i].p_filesz;
  40. if (seg_start > fw->size || seg_end > fw->size)
  41. return true;
  42. }
  43. return false;
  44. }
  45. /**
  46. * qcom_mdt_get_size() - acquire size of the memory region needed to load mdt
  47. * @fw: firmware object for the mdt file
  48. *
  49. * Returns size of the loaded firmware blob, or -EINVAL on failure.
  50. */
  51. ssize_t qcom_mdt_get_size(const struct firmware *fw)
  52. {
  53. const struct elf32_phdr *phdrs;
  54. const struct elf32_phdr *phdr;
  55. const struct elf32_hdr *ehdr;
  56. phys_addr_t min_addr = PHYS_ADDR_MAX;
  57. phys_addr_t max_addr = 0;
  58. int i;
  59. ehdr = (struct elf32_hdr *)fw->data;
  60. phdrs = (struct elf32_phdr *)(ehdr + 1);
  61. for (i = 0; i < ehdr->e_phnum; i++) {
  62. phdr = &phdrs[i];
  63. if (!mdt_phdr_valid(phdr))
  64. continue;
  65. if (phdr->p_paddr < min_addr)
  66. min_addr = phdr->p_paddr;
  67. if (phdr->p_paddr + phdr->p_memsz > max_addr)
  68. max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
  69. }
  70. return min_addr < max_addr ? max_addr - min_addr : -EINVAL;
  71. }
  72. EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
  73. /**
  74. * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
  75. * @dev: device handle to associate resources with
  76. * @fw: firmware of mdt header or mbn
  77. * @firmware: name of the firmware, for construction of segment file names
  78. * @data_len: length of the read metadata blob
  79. * @metadata_phys: phys address for the assigned metadata buffer
  80. *
  81. * The mechanism that performs the authentication of the loading firmware
  82. * expects an ELF header directly followed by the segment of hashes, with no
  83. * padding inbetween. This function allocates a chunk of memory for this pair
  84. * and copy the two pieces into the buffer.
  85. *
  86. * In the case of split firmware the hash is found directly following the ELF
  87. * header, rather than at p_offset described by the second program header.
  88. *
  89. * The caller is responsible to free (kfree()) the returned pointer.
  90. *
  91. * Return: pointer to data, or ERR_PTR()
  92. */
  93. void *qcom_mdt_read_metadata(struct device *dev, const struct firmware *fw, const char *firmware,
  94. size_t *data_len, bool dma_phys_below_32b, dma_addr_t *metadata_phys)
  95. {
  96. const struct elf32_phdr *phdrs;
  97. const struct elf32_hdr *ehdr;
  98. const struct firmware *seg_fw;
  99. struct device *scm_dev = NULL;
  100. size_t hash_index;
  101. size_t hash_size;
  102. size_t ehdr_size;
  103. char *fw_name;
  104. void *data;
  105. int ret;
  106. if (fw->size < sizeof(struct elf32_hdr)) {
  107. dev_err(dev, "Image is too small\n");
  108. return ERR_PTR(-EINVAL);
  109. }
  110. ehdr = (struct elf32_hdr *)fw->data;
  111. phdrs = (struct elf32_phdr *)(ehdr + 1);
  112. if (ehdr->e_phnum < 2 || ehdr->e_phoff > fw->size ||
  113. (sizeof(phdrs) * ehdr->e_phnum > fw->size - ehdr->e_phoff))
  114. return ERR_PTR(-EINVAL);
  115. if (phdrs[0].p_type == PT_LOAD)
  116. return ERR_PTR(-EINVAL);
  117. for (hash_index = 1; hash_index < ehdr->e_phnum; hash_index++) {
  118. if (phdrs[hash_index].p_type != PT_LOAD &&
  119. (phdrs[hash_index].p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
  120. break;
  121. }
  122. if (hash_index >= ehdr->e_phnum)
  123. return ERR_PTR(-EINVAL);
  124. ehdr_size = phdrs[0].p_filesz;
  125. hash_size = phdrs[hash_index].p_filesz;
  126. /* Overflow check */
  127. if (ehdr_size > SIZE_MAX - hash_size)
  128. return ERR_PTR(-ENOMEM);
  129. /*
  130. * During the scm call memory protection will be enabled for the metadata
  131. * blob, so make sure it's physically contiguous, 4K aligned and
  132. * non-cachable to avoid XPU violations.
  133. */
  134. if (metadata_phys) {
  135. if (!dma_phys_below_32b) {
  136. scm_dev = qcom_get_scm_device();
  137. if (!scm_dev)
  138. return ERR_PTR(-EPROBE_DEFER);
  139. data = dma_alloc_coherent(scm_dev, ehdr_size + hash_size,
  140. metadata_phys, GFP_KERNEL);
  141. } else {
  142. data = dma_alloc_coherent(dev, ehdr_size + hash_size,
  143. metadata_phys, GFP_KERNEL);
  144. }
  145. } else {
  146. data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
  147. }
  148. if (!data)
  149. return ERR_PTR(-ENOMEM);
  150. /* copy elf header */
  151. memcpy(data, fw->data, ehdr_size);
  152. if (qcom_mdt_bins_are_split(fw)) {
  153. fw_name = kstrdup(firmware, GFP_KERNEL);
  154. if (!fw_name) {
  155. ret = -ENOMEM;
  156. goto free_metadata;
  157. }
  158. snprintf(fw_name + strlen(fw_name) - 3, 4, "b%02d", hash_index);
  159. ret = request_firmware_into_buf(&seg_fw, fw_name, dev, data + ehdr_size, hash_size);
  160. kfree(fw_name);
  161. if (ret)
  162. goto free_metadata;
  163. release_firmware(seg_fw);
  164. } else {
  165. memcpy(data + ehdr_size, fw->data + phdrs[hash_index].p_offset, hash_size);
  166. }
  167. *data_len = ehdr_size + hash_size;
  168. return data;
  169. free_metadata:
  170. if (metadata_phys) {
  171. if (!dma_phys_below_32b)
  172. dma_free_coherent(scm_dev, ehdr_size + hash_size, data, *metadata_phys);
  173. else
  174. dma_free_coherent(dev, ehdr_size + hash_size, data, *metadata_phys);
  175. } else
  176. kfree(data);
  177. return ERR_PTR(ret);
  178. }
  179. EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
  180. static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *firmware,
  181. int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size,
  182. phys_addr_t *reloc_base, bool pas_init, bool dma_phys_below_32b,
  183. struct qcom_mdt_metadata *mdata)
  184. {
  185. const struct elf32_phdr *phdrs;
  186. const struct elf32_phdr *phdr;
  187. const struct elf32_hdr *ehdr;
  188. const struct firmware *seg_fw;
  189. phys_addr_t mem_reloc;
  190. phys_addr_t min_addr = PHYS_ADDR_MAX;
  191. phys_addr_t max_addr = 0;
  192. dma_addr_t metadata_phys = 0;
  193. struct device *scm_dev = NULL;
  194. size_t metadata_len = 0;
  195. size_t fw_name_len;
  196. ssize_t offset;
  197. void *metadata = NULL;
  198. char *fw_name;
  199. bool relocate = false;
  200. bool is_split;
  201. void *ptr;
  202. int ret = 0;
  203. int i;
  204. if (!fw || !mem_region || !mem_phys || !mem_size)
  205. return -EINVAL;
  206. is_split = qcom_mdt_bins_are_split(fw);
  207. ehdr = (struct elf32_hdr *)fw->data;
  208. phdrs = (struct elf32_phdr *)(ehdr + 1);
  209. fw_name_len = strlen(firmware);
  210. if (fw_name_len <= 4)
  211. return -EINVAL;
  212. fw_name = kstrdup(firmware, GFP_KERNEL);
  213. if (!fw_name)
  214. return -ENOMEM;
  215. if (pas_init) {
  216. metadata = qcom_mdt_read_metadata(dev, fw, firmware, &metadata_len,
  217. dma_phys_below_32b, &metadata_phys);
  218. if (IS_ERR(metadata)) {
  219. ret = PTR_ERR(metadata);
  220. dev_err(dev, "error %d reading firmware %s metadata\n",
  221. ret, fw_name);
  222. goto out;
  223. }
  224. if (mdata) {
  225. mdata->buf = metadata;
  226. mdata->buf_phys = metadata_phys;
  227. mdata->size = metadata_len;
  228. }
  229. ret = qcom_scm_pas_init_image(pas_id, metadata_phys);
  230. if (ret) {
  231. dev_err(dev, "invalid firmware metadata\n");
  232. goto deinit;
  233. }
  234. }
  235. for (i = 0; i < ehdr->e_phnum; i++) {
  236. phdr = &phdrs[i];
  237. if (!mdt_phdr_valid(phdr))
  238. continue;
  239. if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
  240. relocate = true;
  241. if (phdr->p_paddr < min_addr)
  242. min_addr = phdr->p_paddr;
  243. if (phdr->p_paddr + phdr->p_memsz > max_addr)
  244. max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
  245. }
  246. if (relocate) {
  247. if (pas_init) {
  248. ret = qcom_scm_pas_mem_setup(pas_id, mem_phys,
  249. max_addr - min_addr);
  250. if (ret) {
  251. dev_err(dev, "unable to setup relocation\n");
  252. goto deinit;
  253. }
  254. }
  255. /*
  256. * The image is relocatable, so offset each segment based on
  257. * the lowest segment address.
  258. */
  259. mem_reloc = min_addr;
  260. } else {
  261. /*
  262. * Image is not relocatable, so offset each segment based on
  263. * the allocated physical chunk of memory.
  264. */
  265. mem_reloc = mem_phys;
  266. }
  267. for (i = 0; i < ehdr->e_phnum; i++) {
  268. phdr = &phdrs[i];
  269. if (!mdt_phdr_valid(phdr))
  270. continue;
  271. offset = phdr->p_paddr - mem_reloc;
  272. if (offset < 0 || offset + phdr->p_memsz > mem_size) {
  273. dev_err(dev, "segment outside memory range\n");
  274. ret = -EINVAL;
  275. break;
  276. }
  277. if (phdr->p_filesz > phdr->p_memsz) {
  278. dev_err(dev,
  279. "refusing to load segment %d with p_filesz > p_memsz\n",
  280. i);
  281. ret = -EINVAL;
  282. break;
  283. }
  284. ptr = mem_region + offset;
  285. if (phdr->p_filesz) {
  286. if (!is_split) {
  287. /* Firmware is large enough to be non-split */
  288. memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
  289. } else {
  290. /* Firmware not large enough, load split-out segments */
  291. snprintf(fw_name + fw_name_len - 3, 4, "b%02d", i);
  292. ret = request_firmware_into_buf(&seg_fw, fw_name, dev,
  293. ptr, phdr->p_filesz);
  294. if (ret) {
  295. dev_err(dev, "failed to load %s\n", fw_name);
  296. break;
  297. }
  298. if (seg_fw->size != phdr->p_filesz) {
  299. dev_err(dev,
  300. "failed to load segment %d from truncated file %s\n",
  301. i, fw_name);
  302. release_firmware(seg_fw);
  303. ret = -EINVAL;
  304. break;
  305. }
  306. release_firmware(seg_fw);
  307. }
  308. }
  309. if (phdr->p_memsz > phdr->p_filesz)
  310. memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
  311. }
  312. if (reloc_base)
  313. *reloc_base = mem_reloc;
  314. deinit:
  315. if (ret)
  316. qcom_scm_pas_shutdown(pas_id);
  317. if (!mdata && pas_init) {
  318. if (dma_phys_below_32b) {
  319. dma_free_coherent(dev, metadata_len, metadata, metadata_phys);
  320. } else {
  321. scm_dev = qcom_get_scm_device();
  322. if (!scm_dev)
  323. goto out;
  324. dma_free_coherent(scm_dev, metadata_len, metadata, metadata_phys);
  325. }
  326. }
  327. out:
  328. kfree(fw_name);
  329. return ret;
  330. }
  331. /**
  332. * qcom_mdt_load() - load the firmware which header is loaded as fw
  333. * @dev: device handle to associate resources with
  334. * @fw: firmware object for the mdt file
  335. * @firmware: name of the firmware, for construction of segment file names
  336. * @pas_id: PAS identifier
  337. * @mem_region: allocated memory region to load firmware into
  338. * @mem_phys: physical address of allocated memory region
  339. * @mem_size: size of the allocated memory region
  340. * @reloc_base: adjusted physical address after relocation
  341. *
  342. * Returns 0 on success, negative errno otherwise.
  343. */
  344. int qcom_mdt_load(struct device *dev, const struct firmware *fw,
  345. const char *firmware, int pas_id, void *mem_region,
  346. phys_addr_t mem_phys, size_t mem_size,
  347. phys_addr_t *reloc_base)
  348. {
  349. return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
  350. mem_size, reloc_base, true, false, NULL);
  351. }
  352. EXPORT_SYMBOL_GPL(qcom_mdt_load);
  353. /**
  354. * qcom_mdt_load_no_init() - load the firmware which header is loaded as fw
  355. * @dev: device handle to associate resources with
  356. * @fw: firmware object for the mdt file
  357. * @firmware: name of the firmware, for construction of segment file names
  358. * @pas_id: PAS identifier
  359. * @mem_region: allocated memory region to load firmware into
  360. * @mem_phys: physical address of allocated memory region
  361. * @mem_size: size of the allocated memory region
  362. * @reloc_base: adjusted physical address after relocation
  363. *
  364. * Returns 0 on success, negative errno otherwise.
  365. */
  366. int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
  367. const char *firmware, int pas_id,
  368. void *mem_region, phys_addr_t mem_phys,
  369. size_t mem_size, phys_addr_t *reloc_base)
  370. {
  371. return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
  372. mem_size, reloc_base, false, false, NULL);
  373. }
  374. EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init);
  375. /**
  376. * qcom_mdt_load_no_free() - load the firmware which header is loaded as fw
  377. * @dev: device handle to associate resources with
  378. * @fw: firmware object for the mdt file
  379. * @firmware: name of the firmware, for construction of segment file names
  380. * @pas_id: PAS identifier
  381. * @mem_region: allocated memory region to load firmware into
  382. * @mem_phys: physical address of allocated memory region
  383. * @mem_size: size of the allocated memory region
  384. * @reloc_base: adjusted physical address after relocation
  385. *
  386. * This function is essentially the same as qcom_mdt_load. The only difference
  387. * between the two is that the metadata is not freed at the end of this call.
  388. * The client must call qcom_mdt_free_metadata for cleanup.
  389. *
  390. * Returns 0 on success, negative errno otherwise.
  391. */
  392. int qcom_mdt_load_no_free(struct device *dev, const struct firmware *fw, const char *firmware,
  393. int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size,
  394. phys_addr_t *reloc_base, bool dma_phys_below_32b,
  395. struct qcom_mdt_metadata *metadata)
  396. {
  397. return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
  398. mem_size, reloc_base, true, dma_phys_below_32b, metadata);
  399. }
  400. EXPORT_SYMBOL(qcom_mdt_load_no_free);
  401. /**
  402. * qcom_mdt_free_metadata() - free the firmware metadata
  403. * @dev: device handle to associate resources with
  404. * @pas_id: PAS identifier
  405. * @mdata: reference to metadata region to be freed
  406. * @err: whether this call was made after an error occurred
  407. *
  408. * Free the metadata that was allocated by mdt loader.
  409. *
  410. */
  411. void qcom_mdt_free_metadata(struct device *dev, int pas_id, struct qcom_mdt_metadata *mdata,
  412. bool dma_phys_below_32b, int err)
  413. {
  414. struct device *scm_dev;
  415. if (err && qcom_scm_pas_shutdown_retry(pas_id))
  416. panic("Panicking, failed to shutdown peripheral %d\n", pas_id);
  417. if (mdata) {
  418. if (!dma_phys_below_32b) {
  419. scm_dev = qcom_get_scm_device();
  420. if (!scm_dev) {
  421. pr_err("%s: scm_dev has not been created!\n", __func__);
  422. return;
  423. }
  424. dma_free_coherent(scm_dev, mdata->size, mdata->buf, mdata->buf_phys);
  425. } else {
  426. dma_free_coherent(dev, mdata->size, mdata->buf, mdata->buf_phys);
  427. }
  428. }
  429. }
  430. EXPORT_SYMBOL(qcom_mdt_free_metadata);
  431. MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format");
  432. MODULE_LICENSE("GPL v2");