Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * Compact binary representation of ihex records. Some devices need their
0004  * firmware loaded in strange orders rather than a single big blob, but
0005  * actually parsing ihex-as-text within the kernel seems silly. Thus,...
0006  */
0007 
0008 #ifndef __LINUX_IHEX_H__
0009 #define __LINUX_IHEX_H__
0010 
0011 #include <linux/types.h>
0012 #include <linux/firmware.h>
0013 #include <linux/device.h>
0014 
0015 /* Intel HEX files actually limit the length to 256 bytes, but we have
0016    drivers which would benefit from using separate records which are
0017    longer than that, so we extend to 16 bits of length */
0018 struct ihex_binrec {
0019     __be32 addr;
0020     __be16 len;
0021     uint8_t data[];
0022 } __attribute__((packed));
0023 
0024 static inline uint16_t ihex_binrec_size(const struct ihex_binrec *p)
0025 {
0026     return be16_to_cpu(p->len) + sizeof(*p);
0027 }
0028 
0029 /* Find the next record, taking into account the 4-byte alignment */
0030 static inline const struct ihex_binrec *
0031 __ihex_next_binrec(const struct ihex_binrec *rec)
0032 {
0033     const void *p = rec;
0034 
0035     return p + ALIGN(ihex_binrec_size(rec), 4);
0036 }
0037 
0038 static inline const struct ihex_binrec *
0039 ihex_next_binrec(const struct ihex_binrec *rec)
0040 {
0041     rec = __ihex_next_binrec(rec);
0042 
0043     return be16_to_cpu(rec->len) ? rec : NULL;
0044 }
0045 
0046 /* Check that ihex_next_binrec() won't take us off the end of the image... */
0047 static inline int ihex_validate_fw(const struct firmware *fw)
0048 {
0049     const struct ihex_binrec *end, *rec;
0050 
0051     rec = (const void *)fw->data;
0052     end = (const void *)&fw->data[fw->size - sizeof(*end)];
0053 
0054     for (; rec <= end; rec = __ihex_next_binrec(rec)) {
0055         /* Zero length marks end of records */
0056         if (rec == end && !be16_to_cpu(rec->len))
0057             return 0;
0058     }
0059     return -EINVAL;
0060 }
0061 
0062 /* Request firmware and validate it so that we can trust we won't
0063  * run off the end while reading records... */
0064 static inline int request_ihex_firmware(const struct firmware **fw,
0065                     const char *fw_name,
0066                     struct device *dev)
0067 {
0068     const struct firmware *lfw;
0069     int ret;
0070 
0071     ret = request_firmware(&lfw, fw_name, dev);
0072     if (ret)
0073         return ret;
0074     ret = ihex_validate_fw(lfw);
0075     if (ret) {
0076         dev_err(dev, "Firmware \"%s\" not valid IHEX records\n",
0077             fw_name);
0078         release_firmware(lfw);
0079         return ret;
0080     }
0081     *fw = lfw;
0082     return 0;
0083 }
0084 #endif /* __LINUX_IHEX_H__ */