A simple Intel HEX format parser/loader.

Signed-off-by: Jan Harkes <[EMAIL PROTECTED]>


 include/linux/ihex_parser.h |   23 +++++
 lib/Kconfig                 |    8 +
 lib/Makefile                |    2 
 lib/ihex_parser.c           |  181 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 214 insertions(+)

Index: linux/lib/Makefile
===================================================================
--- linux.orig/lib/Makefile     2005-04-05 15:21:30.000000000 -0400
+++ linux/lib/Makefile  2005-04-05 15:21:45.000000000 -0400
@@ -34,6 +34,8 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_infla
 obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
 obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
 
+obj-$(CONFIG_IHEX_PARSER) += ihex_parser.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
Index: linux/lib/ihex_parser.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux/lib/ihex_parser.c     2005-04-05 15:29:55.000000000 -0400
@@ -0,0 +1,181 @@
+/*
+ * Parser/loader for IHEX formatted data.
+ *
+ * Copyright (C) 2005 Jan Harkes <[EMAIL PROTECTED]>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License version
+ *     2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ihex_parser.h>
+
+MODULE_AUTHOR("Jan Harkes <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("IHEX formatted data parser");
+MODULE_LICENSE("GPL");
+
+#ifndef QUIET
+#define dbg(msg, ...) printk(KERN_WARNING "%s: line %d: " msg, __FUNCTION__, 
line, ## __VA_ARGS__)
+#else
+#define dbg(msg, ...) do {} while(0)
+#endif
+
+/**
+ * nibble/hex are little helpers to parse hexadecimal numbers to a byte value
+ **/
+static __u8 nibble(const __u8 n)
+{
+       if      (n >= '0' && n <= '9') return n - '0';
+       else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
+       else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
+       return 0;
+}
+static __u8 hex(const __u8 *data, __u8 *crc)
+{
+       __u8 val = (nibble(data[0]) << 4) | nibble(data[1]);
+       *crc += val;
+       return val;
+}
+
+/**
+ * load_ihex:
+ *
+ * Description:
+ *     @data  is expected to point at a block of Intel HEX formatted data.
+ *     @size  is the size of the data block.
+ *
+ *     @load will be called for each record that is found in the IHEX data.
+ *
+ *     @context will be passed on to @load.
+ *
+ **/
+int load_ihex(const u8 *data, const size_t size, void *context,
+             int (*load)(struct ihex_record *record, void *context))
+{
+       struct ihex_record *record;
+       __u32 offset = 0;
+       __u8 type, crc = 0;
+       int i, j, err = 0;
+       int line = 1;
+
+       record = kmalloc(sizeof(*record), GFP_KERNEL);
+       if (!record) {
+               dbg("Allocation failed\n");
+               return -ENOMEM;
+       }
+
+       i = 0;
+next_record:
+       /* search for the start of record character */
+       while (i < size) {
+               if (data[i] == '\n') line++;
+               if (data[i++] == ':') break;
+       }
+
+       /* Minimum record length would be about 10 characters */
+       if (i + 10 > size) {
+               dbg("Can't find valid record\n");
+               err = -EINVAL;
+               goto done;
+       }
+
+       record->len = hex(data + i, &crc);
+       i += 2;
+
+       /* now check if we have enough data to read everything */
+       if (i + 8 + (record->len * 2) > size) {
+               dbg("Not enough data to read complete record\n");
+               err = -EINVAL;
+               goto done;
+       }
+
+       record->address  = hex(data + i, &crc) << 8; i += 2;
+       record->address |= hex(data + i, &crc); i += 2;
+       record->address += offset;
+       type = hex(data + i, &crc); i += 2;
+
+       for (j = 0; j < record->len; j++, i += 2)
+               record->data[j] = hex(data + i, &crc);
+
+       /* check CRC */
+       (void)hex(data + i, &crc); i += 2;
+       if (crc != 0) {
+               dbg("CRC failure\n");
+               err = -EINVAL;
+               goto done;
+       }
+
+       /* Done reading the record */
+       switch (type) {
+       case 0:
+               /* old style EOF record? */
+               if (!record->len)
+                       break;
+
+               err = load(record, context);
+               if (err < 0) {
+                       dbg("Firmware load failed (err %d)\n", err);
+                       break;
+               } else
+                   err = 0;
+               goto next_record;
+
+       case 1: /* End-Of-File Record */
+               if (record->address || record->len) {
+                       dbg("Bad EOF record (type 01) format\n");
+                       err = -EINVAL;
+               }
+               break;
+
+       case 2: /* Extended Segment Address Record (HEX86) */
+       case 4: /* Extended Linear Address Record (HEX386) */
+               if (record->address || record->len != 2) {
+                       dbg("Bad HEX86/HEX386 record (type %02X)\n", type);
+                       err = -EINVAL;
+                       break;
+               }
+
+               /* We shouldn't really be using the offset for HEX86 because
+                * the wraparound case is specified quite differently. */
+               offset = record->data[0] << 8 | record->data[1];
+               offset <<= (type == 2 ? 4 : 16);
+               goto next_record;
+
+       case 3: /* Start Segment Address Record */
+       case 5: /* Start Linear Address Record */
+               if (record->address || record->len != 4) {
+                       dbg("Bad Start Address record (type %02X)\n", type);
+                       err = -EINVAL;
+                       break;
+               }
+
+               /* These records contain the CS/IP or EIP where execution
+                * starts. Don't really know what to do with them. */
+               goto next_record;
+
+       default:
+               dbg("Unknown record (type %02X)\n", type);
+               err = -EINVAL;
+               break; /* unknown record type */
+       }
+done:
+       kfree(record);
+       return err;
+}
+
+static int __init no_init(void)
+{
+       return 0;
+}
+
+static void __exit no_exit(void)
+{
+}
+
+module_init(no_init);
+module_exit(no_exit);
+
+EXPORT_SYMBOL(load_ihex);
+
Index: linux/include/linux/ihex_parser.h
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux/include/linux/ihex_parser.h   2005-04-05 15:21:45.000000000 -0400
@@ -0,0 +1,23 @@
+/*
+ * Definitions for parser/loader for IHEX formatted data.
+ *
+ * Copyright (C) 2005 Jan Harkes <[EMAIL PROTECTED]>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License version
+ *     2 as published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_IHEX_PARSER_H
+#define _LINUX_IHEX_PARSER_H
+
+struct ihex_record {
+       __u32 address;
+       __u8  len;
+       __u8  data[255];
+};
+
+int load_ihex(const u8 *data, const size_t size, void *context,
+             int (*load)(struct ihex_record *record, void *context));
+
+#endif
Index: linux/lib/Kconfig
===================================================================
--- linux.orig/lib/Kconfig      2005-04-05 15:08:37.000000000 -0400
+++ linux/lib/Kconfig   2005-04-05 15:21:45.000000000 -0400
@@ -57,5 +57,13 @@ config REED_SOLOMON_ENC16
 config REED_SOLOMON_DEC16
        boolean
 
+config IHEX_PARSER
+       tristate "Intel HEX formatted data parser"
+       help
+         This option is provided for the case where no in-kernel-tree
+         modules require IHEX parsing, but a module built outside the
+         kernel tree does. Such modules that need to parse Intel HEX
+         formatted data require M here.
+
 endmenu
 

--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to