diff --git a/Documentation/user/imd.rst b/Documentation/user/imd.rst new file mode 100644 index 0000000..e0251d6 --- /dev/null +++ b/Documentation/user/imd.rst @@ -0,0 +1,54 @@ + +.. _imd: + +Image MetaData (IMD) +==================== + +barebox images can be enriched with metadata. This is useful to get information +the board an image is compiled for and which barebox version an image contains. + +There are predefined tags for: + +- The build timestamp +- The barebox release version +- The model (board) the image is compiled for +- The toplevel device tree compatible properties the image can handle + +Additionally there is a generic key/value tag to add information which does not +fit into the above categories, for example the memory size for boards which come +with different memory sizes which can't be automatically detected. + +The informations can be extracted with the ``bareboximd`` tool which lives under +``scripts/`` in the barebox sourcecode. If enabled it is compiled for the compile +host and also for the target architecture. barebox itself has the :ref:`command_imd` +command to extract the informations. Here is an example output of the tool called +without additional options:: + + # imd barebox-phytec-pbab01dl-1gib.img + build: #890 Wed Jul 30 16:15:24 CEST 2014 + release: 2014.07.0-00167-ge6632a9-dirty + parameter: memsize=1024 + of_compatible: phytec,imx6x-pbab01 phytec,imx6dl-pfla02 fsl,imx6dl + model: Phytec phyFLEX-i.MX6 Duallite Carrier-Board + +Single informations can be extracted with the ``-t `` option:: + + # imd barebox-phytec-pbab01dl-1gib.img -t release + 2014.07.0-00167-ge6632a9-dirty + +Since the barebox hush does not have output redirection the barebox too has the +``-s `` option to assign the output to a variable for later evaluation. + +Limitations +----------- + +The IMD tags are generated in the barebox binary before a SoC specific image is +generated. Some SoCs encrypt or otherwise manipulate the images in a way that the +IMD information is lost. The IMD mechanism does not work on these SoCs. A known +example is the Freescale i.MX28. + +IMD and barebox_update +---------------------- + +The IMD informations could well be used to check if an image is suitable for updating +barebox for a particular board. Support for such a check is planned but not yet implemented. diff --git a/Documentation/user/updating.rst b/Documentation/user/updating.rst index 2a963b6..6a1a733 100644 --- a/Documentation/user/updating.rst +++ b/Documentation/user/updating.rst @@ -27,3 +27,6 @@ available for your board. It is recommended to implement it, but you can also update barebox manually using :ref:`command_erase` and :ref:`command_cp` commands. The exact commands are board specific. + +**NOTE** barebox images can be enriched with metadata which can be used to check +if a given image is suitable for updating barebox, see :ref:`imd`. diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst index 0eac0aa..3d68bbb 100644 --- a/Documentation/user/user-manual.rst +++ b/Documentation/user/user-manual.rst @@ -19,6 +19,7 @@ hush defaultenv-2 updating + imd devicetree pbl multi-image diff --git a/arch/arm/boards/freescale-mx53-qsb/lowlevel.c b/arch/arm/boards/freescale-mx53-qsb/lowlevel.c index 51b9ef8..7d1c1d5 100644 --- a/arch/arm/boards/freescale-mx53-qsb/lowlevel.c +++ b/arch/arm/boards/freescale-mx53-qsb/lowlevel.c @@ -2,6 +2,7 @@ #include #include #include +#include extern char __dtb_imx53_qsb_start[]; diff --git a/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c b/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c index 55aae00..1d08f05 100644 --- a/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c +++ b/arch/arm/boards/phytec-phyflex-imx6/lowlevel.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,11 @@ extern char __dtb_imx6dl_phytec_pbab01_start[]; extern char __dtb_imx6s_phytec_pbab01_start[]; +BAREBOX_IMD_TAG_STRING(phyflex_mx6_memsize_512M, IMD_TYPE_PARAMETER, "memsize=512", 0); +BAREBOX_IMD_TAG_STRING(phyflex_mx6_memsize_1G, IMD_TYPE_PARAMETER, "memsize=1024", 0); +BAREBOX_IMD_TAG_STRING(phyflex_mx6_memsize_2G, IMD_TYPE_PARAMETER, "memsize=2048", 0); +BAREBOX_IMD_TAG_STRING(phyflex_mx6_memsize_4G, IMD_TYPE_PARAMETER, "memsize=4096", 0); + ENTRY_FUNCTION(start_phytec_pbab01_1gib, r0, r1, r2) { void *fdt; @@ -65,6 +71,8 @@ arm_setup_stack(0x00920000 - 8); + IMD_USED(phyflex_mx6_memsize_1G); + if (IS_ENABLED(CONFIG_DEBUG_LL)) setup_uart(); @@ -81,6 +89,8 @@ arm_setup_stack(0x00920000 - 8); + IMD_USED(phyflex_mx6_memsize_2G); + if (IS_ENABLED(CONFIG_DEBUG_LL)) setup_uart(); @@ -97,6 +107,8 @@ arm_setup_stack(0x00920000 - 8); + IMD_USED(phyflex_mx6_memsize_4G); + fdt = __dtb_imx6q_phytec_pbab01_start - get_runtime_offset(); barebox_arm_entry(0x10000000, 0xEFFFFFF8, fdt); @@ -110,6 +122,8 @@ arm_setup_stack(0x00920000 - 8); + IMD_USED(phyflex_mx6_memsize_1G); + fdt = __dtb_imx6dl_phytec_pbab01_start - get_runtime_offset(); barebox_arm_entry(0x10000000, SZ_1G, fdt); @@ -123,6 +137,8 @@ arm_setup_stack(0x00920000 - 8); + IMD_USED(phyflex_mx6_memsize_512M); + fdt = __dtb_imx6s_phytec_pbab01_start - get_runtime_offset(); barebox_arm_entry(0x10000000, SZ_512M, fdt); diff --git a/arch/arm/boards/tqma53/lowlevel.c b/arch/arm/boards/tqma53/lowlevel.c index 0a67228..cd87212 100644 --- a/arch/arm/boards/tqma53/lowlevel.c +++ b/arch/arm/boards/tqma53/lowlevel.c @@ -5,6 +5,7 @@ #include #include #include +#include extern char __dtb_imx53_mba53_start[]; @@ -34,6 +35,8 @@ imx53_barebox_entry(fdt); } +BAREBOX_IMD_TAG_STRING(tqma53_memsize_512M, IMD_TYPE_PARAMETER, "memsize=512", 0); + ENTRY_FUNCTION(start_imx53_mba53_512mib, r0, r1, r2) { void *fdt; @@ -42,6 +45,8 @@ arm_setup_stack(0xf8020000 - 8); + IMD_USED(tqma53_memsize_512M); + imx53_init_lowlevel_early(800); fdt = __dtb_imx53_mba53_start - get_runtime_offset(); @@ -49,6 +54,8 @@ start_imx53_tqma53_common(fdt); } +BAREBOX_IMD_TAG_STRING(tqma53_memsize_1G, IMD_TYPE_PARAMETER, "memsize=1024", 0); + ENTRY_FUNCTION(start_imx53_mba53_1gib, r0, r1, r2) { void *fdt; @@ -57,6 +64,8 @@ arm_setup_stack(0xf8020000 - 8); + IMD_USED(tqma53_memsize_1G); + imx53_init_lowlevel_early(800); fdt = __dtb_imx53_mba53_start - get_runtime_offset(); diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S index d958873..bb0354a 100644 --- a/arch/arm/lib/barebox.lds.S +++ b/arch/arm/lib/barebox.lds.S @@ -75,6 +75,8 @@ . = ALIGN(4); .data : { *(.data*) } + .barebox_imd : { BAREBOX_IMD } + . = .; __barebox_cmd_start = .; .barebox_cmd : { BAREBOX_CMDS } diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S index 76184a0..9afee29 100644 --- a/arch/arm/lib/pbl.lds.S +++ b/arch/arm/lib/pbl.lds.S @@ -54,6 +54,8 @@ . = ALIGN(4); .rodata : { *(.rodata*) } + .barebox_imd : { BAREBOX_IMD } + _etext = .; /* End of text and rodata section */ . = ALIGN(4); diff --git a/commands/Kconfig b/commands/Kconfig index 61816f5..96f27ad 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -148,6 +148,15 @@ Show information about iomem/ioport usage. Pendant to 'cat /proc/iomem' and 'cat /proc/ioports' under Linux. +config CMD_IMD + tristate + prompt "imd" + select IMD + help + barebox images can have metadata in them which contains information + like the barebox version and the build time. Say yes here to get the + imd command which can extract that information from images. + config CMD_MEMINFO tristate prompt "meminfo" diff --git a/commands/Makefile b/commands/Makefile index d42aca5..4474136 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -100,3 +100,4 @@ obj-$(CONFIG_CMD_2048) += 2048.o obj-$(CONFIG_CMD_REGULATOR) += regulator.o obj-$(CONFIG_CMD_LSPCI) += lspci.o +obj-$(CONFIG_CMD_IMD) += imd.o diff --git a/commands/imd.c b/commands/imd.c new file mode 100644 index 0000000..f1a22ce --- /dev/null +++ b/commands/imd.c @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2014 Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 2 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. + * + */ + +#include +#include +#include +#include +#include + +int imd_command_setenv(const char *variable_name, const char *value) +{ + return setenv(variable_name, value); +} + +static int do_imd(int argc, char *argv[]) +{ + int ret; + + ret = imd_command(argc, argv); + + if (ret == -ENOSYS) + return COMMAND_ERROR_USAGE; + + return ret; +} + +BAREBOX_CMD_HELP_START(imd) +BAREBOX_CMD_HELP_TEXT("extract metadata from barebox binary") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-t ", "only show information of ") +BAREBOX_CMD_HELP_OPT ("-n ", "for tags with multiple strings only show string ") +BAREBOX_CMD_HELP_OPT ("-s VARNAME", "set variable VARNAME instead of showing information") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Without options all information available is printed. Valid types are:") +BAREBOX_CMD_HELP_TEXT("release, build, model, of_compatible") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(imd) + .cmd = do_imd, + BAREBOX_CMD_DESC("extract metadata from barebox binary") + BAREBOX_CMD_OPTS("[nst] FILE") + BAREBOX_CMD_GROUP(CMD_GRP_INFO) + BAREBOX_CMD_HELP(cmd_imd_help) +BAREBOX_CMD_END diff --git a/common/Kconfig b/common/Kconfig index bba7f15..7ca60f2 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -457,6 +457,13 @@ on a device and it allows the Operating System to install / update kernels. +config IMD + bool "barebox metadata support" + +config IMD_TARGET + bool "build bareboximd target tool" + depends on IMD + config KERNEL_INSTALL_TARGET bool depends on !SANDBOX diff --git a/common/Makefile b/common/Makefile index 204241c..64c26be 100644 --- a/common/Makefile +++ b/common/Makefile @@ -43,7 +43,9 @@ obj-$(CONFIG_SHELL_HUSH) += hush.o obj-$(CONFIG_SHELL_SIMPLE) += parser.o obj-$(CONFIG_UIMAGE) += image.o uimage.o -obj-$(CONFIG_MENUTREE) += menutree.o +obj-$(CONFIG_MENUTREE) += menutree.o +lwl-$(CONFIG_IMD) += imd-barebox.o +obj-$(CONFIG_IMD) += imd.o quiet_cmd_pwd_h = PWDH $@ ifdef CONFIG_PASSWORD diff --git a/common/imd-barebox.c b/common/imd-barebox.c new file mode 100644 index 0000000..e9cd37d --- /dev/null +++ b/common/imd-barebox.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +/* + * Mark a imd entry as used so that the linker cannot + * throw it away. + */ +void imd_used(const void *used) +{ +} + +struct imd_header imd_start_header +__BAREBOX_IMD_SECTION(.barebox_imd_start) = { + .type = cpu_to_le32(IMD_TYPE_START), +}; + +struct imd_header imd_end_header +__BAREBOX_IMD_SECTION(.barebox_imd_end) = { + .type = cpu_to_le32(IMD_TYPE_END), +}; + +BAREBOX_IMD_TAG_STRING(imd_build_tag, IMD_TYPE_BUILD, UTS_VERSION, 1); +BAREBOX_IMD_TAG_STRING(imd_release_tag, IMD_TYPE_RELEASE, UTS_RELEASE, 1); diff --git a/common/imd.c b/common/imd.c new file mode 100644 index 0000000..2c837d6 --- /dev/null +++ b/common/imd.c @@ -0,0 +1,322 @@ +/* + * (C) Copyright 2014 Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 2 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. + * + */ +#ifdef __BAREBOX__ +#include +#include +#include +#include +#include +#include +#endif + +/* + * imd_next - return a pointer to the next metadata field. + * @imd The current metadata field + */ +struct imd_header *imd_next(struct imd_header *imd) +{ + int length; + + length = imd_read_length(imd); + length = ALIGN(length, 4); + length += 8; + + return (void *)imd + length; +} + +struct imd_header *imd_find_type(struct imd_header *imd, uint32_t type) +{ + imd_for_each(imd, imd) + if (imd_read_type(imd) == type) + return imd; + + return NULL; +} + +static int imd_next_validate(void *buf, int bufsize, int start_ofs) +{ + int length, size; + struct imd_header *imd = buf + start_ofs; + + size = bufsize - start_ofs; + + if (size < 8) { + debug("trunkated tag at offset %dd\n", start_ofs); + return -EINVAL; + } + + length = imd_read_length(imd); + length = ALIGN(length, 4); + length += 8; + + if (size < length) { + debug("tag at offset %d with size %d exceeds bufsize %d\n", + start_ofs, size, bufsize); + return -EINVAL; + } + + debug("tag at offset %d has length %d\n", start_ofs, length); + + return length; +} + +static int imd_validate_tags(void *buf, int bufsize, int start_ofs) +{ + int ret; + struct imd_header *imd = buf + start_ofs; + + while (1) { + uint32_t type; + + ret = imd_next_validate(buf, bufsize, start_ofs); + if (ret < 0) { + debug("Invalid tag at offset %d\n", start_ofs); + return -EINVAL; + } + + imd = (void *)imd + ret; + start_ofs += ret; + + type = imd_read_type(imd); + + if (!imd_type_valid(type)) { + debug("Invalid: tag: 0x%08x\n", type); + return -EINVAL; + } + + if (type == IMD_TYPE_END) + return 0; + } +} + +/* + * imd_search_validate - find valid metadata in a buffer + * @buf the buffer + * @size buffer size + * @start The returned pointer to the metadata + * + * This iterates over a buffer and searches for metadata. The metadata + * is checked for consistency (length fields not exceeding buffer and + * presence of end header) and returned in @start. The returned pointer + * is only valid when 0 is returned. The returned data may be unaligned. + */ +static int imd_search_validate(void *buf, int size, struct imd_header **start) +{ + int start_ofs = 0; + int i, ret; + + for (i = start_ofs; i < size - 32; i++) { + uint32_t type; + + type = imd_read_le32(buf + i); + + if (type != IMD_TYPE_START) + continue; + + debug("Start tag found at offset %d\n", i); + + ret = imd_validate_tags(buf, size, i); + if (!ret) { + *start = buf + i; + return 0; + } + } + + return -EINVAL; +} + +struct imd_type_names { + uint32_t type; + const char *name; +}; + +static struct imd_type_names imd_types[] = { + { + .type = IMD_TYPE_RELEASE, + .name = "release", + }, { + .type = IMD_TYPE_BUILD, + .name = "build", + }, { + .type = IMD_TYPE_MODEL, + .name = "model", + }, { + .type = IMD_TYPE_PARAMETER, + .name = "parameter", + }, { + .type = IMD_TYPE_OF_COMPATIBLE, + .name = "of_compatible", + }, +}; + +static const char *imd_type_to_name(uint32_t type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(imd_types); i++) + if (imd_types[i].type == type) + return imd_types[i].name; + + return "unknown"; +} + +static uint32_t imd_name_to_type(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(imd_types); i++) + if (!strcmp(imd_types[i].name, name)) + return imd_types[i].type; + + return IMD_TYPE_INVALID; +} + +static char *imd_string_data(struct imd_entry_string *imd_string, int index) +{ + int i, total = 0, l = 0; + int len = imd_read_length(&imd_string->header); + char *p = imd_string->data; + + for (i = 0; total < len; total += l, p += l) { + l = strlen(p) + 1; + if (i++ == index) + return p; + } + + return NULL; +} + +static char *imd_concat_strings(struct imd_entry_string *imd_string) +{ + int i, len = imd_read_length(&imd_string->header); + char *str; + + str = malloc(len); + if (!str) + return NULL; + + memcpy(str, imd_string->data, len); + + for (i = 0; i < len - 1; i++) + if (str[i] == 0) + str[i] = ' '; + + return str; +} + +int imd_command_verbose; + +int imd_command(int argc, char *argv[]) +{ + int ret, opt, strno = -1; + void *buf; + size_t size; + uint32_t type = IMD_TYPE_INVALID; + struct imd_header *imd_start, *imd; + const char *filename; + const char *variable_name = NULL; + char *str; + + imd_command_verbose = 0; + + while ((opt = getopt(argc, argv, "vt:s:n:")) > 0) { + switch(opt) { + case 't': + type = imd_name_to_type(optarg); + if (type == IMD_TYPE_INVALID) { + fprintf(stderr, "no such type: %s\n", optarg); + return -ENOSYS; + } + break; + case 's': + variable_name = optarg; + break; + case 'v': + imd_command_verbose = 1; + break; + case 'n': + strno = simple_strtoul(optarg, NULL, 0); + break; + default: + return -ENOSYS; + } + } + + if (optind == argc) { + fprintf(stderr, "No image given\n"); + return -ENOSYS; + } + + filename = argv[optind]; + + ret = read_file_2(filename, &size, &buf, 0x100000); + if (ret && ret != -EFBIG) + return -errno; + + ret = imd_search_validate(buf, size, &imd_start); + if (ret) + return ret; + + if (type == IMD_TYPE_INVALID) { + imd_for_each(imd_start, imd) { + uint32_t type = imd_read_type(imd); + + if (imd_is_string(type)) { + struct imd_entry_string *imd_string = + (struct imd_entry_string *)imd; + + str = imd_concat_strings(imd_string); + + printf("%s: %s\n", imd_type_to_name(type), str); + } else { + debug("Unknown tag 0x%08x\n", type); + } + } + } else { + imd = imd_find_type(imd_start, type); + if (!imd) { + debug("No tag of type 0x%08x found\n", type); + return -ENODATA; + } + + if (imd_is_string(type)) { + struct imd_entry_string *imd_string = + (struct imd_entry_string *)imd; + + if (strno >= 0) + str = imd_string_data(imd_string, strno); + else + str = imd_concat_strings(imd_string); + + if (!str) + return -ENODATA; + + if (variable_name) + imd_command_setenv(variable_name, str); + else + printf("%s\n", str); + + if (strno < 0) + free(str); + } else { + printf("tag 0x%08x present\n", type); + } + } + + return 0; +} diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h index 5dabda3..66abff3 100644 --- a/include/asm-generic/barebox.lds.h +++ b/include/asm-generic/barebox.lds.h @@ -53,6 +53,12 @@ KEEP(*(.dtb.rodata.*)); \ __dtb_end = .; +#define BAREBOX_IMD \ + KEEP(*(.barebox_imd_start)) \ + KEEP(*(.barebox_imd_1*)) \ + *(.barebox_imd_0*) \ + KEEP(*(.barebox_imd_end)) + #if defined(CONFIG_ARCH_BAREBOX_MAX_BARE_INIT_SIZE) && \ CONFIG_ARCH_BAREBOX_MAX_BARE_INIT_SIZE < CONFIG_BAREBOX_MAX_BARE_INIT_SIZE #define MAX_BARE_INIT_SIZE CONFIG_ARCH_BAREBOX_MAX_BARE_INIT_SIZE diff --git a/include/image-metadata.h b/include/image-metadata.h new file mode 100644 index 0000000..34dae5c --- /dev/null +++ b/include/image-metadata.h @@ -0,0 +1,117 @@ +#ifndef __INCLUDE_IMAGE_METADTA_H +#define __INCLUDE_IMAGE_METADTA_H + +/* + * barebox Image MetaData (IMD) + * + * IMD is a mechanism to store metadata in barebox images. With IMD + * it's possible to extract the release, the build timestamp and the + * board type from a barebox image. + * + * Since there is no fixed place in the image suitable for all SoC image + * types the metadata can be stored anywhere in the image and is found + * by iterating over the image. The metadata starts with a start header + * and ends with an end header. All tags in between carry the payload. + * + * Make sure source files containing IMD data are compiled with lwl-y so + * that the tags end up in the PBL if one exists and in the regular image + * without PBL. + * + * The following types exist: + */ +#define IMD_TYPE_START 0x640c0001 +#define IMD_TYPE_RELEASE 0x640c8002 /* The barebox release aka UTS_RELEASE */ +#define IMD_TYPE_BUILD 0x640c8003 /* build number and timestamp (UTS_VERSION) */ +#define IMD_TYPE_MODEL 0x640c8004 /* The board name this image is for */ +#define IMD_TYPE_OF_COMPATIBLE 0x640c8005 /* the device tree compatible string */ +#define IMD_TYPE_PARAMETER 0x640c8006 /* A generic parameter. Use key=value as data */ +#define IMD_TYPE_END 0x640c7fff +#define IMD_TYPE_INVALID 0xffffffff + +/* + * The IMD header. All data is stored in little endian format in the image. + * The next header starts at the next 4 byte boundary after the data. + */ +struct imd_header { + uint32_t type; /* One of IMD_TYPE_* above */ + uint32_t datalength; /* Length of the data (exluding the header) */ +}; + +/* + * A IMD string. Set bit 15 of the IMD_TYPE to indicate the data is printable + * as string. + */ +struct imd_entry_string { + struct imd_header header; + char data[]; +}; + +static inline int imd_is_string(uint32_t type) +{ + return (type & 0x8000) ? 1 : 0; +} + +static inline int imd_type_valid(uint32_t type) +{ + return (type & 0xffff0000) == 0x640c0000; +} + +struct imd_header *imd_next(struct imd_header *imd); + +#define imd_for_each(start, imd) \ + for (imd = imd_next(start); imd_read_type(imd) != IMD_TYPE_END; imd = imd_next(imd)) + +static inline uint32_t imd_read_le32(void *_ptr) +{ + uint8_t *ptr = _ptr; + + return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); +} + +static inline uint32_t imd_read_type(struct imd_header *imd) +{ + return imd_read_le32(&imd->type); +} + +static inline uint32_t imd_read_length(struct imd_header *imd) +{ + return imd_read_le32(&imd->datalength); +} + +struct imd_header *imd_find_type(struct imd_header *imd, uint32_t type); + +extern int imd_command_verbose; +int imd_command_setenv(const char *variable_name, const char *value); +int imd_command(int argc, char *argv[]); + +#ifdef __BAREBOX__ + +#include + +#define __BAREBOX_IMD_SECTION(_section) \ + __attribute__ ((unused,section (__stringify(_section)))) \ + __attribute__((aligned(4))) + +#define BAREBOX_IMD_TAG_STRING(_name, _type, _string, _keep_if_unused) \ + const struct imd_entry_string __barebox_imd_##_name \ + __BAREBOX_IMD_SECTION(.barebox_imd_ ## _keep_if_unused ## _ ## _name) = { \ + .header.type = cpu_to_le32(_type), \ + .header.datalength = cpu_to_le32(sizeof(_string)), \ + .data = _string, \ + } + + +#ifdef CONFIG_IMD +void imd_used(const void *); +#else +static inline void imd_used(const void *unused) +{ +} +#endif + +#define IMD_USED(_name) \ + imd_used(&__barebox_imd_##_name) + +#endif /* __BAREBOX__ */ + +#endif /* __INCLUDE_IMAGE_METADTA_H */ diff --git a/scripts/Makefile b/scripts/Makefile index 9c77680..2050ec4 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -10,6 +10,7 @@ hostprogs-y += bareboxenv hostprogs-y += bareboxcrc32 hostprogs-y += kernel-install +hostprogs-$(CONFIG_IMD) += bareboximd hostprogs-$(CONFIG_KALLSYMS) += kallsyms hostprogs-$(CONFIG_ARCH_MVEBU) += kwbimage kwboot hostprogs-$(CONFIG_ARCH_NETX) += gen_netx_image @@ -29,6 +30,7 @@ targetprogs-$(CONFIG_BAREBOXENV_TARGET) += bareboxenv-target targetprogs-$(CONFIG_KERNEL_INSTALL_TARGET) += kernel-install-target targetprogs-$(CONFIG_BAREBOXCRC32_TARGET) += bareboxcrc32-target +targetprogs-$(CONFIG_IMD_TARGET) += bareboximd-target # Let clean descend into subdirs subdir- += basic kconfig setupmbr diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index b546c42..7d97d57 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -210,7 +210,7 @@ # Generate an assembly file to wrap the output of the device tree compiler quiet_cmd_dt_S_dtb = DTB $@ -cmd_dt_S_dtb = $(srctree)/scripts/gen-dtb-s $(subst -,_,$(*F)) $< > $@ +cmd_dt_S_dtb = $(srctree)/scripts/gen-dtb-s $(subst -,_,$(*F)) $< $(CONFIG_IMD) > $@ $(obj)/%.dtb.S: $(obj)/%.dtb $(srctree)/scripts/gen-dtb-s FORCE $(call if_changed,dt_S_dtb) diff --git a/scripts/bareboximd.c b/scripts/bareboximd.c new file mode 100644 index 0000000..a3622af --- /dev/null +++ b/scripts/bareboximd.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2014 Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 2 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. + * + */ + +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/image-metadata.h" + +static void debug(const char *fmt, ...) +{ + va_list ap; + + if (!imd_command_verbose) + return; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +int imd_command_setenv(const char *variable_name, const char *value) +{ + fprintf(stderr, "-s option ignored\n"); + + return -EINVAL; +} + +static int read_file_2(const char *filename, size_t *size, void **outbuf, loff_t max_size) +{ + off_t fsize; + ssize_t rsize; + int ret, fd; + void *buf; + + *size = 0; + *outbuf = NULL; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); + return -errno; + } + + fsize = lseek(fd, 0, SEEK_END); + if (fsize == -1) { + fprintf(stderr, "Cannot get size %s: %s\n", filename, strerror(errno)); + ret = -errno; + goto close; + } + + if (fsize < max_size) + max_size = fsize; + + if (lseek(fd, 0, SEEK_SET) == -1) { + fprintf(stderr, "Cannot seek to start %s: %s\n", filename, strerror(errno)); + ret = -errno; + goto close; + } + + buf = malloc(max_size); + if (!buf) { + fprintf(stderr, "Cannot allocate memory\n"); + ret = -ENOMEM; + goto close; + } + + *outbuf = buf; + while (*size < max_size) { + rsize = read(fd, buf, max_size-*size); + if (rsize == 0) { + ret = -EIO; + goto free; + } else if (rsize < 0) { + if (errno == EAGAIN) + continue; + else { + ret = -errno; + goto free; + } + } /* ret > 0 */ + buf += rsize; + *size += rsize; + } + + ret = 0; + goto close; +free: + *outbuf = NULL; + free(buf); +close: + close(fd); + return ret; +} + +static unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) +{ + return strtoul(cp, endp, base); +} + +#include "../common/imd.c" + +static void usage(const char *prgname) +{ + printf( +"Extract metadata from a barebox image\n" +"\n" +"Usage: %s [OPTIONS] FILE\n" +"Options:\n" +"-t only show information of \n" +"-n for tags with multiple strings only show string \n" +"\n" +"Without options all information available is printed. Valid types are:\n" +"release, build, model, of_compatible\n", + prgname); +} + +int main(int argc, char *argv[]) +{ + int ret; + + ret = imd_command(argc, argv); + if (ret == -ENOSYS) { + usage(argv[0]); + exit(1); + } + + if (ret) + fprintf(stderr, "%s\n", strerror(-ret)); + + return ret ? 1 : 0; +} diff --git a/scripts/gen-dtb-s b/scripts/gen-dtb-s index 44136b0..434612f 100755 --- a/scripts/gen-dtb-s +++ b/scripts/gen-dtb-s @@ -2,8 +2,46 @@ name=$1 dtb=$2 +imd=$3 echo "#include " + +le32() { + printf ".byte 0x%02x, 0x%02x, 0x%02x, 0x%02x\n" \ + $(($1 & 0xff)) \ + $((($1 >> 8) & 0xff)) \ + $((($1 >> 16) & 0xff)) \ + $((($1 >> 24) & 0xff)) +} + +FDTGET=scripts/dtc/fdtget + +if [ "$imd" = "y" ]; then + echo ".section .barebox_imd_0.${name},\"a\"" + echo ".global __imd_${name}_start" + echo "__imd_${name}_start:" + + compat=$($FDTGET -d notfound -t bi "$dtb" / compatible | sed "s^ ^,^g") + if [ "$compat" != "notfound" ]; then + + compatlen=$($FDTGET -t s "$dtb" / compatible | wc -c) + le32 0x640c8005 + le32 $compatlen + echo ".byte " $compat + echo ".balign 4" + fi + + model=$($FDTGET -d notfound -t bi "$dtb" / model | sed "s^ ^,^g") + + if [ "$model" != "notfound" ]; then + modellen=$($FDTGET -t s "$dtb" / model | wc -c) + le32 0x640c8004 + le32 $compatlen + echo ".byte " $model + echo ".balign 4" + fi +fi + echo ".section .dtb.rodata.${name},\"a\"" echo ".balign STRUCT_ALIGNMENT" echo ".global __dtb_${name}_start" @@ -12,3 +50,7 @@ echo "__dtb_${name}_end:" echo ".global __dtb_${name}_end" echo ".balign STRUCT_ALIGNMENT" + +if [ "$imd" = "y" ]; then + echo ".word __imd_${name}_start" +fi