This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH RFC] bfd/armimxboot.c: new backend for arm imx bootable files
- From: Philippe De Muyter <phdm at macqel dot be>
- To: binutils at sourceware dot org
- Cc: Philippe De Muyter <phdm at macqel dot be>
- Date: Thu, 17 Jul 2014 16:24:09 +0200
- Subject: [PATCH RFC] bfd/armimxboot.c: new backend for arm imx bootable files
- Authentication-results: sourceware.org; auth=none
Add a backend for objdump for the bootable files for the Freescale
i.MX6 processors. Such files are produced by compiling U-Boot
or by using the iMX6 SDK from Freescale, and are understood by
the boot rom of the i.MX6 processors.
* bfd/armimxboot.c: new file.
* bfd/Makefile.am(BFD32_BACKENDS,BFD32_BACKENDS_CFILES): add hooks
* bfd/Makefile.in: regenerate
* bfd/bfd.c(tdata): add arm_imx_boot_data
* bfd/targets.c(_bfd_target_vector): add &arm_imx_boot_vec
* bfd/bfd-in2.h: regenerate
---
This has been tested on a i586 host only and lacks endianness conversion
when reading headers, because I don't know the bfd way to handle that.
bfd/Makefile.am | 2 +
bfd/Makefile.in | 3 +
bfd/armimxboot.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
bfd/bfd-in2.h | 1 +
bfd/bfd.c | 1 +
bfd/targets.c | 2 +
6 files changed, 265 insertions(+)
create mode 100644 bfd/armimxboot.c
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 6f64f06..f4a794c 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -263,6 +263,7 @@ BFD32_BACKENDS = \
aout-tic30.lo \
aout0.lo \
aout32.lo \
+ armimxboot.lo \
armnetbsd.lo \
bout.lo \
cf-i386lynx.lo \
@@ -450,6 +451,7 @@ BFD32_BACKENDS_CFILES = \
aout-tic30.c \
aout0.c \
aout32.c \
+ armimxboot.c \
armnetbsd.c \
bout.c \
cf-i386lynx.c \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 2c385d5..81c2fdb 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -565,6 +565,7 @@ BFD32_BACKENDS = \
aout-tic30.lo \
aout0.lo \
aout32.lo \
+ armimxboot.lo \
armnetbsd.lo \
bout.lo \
cf-i386lynx.lo \
@@ -752,6 +753,7 @@ BFD32_BACKENDS_CFILES = \
aout-tic30.c \
aout0.c \
aout32.c \
+ armimxboot.c \
armnetbsd.c \
bout.c \
cf-i386lynx.c \
@@ -1254,6 +1256,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive64.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archures.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armimxboot.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armnetbsd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfdio.Plo@am__quote@
diff --git a/bfd/armimxboot.c b/bfd/armimxboot.c
new file mode 100644
index 0000000..fd1e5cb
--- /dev/null
+++ b/bfd/armimxboot.c
@@ -0,0 +1,256 @@
+/* BFD back end for i.MX 6 bootable files
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Written by Philippe De Muyter of Macq S.A.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "libaout.h" /* BFD a.out internal data structures */
+
+struct boot_data {
+ long dest;
+ long image_len;
+ long plugin;
+};
+
+struct ivt_header {
+#define IVT_MAGIC0 0x402000d1
+#define IVT_MAGIC1 0x412000d1
+ long header;
+ long start_addr;
+ long reserv1;
+ long dcd_ptr;
+ long boot_data_ptr; /* struct boot_data * */
+ long self_ptr; /* struct ivt_header *, this - boot_data.start = offset linked at */
+ long app_code_csf;
+ long reserv2;
+};
+
+struct arm_imx_boot_data_struct
+{
+ asection *text_section;
+ asection *dcd_section;
+ struct ivt_header ivt;
+};
+
+#define imx_textsec(bfd) ((bfd)->tdata.arm_imx_boot_data->text_section)
+#define imx_dcdsec(bfd) ((bfd)->tdata.arm_imx_boot_data->dcd_section)
+
+/* Handle arm i.MX 6 files bootable by the internal Boot ROM. */
+
+static int read_ivt(bfd *abfd, struct ivt_header *ivt)
+{
+ int val;
+
+ val = bfd_bread ((void *) ivt, (bfd_size_type) sizeof *ivt, abfd);
+ if (val != sizeof *ivt)
+ {
+ /* Too small to be a imx file */
+ return 0;
+ }
+
+ /* Sanity checks */
+ if ((ivt->header != IVT_MAGIC0 && ivt->header != IVT_MAGIC1)
+ || ivt->reserv1 != 0 || ivt->reserv2 != 0)
+ {
+ return 0;
+ }
+ return 1;
+}
+
+static const bfd_target *
+imx_file_p (bfd *abfd)
+{
+ struct ivt_header ivt;
+ struct boot_data bd;
+ struct arm_imx_boot_data_struct *rawptr;
+ long dcd_header;
+ long dcd_length;
+ bfd_size_type amt;
+ flagword flags;
+ long offset = 0;
+ struct stat statbuf;
+
+ if (bfd_stat (abfd, &statbuf) < 0)
+ return 0;
+
+ if (!read_ivt(abfd, &ivt))
+ {
+ char buf[0x400];
+
+ offset = sizeof buf;
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0
+ || bfd_bread (buf, (bfd_size_type) sizeof buf, abfd) != sizeof buf
+ || buf[0] != 0
+ || memcmp(buf, buf + 1, sizeof buf - 1) != 0
+ || !read_ivt(abfd, &ivt))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+ }
+
+ if (bfd_seek (abfd, offset + ivt.boot_data_ptr - ivt.self_ptr, SEEK_SET) != 0
+ || bfd_bread ((void *) &bd, (bfd_size_type) sizeof bd, abfd) != sizeof bd)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+
+ if (ivt.dcd_ptr)
+ {
+ if (bfd_seek (abfd, offset + ivt.dcd_ptr - ivt.self_ptr, SEEK_SET) != 0
+ || bfd_bread ((void *) &dcd_header, (bfd_size_type) sizeof dcd_header, abfd) != sizeof dcd_header)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+ dcd_length = (dcd_header & 0xff00) | ((dcd_header >> 16) & 0xff);
+ }
+ else
+ dcd_length = 0;
+
+ /* OK, we believe you. You're a imx file (sure, sure). */
+
+ amt = sizeof (struct arm_imx_boot_data_struct);
+ rawptr = (struct arm_imx_boot_data_struct *) bfd_zmalloc (amt);
+ if (rawptr == NULL)
+ return 0;
+
+ abfd->tdata.arm_imx_boot_data = rawptr;
+
+ rawptr->ivt = ivt; /*Copy the ivt into the tdata part of the bfd */
+
+ /* Create the sections. */
+
+ flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS + SEC_CODE + SEC_READONLY;
+ imx_textsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".text",
+ flags);
+ if (imx_textsec (abfd) == NULL)
+ goto fail;
+
+ if (dcd_length)
+ {
+ flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS + SEC_DATA + SEC_READONLY;
+ imx_dcdsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".dcd",
+ flags);
+ if (imx_dcdsec (abfd) == NULL)
+ goto fail;
+
+ imx_dcdsec (abfd)->size = dcd_length;
+
+ imx_dcdsec (abfd)->vma = ivt.dcd_ptr;
+
+ imx_dcdsec (abfd)->filepos = offset + ivt.dcd_ptr - ivt.self_ptr;
+
+ /* Align to word at least */
+ imx_dcdsec (abfd)->alignment_power = 2;
+
+ if (imx_dcdsec (abfd)->size > statbuf.st_size - imx_dcdsec (abfd)->filepos)
+ imx_dcdsec (abfd)->size = statbuf.st_size - imx_dcdsec (abfd)->filepos;
+ }
+
+ imx_textsec (abfd)->size = bd.image_len;
+
+ imx_textsec (abfd)->vma = ivt.start_addr;
+
+ imx_textsec (abfd)->filepos = offset + ivt.start_addr - ivt.self_ptr;
+
+ /* Align to word at least */
+ imx_textsec (abfd)->alignment_power = 2;
+
+ if (imx_textsec (abfd)->size > statbuf.st_size - imx_textsec (abfd)->filepos)
+ imx_textsec (abfd)->size = statbuf.st_size - imx_textsec (abfd)->filepos;
+
+ bfd_default_set_arch_mach (abfd, bfd_arch_arm, 0L);
+ return abfd->xvec;
+
+ fail:
+ bfd_release (abfd, abfd->tdata.any);
+ abfd->tdata.any = NULL;
+ bfd_section_list_clear (abfd);
+ return NULL;
+}
+
+/* If somebody calls any byte-swapping routines, shoot them. */
+static void
+swap_abort (void)
+{
+ abort (); /* This way doesn't require any declaration for ANSI to fuck up */
+}
+
+#define NO_GET ((bfd_vma (*) (const void *)) swap_abort)
+#define NO_PUT ((void (*) (bfd_vma, void *)) swap_abort)
+#define NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort)
+#define NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort)
+#define NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort)
+#define NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort)
+
+const bfd_target arm_imx_boot_vec =
+ {
+ "arm-imx-boot",
+ bfd_target_unknown_flavour,
+ BFD_ENDIAN_LITTLE, /* target byte order */
+ BFD_ENDIAN_LITTLE, /* target headers byte order */
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+ (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
+ | SEC_RELOC | SEC_HAS_CONTENTS), /* section_flags */
+ 0, /* symbol prefix */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ 0, /* match priority. */
+ NO_GET64, NO_GETS64, NO_PUT64, /* 64 bit data */
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32, /* 32 bit data */
+ NO_GET, NO_GETS, NO_PUT, /* 16 bit data */
+ NO_GET64, NO_GETS64, NO_PUT64, /* 64 bit hdrs */
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32, /* 32 bit hdrs */
+ NO_GET, NO_GETS, NO_PUT, /* 16 bit hdrs */
+
+ { /* bfd_check_format */
+ _bfd_dummy_target, /* unknown format */
+ imx_file_p, /* object file */
+ _bfd_dummy_target, /* archive */
+ imx_file_p /* a imx6 bootable file */
+ },
+ { /* bfd_set_format */
+ bfd_false, bfd_false,
+ bfd_false, bfd_false
+ },
+ { /* bfd_write_contents */
+ bfd_false, bfd_false,
+ bfd_false, bfd_false
+ },
+
+ BFD_JUMP_TABLE_GENERIC (_bfd_generic),
+ BFD_JUMP_TABLE_COPY (_bfd_generic),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+ BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
+ BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+ BFD_JUMP_TABLE_WRITE (_bfd_generic),
+ BFD_JUMP_TABLE_LINK (_bfd_nolink),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ NULL,
+
+ NULL /* backend_data */
+ };
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 3886adc..8bc9fbb 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6452,6 +6452,7 @@ struct bfd
union
{
struct aout_data_struct *aout_data;
+ struct arm_imx_boot_data_struct *arm_imx_boot_data;
struct artdata *aout_ar_data;
struct _oasys_data *oasys_obj_data;
struct _oasys_ar_data *oasys_ar_data;
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 8b60911..bfe7a59 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -264,6 +264,7 @@ CODE_FRAGMENT
. union
. {
. struct aout_data_struct *aout_data;
+. struct arm_imx_boot_data_struct *arm_imx_boot_data;
. struct artdata *aout_ar_data;
. struct _oasys_data *oasys_obj_data;
. struct _oasys_ar_data *oasys_ar_data;
diff --git a/bfd/targets.c b/bfd/targets.c
index 81a3695..642c2ed 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -595,6 +595,7 @@ extern const bfd_target arm_elf32_symbian_be_vec;
extern const bfd_target arm_elf32_symbian_le_vec;
extern const bfd_target arm_elf32_vxworks_be_vec;
extern const bfd_target arm_elf32_vxworks_le_vec;
+extern const bfd_target arm_imx_boot_vec;
extern const bfd_target arm_pe_be_vec;
extern const bfd_target arm_pe_le_vec;
extern const bfd_target arm_pe_epoc_be_vec;
@@ -988,6 +989,7 @@ static const bfd_target * const _bfd_target_vector[] =
&arm_elf32_symbian_le_vec,
&arm_elf32_vxworks_be_vec,
&arm_elf32_vxworks_le_vec,
+ &arm_imx_boot_vec,
&arm_pe_be_vec,
&arm_pe_le_vec,
&arm_pe_epoc_be_vec,
--
1.8.1.4